本文以比特币测试网络(bitcoin-testnet)作为开发试验环境,以结合Node js实现PPkPub开源项目ODIN的标识注册功能作为具体应用案例
本文以比特币测试网络(bitcoin-testnet)作为开发试验环境,以结合Node.js实现PPkPub开源项目ODIN的标识注册功能作为具体应用案例,来说明如何利用多重签名交易形式来嵌入自定义数据并签名后广播,再被矿工节点确认存入区块链后,最终能被读取解析得到注册结果,这样就实现了一个从写入区块链到从区块链读取的完整过程。
一、了解ODIN开放标识的定义
ODIN作为PPkPub 开放小组发布的第一个开源项目,是Open Data Index Name 即“开放数据索引命名标识”的缩写。广义上,ODIN 是指在网络环境下标识和交换数据内容索引的一种开放性系统,它遵从URI(统一资源标识符) 规范,并为基于数字加密货币区块链(BlockChain)的自主开放、 安全可信的数据内容管理和知识产权管理提供了一个可扩展的框架。它包括4 个组成要素:标识符、 解析系统、 元数据和规则(Policies) 。 狭义上,ODIN 是指标识任何数据内容对象的一种永久性开放标识符。
ODIN 可以被形象地理解为“数据时代的自主域名”,是基于比特币区块链定义并可扩展兼容更多区块链的完全开放、 去中心化的命名标识体系,相比传统的 DNS 域名拥有更多创新特性,可以很好地被应用到大数据、智能设备和物联网等新兴领域。
参考了XCP(合约币)和Mastercoin(万事达币)等数字加密货币的技术原理,ODIN的实现是通过将特定消息数据按比特币协议规范进行特定编码后,作为比特币交易广播到比特币网络上存入区块链。
每个ODIN信息包括以下特性:(a)一个比特币源地址(对应ODIN消息生成者)
(b) 一个比特币目的地址(对应受ODIN消息指向的目标个体,当消息生成者与受消息指向的目标个体相同时,该地址为空)
(c)若干个1-of-N多重签名输出比特币地址公钥(经由ODIN数据包编码生成,实际生成交易时从ODIN设置数据中按顺序每提取32个字节,并在该32个字节的前部加上1个字节对应该字符串的长度值,总共33个字节对应一个比特币公钥,最后不足33个字节的自动在尾部追加二进制0填满直到正好达到33字节对应一个压缩公钥)
(d)比特币源地址中有一定数量的比特币余额(建议有0.001BTC以上,用于生成从源地址发送到目的地址的若干有效交易条目以嵌入ODIN数据包。注: 因为比特币1-of-N多重签名交易的特点,这些比特币金额不会发生实际支出,将在下一个ODIN消息中被回收循环利用)
(e)以比特币计的消息成本固定费用(缺省是0.0001 BTC),将支付给收录这个交易数据块的比特币网络矿工。
(f)一个比特币找零地址(与上述第一项的比特币源地址相同,用于按照比特币交易协议将输入交易的比特币金额在生成若干条满足嵌入ODIN数据包的交易条目后多出的金额回收到消息发送者账户)
上述的特性(c)是技术实现的关键,ODIN数据块会嵌入到比特币交易的多重签名输出数据块中,是1-of-N输出,每个数据块的第一个公钥固定是发送者的,因而输出的币值可以赎回循环使用,存贮第二个到第N个公钥的地址空间用来存贮编码的ODIN消息数据。关于比特币多重签名交易的详细说明请参考比特币协议规范。 注:N建议取值不超过10。对于1条1-of-10多重签名输出仍无法容纳的ODIN数据块,可依样扩展存入第2条,第3条等更多条多重签名输出记录中即可。
每个ODIN信息数据块的格式按字节顺序定义如下:
第1-32字节 : 前缀特征标识,32个字节的ASCII字符串”P2P is future! ppkpub.org->ppk:0″(不含两侧的双引号)
第33字节 : 消息类型,1个字节。
第34字节到消息结束为按消息类型区分的不同消息数据,详见具体的ODIN 消息类型中的定义。
注:为了便于识别,每个ODIN消息都以32字节的ASCII字符串”P2P is future! ppkpub.org->ppk:0″(不含两侧的引号)作为前缀特征标识,这个字符串非常长,因而不可能把ODIN的特定交易和其它的比特币交易搞混。
二、将ODIN标识注册到区块链上的实例解析
下文是ODIN协议里对于“新注册ODIN标识”的具体消息定义: ———————————————————————————————————— 新注册ODIN标识
比特币源地址:对应ODIN标识注册者 比特币目的地址:对应ODIN标识拥有者
消息数据块的格式按字节顺序定义如下:第1-32字节 : 前缀特征标识,32个字节的ASCII字符串”P2P is future! ppkpub.org->ppk:0″(不含两侧的双引号)第33字节 : 消息类型,1个字节,取值为ASCII字符R第34字节 : 消息正文数据格式,1个字节。 取值定义:ASCII字符, T 表示“UTF-8编码文本字符串”, G 表示“经gzip算法压缩得到的二进制数据,需解压后可得到UTF-8编码的原始文本字符串”第35-36字节: 消息正文数据字节长度,2个字节的无符号短整型二进制数据,取值范围为0-65535。第37字节到消息正文指定长度结束是按字节存放的消息正文数据,需根据第34字节的数据格式取值来获得原始消息文本,为UTF-8编码的JSON格式字符串,对应一个JSON对象数据,说明如下: { ”title”:”说明:个体名称字符串”, ”email”:”说明:个体的公开EMAIL,可选”, ”auth”:”说明:配置权限,取值定义见下方注释”, ”ap_list”:["说明:若干个数据访问点AP的URL数组,最少需填写一个",...,"xxxx"], ”catalog”:”说明:数据源类型,可选保留字段,待补充” }
注:配置权限的取值说明:ASCII字符0,1或2 0表示“注册者或拥有者任一方都可以修改拥有者相关信息”, 1表示“只有注册者能修改拥有者相关信息”, 2表示“注册者和拥有者必须共同确认才能修改拥有者相关信息”,
————————————————————————————————————
假设有下述示例的一段ODIN标识注册信息:{“title”:”PPk-ODIN-sample”,”email”:”ppkpub@gmail.com”,”auth”:”2″,”ap_list”:["http://ppkpub.org/AP/"]}
那么就可以按照上述的消息定义将其组装为一条比特币交易记录以广播到比特币网络上生效,对应交易的原始数据示例如下(将原始二进制数据按字节以16进制ASCII码形式输出,便于分析):01000000032237b858f1a697cc2d26a451bd3fd3ef1944eb53f579b4fac38e5ecb5c0fc42c010000006b483045022100da55a2d9f97695db12aecc0113662437957a6d4f17064ff49602ddc39904c31302201e81eae0c84f25019485ae4a2ce9b67c0e8485599df87ab876b469e3cbbd24100121022e9f31292873eee495ca9744fc410343ff373622cca60d3a4c926e58716114b9ffffffff2ef89686bebf72bd31b8f27780223f7b5f448d0110b6fdda19595a073f42a301000000006b483045022100d49360fa6bd45b92a068127db31c9cfd93af87543799968a5b076c2fea151f9b0220647900f5fc763f5a3eed13d382e13a3bddd15646867b56f1be9d2629b2ccb4360121022e9f31292873eee495ca9744fc410343ff373622cca60d3a4c926e58716114b9ffffffffd704b1c1977cd50be182134b18fafaa16db1e917dfe4f93bcab1584aabf323d4010000006b483045022100fb88f75cae8accfe969cd89afbca677ff78a4914f5f506d6e5d481baf484e9f2022039f560414ec5a778a19565f7fe9e51b6acf7b841b4ba2188785a5bb6051d7d510121022e9f31292873eee495ca9744fc410343ff373622cca60d3a4c926e58716114b9ffffffff037d160000000000001976a91451a09d25106715f09a14cac6367c3f4f2408590d88ac7d16000000000000cf5121022e9f31292873eee495ca9744fc410343ff373622cca60d3a4c926e58716114b9212050325020697320667574757265212070706b7075622e6f72672d3e70706b3a302120525400657b227469746c65223a2250506b2d4f44494e2d73616d706c65222c222120656d61696c223a2270706b70756240676d61696c2e636f6d222c22617574682221203a2232222c2261705f6c697374223a5b22687474703a2f2f70706b7075622e6f210972672f41502f225d7d000000000000000000000000000000000000000000000056aee6cac223000000001976a914391ef5239da2a3904cda1fd995fb7c4377487ea988ac00000000 对上述报文按协议规则可按字段分解说明如下:
01000000 // 版本号,UINT32
03 // Tx输入数量,变长INT。0×03=3个输入。
/*** 接下来是第一组Input Tx ***/2237b858f1a697cc2d26a451bd3fd3ef1944eb53f579b4fac38e5ecb5c0fc42c // Tx交易的Hash值,固定32字节01000000 // 消费的Tx位于前向交易输出的第0个,UINT32,固定4字节6b // 接下来对应签名数据的长度, 0x6b = 107字节 。 // 这107字节长度的签名,含有两个部分:私钥签名 + 公钥。 // 当这里的数值为00时,则表示为尚未经过签名的原始交易48 // 对应私钥签名的数据长度,0×48 = 72字节3045022100da55a2d9f97695db12aecc0113662437957a6d4f17064ff49602ddc39904c31302201e81eae0c84f25019485ae4a2ce9b67c0e8485599df87ab876b469e3cbbd241001 //私钥签名内容21 // 对应公钥的数据长度,0×21 = 33字节022e9f31292873eee495ca9744fc410343ff373622cca60d3a4c926e58716114b9 //对应公钥数据ffffffff // 序列号,UINT32, 固定4字节。该字段是目前未被使用的交易替换功能,默认都设成0xFFFFFFFF
/*** 第二组Input Tx。与上同理,省略分解 ***/2ef89686bebf72bd31b8f27780223f7b5f448d0110b6fdda19595a073f42a301000000006b483045022100d49360fa6bd45b92a068127db31c9cfd93af87543799968a5b076c2fea151f9b0220647900f5fc763f5a3eed13d382e13a3bddd15646867b56f1be9d2629b2ccb4360121022e9f31292873eee495ca9744fc410343ff373622cca60d3a4c926e58716114b9ffffffff
/*** 第三组Input Tx。与上同理,省略分解 ***/d704b1c1977cd50be182134b18fafaa16db1e917dfe4f93bcab1584aabf323d4010000006b483045022100fb88f75cae8accfe969cd89afbca677ff78a4914f5f506d6e5d481baf484e9f2022039f560414ec5a778a19565f7fe9e51b6acf7b841b4ba2188785a5bb6051d7d510121022e9f31292873eee495ca9744fc410343ff373622cca60d3a4c926e58716114b9ffffffff03 // Tx输出交易数量,变长INT类型。0×03=3个输出。
/*** 第一组输出 ***/7d16000000000000 //输出的比特币数量,UINT64,8个字节。字节序需翻转得到0x000000000000167d = 5757 satoshi = 0.00005757 BTC19 //输出描述脚本字节数, 0×19 = 25字节,由一些操作码与数值构成76 //脚本起始操作 0×76 代表 OP_DUP(复制栈顶元素)a9 //地址类型 0xa9 代表 OP_HASH160(栈顶项进行两次HASH,先用SHA-256,再用RIPEMD-160)14 //地址长度 0×14 = 20字节51a09d25106715f09a14cac6367c3f4f2408590d //对应ODIN标识拥有者地址的HASH160值,20字节88 //0×88 代表 OP_EQUALVERIFY (运行脚本的二进制算术和条件,如结果为0,之后运行OP_VERIFY)ac //Oxac 代表 OP_CHECKSIG (交易所用的签名必须是哈希值和公钥的有效签名,如果为真,则返回1)
/*** 第二组输出 ***/7d16000000000000 //输出的比特币数量,UINT64,8个字节。字节序需翻转,cf //输出描述脚本字节数, 0xcf = 207字节,由一些操作码与数值构成51 //Ox51代表OP_1(将脚本代码1压入堆栈)21 //压入堆栈的第1个公钥的数据长度,0×21 = 33字节。对应ODIN标识注册者地址的公钥022e9f31292873eee495ca9744fc410343ff373622cca60d3a4c926e58716114b921 //压入堆栈的第2个公钥的数据长度。从第2个公钥开始嵌入ODIN标识消息内容2050325020697320667574757265212070706b7075622e6f72672d3e70706b3a3021 //压入堆栈的第3个公钥的数据长度20525400657b227469746c65223a2250506b2d4f44494e2d73616d706c65222c2221 //压入堆栈的第4个公钥的数据长度20656d61696c223a2270706b70756240676d61696c2e636f6d222c22617574682221 //压入堆栈的第5个公钥的数据长度203a2232222c2261705f6c697374223a5b22687474703a2f2f70706b7075622e6f21 //压入堆栈的第6个公钥的数据长度0972672f41502f225d7d000000000000000000000000000000000000000000000056 //Ox56 代表 OP_6 (将脚本代码6压入堆栈)。与前面的0×51合在一起表示1of6多重签名ae //Oxae 代表 OP_CHECKMULTISIG (执行多重签名验证)
/*** 第三组输出 ***/e6cac22300000000 //输出的比特币数量,UINT64,8个字节。字节序需翻转,19 //输出描述脚本字节数, 0×19 = 25字节,由一些操作码与数值构成76 //脚本起始操作 0×76 代表 OP_DUP(复制栈顶元素)a9 //地址类型 0xa9 代表 OP_HASH160(栈顶项进行两次HASH,先用SHA-256,再用RIPEMD-160)14 //地址长度 0×14 = 20字节391ef5239da2a3904cda1fd995fb7c4377487ea9 // 对应的HASH160值,20字节88 //0×88 代表 OP_EQUALVERIFY (运行脚本的二进制算术和条件,如结果为0,之后运行OP_VERIFY)ac //Oxac 代表 OP_CHECKSIG (交易所用的签名必须是哈希值和公钥的有效签名,如果为真,则返回1)
00000000 // 锁定时间,UINT32,固定4字节
结合前文说说明的ODIN协议定义内容,通过上述交易数据中的蓝色区域部分就可以还原解析出对应ODIN标识注册消息。
三、运行示例程序
示例程序包括两部分:1. OdinMonitorTestnet.js : 监测比特币测试网络Testnet相关区块链数据的变化,从中解析出新注册的ODIN标识。 源码可以从这里下载: http://ppkpub.org/sample/OdinMonitorTestnet.js
2. OdinRegisterTestnet.js : 在比特币测试网络Testnet注册一个新的ODIN标识。 源码可以从这里下载: http://ppkpub.org/sample/OdinRegisterTestnet.js
将上述示例代码下载保存到已安装Node.js的测试环境下(保存文件名为 OdinRegisterTestnet.js和OdinMonitorTestnet.js)。 关于如何安装Node.js测试环境, 如有需要可以参考《比特币区块链开发由浅入深指南1》里面的说明进行安装( http://www.8btc.com/blockchain_develope_lesson_1 )。
在运行上述示例程序前,请确认已安装比特币测试网络(bitcoin-testnet)的Docker运行环境。如尚未安装可以参考《比特币区块链开发由浅入深指南2》里面的说明进行安装( http://www.8btc.com/ppkpub_blockchain_develope_lesson_2 )。
在Node.js开发测试环境新开一个文本终端窗口,在命令行下输入以下命令启动监测示例程序: node OdinMonitorTestnet.js
然后新开一个文本终端窗口,在命令行下输入以下命令运行注册示例程序: node OdinRegisterTestnet.js
运行注册示例程序后,到比特币测试网络(bitcoin-testnet)的Docker运行环境的命令行下输入”make generate BLOCKS=6″, 模拟产生新的区块记录,刚产生的交易记录就会得到有效的确认并被存入区块链中。 这时在监测程序的运行界面上就会提示解析到新的ODIN标识注册记录(如下图所示)。
编辑:却原来
关键词: 由浅入深区块实战