溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Solidity Event是怎么實(shí)現(xiàn)的

發(fā)布時(shí)間:2021-12-07 15:33:20 來(lái)源:億速云 閱讀:192 作者:iii 欄目:互聯(lián)網(wǎng)科技

本篇內(nèi)容主要講解“Solidity Event是怎么實(shí)現(xiàn)的”,感興趣的朋友不妨來(lái)看看。本文介紹的方法操作簡(jiǎn)單快捷,實(shí)用性強(qiáng)。下面就讓小編來(lái)帶大家學(xué)習(xí)“Solidity Event是怎么實(shí)現(xiàn)的”吧!

一個(gè)Solidity Event的定義如下:

event Deposit(
    address indexed _from,
    bytes32 indexed _id,
    uint _value
);
  • 最多 3 indexed參數(shù).

  • 如果一個(gè) indexed 參數(shù)的類型是大于32 bytes (比如 string 和 bytes), 就不存實(shí)際數(shù)據(jù), 而是存數(shù)據(jù)的KECCAK256摘要(Digest).

EVM Log Primitives

先來(lái)看log0log1, ..., log4 EVM 指令.

EVM 日志功能使用不同的術(shù)語(yǔ):

  • “topics”: 最多 4 個(gè)topics. 每個(gè)topic 32 bytes.

  • “data”: 數(shù)據(jù)是event的Payload. 可以是任意長(zhǎng)度的bytes.

一個(gè)Solidity event 如何映射到一個(gè)log 原語(yǔ)?

  • 所有“non-indexed 參數(shù)” 被存為data.

  • 每個(gè)“indexed 參數(shù)” 被存為一個(gè)32 bytes的topic.

The log0 Primitive

Log0生成一個(gè)只有data的日志項(xiàng)目, 沒有topic. data可以任意長(zhǎng)度的 bytes.

下面看一個(gè)例子

pragma solidity ^0.4.18;
contract Logger {
  function Logger() public {
    log0(0xc0fefe);
  }
}

編譯后

0x40指針是內(nèi)存的空閑指針。第一部分將數(shù)據(jù)導(dǎo)入內(nèi)存,第二部分將數(shù)據(jù)的大小在棧上準(zhǔn)備好

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

在執(zhí)行l(wèi)og0前, 在棧上有2個(gè)參數(shù): [0x60 0x20].

  • start: 0x60 是用來(lái)存放數(shù)據(jù)的內(nèi)存指針.

  • size: 0x20 (或者32) 指定了載入數(shù)據(jù)的大小.

Logging With Topics

下面的例子使用 log2 原語(yǔ). 第一個(gè)參數(shù)是數(shù)據(jù)(可以任意長(zhǎng)字節(jié)),其后跟著 2個(gè) topics (每個(gè)32 bytes ):

// log-2.sol
pragma solidity ^0.4.18;

contract Logger {
  function Logger() public {
    log2(0xc0fefe, 0xaaaa1111, 0xbbbb2222);
  }
}

匯編代碼是非常相似的。唯一的區(qū)別是2個(gè)topics (0xbbbb22220xaaaa1111)被推倒了棧上:

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

數(shù)據(jù)還是0xc0fefe, 被拷貝到內(nèi)存. 執(zhí)行 log2前,狀態(tài)如下:

stack: [0x60 0x20 0xaaaa1111 0xbbbb2222]
memory: {
  0x60: 0xc0fefe
}
log2

頭兩個(gè)參數(shù)指定日志數(shù)據(jù)的內(nèi)存領(lǐng)域,2個(gè)新增的棧上元素是2個(gè)32 bytes 的topics.

All EVM Logging Primitives

EVM支持5個(gè)日志的原語(yǔ):

0xa0 LOG0
0xa1 LOG1
0xa2 LOG2
0xa3 LOG3
0xa4 LOG4

Logging Testnet Demo

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);
  }
}

這個(gè)合約被部署到Rinkeby測(cè)試網(wǎng)絡(luò). 在: https://rinkeby.etherscan.io/tx/0x0e88c5281bb38290ae2e9cd8588cd979bc92755605021e78550fbc4d130053d1

Solidity Events

下面是一個(gè)Log事件,帶著3個(gè)uint256的參數(shù)(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

數(shù)據(jù)是事件參數(shù), ABI編碼:

0000000000000000000000000000000000000000000000000000000000000001
0000000000000000000000000000000000000000000000000000000000000002
0000000000000000000000000000000000000000000000000000000000000003

有一個(gè)topic, 1個(gè) 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'

因?yàn)镾olidity事件為事件簽名用掉了一個(gè)topic, 留給indexed 參數(shù)的只有3個(gè)topic.

Solidity Event With Indexed Arguments

下面是有一個(gè) indexed uint256 參數(shù)的事件:

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個(gè)topic:

0x00032a912636b05d31af43f00b91359ddcfddebcffa7c15470a13ba1992e10f0
0x0000000000000000000000000000000000000000000000000000000000000002
  • 第一個(gè)topic是方法的簽名.

  • 第二個(gè)topic是indexed參數(shù)的值.

除了indexed 參數(shù),數(shù)據(jù)是ABI編碼:

0000000000000000000000000000000000000000000000000000000000000001
0000000000000000000000000000000000000000000000000000000000000003

String/Bytes Event Parameter

將事件的參數(shù)設(shè)為字符串:

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個(gè)topics:

0xb857d3ea78d03217f929ae616bf22aea6a354b78e5027773679b7b4a6f66e86b
0xb5553de315e0edf504d9150af82dafa5c4667fa618ed0a6f19c69b41166c5510
  • 第一個(gè)topic是方法的簽名.

  • 第二個(gè)topic是字符串參數(shù)的SHA256摘要.

驗(yàn)證“b”的哈希值和第二個(gè)topic是一樣的:

>>> sha3("b").hex()
'b5553de315e0edf504d9150af82dafa5c4667fa618ed0a6f19c69b41166c5510'

日志數(shù)據(jù)是2個(gè)non-indexed 字符串 “a” 和 “c”, ABI編碼:

0000000000000000000000000000000000000000000000000000000000000040
0000000000000000000000000000000000000000000000000000000000000080
0000000000000000000000000000000000000000000000000000000000000001
6100000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000001
6300000000000000000000000000000000000000000000000000000000000000

indexed 字符串參數(shù)沒有被存儲(chǔ),所以DApp客戶無(wú)法恢復(fù)它.

如果你確實(shí)需要最初的字符串, 那就記錄2次, indexed 和 non-indexed:

event Log(string a, string indexed indexedB, string b);
Log("a", "b", "b");

到此,相信大家對(duì)“Solidity Event是怎么實(shí)現(xiàn)的”有了更深的了解,不妨來(lái)實(shí)際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI