一個Solidity Event的定義以下:git
event Deposit( address indexed _from, bytes32 indexed _id, uint _value );
先來看log0
, log1
, ..., log4
EVM 指令.github
EVM 日誌功能使用不一樣的術語:網絡
一個Solidity event 如何映射到一個log 原語?測試
Log0生成一個只有data的日誌項目, 沒有topic. data能夠任意長度的 bytes.ui
下面看一個例子編碼
pragma solidity ^0.4.18;
contract Logger { function Logger() public { log0(0xc0fefe); } }
編譯後spa
0x40指針是內存的空閒指針。第一部分將數據導入內存,第二部分將數據的大小在棧上準備好3d
memory: { 0x40 => 0x60 } tag_1: // copy data into memory 0xc0fefe [0xc0fefe] mload(0x40) [0x60 0xc0fefe] swap1 [0xc0fefe 0x60] dup2 [0x60 0xc0fefe 0x60] mstore [0x60] memory: { 0x40 => 0x60 0x60 => 0xc0fefe } // calculate data start position and size 0x20 [0x20 0x60] add [0x80] mload(0x40) [0x60 0x80] dup1 [0x60 0x60 0x80] swap2 [0x60 0x80 0x60] sub [0x20 0x60] swap1 [0x60 0x20] log0
在執行log0前
, 在棧上有2個參數: [0x60 0x20]
.指針
start
: 0x60 是用來存放數據的內存指針.size
: 0x20 (或者32) 指定了載入數據的大小.下面的例子使用 log2
原語. 第一個參數是數據(能夠任意長字節),其後跟着 2個 topics (每一個32 bytes ):日誌
// log-2.sol pragma solidity ^0.4.18; contract Logger { function Logger() public { log2(0xc0fefe, 0xaaaa1111, 0xbbbb2222); } }
彙編代碼是很是類似的。惟一的區別是2個topics (0xbbbb2222
, 0xaaaa1111
)被推倒了棧上:
tag_1: // push topics 0xbbbb2222 0xaaaa1111 // copy data into memory 0xc0fefe mload(0x40) swap1 dup2 mstore 0x20 add mload(0x40) dup1 swap2 sub swap1 // create log log2
數據仍是0xc0fefe
, 被拷貝到內存. 執行 log2
前,狀態以下:
stack: [0x60 0x20 0xaaaa1111 0xbbbb2222] memory: { 0x60: 0xc0fefe } log2
頭兩個參數指定日誌數據的內存領域,2個新增的棧上元素是2個32 bytes 的topics.
EVM支持5個日誌的原語:
0xa0 LOG0 0xa1 LOG1 0xa2 LOG2 0xa3 LOG3 0xa4 LOG4
pragma solidity ^0.4.18; contract Logger { function Logger() public { log0(0x0); log1(0x1, 0xa); log2(0x2, 0xa, 0xb); log3(0x3, 0xa, 0xb, 0xc); log4(0x4, 0xa, 0xb, 0xc, 0xd); } }
這個合約被部署到Rinkeby測試網絡. 在: https://rinkeby.etherscan.io/tx/0x0e88c5281bb38290ae2e9cd8588cd979bc92755605021e78550fbc4d130053d1
下面是一個Log事件,帶着3個uint256的參數(non-indexed):
pragma solidity ^0.4.18; contract Logger { event Log(uint256 a, uint256 b, uint256 c); function log(uint256 a, uint256 b, uint256 c) public { Log(a, b, c); } }
生成的原始日誌在:
https://rinkeby.etherscan.io/tx/0x9d3d394867330ae75d7153def724d062b474b0feb1f824fe1ff79e772393d395
數據是事件參數, ABI編碼:
0000000000000000000000000000000000000000000000000000000000000001 0000000000000000000000000000000000000000000000000000000000000002 0000000000000000000000000000000000000000000000000000000000000003
有一個topic, 1個 32 bytes hash:
0x00032a912636b05d31af43f00b91359ddcfddebcffa7c15470a13ba1992e10f0
這是事件類型的簽名的SHA3哈希:
# Install pyethereum # https://github.com/ethereum/pyethereum/#installation > from ethereum.utils import sha3 > sha3("Log(uint256,uint256,uint256)").hex() '00032a912636b05d31af43f00b91359ddcfddebcffa7c15470a13ba1992e10f0'
由於Solidity事件爲事件簽名用掉了一個topic, 留給indexed 參數的只有3個topic.
下面是有一個 indexed uint256
參數的事件:
pragma solidity ^0.4.18; contract Logger { event Log(uint256 a, uint256 indexed b, uint256 c); function log(uint256 a, uint256 b, uint256 c) public { Log(a, b, c); } }
有2個topic:
0x00032a912636b05d31af43f00b91359ddcfddebcffa7c15470a13ba1992e10f0 0x0000000000000000000000000000000000000000000000000000000000000002
除了indexed 參數,數據是ABI編碼:
0000000000000000000000000000000000000000000000000000000000000001 0000000000000000000000000000000000000000000000000000000000000003
將事件的參數設爲字符串:
pragma solidity ^0.4.18; contract Logger { event Log(string a, string indexed b, string c); function log(string a, string b, string c) public { Log(a, b, c); } }
交易在: https://rinkeby.etherscan.io/tx/0x21221c2924bbf1860db9e098ab98b3fd7a5de24dd68bab1ea9ce19ae9c303b56
有2個topics:
0xb857d3ea78d03217f929ae616bf22aea6a354b78e5027773679b7b4a6f66e86b 0xb5553de315e0edf504d9150af82dafa5c4667fa618ed0a6f19c69b41166c5510
驗證「b」的哈希值和第二個topic是同樣的:
>>> sha3("b").hex() 'b5553de315e0edf504d9150af82dafa5c4667fa618ed0a6f19c69b41166c5510'
日誌數據是2個non-indexed 字符串 「a」 和 「c」, ABI編碼:
0000000000000000000000000000000000000000000000000000000000000040 0000000000000000000000000000000000000000000000000000000000000080 0000000000000000000000000000000000000000000000000000000000000001 6100000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000001 6300000000000000000000000000000000000000000000000000000000000000
indexed 字符串參數沒有被存儲,因此DApp客戶沒法恢復它.
若是你確實須要最初的字符串, 那就記錄2次, indexed 和 non-indexed:
event Log(string a, string indexed indexedB, string b); Log("a", "b", "b");