id:BSN_2021 公众号:BSN 研习社 作者:红枣科技史博涵
随着区块链概念的遍及,这项新型技术逐步走进公众视线。目前行业整体方兴未艾,数字商品、隐衷爱护、供应链金融等业务也在热火朝天的发展。为满足公众需要,使宽广开发者能够低成本低门槛的对接区块链技术,BSN在2022年1月25日推出了BSN-DDC根底网络(DDC网络)。
DDC网络由十多条技术体系欠缺并各具特点的BSN凋谢联盟链组成,通过部署BSN官网DDC智能合约,向有基于DDC/NFT技术的相干业务需要的平台方提供疾速接入服务,使其可灵便地对DDC/NFT的生成、转移和销毁等操作进行治理。
为不便大家更好的理解和应用官网DDC,咱们将对DDC的交易信息进行具体解析。因为目前DDC网络中最为宽泛应用的武汉链(基于ETH)、文昌链(基于IRITA)和泰安链(基于FISCO BCOS)都集成了EVM(以太坊虚拟机),所以这里的解析也应用以太坊中的规范办法。本文以武汉链为例,通过调用DDC-721合约的mint办法来生成一个DDC,并解析其交易信息。武汉链中DDC官网合约的开源代码能够在https://github.com/BSN-DDC/wuhanchain/tree/master/ddc-contract中找到。
一、生成DDC
生成DDC的流程大抵如下:
- 请求者通过RPC网关发送已签名的交易申请到官网DDC-721合约
- DDC-721合约会调用mint办法进行DDC的生成
- 执行mint办法后会按程序判断是否满足生成条件,而后会顺次按程序执行_mintAndPay和_pay办法。
- 在执行_pay办法时,会调用计费合约中的pay办法,此时会进行业务费的扣除,即生成1个DDC须要扣除1元业务费,并且触发Pay事件
- 胜利扣除业务费后,会继续执行mint办法生成DDC,并且触发Transfer事件,最终实现本次交易。
本次示例中,填入的DDC URI的内容为:
{"url":"https://ddc.bsnbase.com/main/index","Name":"BSN-DDC","Type":"DDC-721"}
胜利生成DDC后,返回了交易hash:
0x5cd1257d4e89bf3c7247c397cfb167b2b4d66c13dbffdb030e6f7d5c3ceddb2d
咱们能够通过解析这个交易hash来获取须要的交易信息。获取信息分须要应用以下两种办法:
eth_getTransactionByHash
: 返回指定交易对应的交易信息eth_getTransactionReceipt
: 返回指定交易对应的回执信息
二、获取交易信息
(一)调用eth_getTransactionByHash
申请信息:
{ "jsonrpc":"2.0", "method":"eth_getTransactionByHash", "params": ["0x5cd1257d4e89bf3c7247c397cfb167b2b4d66c13dbffdb030e6f7d5c3ceddb2d"], "id":1}
响应信息:
{ "jsonrpc": "2.0", "id": 1, "result": { "blockHash": "0x9a5bbfc07c318794a502f55905815f9b60fd42129bb0308745cd592fd4e633a9", "blockNumber": "0x37dcf3", "from": "0xa30f403fc5f6be6d1eab5465511d4866c97fddf8", "gas": "0x45a9d", "gasPrice": "0xb2d05e00", "hash": "0x5cd1257d4e89bf3c7247c397cfb167b2b4d66c13dbffdb030e6f7d5c3ceddb2d", "input":"0xd0def521000000000000000000000000a30f403fc5f6be6d1eab5465511d4866c97fddf80000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000004e7b2275726c223a2268747470733a2f2f6464632e62736e626173652e636f6d2f6d61696e2f696e646578222c224e616d65223a2242534e2d444443222c2254797065223a224444432d373231227d000000000000000000000000000000000000", "nonce": "0x1", "to": "0xad3b52b4f4bd9198dc69dd9ce4ac9846667461a2", "transactionIndex": "0x3", "value": "0x0", "type": "0x0", "v": "0x2b8a", "r": "0xe6b6a3eb68875ac4efdcab11239095f92ab86018cedf6d5522074ebde0657a7e", "s": "0x7e66438dcfa90da0d8f0b20513f99ea8c4f2d6ba7ba1da87e9735f6be32d59e5" }}
从响应信息中的result里咱们能够直观看到一些重要的数据:
blockHash
: 蕴含本次交易的区块哈希;blockNumber
: 蕴含本次交易的区块号;hash
: 本次交易的哈希值;from
: 发送方地址,指交易的发起者;to
: 这里的接管方地址不是生成DDC时提供的指标地址,而是交易发送方调用的DDC-721合约地址;gas
: 发送方提供的gas可用量。能够是零碎主动计算得出,或者自行设置;gasLimit
: 示意本次交易能够发送的最大gas数量。如果链账户中的能量值余额小于这个数量,或者此笔交易耗费的gas超过这个数量,则此交易无奈进行;gasPrice
: 本次交易的gas的价格;nonce
: 本次交易之前发送方曾经生成的交易数量。为了避免交易反复进行,每个地址里的每笔交易必须有一个惟一的nonce数值。这个nonce值从0开始递增,每发送一笔交易,nonce便加1。本例中的nonce值0x1示意在此交易前发送方已实现了1笔交易;transactionIndex
: 交易在块中索引的地位。也就是说此交易在区块中排在第几个,这个值从0x0开始顺次递增;value
: 发送的以太币数量。在凋谢联盟链中,因为禁止链账户之间对gas进行横向转移,此值为0。
其余的信息还包含交易类型(type)以及交易签名(r、s、v)等,在这里就不深刻探讨了。接下来咱们重点解析一下交易信息中的input数据,看看这外面都蕴含了哪些重要信息。
(二) 解析Input内容
input是随交易发送的数据。如果input的值为0x,阐明是非合约调用,否则是合约办法调用。
本例中调用了非法办法mint(address,string)
,失去的input值为:
0xd0def521000000000000000000000000a30f403fc5f6be6d1eab5465511d4866c97fddf80000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000004e7b2275726c223a2268747470733a2f2f6464632e62736e626173652e636f6d2f6d61696e2f696e646578222c224e616d65223a2242534e2d444443222c2254797065223a224444432d373231227d000000000000000000000000000000000000
此数据分为2个局部: 办法名称的哈希值+办法中的参数
1、办法名称的哈希值
d0def521
占4个字节,是mint(address,string)办法的签名编码。
具体计算方法为先对mint(address,string)做keccak256计算,生成32位哈希值
0xd0def521cdae71c63ecace61ee5a1cca744cf981e4d6ff45cdd07ec87394aad5
而后再将此哈希值做bytes4计算,最终生成0xd0def521(如下图所示)
2、办法中的参数
此局部数据的构造依据办法自身的参数设置来决定。本例中的办法有两个参数: 生成DDC的指标地址(address)以及填入的ddcuri的内容(string)
address
: 占32个字节,而武汉链的地址为20字节,所以高位主动补零,显示为:000000000000000000000000a30f403fc5f6be6d1eab5465511d4866c97fddf8
string
: 残余字节,本例中的输出是ddcuri0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000004e7b2275726c223a2268747470733a2f2f6464632e62736e626173652e636f6d2f6d61696e2f696e646578222c224e616d65223a2242534e2d444443222c2254797065223a224444432d373231227d000000000000000000000000000000000000
此数据乍看之下十分凌乱。实际上是把字符串转换成16进制示意,所以为了不便识别和浏览,须要将其转换为字符串模式。转换后为:
@N{"url":"https://ddc.bsnbase.com/main/index","Name":"BSN-DDC","Type":"DDC-721"}
能够看出,花括号中的内容与生成DDC时输出的ddcuri内容完全一致。
三、获取交易回执
(一)调用eth_getTransactionReceipt
申请信息:
{ "jsonrpc":"2.0", "method":" eth_getTransactionReceipt", "params": ["0x5cd1257d4e89bf3c7247c397cfb167b2b4d66c13dbffdb030e6f7d5c3ceddb2d"], "id":1}
响应信息:
{ "jsonrpc": "2.0", "id": 1, "result": { "blockHash":"0x9a5bbfc07c318794a502f55905815f9b60fd42129bb0308745cd592fd4e633a9", "blockNumber": "0x37dcf3", "contractAddress": null, "cumulativeGasUsed": "0x5de907", "effectiveGasPrice": "0xb2d05e00", "from": "0xa30f403fc5f6be6d1eab5465511d4866c97fddf8", "gasUsed": "0x41043", "logs": [ { "address": "0xca97bf3a19403805d391102908665b16b4d0217c", "topics": [ "0x750e56f33a72767cd99db8943f4d04ca416c55fb783003107a869f5d5062dbab", "0x000000000000000000000000a30f403fc5f6be6d1eab5465511d4866c97fddf8", "0x000000000000000000000000ad3b52b4f4bd9198dc69dd9ce4ac9846667461a2" ], "data":"0xd0def521000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000064000000000000000000000000000000000000000000000000000000000003087f", "blockNumber": "0x37dcf3", "transactionHash": "0x5cd1257d4e89bf3c7247c397cfb167b2b4d66c13dbffdb030e6f7d5c3ceddb2d", "transactionIndex": "0x3", "blockHash": "0x9a5bbfc07c318794a502f55905815f9b60fd42129bb0308745cd592fd4e633a9", "logIndex": "0x35", "removed": false }, { "address": "0xad3b52b4f4bd9198dc69dd9ce4ac9846667461a2", "topics": [ "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x000000000000000000000000a30f403fc5f6be6d1eab5465511d4866c97fddf8", "0x000000000000000000000000000000000000000000000000000000000003087f" ], "data": "0x", "blockNumber": "0x37dcf3", "transactionHash": "0x5cd1257d4e89bf3c7247c397cfb167b2b4d66c13dbffdb030e6f7d5c3ceddb2d", "transactionIndex": "0x3", "blockHash": "0x9a5bbfc07c318794a502f55905815f9b60fd42129bb0308745cd592fd4e633a9", "logIndex": "0x36", "removed": false } ], "logsBloom": "0x00000000000000000000000000000000000000000000000200000000000000000800000000000000000000000000000000040000000000000000000000000000000000020000000000000008000800000000000000000000000000000000000000000000020000000000000800000800000000000000000080000010000000000000000000000100000000000000000000000000000000000000000000000000000000000040000000000020000000000000000000000000000000000000000000010002000000000000000000000000001000000000000000000000800020000000010000000000000000020000000100800000000000000000000000000000", "status": "0x1", "to": "0xad3b52b4f4bd9198dc69dd9ce4ac9846667461a2", "transactionHash": "0x5cd1257d4e89bf3c7247c397cfb167b2b4d66c13dbffdb030e6f7d5c3ceddb2d", "transactionIndex": "0x3", "type": "0x0" }}
这里的响应信息里蕴含的参数很多都与交易信息中统一,比方块哈希、块号、交易哈希、交易的发送方地址和接管方地址、交易索引等。
其余的参数蕴含的信息如下:
contractAddress
: 如果本次交易是部署合约,那么就会返回生成的合约地址,如果是其余类型的交易,那么会返回nullcumulativeGasUsed
: 交易所在块耗费的gas总量。这里的gas总量指的是依据transactionIndex来排列的到此交易为止的全副交易耗费的所有gas,也就是这个区块中此交易与排在它前边的所有交易耗费的gas之和。effectiveGasPrice
: 本次交易的理论gas价格。gasUsed
: 本次交易耗费的gas用量。本次交易耗费的能量值为: gasUsed * effectiveGasPrice。 再依据武汉链中能量值的比例为1元 = 4,200,000,000,000,000能够计算出本次交易耗费的理论费用。logsBloom
: bloom过滤器,轻客户端用来疾速提取相干日志。如果这个值是全零,阐明交易日志不存在,即”logs”: []status
: 0x1示意交易胜利,0x0示意交易失败
在交易回执信息中,最重要的数据是logs,接下来咱们看看logs中都蕴含了哪些重要信息。
(二)logs解析
智能合约通过事件(event)来产生日志(log)。日志中存储的gas费用要比合约的存储便宜很多(日志每个字节破费8个gas,而合约存储是每32个字节须要20000个gas)。想要通过合约向用户返回数据,则需将数据以事件的模式传给用户,用户拿到交易回执后通过解析日志拿到数据。
在调用eth_getTransactionByHash办法失去的Input中,只能拿到调用合约以及function的信息,即合约在调用时的办法和输出的参数信息,而不能拿到function运行后外部产生的事件(事件不肯定和function领有雷同名称和参数)。
比方在本例中,function是mint(address,string)
,而须要触发的事件有两个,首先是调用Charge合约领取业务费的Pay(address indexed payer,address indexed payee,bytes4 sig,uint32 amount,uint256 ddcId)
事件,实现后,再触发生成DDC的DDC-721合约中的Transfer(address indexed from,address indexed to,uint256 indexed ddcId)
事件。
Logs是由多个雷同构造的log组合而成。log中的第一个参数为address,即触发事件的合约地址。在第一个log中,address是0xca97bf3a19403805d391102908665b16b4d0217c
,即用来领取业务费的Charge合约的地址;第二个log中的address是0xad3b52b4f4bd9198dc69dd9ce4ac9846667461a2
,即生成DDC的DDC-721合约地址。
除此以外,logs里还有还有块号、块哈希、交易哈希、交易索引、日志索引等在交易信息中也能够查到的信息,用来作为此笔交易在区块链中的标识。
在logs中,还有一个最为重要的数据 — Topics,上面咱们进行具体解析。
(三) Topics解析
Topics[]是一个数组,蕴含了此次交易中所有被触发的事件信息。在具体分析其内容之前,咱们首先来看一个概念: indexed。
在本例中被触发的两个事件里都蕴含了indexed参数,这是solidity语言编写智能合约的时候一个标记参数的属性值。它的作用是在润饰事件时,将参数作为topics存储。也就是说,所有被标记为indexed的参数都会被放到topics里。在Pay事件中的payer和payee,以及Transfer事件中的from、to和ddcId参数都会被记录到topics中。
接下来咱们这两个log中的topics的具体形成:
1) Topics[0]
指向特定的事件,是事件的签名。
在第一个log中为Pay事件的签名:0x750e56f33a72767cd99db8943f4d04ca416c55fb783003107a869f5d5062dbab
签名的办法是对事件的字符做keccak散列运算,即keccak("Pay(address,address,bytes4,uint32,uint256)")
第二个log中的topics[0]的值能够通过同样办法对Transfer事件进行计算得出:0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef
须要留神的是事件中的参数类型须要写残缺,如Pay(address,address,bytes,uint,uint)就不行,须要将bytes和uint后边的具体类型补充残缺。
2) Topics[1]
第一个被indexed标记的参数,这里是address类型from参数补齐64位后果。
在第一个log中此值示意是发动交易的0xa30f403fc5f6be6d1eab5465511d4866c97fddf8
地址;
这里值得关注的是第二个log中的topics[1]为:0x0000000000000000000000000000000000000000000000000000000000000000
也就是0x0,称作空地址(null address),示意是生成DDC的from地址。
3) Topics[2]
第二个被indexed标记的参数,这里是address类型to参数补齐64位后果。
第一个log中的地址为0xad3b52b4f4bd9198dc69dd9ce4ac9846667461a2
。这个地址是DDC-721合约地址,也就是说,第一个log示意交易发起方在调用DDC-721合约时,须要先向其领取业务费。
第二个log中的地址为0xa30f403fc5f6be6d1eab5465511d4866c97fddf8
,是生成DDC的指标地址。
4) Topics[3]
第三个被indexed标记的参数。
这个参数只在第二个log的Topics中存在,是Transfer事件中被indexed标记的第三个参数,示意本次交易所生成的DDC ID,用16进制来示意。
以上就是Topics中的全副参数。须要阐明的是,indexed只能为事件中最多三个参数做标记。然而咱们能够看到,在Pay事件中,总共有五个参数,其中的三个参数sig、amount和ddcId并未被indexed标记。那么这三个参数又传到哪里去了呢?
此时咱们留神到在topics的后边还有一个data参数。是的,所有未被indexed标记的参数,最终都会传入data中。
(四) Data解析
data中的内容是没有indexed标记的value的值转化为16进制,并补齐64位。
依据这个形容,咱们把第一个事件中的data依照64位16进制拆分,失去:
d0def521000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000064000000000000000000000000000000000000000000000000000000000003087f
去掉补位的0,能够失去以下后果:
d0def521643087f
这三个参数别离对应的是sig、amount和ddcId。
d0def521
: 这个参数咱们在交易信息中曾经剖析过了,是mint(address,string)办法的bytes4签名值;64
: 从16进制转换成10进制为100,也就是指领取的业务费金额,单位是人民币(分),即1元钱;3087f
: 从16进制转换成10进制为198783,是DDC ID。
此时DDC官网门户搜寻198783就能够看到这个DDC的信息了:
四、总结
此文章仅对DDC-721合约生成DDC的交易进行了解析。对于其余的交易,比方DDC的流转、销毁、受权,以及DDC-1155合约的批量平安生成等交易,读者都能够尝试自行解析。这里咱们仅对DDC的交易剖析提供一个大抵的思路:
在对官网DDC进行交易后,咱们能够首先调用eth_getTransactionReceipt
查看交易回执中status参数来确定此交易是否胜利。
交易胜利后,咱们能够通过eth_getTransactionByHash
返回后果中的input,以及eth_getTransactionReceipt
返回后果中的logs来对交易内容进行残缺的解读,比方生成DDC后能够间接在logs中的topics里获取到DDC ID的信息,也能够在input中获取到生成DDC时输出的ddcuri的内容。
援用材料:
https://copyfuture.com/blogs-...
https://blog.csdn.net/qq_4220...
http://cw.hubwiz.com/card/c/e...
https://www.jinse.com/news/bl...
https://blog.csdn.net/tianlon...
https://blog.csdn.net/weixin_...