比特币符文是比特币链上新资产发行的协议,它允许使用比特币交易来发行、铸造和转移比特币原生的数字货币。
符石 (Runestone)
符文协议的信息,称为符石(runestone),存储在比特币交易的输出UTXO中。
- 符石输出的脚本(Script PublicKey)以
OP_RETURN
开头,后面跟OP_13
,然后是0个或者多个数据推入。这些推入的数据是经过编码的128位的整数。 - 符石包含的信息,可以声明发行一个新的符文,或者铸造已经存在的符文,以及从交易的输入UTXO转移符文到输出UTXO。
- 一个交易的输出UTXO可以持有多个符文。
- 符文通过ID来唯一辨识,ID由符文发行的交易索引和区块高度组成,用文本
BLOCK:TX
来表示。比如,在第500个区块里的第20个交易发行的符文的id是500:20
。
// 符石声明 |
符石解译
从交易中解译符石包含如下步骤:
- 找到交易中锁定脚本(script pubkey)以
OP_RETURN OP_13
开头的第一个输出。 - 把接下来的数据推入合并成一个字节数组。
- 把字节数据按照小端编码解码128位的整数数组。
- 解析整数数组得到Message信息。
- 解析Mesage信息得到符石。
解译过程中有可能会得到非法的符石,即纪念碑。
// 无类型信息 |
发行 (Etching)
通过发行可以创造符文。在发行的时候可以设置符文的属性,一旦设置好了,任何人,包括发行人都不可以改变这些属性。
pub struct Etching { |
名称
符文名称由A-Z的字母组成,在1-16个字符长度之间。名字可以包含分隔符来•
增强可读性。注意,分隔符和名字唯一性不相干,只是增强可读性而已,相同字母顺序的符文,即使有不同的分隔符,都被看成是相同的。分隔符不算在符文名字的长度里。
符石的名称可以通过26进制的整数来编码:
Name | Encoding |
---|---|
A | 0 |
B | 1 |
… | … |
Y | 24 |
Z | 25 |
AA | 26 |
AB | 27 |
… | … |
AY | 50 |
AZ | 51 |
BA | 52 |
依次类推。
如果发行的时候忽略符文名称,会按照下述方式生成默认的名称:fn reserve(block: u64, tx: u32) -> Rune {
Rune(6402364363415443603228541259936211926
+ (u128::from(block) << 32 | u128::from(tx))
}
6402364363415443603228541259936211926
对应的是符文名称AAAAAAAAAAAAAAAAAAAAAAAAAA
。最开始的时候,小于AAAAAAAAAAAAAAAAAAAAAAAAAAA
及其的符文名称被锁定。新的符文名称必须在其被锁定的区块到来后才能使用。在最开始,所有的符文名称都不小于13个字符,新的符文名称在840,000区块开始解锁,这个区块也是符文协议生效的区块。在这之后,每17,500个区块周期,下一个最短的符文名称陆续被解锁。所以,在区块840,000和区块857,500之间,12字符的符文名字被解锁;在区块857,500和区块 875,000 之间,11字符的符文名字被解锁,依此类推,直到在区块1,032,500和区块1,050,000之间,1个字符的符文名字被解锁。
为了防止提前发布发行交易,如果一个非预留名称的符文被发行,发行的交易中必须包含一个已经提交的符文名称证明。这个证明需要在输入的见证中包含一个以小端整数编码的符文名称,而这个输入花费的输出必须要有6个以上的区块链确认。如果不存在这样的一个证明,那么发行会被认为无效。
可分性
可分性定义了符文的原子大小。可分性表示为符文数量中小数点后允许的位数。可分性为0的符文不可以被细分;可分性为1的符文可以被细分为10个原子单位;可分性为1的符文可以被细分为100个原子单位,一次类推。
符号
符文的货币符号是一个单独的Unicode编码,比如$
,⧉
,或者🧿
,在符文数量的后面展示。
一个可分性为2的符号为🧿
的符文的101个原子货币表示为 1.01🧿
。
如果一个符文没定义符号,默认的符号是通用货币符号¤
,这个符号也称为圣甲虫。
预铸造
发行符文的时候可以把供应量的部分预留给发行人,这个称为预铸造。
条款(Terms)
pub struct Terms { |
符文可以公开铸造,允许任何人去获取一部分供应。公开铸造涉及到条款,条款在发行的时候来指定。
只有在所有条款都满足的条件下才可以铸造,任何一个条款不满足的情况下铸造终止。比如,一个铸造可以要求在某个起始区块和某个终止区块内进行,并且设定了铸造次数的上限。那么,只有在这两个区块之间,并且铸造次数没达到设定的上限时,铸造才可以进行。
最大铸造次数 (Cap)
一个符文可以铸造的最大次数,达到最大铸造次数后,铸造关闭。
单次铸造量 (Amount)
每个铸造创造固定量的货币。
开始区块 (Start Height)
铸造从该区块开始
结束区块 (End Height)
在该区块及之后的区块,铸造都不能进行
开始区块偏移 (Start Offset)
指定符文可以开始铸造的相对区块,相对于符文被发行的区块而言。
结束区块偏移 (End Offset)
指定服务不可以铸造的相对区块,相对于符文被发行的区块而言
下面是发行的代码实现。
// 发行 rune |
铸造 (Minting)
当一个符文可以公开铸造时,任何人都可以通过铸造交易创造固定量的该符文的新货币。
- 符石通过在
Mint
字段指定符文ID来铸造符文。 - 如果铸造是公开的,铸造的符文会加到交易输入的未分配符文中。
- 这些符文可以使用
edicts
来进行转移,否则的话,会被转移到第一个非OP_RETURN
输出,或者使用Pointer
字段来指定输出。 - 铸造可以在发行后在任意的交易里进行,包括在发行的区块。
下面是铸造的代码实现。
// 铸造 |
转移 (Transfering)
当交易的输入包含符文,或者新的符文被预铸造或者公开铸造时,这些符文被转移到了交易的输出。符文石中的法令Edicts
负责定义输入如何转移到输出。
法令 (Edicts)
一个符文石可以包含任意数量的法令。法令由符文ID,符文数量以及一个输出数量组成。法令按顺序进行处理,将未分配的符文分配到交易输出。
pub struct Edict { |
符文ID中的区块高度和交易索引都采用增量编码。法令中的第一个符文ID的区块高度是绝对高度,接下来的ID编码分别是和上个ID的差值。如果差值为0,交易ID的索引也为差值,否则就是绝对索引。
下面是一个包含4个法令的例子:
block | TX | amount | output |
---|---|---|---|
10 | 5 | 5 | 1 |
50 | 1 | 25 | 4 |
10 | 7 | 1 | 8 |
10 | 5 | 10 | 3 |
首先对法令按照区块高度和交易索引进行排序:
block | TX | amount | output |
---|---|---|---|
10 | 5 | 5 | 1 |
10 | 5 | 10 | 3 |
10 | 7 | 1 | 8 |
50 | 1 | 25 | 4 |
接着进行增量编码:
block | TX | amount | output |
---|---|---|---|
10 | 5 | 5 | 1 |
0 | 0 | 10 | 3 |
0 | 2 | 1 | 8 |
50 | 1 | 25 | 4 |
下面是符文转移的一些规则:
- 如果一个法令分配了大于未分配状态的符文,
amount
会被缩减为可分配的最大数量。 - 在发行符文的时候还不知道符文的ID,因此可以用
0:0
来表示当前交易里发行的符文。 - 指令中如果
amount
指定为0,那么会分配所有的未分配符文。 - 指令中
output
如果等于输出utxo数量,会按次序给每个非OP_RETURN
输出分配amount
数量的符文。 - 指令中如果
amount
指定为0,output
等于utxo数量,会把该符文平均分配给每一个非OP_RETURN
的输出。如果符文不可整除的话,前面R个输出会多1个符文,R是未分配符文除以非OP_RETURN
输出的取余。 - 如果任何指令的符文ID
block
为0,且tx
大于0,或者output
大于交易输出utxo个数,这个符石被称为纪念碑。 - 注意到,纪念碑中的指令不会被处理,交易中的所有输入符文都将被燃烧。
指针 (Pointer)
处理完所有法令后,剩余的未分配符文将传输到交易的第一个非 OP_RETURN
输出。符石可以选择包含一个指针替代默认输出的指针。
燃烧 (Burning)
可以通过使用法令或指针将符文传输到OP_RETURN
输出来燃烧符文。
纪念碑
符石可能因多种原因而出现格式错误,包括符石OP_RETURN
中的非推送数据操作码、无效的变体或无法识别的符石字段等,格式错误的符文石称为纪念碑.
在包含纪念碑的交易中的符文会被烧毁。在包含纪念碑的交易中蚀刻的符文被设置为不可铸造。在包含纪念碑的交易中的铸币计入铸币上限,但铸造的符文会被烧毁。
纪念碑是一种升级机制,允许符文被赋予新的语义,从而改变符文的创建和传输方式,同时不会误导未升级的客户端这些符文的位置,因为未升级的客户端会看到这些符文已被烧毁。
索引符文
通过索引符文,可以快速查询某个UTXO拥有哪些符文,以及对应的数量。
// rune 索引更新结构体 |