以太坊智能合约函数参数ABI编码,动态类型string编码,函数参数的ABI编码, 含c++代码

官方文档讲得不全也不是很清楚,特别是动态类型string。这里补充。

以太坊的智能合约ABI编码,官方文档和说明:https://solidity.readthedocs.io/en/v0.6.8/abi-spec.html

一个实用的工具,可直接生成ABI编码。
比如下图使用
以太坊智能合约函数参数ABI编码,动态类型string编码,函数参数的ABI编码, 含c++代码_第1张图片
这里侧重于solidity智能合约的构造方法的ABI编码构造。

普通方法的编码官网说得很清楚了。

构造函数的ABI编码由两部分构成,一是编译后的智能合约代码,而是构造函数的参数。

  1. 使用remix编译智能合约,复制编译后的十六进制码。

以太坊智能合约函数参数ABI编码,动态类型string编码,函数参数的ABI编码, 含c++代码_第2张图片
2. 我们智能合约的构造方法是:

constructor (uint256 _deadline, uint32 _reward, string memory _code) public{

现在的问题是,如果我们使用后台提交一个智能合约,需要提交该智能合约的构造函数的参数的值,但是,上面第一步的所复制的编码中不包含参数的值,因此,需要我们自己构造构造函数的值的ABI编码。

换一种说法描述上面的问题,如果使用remix部署我们上面的智能合约的话,因为只有一个构造函数,且是带参数的,因此deploy前需要填写这些参数的值,如下图。现在remix自动帮我们对参数进行ABI编码了,并将它追加在第一步所复制的数据的后面。如果我们自己在后台构造和部署智能合约,如何进行ABI编码构造方法的参数?
以太坊智能合约函数参数ABI编码,动态类型string编码,函数参数的ABI编码, 含c++代码_第3张图片

  1. 根据constructor (uint256 _deadline, uint32 _reward, string memory _code) ,假如取值(3, 2, “helloworld”),第一个参数是uint256,0x0000000000000000000000000000000000000000000000000000000000000003,使用0填充,uint32同理,追加到前面的数中。第三个是string,动态类型,因此先填下面这个固定的数,以60为结尾,长度为64。0000000000000000000000000000000000000000000000000000000000000060,变成:

以太坊智能合约函数参数ABI编码,动态类型string编码,函数参数的ABI编码, 含c++代码_第4张图片
为什么要追加这个"0000000…0060"呢?看下文。
4. 接下来追加string的长度(使用16进制表示)用0填充前面部分;再追加字符串的16进制表示,用0填充后面部分。
以太坊智能合约函数参数ABI编码,动态类型string编码,函数参数的ABI编码, 含c++代码_第5张图片
5. 因为0填充是以64长度为单位的,因此,当字符串的16进制编码长度操作了64长度,后面统一使用0填充。因此有
以太坊智能合约函数参数ABI编码,动态类型string编码,函数参数的ABI编码, 含c++代码_第6张图片

官网没有说清楚的是,为什么要追加上面的值0000000000000000000000000000000000000000000000000000000000000060。原因是,string类型是动态类型,长度不是固定的,因此,需要将string数据从哪里开始的这个信息编码进去,这个信息我们称为offset。现在的offset=60(16进制)=96(10进制),我们的字符串的长度表示是使用十进制的,又因为我们需要编码的参数为(uint256 _deadline, uint32 _reward, string memory _code),前面两个参数+offset,相当于3个数,每一个数的长度是一样的,因此 ** 每一个数的长度为96/3 = 32。** 这就是我们的结论。

根据上面这个结论,如果所编码的参数变为四个(uint256 _deadline, uint32 _reward, uint32 other, string memory _code),那么string前面的offset变为32*4 = 128(10进制) = 80 (16进制)。使用线上工具验证结果一致:
以太坊智能合约函数参数ABI编码,动态类型string编码,函数参数的ABI编码, 含c++代码_第7张图片
在solidity中的bytes类型也是动态类型,编码方式跟string类似。

谢谢

c++代码


// deadline, uint256; reward, uint32, 
string appendParams_ABIEncode(string contractCode, unsigned long long deadline, unsigned int reward, string evalCode) {
	stringstream temp_time;
	temp_time << setfill('0') << setw(64) << hex << deadline;
	stringstream temp_reward;
	temp_reward << setfill('0') << setw(64) << hex << reward;

	stringstream temp_len;
	temp_len << setfill('0') << setw(64) << hex << evalCode.length();

	string code_hex = toHex(evalCode);
	int padding_num = code_hex.length() % 64;
	if (padding_num != 0) {
		padding_num = 64 - padding_num;
	}

	string padding = string(padding_num, '0');

	code_hex += padding;

	contractCode = contractCode 
		+ temp_time.str() 
		+ temp_reward.str() 
		//后面是字符串,动态空间,所以要加这个,没在文档中找到这个定义。https://abi.hashex.org/
		+ string("0000000000000000000000000000000000000000000000000000000000000060") 
		+ temp_len.str() + code_hex;
	return contractCode;
}

调用:

const string compiledCode = "";
string requestData = appendParams_ABIEncode(compiledCode, 20200529124532, 20, "dsfasdjfkldsjkaflksdjfljsdflksdj");

cout << requestData << endl;

你可能感兴趣的:(区块链,科技前沿)