智能合約應用程序二進制接口規範

概述

本文章主要寫調用合約發送交易參數組裝編碼過程;java

在web3j源碼中有一個codegen module模塊,其中有個項功能是將solidity文件轉換成java文件,該文件包含了合約的全部接口與deploy、load,這樣對其餘程序員來講,下降了他們對接區塊鏈與智能合約時的學習成本;但這種方式也存在一些弊端,須要改進,如每編寫一個合約都須要手動的生成一個對應的java文件,若是合約隨着業務的變化一直在變,那麼就須要不停的更新java文件,並附加到項目工程中,致使沒更新一個合約就要從新更新項目版本;程序員

so爲了解決這個問題,只能拋棄web3j的方法,使用輸入參數的形式,也就是部署合約與調用合約接口由專門的統一接口提供; 如:部署合約接口(deploy)、調用合約接口,發送交易(sendContractTransaction)、調用合約接口,不發生交易(callContract)。 下面就對這3個接口作一個詳細的解析;由於每一個鏈都有不一樣的數據結構和標準,因此這裏以eth爲例,其餘以太坊系列的使用solidity語言的相似一次類推;web

知識預備

智能合約應用程序二進制接口規範

這裏不講智能合約具體是啥,幹什麼用,若想了解可參考小編的另外一篇關於solidity的博客;json

這裏講智能合約應用程序二進制接口規範; 主要有如下基本類型:數組

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官方文檔curl

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)ide

  • 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:第三個參數的第三個條目。

0xa5643bf20000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000464617665000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003

 

合約事件也是同理,只是對應以太坊的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": "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675"
}]

 

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: ["0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675"]

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設計;

相關文章
相關標籤/搜索