先买断未来的序列号:XRPL 票据如何解离线签名的排队难题 图 1
先买断未来的序列号:XRPL 票据如何解离线签名的排队难题 · 图 1

序列号:XRP Ledger 防重放的闸门

XRP Ledger 给每个账户维护一个严格递增的序列号(Sequence)。每成功执行一笔交易,账户序列号加一;下一笔交易必须带上恰好等于当前值的那个号,否则会被拒。这套机制顺手堵死了重放:同一笔签名交易最多生效一次,因为它绑定了唯一一次性的序列号。但代价也摆在眼前——离线签好的交易必须按号排队。一台发起端如果不知道前一笔是否已经落地,就没法给下一笔确定正确序列号,多系统并行的场景里这尤其棘手。

TicketCreate:把未来若干号一次性买断

XRP Ledger 给出的解法是票据(Ticket)。官方参考页描述的 TicketCreate 交易可以预留一批未来序列号,一次最多 250 张;创建成功的票据以账本对象形式挂在账户下,查询账户信息里的票据计数可以看到当前持有多少。它有一个相当特殊的细节:TicketCreate 是唯一一笔能让账户序列号一次跳多格的交易——序列号一次增加一加上所创建的票数。想批量留 50 个号,账户的下一个序列号会直接跳过这 50 格。失败面也明确:数量字段不合法报 temINVALID_COUNT,超过 250 张上限或撞上账户对象数量限制报 tecDIR_FULL,且整笔交易要么全部创建、要么一张都不生成,不存在部分成功。

一笔交易预留出一段未来序列号、后续签名交易按需取用

TicketSequence:签名时不猜号,改用票据顶替

预留了票据之后,真正要离线签发的交易在通用字段里填 TicketSequence,指定用哪张票据顶替序列号。官方文档对这对字段的关系写得很死:一旦提供 TicketSequence,Sequence 字段必须为 0,两者不能同时携带有效值;票据交易也不能与 AccountTxnID 字段同用——后者靠”上一笔交易哈希”把交易链起来,和票据这种乱序机制天然冲突。使用时票据本身还要求账户的常规密钥或签名方列表正常授权。票据被消费即失效,同一张票不能付两笔钱。

什么场景真的需要它

票据的典型用场是多发起端容灾与离线批量签发。主发起端与备用发起端同时在线时,谁也不知道对方会不会先抢注序列号;预先发一批票据、让两边的离线签名各绑一张,互不踩踏。签名网关(signing authority)想给客户预先签好一叠未来的支付指令,也不必锁定执行顺序。反过来,如果你的交易全部在线实时提交、单发起端、由服务器自动填充序列号,票据带来的只是额外的账本对象和一次性的创建成本,没有必要。

别把票据当成队列或定时任务

容易误读的地方在于票据不提供时间排序、不提供定时执行,它只是把”这格序列号属于我、随时可用”这个权利冻结下来;什么时候把绑定该票据的交易提交上去、以什么顺序被账本接受,仍取决于提交时机与手续费竞价。此外票据功能本身受修正案门控(TicketBatch),不同网络是否启用要在链上核验,不能想当然。评估任何”离线预签名”方案时,先问三件事:重放怎么防、多发起端怎么协调、失败的那一笔怎么补——票据只精确回答前两问的一半。

离线签名与自动填充的矛盾

XRPL 的交易里不少字段是可以由服务器或客户端库自动补全的,但官方文档同时点明:自动填充需要一条到 XRP Ledger 的活跃连接,离线状态下做不到。序列号正是典型——离线签发时你无法查询”下一个号是多少”。票据机制补的正是这个缺口:号已经在链上买断、写在账本对象里,签名方只要知道自己持有哪张票,就能在完全不联网的情况下产出一笔合法的待播交易。代价是资金效率:票据占着账户的账本对象名额、创建时要付一次性费用并受所有权储备约束,250 张的上限也决定了它是为批量场景准备的,不是给高频逐笔提交的常规路径。

风险提示:本文为机制说明,不构成投资建议;字段规则与限制值以 XRP Ledger 官方文档当前版本为准。