关于区块链:武汉链基于ETHBSN官方DDC链上数据解析

29次阅读

共计 10731 个字符,预计需要花费 27 分钟才能阅读完成。

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 的流程大抵如下:

  1. 请求者通过 RPC 网关发送已签名的交易申请到官网 DDC-721 合约
  2. DDC-721 合约会调用 mint 办法进行 DDC 的生成
  3. 执行 mint 办法后会按程序判断是否满足生成条件,而后会顺次按程序执行_mintAndPay 和_pay 办法。
  4. 在执行_pay 办法时,会调用计费合约中的 pay 办法,此时会进行业务费的扣除,即生成 1 个 DDC 须要扣除 1 元业务费,并且触发 Pay 事件
  5. 胜利扣除业务费后,会继续执行 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 : 残余字节,本例中的输出是 ddcuri

    0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000004e7b2275726c223a2268747470733a2f2f6464632e62736e626173652e636f6d2f6d61696e2f696e646578222c224e616d65223a2242534e2d444443222c2254797065223a224444432d373231227d000000000000000000000000000000000000

    此数据乍看之下十分凌乱。实际上是把字符串转换成 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 : 如果本次交易是部署合约,那么就会返回生成的合约地址,如果是其余类型的交易,那么会返回 null
  • cumulativeGasUsed : 交易所在块耗费的 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 进制拆分,失去:

d0def52100000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000064
000000000000000000000000000000000000000000000000000000000003087f

去掉补位的 0,能够失去以下后果:

d0def521
64
3087f

这三个参数别离对应的是 sigamountddcId

  • 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_…

正文完
 0