智能合约应⽤程序⼆进制接⼝规范
概述
本⽂章主要写调⽤合约发送交易参数组装编码过程;
在web3j源码中有⼀个codegen module模块,其中有个项功能是将solidity⽂件转换成java⽂件,该⽂件包含了合约的所有接⼝与deploy、load,这样对其他程序员来说,降低了他们对接区块链与智能合约时的学习成本;但这种⽅式也存在⼀些弊端,需要改进,如每编写⼀个合约都需要⼿动的⽣成⼀个对应的java⽂件,如果合约随着业务的变化⼀直在变,那么就需要不停的更新java⽂件,并附加到项⽬⼯程中,导致没更新⼀个合约就要重新更新项⽬版本;
so为了解决这个问题,只能抛弃web3j的⽅法,使⽤输⼊参数的形式,也就是部署合约与调⽤合约接⼝由专门的统⼀接⼝提供;如:部署合约接⼝(deploy)、调⽤合约接⼝,发送交易(sendContractTransaction)、调⽤合约接⼝,不发⽣交易(callContract)。下⾯就对这3个接⼝做⼀个详细的解析;因为每个链都有不同的数据结构和标准,所以这⾥以eth为例,其他以太坊系列的使⽤solidity语⾔的类似⼀次类推;
知识预备
智能合约应⽤程序⼆进制接⼝规范
这⾥不讲智能合约具体是啥,⼲什么⽤,若想了解可参考⼩编的另⼀篇关于solidity的博客;
这⾥讲智能合约应⽤程序⼆进制接⼝规范;主要有以下基本类型:
uint<M>: unsigned integer type of M bits, 0 < M <= 256, M % 8 == 0. e.g. uint32, uint8, uint256.
字符串长度规则int<M>: two’s complement signed integer type of M bits, 0 < M <= 256, M % 8 == 0.
address: equivalent to uint160, except for the assumed interpretation and language typing. For computing the function selector, address is used.
uint, int: synonyms for uint256, int256 respectively. For computing the function selector, uint256 and int256 have to be used.
bool: equivalent to uint8 restricted to the values 0 and 1. For computing the function selector, bool is used.
fixed<M>x<N>: signed fixed-point decimal number of M bits, 8 <= M <= 256, M % 8 ==0, and 0 < N <= 80, which denotes the value v as v / (10 ** N).
ufixed<M>x<N>: unsigned variant of fixed<M>x<N>.
fixed, ufixed: synonyms for fixed128x18, ufixed128x18 respectively. For computing the function selector, fixed128x18 and ufixed128x18 have to be used.
bytes<M>: binary type of M bytes, 0 < M <= 32.
function: an address (20 bytes) followed by a function selector (4 bytes). Encoded identical to bytes24.
The following (fixed-size) array type exists:
<type>[M]: a fixed-length array of M elements, M >= 0, of the given type.
The following non-fixed-size types exist:
bytes: dynamic sized byte sequence.
string: dynamic sized unicode string assumed to be UTF-8 encoded.
<type>[]: a variable-length array of elements of the given type.
Types can be combined to a tuple by enclosing a finite non-negative number of them inside parentheses, separated by commas:
(T1,T2,...,Tn): tuple consisting of the types T1, …, Tn, n >= 0
It is possible to form tuples of tuples, arrays of tuples and so on. It is also possible to form zero-tuples (where n == 0).
⼩编主要讲解如何解析合约⽅法编码问题,⽐较常见的2中,静态类型(static type)与动态类型(dynamic type),其中静态类型分基本类型与固定数组长度
这⾥写个合约做讲解来之solidity官⽅⽂档
pragma solidity ^0.4.16;
contract Foo {
// 基本类型
function baz(uint32 x, bool y) public pure returns (bool r) { r = x > 32 || y; }
/
/ 固定数组长度
function bar(bytes3[2]) public pure {}
// 动态类型
function sam(bytes, bool, uint[]) public pure {}
}
例如:调⽤baz(69,true),可由68字节组成,可细分为methodId+arg1(uint32 69)+arg2(bool true)
methodId:⽅法ID。这是作为签名的ASCII形式的Keccak散列的前4个字节导出的baz(uint32,bool);0xcdcd77c0
arg1(uint32 69):第⼀个参数,uint32值69填充为32字节,0x0000000000000000000000000000000000000000000000000000000000000045
arg2(bool true):第⼆个参数,布尔值true,填充为32个字节;0x0000000000000000000000000000000000000000000000000000000000000001
0xcdcd77c000000000000000000000000000000000000000000000000000000000000000450000000000000000000000000000000000000000000000000000000000000001
返回⼀个bool。因为bool true为1 false为0,所以输出若为false则0x0000000000000000000000000000000000000000000000000000000000000000
例如:调⽤bar(["abc","def"]),则有68字节组成;可细分为methodId+arg1(bytes3[2])
methodId:⽅法ID。这是作为签名的ASCII形式的Keccak散列的前4个字节导出的bar(bytes3[2]);0xfce353f6
0x6162630000000000000000000000000000000000000000000000000000000000:第⼀个参数的第⼀部分,⼀个bytes3值"abc"(左对齐)。
0x6465660000000000000000000000000000000000000000000000000000000000:第⼀个参数的第⼆部分,⼀个bytes3值"def"(左对齐)。
0xfce353f661626300000000000000000000000000000000000000000000000000000000006465660000000000000000000000000000000000000000000000000000000000
如果想调⽤sam("dave",true,[1,2,3]),注意,uint将被替换成uint256
0xa5643bf2:⽅法ID。这来⾃签名sam(bytes,bool,uint256[])。请注意,它将uint替换为其规范表⽰uint256。
0x0000000000000000000000000000000000000000000000000000000000000060:第⼀个参数(动态类型)的数据部分的位置,以参数块开头的字节为单位。在这种情况下,0x60。这⾥再补充⼀遍0x60是怎么计算出来的,是指从第60个偏移量开始为该动态类型的内容;下⾯的xa同理
0x0000000000000000000000000000000000000000000000000000000000000001:第⼆个参数:布尔值true。
0x00000000000000000000000000000000000000000000000000000000000000a0:第三个参数(动态类型)的数据部分的位置,以字节为单位。在这种情况下,0xa0。
0x0000000000000000000000000000000000000000000000000000000000000004:第⼀个参数的数据部分,它以元素中字节数组的长度开始,在本例中为
4。0x6461766500000000000000000000000000000000000000000000000000000000:第⼀个参数的内容:UTF-8(在本例中等于ASCII)编码"dave",右边填充32个字
节。0x0000000000000000000000000000000000000000000000000000000000000003:第三个参数的数据部分,它以元素中数组的长度开始,在本例中为
3。0x0000000000000000000000000000000000000000000000000000000000000001:第三个参数的第⼀个条⽬。0x0000000000000000000000000000000000000000000000000000000000000002:第
三个参数的第⼆个条⽬。0x0000000000000000000000000000000000000000000000000000000000000003:第三个参数的第三个条⽬。
0xa5643bf20000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000a00
合约事件也是同理,只是对应以太坊的logs中的topics
eth接⼝
eth_sendTransaction
Creates new message call transaction or a contract creation, if the data field contains code.
Parameters
1. Object - The transaction object
from: DATA, 20 Bytes - The address the transaction is send from.
to: DATA, 20 Bytes - (optional when creating new contract) The address the transaction is directed to.
gas: QUANTITY - (optional, default: 90000) Integer of the gas provided for the transaction execution. It will return unused gas.
gasPrice: QUANTITY - (optional, default: To-Be-Determined) Integer of the gasPrice used for each paid gas
value: QUANTITY - (optional) Integer of the value sent with this transaction
data: DATA - The compiled code of a contract OR the hash of the invoked method signature and encoded parameters. For details see Ethereum Contract ABI
nonce: QUANTITY - (optional) Integer of a nonce. This allows to overwrite your own pending transactions that use the same nonce.
params: [{
"from": "0xb60e8dd61c5d32be8058bb8eb970870f07233155",
"to": "0xd46e8dd67c5d32be8058bb8eb970870f07244567",
"gas": "0x76c0", // 30400
"gasPrice": "0x9184e72a000", // 10000000000000
"value": "0x9184e72a", // 2441406250
"data": "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f0724********bb8eb970870f072445675"
}]
Returns DATA, 32 Bytes - the transaction hash, or the zero hash if the transaction is not yet available.
Example
// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"eth_sendTransaction","params":[{see above}],"id":1}'
// Result
{
"id":1,
"jsonrpc": "2.0",
"result": "0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331"
}
eth_sendRawTransaction
Creates new message call transaction or a contract creation for signed transactions.
Parameters
1. DATA, The signed transaction data.
params: ["0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f0724********bb8eb970870f072445675"]
Returns DATA, 32 Bytes - the transaction hash, or the zero hash if the transaction is not yet available.
Use eth_getTransactionReceipt to get the contract address, after the transaction was mined, when you created a contract.
Example
// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"eth_sendRawTransaction","params":[{see above}],"id":1}'
// Result
{
"id":1,
"jsonrpc": "2.0",
"result": "0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331"
}
调⽤合约接⼝,发送交易(sendContractTransaction)
这⾥先以调⽤合约接⼝,发送交易(sendContractTransaction)为例,
输⼊:合约地址,合约⽅法名称,合约参数,合约ABI
1. 检验参数
要求合约地址不为空,去前缀0x时,长度为40字节;
合约ABI不能为空
合约⽅法名真是存在ABI json中
2. 通过合约⽅法名称,获取abi中的⽅法全名如(sam(bytes,bool,uint256[]))
若合约⽅法名称为空则获取合约构造⽅法
3. 检验合约参数类型是否匹配与是否规范
⽅法全名中参数类型与合约⽅法参数个数是否⼀样
⽅法全名中参数类型与合约⽅法参数类型是否⼀样,并校验对应类型的参数规范限定,如:address类型则必须符合去前缀0x,长度为40字节;
4. 对⽅法全名作ASCII形式的Keccak散列的签名的前4个字节导出
若该⽅法名为构造函数则⽆需签名,直接返回空字符串""(因为此处是以调⽤sendContractTransaction所以没有部署合约时的bin参数,若是调⽤构造函数则表明是deploy即需要在前⾯insert 合约
⼆进制编码bin)
5. 对参数进⾏编码(编码规则参考预备知识)
若参数长度为0,则直接返回空字符串""
若不为零,则根据编码规则参考预备知识
6. 将4与5结果拼接作为 eth_sendTransaction 接⼝的data参数
7. 补全eth_sendTransaction其他参数,将这些参数作为⼀个对象处理,Transaction
8. 对Transaction 进⾏RLP编码该处为byte[]类型所以⽆法打印(可转换成⼗六进制字符串输出)
9. ⽤以太坊钱包私钥对8步骤结果进⾏签名,以⼗六进制字符串输出
其中,6,7步骤根据不同的区块链数据结构与编码要求修改,1~5则是根据solidity语⾔做修改(⼀般不会有改动)输出:合约⼗六进制编码字符串
合约数据结构UML设计;

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。