Runes 转账的 edict:代币是怎么被一条条派到输出上的 图 1
Runes 转账的 edict:代币是怎么被一条条派到输出上的 · 图 1

Runes 转账的 edict:代币是怎么被一条条派到输出上的

一笔 Runes 交易的两个世界

读 Runes 交易时会遇到两套规则。一套管比特币本身:输入输出、脚本、手续费,全部由共识决定。另一套管代币:这笔交易带着一个 Runestone,里面的 edict 列表决定“输入的 Runes 各自去哪个输出”。Bitcoin Core 只审前一套,索引器负责后一套。edict 就是两套规则之间的合同条款,写清楚它,大多数“我的币去哪了”的问题就有了确定的答案。

edict 的字段与触发方式

按规范的数据结构,Runestone 的核心是 edicts、etching、mint、pointer 四项。每条 edict 包含 rune ID、amount、output 三个概念字段;在字节层面,整数序列里一旦出现 tag 为 0 且值为 0 的项,其后的整数就被解释为四元一组的 edict 序列,依次是 rune ID 的区块高度、rune ID 的交易索引、数量、输出编号。rune ID 本身就是一对数字——这份代币被铭刻时的区块高度和那笔交易在区块里的索引,所以四元组前两项共同指名“分的是哪种币”。

分配循环的默认规则

规范的分配语义可以概括为:输入里的 Runes 先按默认规则铺在输出上——未加指引时,剩余代币跟随第一个输出(可由 Runestone 的 pointer 字段改写默认去向);然后 edict 按书写顺序逐条执行,每条从“尚未被 edict 分配掉的余额”里取出指定数量,指派给指定输出。顺序因此重要:先写的 edict 优先拿到额度,写反顺序的批量工具会产出与预期不同的分布。规范同时明确,edict 处理的是“unallocated”部分——已经被前面 edict 指派的额度不会被二次分配。

出错的代价

edict 出错分两个层级。字节层级:整数序列的 varint 不合法、载荷里混入非数据推送操作码,整块 Runestone 降级为 Cenotaph,这笔交易的 etching、mint、edict 全部作废,涉及的代币按规则销毁——这个场景前文已有专述。语义层级:edict 写得合法但指向不存在的输出编号、或者数量对不上,解析器不会按你的意图“救回”,索引器按字面执行,结果就是资金进入意料之外的输出甚至被留在默认输出。这类事故没有共识层回滚,能否追回取决于后续地址归属,多数靠不上。

实操建议

批量分发或做空投时,先把构造工具的完整输出存成文件,用 ord decode 逐条核对 edict 四元组与输出数量是否吻合;小量试发一笔、确认各索引口径到账一致,再执行剩余批次。对显示“交易失败但 Gas 已付”“交易成功币没动”的界面提示,先分清失败发生在比特币层(共识拒绝)还是 Runes 层(语义未生效),两者的排障路径完全不同。本文为机制说明,不构成任何投资建议。

整数是怎么打包的

字节层面,Runestone 载荷是 LEB128 变长整数序列——每个字节的最高位是续行标志,只有最后一字节高位为零,短数占一字节,长数自动加长。规范为这套编码划了红线:单个 varint 超过十八字节、数值溢出 u128、缓冲区在续行结束前耗尽,任一种情况都把整块 runestone 判成 cenotaph。加上载荷里混入非数据推送操作码同样出局的规则,解析变成一个非此即彼的闸门:要么完整读懂,要么整体作废,不存在读了一半将错就错的中间态。对普通用户,需要记住的配套约定是:字段按 tag 与值交替排列,重复出现的 tag 把值追加而不是覆盖;tag 序列里遇到零值,其后整数被切换为四元一组的 edict 模式。看懂这条流水线,你才知道一笔交易的 decode 报错到底出在哪一环——操作码、varint 还是字段顺序,这比在钱包界面反复刷新有用得多。

与比特币找零逻辑的对照

第一次读 edict 的人常把它类比成比特币的找零,其实两者逻辑相反。比特币找零是自动的:输入总额减去输出指定额,余额进找零输出,规则没有意志。edict 是指令性的:它明确宣布多少数量的哪种代币去哪个输出,剩余部分才按默认规则铺到第一个输出或由 pointer 改写默认。差异带来一个实操结论:Runes 交易的输出布局对代币分布的影响比比特币交易更大,因为 edict 的输出编号指的是这笔交易的输出序号,任何改变输出的操作(追加一个输出、调整找零)都可能让原本正确的编号指向错位的接收方。批量工具之所以要求你精确描述输出表,就是因为它要按同一张表同时生成比特币布局与 edict 编号。用户不需要亲手写 edict,但看懂它,才能在出错时判断是工具的表错了还是签名的单错了。