美文网首页Dapp开发以太坊- Ethereum
以太坊开发(二十一)详解 Solidity 事件Event -

以太坊开发(二十一)详解 Solidity 事件Event -

作者: yuyangray | 来源:发表于2018-05-12 10:49 被阅读145次

    很多同学对Solidity 中的Event有疑问,这篇文章就来详细的看看Solidity 中Event到底有什么用?

    写在前面

    本文在监听合约事件是对上一篇以太坊开发(二十)Web3与智能合约交互实战进行补充,如果阅读了上一篇可以更好的理解本文。

    什么是事件Evnet

    事件是以太坊虚拟机(EVM)日志基础设施提供的一个便利接口。当被发送事件(调用)时,会触发参数存储到交易的日志中(一种区块链上的特殊数据结构)。这些日志与合约的地址关联,并记录到区块链中.
    来捋这个关系:区块链是打包一系列交易的区块组成的链条,每一个交易“收据”会包含0到多个日志记录,日志代表着智能合约所触发的事件。

    在DAPP的应用中,如果监听了某事件,当事件发生时,会进行回调。

    不过要注意:日志和事件在合约内是无法被访问的,即使是创建日志的合约。

    在Solidity 代码中,使用event 关键字来定义一个事件,如:

    event EventName(address bidder, uint amount);
    

    这个用法和定义函数式一样的,并且事件在合约中同样可以被继承。触发一个事件使用emit(说明,之前的版本里并不需要使用emit),如:

    emit EventName(msg.sender, msg.value);
    

    触发事件可以在任何函数中调用,如:

    function testEvent() public {
    
        // 触发一个事件
         emit EventName(msg.sender, msg.value); 
    }
    

    监听事件

    通过上面的介绍,可能大家还是不清楚事件有什么作用,如果你跟过以太坊开发(二十)Web3与智能合约交互实战这篇文章,你会发现点击”Updata Info”按钮之后,虽然调用智能合约成功,但是当前的界面并没有得到更新。
    使用事件监听,就可以很好的解决这个问题,让看看如何实现。

    修改合约,定义事件及触发事件

    先回顾一下合约代码:

    pragma solidity ^0.4.21;
    
    contract InfoContract {
        
       string fName;
       uint age;
       
       function setInfo(string _fName, uint _age) public {
           fName = _fName;
           age = _age;
       }
       
       function getInfo() public constant returns (string, uint) {
           return (fName, age);
       }   
    }
    

    首先,需要定义一个事件:

    event Instructor(
          string name,
          uint age
       );
    

    这个事件中,会接受两个参数:name 和 age , 也就是需要跟踪的两个信息。

    然后,需要在setInfo函数中,触发Instructor事件,如:

    function setInfo(string _fName, uint _age) public {
        fName = _fName;
        age = _age;
        emit Instructor(_fName, _age);
    }
    

    点击Updata Info按钮之后,会调用setInfo函数,函数时触发Instructor事件。

    合约完整代码

    pragma solidity ^0.4.21;
    
    contract InfoContract {
        
       string fName;
       uint age;
       
       event Instructor(
          string name,
          uint age
       );
       
       function setInfo(string _fName, uint _age) public {
           fName = _fName;
           age = _age;
           emit Instructor(_fName, _age);
       }
       
       function getInfo() public constant returns (string, uint) {
           return (fName, age);
       }   
    }
    

    使用Web3监听事件,刷新UI

    现在需要使用Web3监听事件,刷新UI。
    先回顾下之前的使用Web3和智能合约交互的代码:

     <script>
           if (typeof web3 !== 'undefined') {
                web3 = new Web3(web3.currentProvider);
            } else {
                // set the provider you want from Web3.providers
                web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:7545"));
            }
            web3.eth.defaultAccount = web3.eth.accounts[0];
            var infoContract = web3.eth.contract([{"constant":true,"inputs":[],"name":"getInfo","outputs":[{"name":"","type":"string"},{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_fName","type":"string"},{"name":"_age","type":"uint256"}],"name":"setInfo","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"}]);
            var info = infoContract.at('0x8cdaf0cd259887258bc13a92c0a6da92698644c0');
            info.getInfo(function(error, result){
                if(!error)
                    {
                        $("#info").html(result[0]+' ('+result[1]+' years old)');
                        console.log(result);
                    }
                else
                    console.error(error);
            });
            $("#button").click(function() {
                info.setInfo($("#name").val(), $("#age").val());
            });
        </script>
    

    现在可以不需要 info.getInfo()来获取信息,而改用监听事件获取信息,先定义一个变量引用事件:

    var instructorEvent = info.Instructor();
    

    然后使用.watch()方法来添加一个回调函数:

    instructorEvent.watch(function(error, result) {
            if (!error)
                {
                    $("#info").html(result.args.name + ' (' + result.args.age + ' years old)');
                } else {
                    console.log(error);
                }
        });
    

    注意:由于改动了合约代码,需要在Remix中重新编译部署并取得ABI和合约地址,具体内容查看上篇文章。

    新的ABI:

    [{"constant":true,"inputs":[],"name":"getInfo","outputs":[{"name":"","type":"string"},{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_fName","type":"string"},{"name":"_age","type":"uint256"}],"name":"setInfo","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"anonymous":false,"inputs":[{"indexed":false,"name":"name","type":"string"},{"indexed":false,"name":"age","type":"uint256"}],"name":"Instructor","type":"event"}]
    

    新的合约地址:

    0xf25186b5081ff5ce73482ad761db0eb0d25abfbf
    

    index.html完整代码:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>Document</title>
    
        <link rel="stylesheet" type="text/css" href="main.css">
    
        <script src="./node_modules/web3/dist/web3.min.js"></script>
    
    </head>
    <body>
        <div class="container">
    
            <h1>Info Contract</h1>
    
            <h2 id="info"></h2>
    
            <label for="name" class="col-lg-2 control-label">Name</label>
            <input id="name" type="text">
    
            <label for="name" class="col-lg-2 control-label">Age</label>
            <input id="age" type="text">
    
            <button id="button">Update Info</button>
    
    
        </div>
    
        <script src="https://code.jquery.com/jquery-3.2.1.slim.min.js"></script>
    
         <script>
           if (typeof web3 !== 'undefined') {
                web3 = new Web3(web3.currentProvider);
            } else {
                // set the provider you want from Web3.providers
                web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:7545"));
            }
            web3.eth.defaultAccount = web3.eth.accounts[0];
            var infoContract = web3.eth.contract([{"constant":true,"inputs":[],"name":"getInfo","outputs":[{"name":"","type":"string"},{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_fName","type":"string"},{"name":"_age","type":"uint256"}],"name":"setInfo","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"anonymous":false,"inputs":[{"indexed":false,"name":"name","type":"string"},{"indexed":false,"name":"age","type":"uint256"}],"name":"Instructor","type":"event"}]);
            // var info = infoContract.at('0x8cdaf0cd259887258bc13a92c0a6da92698644c0');
            var info = infoContract.at('0xf25186b5081ff5ce73482ad761db0eb0d25abfbf');
            var instructorEvent = info.Instructor();
            instructorEvent.watch(function(error, result) {
            if (!error)
                {
                    $("#info").html(result.args.name + ' (' + result.args.age + ' years old)');
                } else {
                    console.log(error);
                }
            });
            // info.getInfo(function(error, result){
            //     if(!error)
            //         {
            //             $("#info").html(result[0]+' ('+result[1]+' years old)');
            //             console.log(result);
            //         }
            //     else
            //         console.error(error);
            // });
            $("#button").click(function() {
                info.setInfo($("#name").val(), $("#age").val());
            });
        </script>
    
    </body>
    </html>
    

    代码更新之后,可以在浏览器查看效果,这时点击”Update Info”按钮之后,会及时更新界面,如图:

    原文:详解 Solidity 事件Event - 完全搞懂事件的使用
    作者:Tiny熊

    相关文章

      网友评论

        本文标题:以太坊开发(二十一)详解 Solidity 事件Event -

        本文链接:https://www.haomeiwen.com/subject/epycdftx.html