![Solidity智能合约开发技术与实战-事件与日志_第1页](http://file4.renrendoc.com/view/588811558a1b1ac958e6c240ffa5fb4f/588811558a1b1ac958e6c240ffa5fb4f1.gif)
![Solidity智能合约开发技术与实战-事件与日志_第2页](http://file4.renrendoc.com/view/588811558a1b1ac958e6c240ffa5fb4f/588811558a1b1ac958e6c240ffa5fb4f2.gif)
![Solidity智能合约开发技术与实战-事件与日志_第3页](http://file4.renrendoc.com/view/588811558a1b1ac958e6c240ffa5fb4f/588811558a1b1ac958e6c240ffa5fb4f3.gif)
![Solidity智能合约开发技术与实战-事件与日志_第4页](http://file4.renrendoc.com/view/588811558a1b1ac958e6c240ffa5fb4f/588811558a1b1ac958e6c240ffa5fb4f4.gif)
![Solidity智能合约开发技术与实战-事件与日志_第5页](http://file4.renrendoc.com/view/588811558a1b1ac958e6c240ffa5fb4f/588811558a1b1ac958e6c240ffa5fb4f5.gif)
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
以太坊Solidity智能合约开发教程事件与日志学前提示事件是以太坊网络的基本功能,借助事件可以将数据记录为日志,保存在区块链上。事件还是与智能合约的外部进行交互的渠道,例如与前端的交互。知识要点7.1事件7.2日志7.1事件7.1.1事件模型.7.1.2定义和触发事件7.1.1事件模型7.1.2定义和触发事件Solidity语言的事件编程包括定义事件、触发事件和监听事件。其中定义和触发事件的功能在智能合约中实现;监听事件可以通过Web3.js实现。1.定义事件在Solidity语言中,可以使用event关键字来定义一个事件,方法如下:event<事件名>(<事件的参数>);例如eventPersonInfoUpdate(stringname,uintage);
2.触发事件可以使用emit关键字触发事件,具体方法如下:emit<事件名>(<事件的实参>);可以在任意函数中触发事件,例如:·functionsetInfo(string_fName,uint_age)public{fName=_fName;age=_age;emitPersonInfoUpdate(_fName,_age);}7.1.3在Web3.js中监听事件1.以WebSocket方式连接到以太坊节点2.订阅合约事件1.以WebSocket方式连接到以太坊节点以WebSocket模式启动以太坊私有链的选项--ws启用WS-RPC服务器--wsaddrvalue指定WS-RPC服务器监听的地址--wsportvalue指定WS-RPC服务器监听的端口--wsoriginsvalue指定websockets请求允许的源。通常使用--wsorigins'*'表示允许所有的连接通过如下命令启动以太坊私有链,并启用WS-RPC服务./geth--datadirethchain--nodiscoverconsole2>>1.log--dev.period1--password'./password.txt'--rpcport8545--rpccorsdomain"*"--rpcaddr=01-rpc--rpcapi="db,eth,net,web3,personal"--ws--wsaddr01--wsport7777--wsorigins在Web3.js中,可以通过如下的代码连接到WS-RPC服务web3=newWeb3(newWviders.WebsocketProvider("ws://01:7777"));【例7-1】contractPerson{stringpublicname;uintpublicage;functionSetInfo(stringmemory_name,uint_age)public{name=_name;age=_age;emitPersonInfoUpdate(_name,_age);}eventPersonInfoUpdate(stringname,uintage);}署合约Personcurl-H‘Content-Type:application/json’--data‘{“jsonrpc”:“2.0”,“method”:“eth_sendTransaction”,“params”:[{“from”:“0xd169d4387c2dcd1ec4e6952bddf0a22c1f8c2b2f”,“data”:“0x60806040523……."}],"id":20}'01:8545执行结果如下{"jsonrpc":"2.0","id":20,"result":"0x4b1501ec48388f48f9cf987f52c6fd7d3fffddcdf9cdfb96679adcea98613449"}获取本次交易的合约地址curl-H'Content-Type:application/json'--data'{"jsonrpc":"2.0","method":"eth_getTransactionReceipt","params":["0x4b1501ec48388f48f9cf987f52c6fd7d3fffddcdf9cdfb96679adcea98613449"],"id":21}'01:8545返回结果如下{"jsonrpc":"2.0","id":21,"result":{"blockHash":"0xdc30bd518cf80fb5d73391e1409ce004c979c10f09bf4f3211cec86737dd3e0f","blockNumber":"0x1d088","contractAddress":"0xed2d42ad9aa54e77fb5c35b7834aedc1171aef57","cumulativeGasUsed":"0x3a33a","from":"0xd169d4387c2dcd1ec4e6952bddf0a22c1f8c2b2f","gasUsed":"0x3a33a","logs":[],"logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","status":"0x1","to":null,"transactionHash":"0x4b1501ec48388f48f9cf987f52c6fd7d3fffddcdf9cdfb96679adcea98613449","transactionIndex":"0x0"}}2.订阅合约事件可以通过如下方法订阅合约事件:<智能合约对象>.events.<事件名>([options][,回调函数])options是可选参数,用于配置率先事件的选项。例如订阅事件MyEvent的代码myContract.events.PersonInfoUpdate(function(error,event){ if(!error){ console.log(event.returnV); console.log(event.returnValues.age);//$("#instructor").html(+'('+event.args.age+'yearsold)');}else{console.log(error);} })event对象包含如下属性
Event:事件名;
Signature:事件签名;
Address:事件源地址。
returnValues:事件的返回数据。例如,可以使用如下代码获取事件对象的参数值:
event.returnValues.<参数名>
logIndex:事件在块中的索引位置。
transactionIndex:事件在交易中的索引位置。
transactionHash:事件所在交易的哈希值。
blockHash:事件所在块的哈希值。
blockNumber:事件所在块的区块号。
raw.data:该字段包含未索引的日志参数。
raw.topics:事件的主题。<智能合约对象>.events.<事件名>()的返回值是一个事件发生器EventEmitter事件发生器可以触发如下的事件。
"data":接收到新的事件时触发。
"changed":当事件从区块链上移除时触发。
"error":当发生错误时触发。可以通过如下方式响应这些事件<智能合约对象>.events.<事件名>([options][,回调函数]).on('data',function(event){console.log(event);}).on('changed',function(event){//将事件从本地数据库删除}).on('error',console.error);【例7-2】$(function(){if(typeofweb3!=='undefined'){web3=newWeb3(web3.currentProvider);}else{//settheprovideryouwantfromWvidersweb3=newWeb3(newWviders.WebsocketProvider("ws://01:7777"));}varmyContract=newweb3.eth.Contract([ { "constant":true, "inputs":[], "name":"name", "outputs":[ { "name":"", "type":"string" } ], "payable":false, "stateMutability":"view", "type":"function" },
{ "constant":true, "inputs":[], "name":"age", "outputs":[ { "name":"", "type":"uint256" } ], "payable":false, "stateMutability":"view", "type":"function" },
{ "constant":false, "inputs":[ { "name":"_name", "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":"PersonInfoUpdate", "type":"event" }],"0xed2d42ad9aa54e77fb5c35b7834aedc1171aef57");使用合约对象web3订阅合约事件PersonInfoUpdate的代码如下//订阅事件
vareventUpdate=myContract.events.PersonInfoUpdate(function(error,event){ if(!error){ console.log(event.returnV); console.log(event.returnValues.age);}else{console.log(error);} }) .on('data',function(event){console.log(event);}).on('changed',function(event){
}).on('error',console.error);在sample7-2.html中定义以下HTML元素,用于输入智能合约Person的name和age变量值。<span>
姓名:<inputtype="text"id="name"></input><br/>
年龄:<inputtype="text"id="age"></input><br/><buttonid="btnSetInfo">修改</button></span>
单击“修改”按钮,将调用智能合约Person的SetInfo()函数,设置name和age变量值,并触发PersonInfoUpdate事件$("#btnSetInfo").click(function(){ alert($("#name").val()+$("#age").val()); myContract.methods.SetInfo($("#name").val(),$("#age").val()).send({from:"0xd169d4387c2dcd1ec4e6952bddf0a22c1f8c2b2f",gas:150000,gasPrice:"10000"})});浏览sample7-2.html的网页在Console面板中查看事件PersonInfoUpdate的参数数据
如果在Console面板中看到如下报错信息,则说明指定的from账户被锁定了web3.min.js:13Uncaught(inpromise)Error:Returnederror:authenticationneeded:passwordorunlock}可以通过如下方法解决此问题(1)在启动以太坊私有链时使用--allow-insecure-unlock选项,具体命令如下:
./geth--datadirethchain--nodiscoverconsole2>>1.log--dev.period1--password'./password.txt'--rpcport8545--rpccorsdomain"*"--rpcaddr=01-rpc--rpcapi="db,eth,net,web3,personal"--ws--wsaddr01--wsport7777--wsorigins'*'--allow-insecure-unlock(2)执行miner.stop()命令停止挖矿。并执行eth.mining命令检查挖矿的状态。如果返回false,则说明挖矿已经停止。(3)执行下面的命令解锁第一个账户:personal.unlockAccount(eth.accounts[0])输入账户密码后,账户被解锁解锁以太坊账户7.2日志7.2.1在Remix中查看日志数据7.2.2底层日志接口7.2.3检索日志7.2.1在Remix中查看日志数据【例7-3】创建一个智能合约MetaCoin,其中定义一个Transfer事件,代码如下:eventTransfer(address_from,address_to,uint256_value);在智能合约MetaCoin中定义了一个映射balances,用于保存各账户地址中的金额mapping(address=>uint256)balances;
智能合约MetaCoin的构造函数的代码如下:
constructor()payablepublic{balances[msg.sender]=100;}定义一个SendCoin()函数,程序模拟账户间的转账functionSendCoin(address_reciver,uint256_amount)publicreturns(boolsufficient){if(balances[msg.sender]<_amount)returnfalse;balances[msg.sender]-=_amount;balances[_reciver]+=_amount;//触发事件
emitTransfer(msg.sender,_reciver,_amount);returntrue;}在Remix中查看已部署的合约输入SendCoin()函数的参数查看交易的明细信息。
7.2.2底层日志接口除了在触发事件时会记录日志,Solidity还提供了一些底层日志接口。通过调用log0、log1、log2、log3、log4、……函数可以直接访问底层的日志组件。【例7-4】例7-3的日志,可以通过底层日志接口log3()函数记录pragmasolidity^0.5.1;
contractMetaCoin{eventTransfer(addressindexed_from,addressindexed_to,uint256_value);functionrecordLog()publicpayable{addressaddr=0x14723A09ACff6D2A60DcdF7aA4AFf308FDDC160C;log3(bytes32(msg.value),bytes32(keccak256('Transfer(address,address,uint256)')),bytes32(bytes20(addr)),bytes32(bytes20(msg.sender)));}}log3()函数包含如下4个实参(1)msg.value:交易金额作为日志的数据部分;(2)keccak256('Transfer(address,address,uint256)'):事件Transfer的AB
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025年度二零二五年度活动场地布置与餐饮服务合同
- 绿色办公与学校环境教育的结合
- 商业案例分享安全生产在砖厂的成效
- 食品药品行业中的巡察与质量控制风险
- 2025年衡水职业技术学院高职单招高职单招英语2016-2024历年频考点试题含答案解析
- 社团内部沟通与协作的技巧
- 2025年苏州工业园区职业技术学院高职单招高职单招英语2016-2024历年频考点试题含答案解析
- 智慧城市建设中勘测项目的安全设计与技术创新
- 社会变迁与学生心理健康问题的新挑战
- 2025年甘肃卫生职业学院高职单招职业适应性测试近5年常考版参考题库含答案解析
- 点亮生命-大学生职业生涯发展与就业指导全套教学课件
- 旅居管家策划方案
- 车间消防安全知识培训课件
- 华为经营管理-华为的研发管理(6版)
- 锂离子电池生产工艺流程图
- 平衡计分卡-化战略为行动
- 幼儿园小班下学期期末家长会PPT模板
- 矿山安全培训课件-地下矿山开采安全技术
- GB/T 6417.1-2005金属熔化焊接头缺欠分类及说明
- 《社会主义市场经济理论(第三版)》第七章社会主义市场经济规则论
- 《腰椎间盘突出》课件
评论
0/150
提交评论