主页 > imtoken钱包怎么激活 > 区块链开发(十五)以太坊中的事件和日志分析和使用
区块链开发(十五)以太坊中的事件和日志分析和使用
以太坊中的事件和日志是一个特别令人困惑的概念,本文将帮助您理清它们。
因为之前的文章,我们讨论了以太坊go-ethereum客户端查询交易列表的一些方法。在本文中,我们专门实现了一个过滤器讨论。让我们了解如何使用此方法。重点是最后一部分。希望对开发有帮助。让我们从基本概念开始,以了解整个过程。
首先,以太坊中的事件和日志基本上是同一个概念。在 Solidity 和 web3.js 中称为事件,在以太坊黄皮书中称为日志。可以理解为:以太坊通过Logs实现Events功能。智能合约代码通过LOG将日志写入区块链。
(如果使用Truffle框架开发也是一样,因为Truffle框架本身封装了Web3.js)
区块链上的日志内容在哪里?
日志内容是交易收据(Transaction Receipts)的一部分。整个日志内容,包括 Receipts 的其他内容,都会生成一个 ReceiptsRoot 并存储在区块的头部。完整的数据存储在链下。
事件和日志有四种主要用途:
1.帮助用户客户端(web3.js)读取智能合约的返回值;
2.智能合约异步通知用户客户端(web3.js);
3.智能合约的存储(比存储便宜得多);
4.我觉得还有第四种,可以帮助我们通过filter过滤掉历史交易数据。具体实现见下篇分析。
我们来一一解释
1.帮助用户客户端(web3.js)读取智能合约的返回值:
假设以下智能合约:
contract ExampleContract {
// some state variables ...
function foo(int256 _value) returns (int256) {
// manipulate state ...
return _value;
}
}
我们可以通过web3.js的消息调用函数模拟调用智能合约:
var returnValue = exampleContract.foo.call(2);
console.log(returnValue) // 2
但在真实环境中,我们需要发送交易来调用智能合约。这时候我们将无法获得智能合约的返回值。因为交易目前只是发送、打包、执行一段时间(需要矿工的工作量证明来实现)。此时调用的返回值就是交易的txid或者tx hash值。
var returnValue = exampleContract.foo.sendTransaction(2, {from: web3.eth.coinbase});
console.log(returnValue) // transaction hash
这就是事件发挥作用的地方:我们经常编写链上方法,或更改链上数据的方法。我们通过在方法前面添加 Event 来做到这一点。
//以下是solidity智能合约代码
contract ExampleContract {
event ReturnValue(address indexed _from, int256 _value);
unction foo(int256 _value) returns (int256) {
ReturnValue(msg.sender, _value);
return _value;
}
}
//以下是web3.js用户客户端代码
var exampleEvent = exampleContract.ReturnValue({_from: web3.eth.coinbase});
exampleEvent.watch(function(err, result) {
if (err) {
console.log(err)
return;
}
console.log(result.args._value)
// check that result.args._from is web3.eth.coinbase then
// display result.args._value in the UI and call
// exampleEvent.stopWatching()
})
exampleContract.foo.sendTransaction(2, {from: web3.eth.coinbase})
交易打包后,会调用web3.js中的回调以太坊区块链查询,然后web3.js可以获取交易中智能合约调用的返回值。
至于为什么打包事务,调用web3.js中的回调。那是另一个问题。简单的解释如下。 web3.js 将连接到以太坊中的一个节点。当节点得知有交易写入区块时,会通知连接的节点相关信息。
2.智能合约异步通知用户客户端(web3.js):
上面的例子是智能合约通知用户客户端的一个典型例子以太坊区块链查询,但是还有更多的异步调用可以类似的方式实现,从而实现智能合约异步调用用户客户端的能力。
注意:智能合约通常以 Solidity 编写并在以太坊节点 (EVM) 上运行。
注意:用户客户端一般用web3.js编写,运行在web服务器上,web3.js连接到以太坊节点。
3.智能合约的存储(比存储便宜得多):
相比存储智能合约账户,以日志的形式存储一些信息要便宜得多。 Storage 中的大致价格为:每 32 字节(256 位)存储 20,000 gas(Gas)。日志大约是每字节 8 个气体(Gas)。
请看下面的例子:
//solidity智能合约代码,模拟用户存款功能
contract CryptoExchange {
event Deposit(uint256 indexed _market, address indexed _sender, uint256 _amount, uint256 _time);
function deposit(uint256 _amount, uint256 _market) returns (int256) {
// perform deposit, update user’s balance, etc
Deposit(_market, msg.sender, _amount, now);
}
//当用户调用智能合约存入一定金额时,智能合约需要主动通知用户客户端更新相应信息。
4.帮助我们通过filter过滤掉历史交易数据。
下面的方法具体实现了通过我们开始讲的filter方法从链中提取历史交易数据的方法。
//以下是web3.js代码:
var depositEvent = cryptoExContract.Deposit({_sender: userAddress});
depositEvent.watch(function(err, result) {
if (err) {
console.log(err)
return;
}
else{
// append details of result.args to UI
//将这笔交易写入客户端资料库中,方便以后查询历史交易数据。
}
})
//通过增加fromBlock参数指定关注的区块范围,来查询所有的交易数据。(获取链上存储的历史交易数据,我们用扒链的办法来获取,因为eth目前没有提供获取历史数据的API。)
var depositEventAll = cryptoExContract.Deposit({_sender: userAddress}, {fromBlock: 0, toBlock: 'latest'});
depositEventAll.watch(function(err, result) {
if (err) {
console.log(err)
return;
}
else{
// append details of result.args to UI
//如果不想再被通知可以调用:
//depositEventAll.stopWatching();
}
})
//注意:indexed关键字表示该字段对日志进行索引,以提高查询效率。
2017年12月24日在深圳举办