首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

Ethereum交易数据的构建原理

当我们需要将某些数据写入区块链,这个写入的过程叫交易。从区块链中取数据叫调用Call。交易有别与传统数据库数据的写入,以太坊区块链需要先将写入的数据编码成16进制的字节码,区块链块中存储的基础类型如:Bytes32,Address.... 那么读取的过程则需要将16进制的字节码转换成utf8编码的字母或汉字,形成有价值意义的信息数据。

常见的交易如转账,Alice给Bob在以太坊链上转账ETH,下面是我在etherscan随便找了一笔ETH转账的交易回执

从回执数据上看,from是发送方,to是收款方,value是转账金额,这笔交易数据的构建还是很简单的。

如果在以太坊链上通过合约转账erc20的代币,那就需要针对合约中的转账方法构建一笔转账交易数据。

from仍然是发送方,而to则变成了该erc20代币的合约地址,具体的erc20转账数量则在input Data中。这笔交易数据最核心的点就在inputData中,以太坊执行合约代码需要依赖于evm虚拟机,而evm只能执行字节码bytecode,上面的input Data是整齐明了的字节码,看上去一目了然。

其中MethodID是函数transfer(address _to, uint256 _value)的函数签名,函数签名我在之前的文章中介绍过,并且也有方便的

ethSignUtil

脚本生成合约中的函数签名,后面两个参数值:000000000000000000000000d0292fc87a77ced208207ec92c3c6549565d84dd,

0000000000000000000000000000000000000000000000000de0b6b3a7640000,则是transfer函数的address收款方地址和value转账的erc20数量。erc20合约中一般转账交易数据就是函数签名+收款方地址+转账数量。

最终的交易数据是这样的

0xa9059cbb

000000000000000000000000d0292fc87a77ced208207ec92c3c6549565d84dd

0000000000000000000000000000000000000000000000000de0b6b3a7640000

那这个交易数据为什么是这样?

以太坊的交易数据最小单位是32字节64位长度为一个值,如上方address地址数据:000000000000000000000000d0292fc87a77ced208207ec92c3c6549565d84dd,表示是一个地址类型的32字节码。一个address类型去掉前缀0x是40位长度,需要补全64位,在address数据左侧补0至总长为64位。

为什么是左则补零?

在evm执行字节码的约定中,凡是静态的基础类型则左补齐零至64长度。而动态类型则是右补齐零至64长度

归纳下常见的静态类型:uint,bool,Address,bytes[0-32], 动态数组类型:bytes,string,address[],bytes32[].....

普通的转账构建的交易数据也是比较简单,而在合约开发中由于业务方法多种多样,可能会涉及静态数组,动态数组,那交易数据的构建就复杂多了。

下面看一个合约方法,参数涉及基本类型以及动态数组。

analysisHex(bytes,bool,uint256[],address,bytes32[])通过ethSignUtil脚本或者remix可以计算出函数签名:4b6112f8

如果需要向合约中这个方法analysisHex发送一笔交易数据,我们明文数据是这样的,"Alice",true,[9,8,7,6],"0x26d59ca6798626bf3bcee3a61be57b7bf157290e",["张三","Bob","老王"]

"Alice" 存储在bytes的动态数组中,true 用bool存储,[9,8,7,6] 存放在uint[]数组中,

"0x26d59ca6798626bf3bcee3a61be57b7bf157290e"是一个address,最后["张三","Bob","老王"] 存储在bytes32的动态数组中。

那么构建这样一笔复杂的交易数据到底会经历什么?答案是: 当然只有你看下去才知道啦

首先我们先来分析这个函数参数字段,其中动态参数类型有:bytes,uint[],bytes32[],基础类型有:bool,address。动态类型参数在构建交易数据的过程中由于不确定参数值需要占几个bytes32的字节,则需要先占位。

记住动态数组类型需要先占位确定动态数组值的位置,而后根据位置补值。这样说可能很抽象,下面我将上述的明文值在remix中构建成交易数据。

0x4b6112f8

