本篇内容主要讲解“Solidity Event是怎么实现的”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Solidity Event是怎么实现的”吧!
一个Solidity Event的定义如下:
event Deposit(
address indexed _from,
bytes32 indexed _id,
uint _value
);
最多 3 indexed参数.
如果一个 indexed 参数的类型是大于32 bytes (比如 string 和 bytes), 就不存实际数据, 而是存数据的KECCAK256摘要(Digest).
先来看log0
, log1
, ..., log4
EVM 指令.
EVM 日志功能使用不同的术语:
“topics”: 最多 4 个topics. 每个topic 32 bytes.
“data”: 数据是event的Payload. 可以是任意长度的bytes.
一个Solidity event 如何映射到一个log 原语?
所有“non-indexed 参数” 被存为data.
每个“indexed 参数” 被存为一个32 bytes的topic.
Log0生成一个只有data的日志项目, 没有topic. data可以任意长度的 bytes.
下面看一个例子
pragma solidity ^0.4.18;
contract Logger {
function Logger() public {
log0(0xc0fefe);
}
}
编译后
0x40指针是内存的空闲指针。第一部分将数据导入内存,第二部分将数据的大小在栈上准备好
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
第一个topic是方法的签名.
第二个topic是indexed参数的值.
除了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
第一个topic是方法的签名.
第二个topic是字符串参数的SHA256摘要.
验证“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");
到此,相信大家对“Solidity Event是怎么实现的”有了更深的了解,不妨来实际操作一番吧!这里是亿速云网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!
亿速云「云服务器」,即开即用、新一代英特尔至强铂金CPU、三副本存储NVMe SSD云盘,价格低至29元/月。点击查看>>
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。
原文链接:https://my.oschina.net/gavinzheng731/blog/1924015