区块链开发之Solidity编程基础合约事件

Posted BBinChina

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了区块链开发之Solidity编程基础合约事件相关的知识,希望对你有一定的参考价值。

事件

事件

事件是以太坊虚拟机(EVM)日志基础设施提供的一个便利接口。用于获取当前发生的事件。

事件和日志有三个用途:

  • 智能合约返回值给用户接口
  • 异步的带数据的触发器
  • 一种比较便宜的存储

智能合约返回值给用户接口

我们可以在 dapp 的用户界面中监听事件,EVM 的日志机制可以反过来“调用”用来监听事件的 javascript 回调函数。

contract ExampleContract 
	//一些状态变量
	function foo(int256 value) returns (int256) 
		//改变状态
		return value;
	

假设exampleContract就是ExampleContract的一个实例,一个前端使用web3.js,通过模拟函数的执行可以获得返回值:

	var returnValue = exampleContract.foo.call(2);
	console.log(returnValue);

但是一旦提交合约调用成为一个交易,则无法得到返回值

	var returnValue = exampleContract.foo.sendTransaction(2,from: web3.eth.coinbase);
	//交易的话,这里应该是一个交易哈希值
	console.log(returnValue);

sendTransaction函数的返回值总是创建交易的哈希。交易并不返回值给前端,这是因为交易没有马上被打包,还未上链。如果想获得一个返回值,那么应该使用事件的方式。

contract ExampleContract 
	event ReturnValue(address indexed from, int256 value);
	function foo(int256 value) returns (int256) 
		//触发事件
		ReturnValue(msg.sender, value);
		return value;
	

前端获取返回值:

//调用事件
var returnValue = exampleContract.ReturnValue( from:web3.eth.coinbase);
//监听事件
exampleEvent.watch(function(err, result)
	if (err) 
		console.log(err);
		return;
	
	console.log(result.args.value);
	//其他业务
	//exampleEvent.stopWatching();
)
//调用foo上链后,watch的回调会被触发,那么前端可以从foo获得返回值
exampleContract.foo.sendTransaction(2,from: web3.eth.coinbase);

异步的带数据的触发器

同理,前端应用可以采用监听事件进行回调的方式来实现异步操作

一种比较便宜的存储

在EVM里,事件被认为是日志(有LOG opcodes),数据可以被存储到日志,当事件被发送时,相应的日志被写到区块链中。根据这种特性,Logs被设计用来成为一种存储,它话费的燃料小于合约的storage,在EVM中Logs基本上每个字节会花费8Gas,而合约storage每32bytes话费20000Gas。
但是Logs不能被任何合约访问

那如何用来做存储呢,假设场景:合约可以记录某个用户当前的余额,也可以记录每个用户的充值记录,但是可以在Logs记录来取代在合约里记录,减少花费。

contract CryptoExchange 
	event Deposit(uint256 indexed market, address indexed sender, uint256 amount, uint256 time);

    function deposit(uint256 amount, uint256 market) returns (int256) 
        Deposit(market, msg.sender, amount, now);
    

cryptoExContract是web3实例化的CryptoExchange,在前端调用

var depositEvent = cryptoExContract.Deposit(sender:userAddress);
depositEvent.watch(function(err, result)
	if (err) 
		console.log(err)
		return
	
)

注意我们的事件参数sender使用关键字indexed修饰,表示索引,用于提高用户获取所有event的效率。
我们也可以从block0开始获取上链的事件

var depositEventAll = cryptoExContract.Deposit(
sender:userAddress,
fromBlock:0, toBlock:'latest'
);
depositEventAll.watch(function(err, result)
	if (err) 
		console.log(err)
		return
	
)

事件里的Indexed参数

一个事件最多三个indexed参数,在用户界面上可以使用 indexed 参数的特定值来进行过滤。
例如合约事件transfer:

event Transfer(address indexed from, address indexed to, uint256 amount);

假设应用监听事件,

1、监听from发送的事件

tokenContract.Transfer(
from:senderAddress
);

2、监听to接收的事件

tokenContract.Transfer(
to:receiverAddress
);

3、监特定from到特定to的事件

tokenContract.Transfer(
from:senderAddress,
to:receiverAddress
);

以上是关于区块链开发之Solidity编程基础合约事件的主要内容,如果未能解决你的问题,请参考以下文章

区块链开发之Solidity编程基础合约继承抽象合约接口

区块链开发之Solidity编程基础合约继承抽象合约接口

区块链开发之Solidity编程基础

区块链开发之Solidity编程基础合约数据存储

区块链开发之Solidity编程基础合约语句及函数修饰符

区块链开发之Solidity编程基础