00000000000000000000000000000000000000000000000000000000000000a0

0000000000000000000000000000000000000000000000000000000000000001

00000000000000000000000000000000000000000000000000000000000000e0

00000000000000000000000026d59ca6798626bf3bcee3a61be57b7bf157290e

0000000000000000000000000000000000000000000000000000000000000180

0000000000000000000000000000000000000000000000000000000000000005

416c696365000000000000000000000000000000000000000000000000000000

0000000000000000000000000000000000000000000000000000000000000004

0000000000000000000000000000000000000000000000000000000000000009

0000000000000000000000000000000000000000000000000000000000000008

0000000000000000000000000000000000000000000000000000000000000007

0000000000000000000000000000000000000000000000000000000000000006

0000000000000000000000000000000000000000000000000000000000000003

e5bca0e4b8890000000000000000000000000000000000000000000000000000

426f620000000000000000000000000000000000000000000000000000000000

e88081e78e8b0000000000000000000000000000000000000000000000000000

这个就是明文

"Alice",true,[9,8,7,6],"0x26d59ca6798626bf3bcee3a61be57b7bf157290e",["张三","Bob","老王"]

构建后的交易字节码数据。不要怕这么长的16进制字符串,你接着看,我负责给你讲明白。

由于具体动态数组的占位计算以及补0的说明篇幅过大,我用markdown写了详细的说明,这里先附上一张图片,详细的文档说明在文末贴出

动态的交易数据类型由于不确定数组的长度,则需要占位,而静态类型的交易数据构建就比较简单些,直接在该参数所在的位置处存储值。我把上述的动态类型改成静态类型

那么它的函数签名也发生了变化,变成了:f8380e5f,那么我们同样传入明文

"Alice",true,[9,8,7,6],"0x26d59ca6798626bf3bcee3a61be57b7bf157290e",["张三","Bob","老王"]

它的交易数据会变成什么样呢?我在remix编码后得到

0xf8380e5f

416c696365000000000000000000000000000000000000000000000000000000

0000000000000000000000000000000000000000000000000000000000000001

0000000000000000000000000000000000000000000000000000000000000009

0000000000000000000000000000000000000000000000000000000000000008

0000000000000000000000000000000000000000000000000000000000000007

0000000000000000000000000000000000000000000000000000000000000006

00000000000000000000000026d59ca6798626bf3bcee3a61be57b7bf157290e

e5bca0e4b8890000000000000000000000000000000000000000000000000000

426f620000000000000000000000000000000000000000000000000000000000

e88081e78e8b0000000000000000000000000000000000000000000000000000

我们最终得到是函数签名+5个参数对应的值,并没有动态数组的占位值。

相对于动态数组交易数据的构建,静态数组果然清净了很多,但是啊还是麻烦呀!

痛苦的过来者在没有使用web3j之前都是拼呀拼呀拼接16进制的字符串构建一笔笔交易数据,下面看看web3j是如何构建交易数据的,附上web3j构建交易数据的核心源码,并根据上述的动态数组交易数据添加注释说明

构建交易数据是区块链发送交易的前提,这些数据还都是未签名的,没有身份归属。需要发送者用私钥进行签名,签名后的数据进入交易池等待矿工的验证,待签名的数据验证通过,这笔交易才算打包入链。

本篇只是介绍交易数据的准备阶段,后续的交易签名包括钱包常用的离线签名、私钥托管的在线签名以及验签,在后续的文章中会介绍。如果本篇的交易数据原理构建对你认识以太坊的交易有了新的高度。那就赶紧关注我吧!持续“刻意链习”!欢迎转载,分享区块链知识,转载请注明出处!

关注公众号

更多帮助

交易数据构建文档说明:

https://github.com/zhjgit/Ethereum-util/blob

/master/dynamicDataExplain.md

web3j交易数据构建的核心源码:

https://github.com/web3j/web3j/blob/master/abi/src/main/java/org/web3j/abi/FunctionEncoder.java

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20190106G08WHG00?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券