最近在Paseo测试网上折腾Coretime,把On-demand和Bulk两种获取方式都完整跑了一遍。这个过程说简单也简单,说复杂也复杂,主要是很多细节文档里没写透,比如批量续期时的参数怎么算、按需订单失败后余额去向、以及测试网水龙头领到的代币够不够用,这些坑我都踩了一遍。这篇文章就把完整流程、命令参数、排查思路都整理出来,给后面要接Coretime的团队和开发者做个参考。
Paseo是当前Polkadot生态里最接近主网环境的测试网之一,Coretime则是中继链资源分配的新模型,替代了早期的插槽拍卖机制。对于平行链团队、基础设施运维者、以及做区块服务开发的工程师来说,在Paseo上提前熟悉Coretime的操作流程,几乎是上线前的必修课。这篇指南会从原理讲到实际操作,再附上我实测过程中遇到的典型问题和解决方案。
1. Coretime到底是什么,为什么值得在Paseo上先跑一遍
1.1 从插槽拍卖到Coretime,资源分配逻辑发生了什么变化
在Coretime模型之前,平行链获得中继链执行资源的主要方式是插槽拍卖(Parachain Slot Auction)。团队需要锁定大量DOT参与竞拍,赢得插槽后,在固定的租赁期内(通常为6到24个月)获得持续的资源分配。这种模式最大的问题是门槛高、灵活性差——如果你的链只需要偶尔执行交易,却必须为一个长期插槽付出全额成本,资源浪费非常明显。
Coretime把中继链的计算资源拆成了更细的粒度,核心单位就是“Core”。你可以把Core理解成中继链上执行平行链区块的一个工作进程,它决定了链在某个时间段内能否被调度和验证。新模型下,获取Core的方式分成两种:
- Bulk Coretime:以月为周期批量购买一段连续时间内拥有的Core使用权,适合业务稳定、需要保证出块频率的平行链。
- On-demand Coretime:按需临时购买,按区块计费,适合低频、开发测试、或者突发流量场景,不需要长期持有。
两种模式解决的问题不同,实际操作中的参数、成本模型和失败处理也完全不一样。
1.2 为什么选Paseo作为练习场
Paseo测试网由社区和生态团队共同维护,它的运行时参数、治理流程和核心模块与主网保持了较高的一致性。相比早期的一些测试网,Paseo上的Coretime模块是可用的,而且水龙头代币获取相对容易,这意味着你可以完整体验从购买、续期到拆分的整个生命周期,而不需要像在主网上那样真的准备一大笔资金。
另一个重要原因是测试成本低。Bulk Coretime的购买需要账户有足够的余额并支付押金,On-demand则需要预存费用。在Paseo上这些花费都是测试代币,你完全可以故意制造一些错误场景,看看模块的报错和资金回收逻辑,这种试错成本在主网上是不可接受的。
2. 实操前的环境准备:账户、浏览器钱包与命令行工具
2.1 创建测试账户并获取Paseo测试币
Coretime操作本质上是一系列链上交易,所以第一步是准备一个可用账户。推荐直接用Substrate系列的浏览器钱包(如Talisman或Polkadot.js扩展),创建一个新账户,然后切换到Paseo网络。这里有个小提醒:Paseo测试网在某些钱包里可能不会默认显示,需要手动添加自定义端点。
添加自定义网络时,常见的Paseo WSS端点格式类似wss://paseo-rpc.polkadot.io,具体以官方文档或社区公告为准。添加成功后,记得复制账户地址,下一步去水龙头领测试币。测试网水龙头通常会要求你提供一个账户地址,然后定期发放一定数量的测试代币。实际操作中,我遇到过水龙头接口暂时不可用的情况,等一下再试就行,不用反复提交。
Paseo上的测试币不需要精确估算要多少,因为Coretime购买的押金和费用都可以在链上查询。但建议至少保证账户里有足够的余额用于支付交易手续费,否则后续步骤会连续报错。我的经验是领一次水龙头通常够用,如果要做多次Bulk购买测试,可能需要多领几次。
2.2 熟悉Polkadot.js Apps界面与Coretime相关面板
操作Coretime最直接的界面是Polkadot.js Apps(apps.polkadot.io),切换到Paseo网络后,左侧导航栏会有“Coretime”或“开发者”相关的菜单。早期版本里Coretime操作入口比较隐蔽,需要自己构造交易,现在导航已经清晰很多,但仍然建议你先花几分钟熟悉几个关键路径:
- 网络状态面板:查看当前Paseo上的Core数量、销售周期、价格参数。
- 链上数据查询:通过“链状态”->“coretime”模块,查询正在进行的销售、已售出的Core、区域(Region)的归属信息。
- 交易面板:通过“外部交易”(Extrinsics)构造购买、续期、拆分、转移等操作。
如果你更习惯命令行,可以安装subxt或者使用polkadot-js/api写脚本。命令行方式在自动化操作和批量处理时优势明显,尤其是后面讲到的Bulk解析和Core拆分,用界面点击反而容易出错。
2.3 安装命令行客户端与脚本依赖
我本地的操作环境是Ubuntu + Node.js,核心依赖是@polkadot/api。建议使用npm或者yarn创建一个项目目录,然后安装:
npm init -y npm install @polkadot/api这里要特别说明一下版本问题。Coretime模块在Polkadot SDK中经历了多次接口调整,@polkadot/api的版本必须与Paseo运行时的版本大致匹配。如果接口不匹配,调用时会出现类似Unable to find extrinsic或者方法签名错误的提示。解决方式是升级@polkadot/api到最新版本,或者锁定与你测试的Paseo运行时兼容的版本。
3. Bulk Coretime获取实操:从链上购买到区域解析
3.1 理解Bulk Coretime的销售周期与Region概念
Bulk Coretime的购买是以“销售周期”为单位的,一个周期通常对应一个月。在每个周期内,中继链会开放有限的Core供抢购。你购买到的不是抽象的“时间片”,而是一个被称为Region(区域)的资源对象。Region可以用坐标来描述,比如Core索引、起始区块号和结束区块号。这个坐标很重要,因为后续的续期、拆分、转移都是围绕Region进行的。
查询当前销售状态,可以用JavaScript脚本:
const { ApiPromise, WsProvider } = require('@polkadot/api'); async function main() { const provider = new WsProvider('wss://paseo-rpc.polkadot.io'); const api = await ApiPromise.create({ provider }); const saleStatus = await api.query.coretime.saleStatus(); console.log('Sale status:', saleStatus.toHuman()); const cores = await api.query.coretime.elasticCoretime(); console.log('Elastic core count:', cores.toHuman()); await provider.disconnect(); } main().catch(console.error);运行后能看到当前销售周期编号、开始区块、结束区块以及Core总数。不同时间点查询,数值会不一样,这取决于链上调度和治理参数。
3.2 通过Extrinsics购买Bulk Coretime
购买Bulk Coretime的入口是coretime.buy交易。购买时你需要指定一个regionId,这个参数看起来复杂,实际上是一个包含Core索引和时间范围的结构体。在Polkadot.js Apps中,你不需要手动构造完整结构,选择coretime.buy后,UI会引导你填写核心参数。
伪代码示意如下:
const tx = api.tx.coretime.buy( { core: 1, begin: 100, end: 10000 } ); const hash = await tx.signAndSend(alice); console.log('Bulk buy extrinsic hash:', hash.toHex());这里有几个关键点需要关注:
- 购买需要支付两部分成本:一部分是Coretime本身的价格,另一部分是保证金(deposit)。保证金在Region释放后可以退还,但如果你持有多个Region,占用的保证金也是不可忽视的资金占用。
- 不是任何时间点都能购买。只能在销售窗口内提交
buy交易,窗口外会直接报错。 - 购买成功后,你的账户会关联一个Region,这个Region可以在链上查询到。
3.3 Region的解析(Partition)与续期(Renew)
购买到Region后,最常见的操作就是解析和续期。
解析(Partition)指的是把一个大的Region拆分成多个小Region。比如你买了一个Core使用一个月的Region,但你只需要其中部分区块的时间,就可以拆成多个连续的小Region,分别用于不同的链或测试环境。拆分的交易入口是coretime.partition,需要指定原始RegionID、要分割的起始点和长度。拆分后原有Region被消耗,生成两个新Region。
续期(Renew)则需要额外注意。波兰的销售模型里,续期并不是简单的“再买一次”,而是针对当前Region在下一周期的延续权利。调用coretime.renew需要传入要续期的RegionID以及续期的Core索引。如果你持有多个Region,续期时很容易把Core索引搞混,导致续期到错误的Core上。我建议在脚本里记录每个Region的购买和续期记录,不要只靠记性。
3.4 实际购买成本如何计算
Bulk Coretime的价格不由固定费率决定,而是由链上销售机制动态计算。通常涉及一个基础价格和一个调整因子,同时实际支付金额会分摊到每个区块。我们可以查询当前销售参数来估算成本:
const params = await api.query.coretime.saleParameters(); console.log(params.toHuman());常见的关键字段包括:minPrice、minPriceThreshold等。实际操作时,你提交购买前UI会显示预估成本,但最终扣款以链上执行为准。我在测试中曾遇到过界面预估与最终扣款不一致的情况,原因是并发交易改变了链上状态,所以涉及金额的操作一定要以链上执行后的实际扣款为准,不要依赖前端显示。
4. On-demand Coretime获取实操:按需购买与订单管理
4.1 On-demand的定价逻辑与订单池机制
如果说Bulk Coretime是“包月套餐”,那On-demand就是“按次计费”。它主要服务两类场景:一是测试环境的偶发交易;二是需要即时纳入中继链的轻量级链,不需要稳定出块。On-demand Coretime按区块竞价,用户提交订单时指定最多愿意支付的价格,系统在下一个可用区块中撮合。如果出价过低,订单可能长时间无法成交,最终被取消。
这部分的核心参数有两个:maxAmount(最大支付额度)和maxSlot(最大延迟区块数)。举例来说,如果你设置maxAmount为某个数值,maxSlot为20,表示你愿意最多等20个区块,如果20个区块内没有成交,订单就失效且退费。合理设置maxSlot可以避免订单无限挂单。
4.2 提交On-demand订单的两种方式
提交On-demand订单有两种常见路径,我分别说一下适用场景。
第一种是在Apps界面直接操作。进入Extrinsics,选择onDemandOrder模块下的placeOrderAllowDeath或类似方法(具体方法名以链上模块为准),填写订单金额和最大延迟区块。这种方式的优点是零代码,适合临时测试,但缺点是参数调整不够灵活,不适合批量或自动化操作。
第二种是脚本方式,适合需要频繁提交订单或者要集成到服务的场景。示例脚本如下:
const tx = api.tx.onDemandOrder.placeOrderAllowDeath( '1000000000000', // 最大支付金额(注意精度) 10 // 最大延迟区块数 ); const hash = await tx.signAndSend(bob); console.log('On-demand order placed:', hash.toHex());这里要注意金额精度问题。Paseo测试币的小数位通常是12位,你看到界面显示1个单位代币,实际链上数值是1000000000000(1后面12个0)。我刚开始测试时没换算精度,订单金额填得极小,结果订单一直不成交,还以为是网络问题。
4.3 查询订单状态与析构处理
提交订单后,可以在链状态中查询正在等待成交的订单队列。如果长时间未成交,可以使用onDemandOrder.removeOrder来手动撤销。撤销后已支付但未消耗的金额会退回账户,但要注意可能产生少量手续费损耗,这是正常现象。
还有一个容易忽略的点:如果订单已经成交并执行了区块生产,撤销操作会失败,因为区块已经完成。判断成交与否可以通过查询成交区块高度,而不是只看钱包余额是否减少。我在测试中多次误以为订单还挂在那里,实际早已经被填充了,只是前端缓存没刷新。
4.4 On-demand的失败场景与退款周期
On-demand订单最常见的问题是余额不足和成交延迟。余额不足的场景比较好理解,交易签名时就会失败。成交延迟则是因为网络拥堵导致竞拍价格被抬高,你的出价排不上队。退款周期方面,如果是订单失效或手动撤销,退款通常在下个区块或数个区块内完成,如果长时间没有退回,需要检查是否误用了placeOrder(可能会销毁部分资金)而不是placeOrderAllowDeath。
这里有个经验之谈:测试时尽量用低maxAmount在非高峰时段操作,既能验证流程,又不用手忙脚乱地撤销订单。
5. 实操中的常见问题与排查技巧实录
5.1 交易提交成功但链上无记录
这个现象我在Paseo上遇到过不止一次。浏览器显示提交成功,但在Explorer里看不到交易,或者交易一直处于Ready状态。排查思路很明确:
- 先确认当前使用的RPC节点是否同步正常。测试网部分公共节点的同步状态并不稳定,切换到备选节点再试。
- 检查交易是否因为手续费太低被池子拒收。测试网有时也会出现交易池拥堵,适当提高手续费,或者换个签名方式(如
signAsync)再提交。 - 使用
api.rpc.author.pendingExtrinsics()查看本地交易池中是否有积压的待处理交易。
我的习惯是,遇到这类问题优先换节点,而不是反复重发交易。因为重发容易造成同一笔操作的多笔交易,后续查账时会造成干扰。
5.2 购买Bulk Coretime时提示Region不可用
这种报错通常发生在对同一个Core的同一时间段重复购买时。Coretime模块的设计保证资源不会被双花,因此如果一个Region已经被购买或已经被拆分、转移,继续对它操作就会失败。
排查时先查询该Region的当前状态:
const region = await api.query.coretime.regions(regionId); console.log(region.toHuman());返回结果是None说明Region不存在或已经消耗;返回Some则可以看到所有者、是否已经细分等信息。还有一种情况是你试图购买的时间范围被分割过,比如分给另一个测试任务了,此时再买原区域就会冲突。解决办法是换一个Core索引或调整时间范围。
5.3 领水之后余额仍然不够支付手续费
Paseo的领水机制通常每小时或每天有次数限制,而且发放数量可能只够一般的转账操作。Coretime的押金和购买费用相对较高,如果提示BalanceLow,不要怀疑是网络问题,就是余额真的不够。
此时建议做两件事:一是多领几次水龙头,但不要并发领取,否则可能被限制;二是检查账户是否需要保留最小可用余额(Existential Deposit),如果总额刚好压在最低线之下,交易会被拒绝。可以先转一笔小额测试币到另一个账户激活,再继续进行Coretime操作。
5.4 批量操作工具的选择建议
在提到批量处理Region时,很多朋友会往“文件批量重命名工具”那个方向想,其实链上资源批量管理和本地文件批处理逻辑有些类似——都是先列出所有目标,然后按规则逐项操作。对于链上批量操作,我推荐直接写脚本,用Promise.all控制并发,或者用api.tx.utility.batch把多个交易打包成一个批次提交,节省手续费并减少RPC请求次数。
const batch = api.tx.utility.batch([ api.tx.coretime.partition(regionA, ...), api.tx.coretime.partition(regionB, ...) ]); await batch.signAndSend(alice);这里有个注意事项:utility.batch中任何一个交易失败,整个批次都不会执行成功的部分(或者按batchAll逻辑回滚)。所以在测试批量操作前,建议先把单个交易全部验证通过,再组装成批次。
5.5 On-demand订单成交时间过长,怎么判断是否该撤单
判断订单是否值得等待,主要看当前链上的成交价和你的出价差距。如果差距很大,等待时长会成倍增加。一个简单的监控做法是每隔几个区块查询一下最新成交价:
const price = await api.query.onDemandOrder.expectedBlockFee(); console.log(price.toHuman());如果最新成交价接近甚至高于你的最大支付额,撤单是更合理的选择。如果成交价明显低于你的出价,那通常只是网络暂时拥堵,可以再等几个区块。
6. 从测试到上线的几点个人体会
在Paseo上完整跑完Bulk和On-demand两条路径后,我最强烈的感受是:Coretime模型对链上团队的资金规划和自动化运维能力要求明显提升了。以前插槽拍卖是“一锤子买卖”,现在则需要持续关注销售周期、Region状态、续期节点,尤其是多条平行链共用同一个账户时,Region的管理复杂度会成倍上升。
我建议准备上线主网的团队,提前把Coretime的操作流程固化成脚本,并把Region的查询、续期、拆分逻辑做成定时任务。不要等到销售窗口快关闭才手动操作,那时候RPC拥堵、手续费上涨、参数填错的风险都会集中爆发。另外,测试网上获得的经验不能原样照搬到主网,因为主网的Coretime价格、Core数量和治理参数可能不同,但流程和接口逻辑基本一致。
最后再分享一个我踩过的坑:用脚本批量提交Coretime交易时,一定要为每笔交易设置合理的nonce管理,或者使用api.derive.tx.signAndSend来处理nonce。我因为忘记处理nonce,导致连续两笔交易发生冲突,第一笔成功后第二笔反复报错,排查了好一会儿才发现是nonce被重复使用了。这种细节不实际跑一遍很难注意到,希望这篇文章能帮你少走这个弯路。