最近符文Runes协议是比特币生态最火的项目,于是我利用晚上的时间,把Runes协议使用Go语言实现了一遍,项目地址:https://github.com/bxelab/runestone,另外也基于这个Runestone库编写对应的一个命令行客户端在这里,基于对Runes协议的深入理解,发现网上很多项目对符文的用法是不对的,于是我这里再写一篇技术文章,详细介绍一下。大家如果要进行符文的开发,可以参考。
Etching(蚀刻)是Rune铭文协议中用于创建新符文的结构。它包含以下可选字段:
divisibility
:表示符文的可分割性。相当于ERC20中的decimal字段,小数位数。type Terms struct {undefined Amount *uint128.Uint128 //Mint一次能够铸造的数量
Cap *uint128.Uint128 //能够Mint多少次
Height 2*uint64 //允许Mint的开始高度和结束高度(绝对值)
Offset 2*uint64 //允许Mint的开始高度和结束高度(相当于发行符文的高度而言的相对值)
}因为允许预挖,而允许后续Mint,所以这个符文的发型总量就是:
预挖+Amount*Cap
符文的数采用uint128,并不是以太坊的uint256也不是比特币的uint64,所以这个符文数量也可以是很大很大的。1.2 RuneId 符文IDpremine
:预挖矿的数量。不设就表示不预挖rune
:符文的名称,以修改后的基数-26整数编码。spacers
:表示在符文名称字符之间显示的间隔符。symbol
:符文的货币符号。一个UTF8字符terms
:包含铸造条款,如数量、上限、开始和结束的区块高度。
这你需要进一步说明一下terms,其定义如下:RuneId是标识符文的唯一标识符,由区块高度和交易索引编码而成,并以BLOCK:TX
的文本形式表示。
Edict(法令)是用于转移符文的结构,包含以下字段:
id
:涉及的符文ID。amount
:转移的符文数量。output
:指定的输出索引。1.4 Runestone符文石Rune协议的消息称为Runestones,它们包含以下字段:edicts
:一个Edict(法令)的集合,用于转移Rune。etching
:一个可选的Etching(蚀刻),用于创建Rune。mint
:一个可选的RuneId,表示要铸造的Rune的ID。pointer
:一个可选的u32,指向未被Edict分配的Rune应转移至的输出。1.5 Cenotaph 墓碑Cenotaph(墓碑)是当Runestones(铭文石)不符合协议规则时产生的结构。它代表无效的铭文操作,可能导致输入的符文被销毁。也就是说如果我们定义了一个符文,但是这个符文又不满足协议规范,那么这个符文就会被标记为墓碑。
通过这些规则,Rune铭文协议确保了Rune名称的唯一性和预测性,同时也提供了一种机制来防止名称被提前抢注或滥用。这种命名规则不仅为Rune铭文协议提供了灵活性,还保证了系统的安全性和稳定性。
我们先定义了一个Etching对象,然后基于该对象构建Runestone,并使用Runestone可对其进行编码,从而得到蚀刻需要的二进制数据。示例代码如下:
runeName := "STUDYZY.GMAIL.COM"
symbol := '曾'
myRune, err := runestone.SpacedRuneFromString(runeName)
if err != nil {
fmt.Println(err)
return
}
amt := uint128.From64(666666)
ca := uint128.From64(21000000)
etching := &runestone.Etching{ //定义Etching
Rune: &myRune.Rune,
Spacers: &myRune.Spacers,
Symbol: &symbol,
Terms: &runestone.Terms{
Amount: &amt,
Cap: &ca,
},
}
r := runestone.Runestone{Etching: etching} // 构建Runestone
data, err := r.Encipher() //编码为二进制
在Rune铭文协议中,使用比特币脚本的OP_RETURN
操作码是实现Etching蚀刻内容上链的关键步骤。OP_RETURN
允许我们将特定的数据,即上面编码成二进制的符文的蚀刻信息,嵌入到比特币区块链的交易中。这些数据被永久记录在区块链上,不可篡改,为每个符文提供了一个独一无二的“印记”。
在交易的输出中使用OP_RETURN
操作码,后跟要MAGIC_NUMBER:OP_13,然后再跟蚀刻的符文信息。这些信息通常包括符文的名称、属性和其他相关数据。这笔输出不要求必须是第0号输出。
以下是构造OP_RETURN脚本的代码:
//build op_return script
builder := txscript.NewScriptBuilder()
// Push OP_RETURN
builder.AddOp(txscript.OP_RETURN)
// Push MAGIC_NUMBER
builder.AddOp(MAGIC_NUMBER)
for len(payload) > 0 {
chunkSize := txscript.MaxScriptElementSize
if len(payload) < chunkSize {
chunkSize = len(payload)
}
chunk := payload[:chunkSize]
builder.AddData(chunk)
payload = payload[chunkSize:]
}
return builder.Script()
在Rune铭文协议中,为了确保蚀刻的合法性和防止抢跑攻击(Front-running),引入了TapScript和Commitment承诺的概念。TapScript是比特币的Taproot结构的一部分,提供了一种更高效和更隐私的交易格式。
func (r Rune) Commitment() []byte {
bytes := r.Value.Big().Bytes()
// Reverse bytes to get little-endian representation
for i, j := 0, len(bytes)-1; i < j; i, j = i+1, j-1 {
bytes[i], bytes[j] = bytes[j], bytes[i]
}
end := len(bytes)
for end > 0 && bytes[end-1] == 0 {
end--
}
return bytes[:end]
}
接下来我们就可以将TapScript构建出来:
func CreateCommitmentScript(pk \*btcec.PublicKey, commitment []byte) ([]byte, error) {
builder := txscript.NewScriptBuilder()
//push pubkey
pk32 := schnorr.SerializePubKey(pk)
builder.AddData(pk32)
builder.AddOp(txscript.OP\_CHECKSIG)
//Commitment script
builder.AddOp(txscript.OP\_FALSE)
builder.AddOp(txscript.OP\_IF)
builder.AddData(commitment)
builder.AddOp(txscript.OP\_ENDIF)
return builder.Script()
}
P2TR(Pay-to-Taproot)交易是一种比特币交易格式,它利用了Taproot结构来提高交易的效率和隐私性。无论是之前的Ordinals协议,BRC20或者是现在的Rune铭文,都是基于P2TR交易。在前面3.1.和3.2步骤中,我们已经构造好了我们要蚀刻铭文的TapScript了,那么接下来就需要给这个脚本对应的地址转移一定数量的BTC(这个交易就叫Commit Transaction提交交易),然后等提交交易上链成功后,等确认数>=6,则我们可以发起Reverse Transaction揭示交易,在这笔交易中才包含了3.2的TapScript和3.1的OP_RETURN。
这笔交易就是一笔普通的转载交易,给TapScript所对应的P2TR地址转一定数量的BTC。注意不要太少,不然可能第二笔揭示交易的时候手续费不够。
提交交易被广播到网络并被包含在一个区块中后,不能立即揭示该蚀刻的详细信息。
必须等待至少6个区块被矿工挖出,这个时间间隔提供了一个观察期,确保提交的蚀刻交易被网络接受,并且没有其他冲突的交易。
在观察期过后,可以创建第二笔交易来揭示蚀刻的详细信息,包括符文的确切名称和其他可能在提交阶段未公开的属性。
揭示交易通常也会包含一个OP_RETURN输出,将蚀刻的详细信息编码为一个数据推送(Data Push)。
这两笔交易共同完成了一个符文的创建和上链过程。第一笔交易确保了名称的安全性和所有权,而第二笔交易则向网络揭示了该符文的全部细节。
通过这种方式,Rune铭文协议不仅保护了创建者的利益,防止了名称被抢注,还确保了网络中的所有参与者都能验证和接受新创建的符文。
通过这种分阶段的交易过程,Rune铭文协议实现了一种安全且透明的方式来引入新的符文到区块链中。这种机制提高了整个系统的可靠性,并且为未来的扩展和协议更新提供了灵活性。
如果我们蚀刻的符文允许Mint,满足Mint的要求(没有被Mint完,Mint高度满足要求等),那么我们可以通过构造一笔Mint交易来铸造已蚀刻定义的符文。
符文的Etching蚀刻在3.3揭示交易中上链到比特币网络,上链的区块高度和该揭示交易所在区块的交易索引值共同构成了符文的唯一标识:RuneId。我们使用 {区块高度}:{揭示交易索引值} 来标识将要铸造的符文,确保其唯一性。我们可以使用Runestone对符文ID进行编码,代码为:
runeIdStr := "2609649:946" //你要Mint的符文ID
runeId, _ := runestone.RuneIdFromString(runeIdStr)
r := runestone.Runestone{Mint: runeId}
data, err := r.Encipher()
与蚀刻类似,使用OP_RETURN
将铸造(Mint)操作记录在区块链上。不同之处在于,我们Mint的时候不再需要P2TR交易,也就是说,我们只需要一笔普通转账交易即可,而不是构造两笔交易。
Runes协议的发明人在发布符文时也在代码中硬编码预定义了一个符文:UNCOMMON•GOODS,这个符文大家都可以挖,其符文ID是:1:0,每个交易挖出一个。
在Rune铭文协议中,符文的转移是通过所谓的“法令”(Edict)来实现的,这是一种特殊的结构,用于指定如何将符文从一个所有者转移到另一个所有者。以下是符文转移过程的详细步骤和规则:
每个Edict包含三个主要字段:
id
:指定要转移的符文的ID。amount
:要转移的符文数量。output
:指定接收转移符文的输出索引。Edict的设计允许在一个Runestones中包含多个法令,从而在一个比特币交易中实现多种符文的同时转移。
runeId1, _ := runestone.RuneIdFromString("2755031:186")
runeId2, _ := runestone.RuneIdFromString("2609649:946")
r := runestone.Runestone{Edicts: []runestone.Edict{
{
ID: *runeId1,
Amount: uint128.From64(1000),
Output: 1,
},
{
ID: *runeId2,
Amount: uint128.From64(100),
Output: 1,
},
}}
data, err := r.Encipher() //Delta编码
与蚀刻和铸造过程类似,转移符文的法令也通过比特币脚本的OP_RETURN
操作码上链。这确保了转移操作的透明性和不可逆性,为所有网络参与者提供了验证转移正确性的能力。
符文的转移遵循比特币的未花费交易输出(UTXO)模型。在比特币网络中,每个交易的输出(UTXO)都代表了一定数量的比特币,可以作为下一个交易的输入。在Rune协议中,UTXO的概念被用来表示和转移特定的符文。
也就是说,我在一个Mint交易中Mint了一个符文A,并占据了1000聪的UTXO。接下来我构造一笔普通转账交易,没有OP_RETURN,把这个UTXO花费掉,并转账给用户B,那么用户B将会收到这个符文A。
在Runestones被执行时,其中的法令会按照它们出现的顺序被处理。这意味着,如果一个Runestones中有多个法令引用了相同的符文ID,它们将按照在Runestones中出现的顺序依次被处理。
在处理法令之前,所有输入的符文(包括新铸造的或预挖的符文)都是未分配的。每个法令会减少相应符文ID的未分配余额,并增加分配给交易输出的余额。
如果一个法令试图分配的符文数量超过了当前未分配的符文数量,该法令的分配数量将被减少到当前未分配的符文数量。这意味着,所有的未分配符文都将被完全分配。
amount
字段为零,则表示将分配该符文ID的所有剩余单位。output
字段等于交易输出的数量,则表示将等量的符文分配到每个非OP_RETURN
的输出。如果Runestones中的任何法令引用了无效的符文ID(例如,区块高度为零且交易索引非零),或者output
字段的值大于交易输出的数量,那么整个Runestones将被视为无效,即成为“墓碑”(Cenotaph),并且所有输入的符文都将被销毁。
当交易中的Runestones不符合协议规则时,如包含无法识别的标签或标志,输入的符文将被销毁,这通过Cenotaph(墓碑)结构来表示。
销毁符文的机制,即所谓的“墓碑”(Cenotaph),会在以下情况下被触发:
当触发销毁机制时,以下步骤会被执行:
通过TapScript+OP_RETURN:用两笔交易将蚀刻内容上链,确保其不可篡改。而且一定记住两笔交易之间的区块高度差至少要达到6。
而在Mint、转账等行为时,通过OP_RETURN实现了符文交易的上链。
最后的最后,我也在发起一个开源项目“BxE协议”,使用基于改进版Ordinals协议为基础,让比特币网络支持EVM图灵完毕的智能合约。这个项目在比特币一层网络实现,无需搭建二层网络,可以实现比特币级的去中心化安全性。白皮书在GitHub上,在该项目中也会接入Runes协议,实现该生态的打通。有兴趣的朋友可以一起参与讨论。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。