干货|捕捉智能合约中的event实战

Solidity 合约调试和event事件(2023版) 目前主流的定义:事件是以太坊虚拟机(EVM)日志基础设施提供的一个便利接口。当被发送事件(调用)时,会触发参数存储到交易的日志中(一种区块链上的特殊数据结构)。这些日志与合约的地址关联,并记录到区块链中。换句话来说区块链是打包一系列交易的区块组成的链条,每一个交易“收据”会包含0到多个日志记录,日志代表着智能合约所触发的事件。event相当于solidity的日志存储成本上来说,event比storage更便宜event可以被客户端程序订阅使用emit触发event事件。 阅读详情

image

1

写在前面

在上一篇文章 Web与智能合约交互实战 中我们已经掌握如何使用 Web3 控制智能合约,并且实现了一个简单的Dapp,可以通过浏览器简单地实现数据的设置和读取。

在本文中,我们将介绍智能合约中的 event,以及如何捕捉智能合约的 event。

在实战环节中,我们将使用 Javascript API 捕捉一个 ERC20 合约中的 Transfer() 事件,并在网页中显示出合约中每个账户的余额。

2

智能合约中的event

event,顾名思义就是智能合约在执行过程中所发生的一系列事件,被记录在 EVM 的日志中,使得程序员可以在 Dapp 的前端页面上调用 Javascript 的回调函数。 event 由智能合约的编写者在代码中使用 event 关键词进行声明,示例如下:

event Deposit(
        address indexed _from,
        bytes32 indexed _id,
        uint _value
    );

当 event 被调用时,其中的参数会被存储在交易的日志当中,示例如下:

function deposit(bytes32 _id) public payable {
        // 这里是函数实际执行的代码

        // 激活Deposit事件,记录在日志中,保存在区块链上
        emit Deposit(msg.sender, _id, msg.value);
    }

3

捕捉 event

使用 Javascript API 可以* 捕捉* event,注意这里说 捕捉 是因为我们既可以实时 监控 事件,也可以从历史区块中 检索 event。

首先将 event 实例化:

var event = myContractInstance.MyEvent({valueA: 23} [, additionalFilterObject])

在创建 event 实例的时候可以使用下面的参数:

  • Object:使用 filter 之后得到的索引返回值,例如,filter 可以是 {‘valueA’: 1, ‘valueB’: [myFirstAddress, mySecondAddress]}。 默认情况下,所有 filter 的值是 null,这意味着这些值会匹配当前合约发送的任意类型的 event。

  • Object:额外的过滤条件,例如可以使用 fromBlock 和 toBlock 限定所要查询的区块的范围,详情可以参考 filter。

  • Function:如果将一个回调函数作为最后一个参数的话,就会立刻开始检索 event,所以没有必要再调用 myEvent.watch(function(){})。

完整的示例如下:

var MyContract = web3.eth.contract(abi);
var myContractInstance = MyContract.at('0x78e97bcc5b5dd9ed228fed7a4887c0d7287344a9');

// 使用一些参数捕捉 event
var myEvent = myContractInstance.MyEvent({some: 'args'}, {fromBlock: 0, toBlock: 'latest'});
myEvent.watch(function(error, result){
   ...
});

// 停止捕捉
myEvent.stopWatching();

4

捕捉 event 实战

在实战环节,我们将实现如何获得一个ERC20合约中,有多少地址拥有代币,以及每个地址有多少代币。

在 ERC20 标准合约 中,有一个 event 定义如下:

event Transfer(address indexed from, address indexed to, uint tokens);

合约中每次执行 transfer() 函数的时候都会调用 Transfer() 事件,因此只需要使用 Javascript 捕捉 Transfer() 事件,就能获取到所有执行过交易的账户地址。 之后使用 Web3 调用合约的 balanceOf() 方法就可以获取每个账户地址的 token 余额。

实现步骤如下:

  • 启动 Ganache 测试环境;

  • 在 Remix 中创建 ERC20 智能合约;

  • 编写前端代码,与合约交互。

前两步关于如何使用 Ganache 搭建本地测试环境以及如何在 Remix 中创建合约的部分可以参见我的上一篇文章 Web与智能合约交互实战。 这里将重点放在第三步。

创建UI

在 index.html 中,我们将创建基础的 UI,功能包括接收 token 的地址输入框,发送 token 数量的输入框(由于这里总是从默认账户发送 token,因此没有设置发送者的地址输入框),以及一个发送按钮,这些将通过 jQuery 实现:

<!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">
    <img id="loader" src="https://loading.io/spinners/double-ring/lg.double-ring-spinner.gif">
    <title>ERC20 Token Sample</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>ERC20 Token</h1>

        <!-- <label for="name" class="col-lg-2 control-label">From</label>
        <input id="from" type="text"> -->

        <label for="name" class="col-lg-2 control-label">To</label>
        <input id="to" type="text">

        <label for="name" class="col-lg-2 control-label">Tokens</label>
        <input id="tokens" type="text">

        <button id="button">Send</button>

        <ol id="instructor"></ol>
    </div>

    <script src="https://code.jquery.com/jquery-3.2.1.slim.min.js"></script>

    <script>
        // 与智能合约的交互代码
        ......
    </script>

</body>
</html>

以及 main.css 文件设定基本的样式:

body {
    background-color:#F0F0F0;
    padding: 2em;
    font-family: 'Raleway','Source Sans Pro', 'Arial';
}
.container {
    width: 50%;
    margin: 0 auto;
}
label {
    display:block;
    margin-bottom:10px;
}
input {
    padding:10px;
    width: 50%;
    margin-bottom: 1em;
}
button {
    margin: 2em 0;
    padding: 1em 4em;
    display:block;
}

#instructor {
    padding:1em;
    background-color:#fff;
    margin: 1em 0;
}

.box div {
    padding:1em;
    background-color:#fff;
    margin: 1em 0;
}

捕捉 event 事件

这部分的主要代码如下:

<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"));
    }
    // 将Ganache创建的第一个账号当作默认账号
    web3.eth.defaultAccount = web3.eth.accounts[0];

    // 添加合约的ABI
    var tokenerc20Contract = web3.eth.contract([{"constant":true,"inputs":.....}]);   

    // 添加合约地址
    var tokenerc20 = tokenerc20Contract.at('0xdca44800d01ab7768902a11757b5ca1801a59efe');
    // 声明transfer事件,所要查找的区块数从0-latest
    var transferEvent = tokenerc20.Transfer({}, {fromBlock: 0, toBlock: 'latest'});
    // 通过前端进行token交易
    $("#button").click(function() {
        $("#loader").show();
        tokenerc20.transfer($("#to").val(), $("#tokens").val());
        });

    var holdersArray = new Array();
    // 查找所有Transfer事件
    transferEvent.watch(function(error, result){
        if (!error)
            {
                $("#loader").hide();

                // 判断From或者To的地址是否在holdersArray中出现
                var isFromExist = false;
                var isToExist = false;
                for (var i = 0; i < holdersArray.length; i++){
                    if (result.args.from == holdersArray[i]) {
                        isFromExist = true;
                    }
                    if (result.args.to == holdersArray[i]) {
                        isToExist = true;
                    }
                }

                // 找的新的账户地址,输出余额信息
                if (isFromExist == false) {
                    var holder = result.args.from;
                    holdersArray.push(holder);
                    var balanceOfHolder = tokenerc20.balanceOf(holder)
                    $("#instructor").append("<div>" + holder + ' has balance of ' + balanceOfHolder + "</div>");
                }
                if (isToExist == false) {
                    var holder = result.args.to;
                    holdersArray.push(holder);
                    var balanceOfHolder = tokenerc20.balanceOf(holder)
                    $("#instructor").append("<div>" + holder + ' has balance of ' + balanceOfHolder + "</div>");
                }
            } else {
                $("#loader").hide();
                console.log(error);
            }
    });
</script>

首先使用 Web3 关联 ERC20 合约,将合约的 ABI 以及合约地址都复制到代码中。

当用户点击发送按钮时,会调用合约中的 transfer() 函数(测试时可以使用 Ganache 创建的10个账户进行交易)。

接下来我们实例化 Transfer() 事件,将过滤条件设置为 {fromBlock: 0, toBlock: ‘latest’},即从所有区块中筛选交易。

在回调函数中,我们将收集所有交易中涉及到的交易双方的地址,并将每个新地址的余额显示在页面上。

最终效果显示如下:

image

文中涉及的所有代码可以在 https://github.com/gitferry/mastering-ethereum/tree/master/Solidity-event 获取。

5

参考链接

http://solidity.readthedocs.io/en/v0.4.21/contracts.html#events

https://github.com/ethereum/wiki/wiki/JavaScript-API#contract-events

http://me.tryblockchain.org/blockchain-solidity-event.html

本文内容作者:HiBlock区块链社区小伙伴——盖盖

原文首发于公众号: ChainLab

以下是我们的社区介绍,欢迎各种合作、交流、学习:)

image

【链块技术44期】智能合约基础语言(八)——Solidity事件   智能合约基础语言(八):Solidity事件 一、目录 ☞事件的定义 ☞web3事件监听 ☞检索日志 ☞底层日志接口 二、事件的定义 事件是使用EVM日志内置功能的方便工具,在DAPP的接口中,它可以反过来调用Javascript的监听事件的回调。 事件在合约中可被继承。当被调用时,会触发参数存储到交易的日志中(一种区块链上的特殊数据结构)。这些日志与合约的地址关联,... 阅读详情

相关推荐

Visual C++与WPF混合开发:C++/CLI桥接技术实现现代化桌面应用

在桌面应用开发领域,混合编程技术是连接不同技术栈、复用核心资产的关键手段。其核心原理在于通过特定的桥接层,实现托管代码与非托管代码之间的互操作,从而打破语言和运行时环境的壁垒。这项技术的核心价值在于,它允许开发者将高性能、高稳定性的原生C++业务逻辑库,与现代化、高表现力的WPF用户界面无缝结合,避免了重写核心代码的巨大成本和风险。在工业控制、数据可视化、上位机软件等对性能和界面均有高要求的应用场景中,这种架构尤为适用。本文以C++/CLI作为桥接技术,详细演示了如何构建一个包含原生C++核心层、C++/C

weixin_33146151的博客 278

Solidity智能合约事件(event)

当被发送事件(调用)时,会触发参数存储到交易的日志中(一种区块链上的特殊数据结构)。这些日志与合约的地址关联,并记录到区块链中.

西京刀客 2491

Weblogic安装与部署

27.免密登录,在目录Oracle\Middleware\Oracle_Home\user_projects\domains\base_domain\servers\AdminServer和Oracle\Middleware\Oracle_Home\user_projects\domains\base_domain\servers\Server-TA目录下,新建security\boot.properties文件,13.点击新建按钮,填写服务器名称,服务器监听地址,再点击下一步,最后点击完成。

m0_46259466的博客 6635

区块链学习笔记21——ETH智能合约

区块链学习笔记21——ETH智能合约 学习视频:北京大学肖臻老师《区块链技术与应用》 笔记参考:北京大学肖臻老师《区块链技术与应用》公开课系列笔记——目录导航页 智能合约部分的内容较多,这里分多篇来写 智能合约简介 智能合约是运行在区块链上的一段代码,代码的逻辑定义了合约的内容 智能合约的账户保存了合约当前的运行状态 balance:当前余额 nonce:交易次数 code:合约代码 storage:存储,数据结构是一棵MPT Solidty是智能合约最常用的语言,其语法上与JavaScript

polarday的博客 1万+

ArcFace vs 传统算法:实测MTCNN+ArcFace在PyCharm中的识别准确率(含完整对比数据)

本文通过PyCharm开发环境实测MTCNN+ArcFace组合在人脸识别中的性能表现,并与传统算法进行多维度对比。实验数据显示,ArcFace在LFW数据集上达到99.83%的准确率,显著优于传统方法。文章还提供了完整的代码实现和工程优化建议,为开发者提供实用的技术参考。

醉三国 236

单路径微分相除和微分自乘相减算法(PGC-SDD-DSM)

PGC-SDD-DSM算法通过融合单路微分相除和差分自乘,解决了传统PGC解调技术对调制深度和光强干扰敏感的问题,显著提升了解调稳定性和抗失真能力。其高信噪比、低谐波失真以及对参数变化的鲁棒性,使其在光纤传感领域具有重要应用价值。PGC-SDD-DSM算法在计算复杂度方面具有显著的优势,主要体现在其高稳定性和低谐波失真上。这些优势使其在光纤光学干涉传感器中表现出色,尤其是在面对光强干扰和调制深度变化时。

百态·数智思维 | 聚焦大数据、量化与未来AI 845

区块链中event和logs的作用以及如何实现

当事件向外广播时,一些第三方程序如果部署了监听区块的脚本,同时广播的事件又符合他们监听的条件,则他们可以获得这次事件的参数,然后进行后续程序的执行。直接通过查询条件进行筛选日志,两种查法的区别在于第一种的直接根据地址和合约方法编码后的字符串进行查询,当你有区块浏览器并能获得该方法编译后的值建议使用这个。日志(logs):由事件广播时生成,事件每广播一次就会生成一条日志,日志能保留广播时的所有信息,可以查询历史记录。两者相辅相成,一些好的项目一边监听事件,一边通过日志补漏,可以完美的与链上数据进行同步。

qq_39528077的博客 1101

手把手教你用OpenCalib完成激光雷达与相机联合标定:从数据准备到结果可视化

本文详细介绍了使用OpenCalib工具链中的lidar2camera模块完成激光雷达与相机联合标定的全流程,包括数据准备、标定命令执行、结果验证与可视化。通过实战指南,帮助读者掌握工业级标定技术,提升自动驾驶和机器人领域的传感器融合精度。

weixin_30872499的博客 400

智能合约漏洞攻击事件_智能合约百科全书攻击漏洞

智能合约漏洞攻击事件Applications on Ethereum manage financial value, making security absolutely crucial. As a nascent, experimental technology, smart contracts have certainly had their fair share of attacks. 以太...

weixin_26747751的博客 6584

[QMT和ptrade量化交易小白入门]-121、如何用K-means聚类,每月自动筛选高流动性ETF

本专栏主要是介绍QMT和ptrade的基础用法,常见函数,写策略的方法,也会分享一些量化交易的思路,大概会写200篇左右。QMT的相关资料较少,在使用过程中不断的摸索,遇到了一些问题,记录下来和大家一起沟通,共同进步。

木头大左的博客 829

在 SAP 中启用应收/应付“代扣税(Withholding Tax)”功能,本质上是激活并配置“扩展代扣税(Extended Withholding Tax)”模型

摘要:SAP中启用应收/应付代扣税功能需完成3个层级12个核心步骤:1)全局激活公司代码代扣税功能;2)配置代扣税规则、税率和科目,包括定义税种类型、代码、总账科目等;3)在供应商/客户主数据中关联代扣税设置。完成后系统可在发票或付款环节自动计算并过账代扣税,支持多税种并行计算和税率年度调整,最终生成税务报表。常见问题排查需检查公司代码激活状态和主数据配置。(149字)

金牌架构师 836

GO语言调用合约实现订阅合约的event

当我们使用GO语言调用合约时,写一个Dapp中通常需要通过监听event事件来获得合约状态内的变化,下面我们就详细的讲一下如何实现。

y943711797的博客 1699

【Unity实战100例】Unity循环UI界面切换卡片功能

功能包括:可以设置半径,高度,速度,元素数量用户可以根据自己的实际需求接入 制作思路:创建每个元素对应的虚拟点,通过旋转管理这些虚拟点,然后把旋转信息和位置信息同步给实际的元素

纯技术流日常开发商业开发记录总结等 7718

查询或解析solidity智能合约事件event或logs日志

我们经常会遇到查询或访问某个合约的历史log日志,并解析合约地址相关日志,当然也可以是某个用户的地址。通过web3js获取此token合约的转账事件,并解析此token合约对应的日志。这是一个token合约,我们将获取此token合约的所有转账事件的历史记录。这是要解析的日志log,下面emit 后面的代码。这里提供了三种直接访问的方案(其它方案这里不阐述)一个Promise对象,其解析值为历史事件对象数组。以上链接是源码链接地址;这是event事件代码。分别是:1:once。读取合约的历史事件。...

q_776355102的博客 2644

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

Java监听链上智能合约事件

1、事件的监听 在智能合约中定义的任何事件都将用Event方法在智能合约封装包中进行表示,该事件采用交易收据,并从中提取索引和非索引事件参数。 监听机制是建立在日志基础之上,如果智能合约触发了一个事件,那么该事件将写入以太坊日志;如果外部应用订阅了这个事件,那么应用就可以在日志中出现该事件后及时监测到,进而获取日志信息。 2、观察者模式和发布订阅模式区别 观察者模式: 所谓观察者模式,其实就是为了实现松耦合(loosely coupled)。 在观察者模式中,观察者需要直接订阅目标事件;在目标发出内容

qq_44016171的博客 1万+

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

Solidity智能合约开发 — 3.3-合约的事件和继承

合约的事件和继承

qincheng168的博客 1236

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

web3j监听智能合约的event事件

假设智能合约中定义了一个事件:pragma solidity ^0.4.0; contract Transfer{ event transfer(address indexed _from, address indexed _to, uint indexed value); function deposit() payable { address current = this;...

1万+

以太坊智能合约 Event 调用实例

先说一下event调用过程:首先需要在合约中定义event,并在某个函数中去触发它。当我们调用该函数的时候就会触发event,那么我们就可以通过在该次调用智能合约产生的block上建立filter来捕获event。具体代码如下: 合约 (部分截取): pragma solidity ^0.4.23; import &quot;./Vote.sol&quot;; import &quot;./SafeMath.sol&quot;...

疯纸的博客 4825

【智能合约】客户端和web端对智能合约的事件Event进行调用的代码示例

客户端和web端对智能合约的事件Event进行调用的代码示例 web truffle 按官网的例子 http://truffleframework.com/boxes/pet-shop truffle作为一个运行测试框架,用的也是web3对智能合约进行调用。 文件所在的位置src/js/app.js initWe...

weixin_34198453的博客 551

[区块链]回顾史上最大智能合约漏洞事件——The DAO事件

乐扣老师讲解The DAO事件 在区块链技术领域,The DAO事件可以算是一个以太坊的丑闻,当然也直接导致了硬分叉。在现实面前,面对黑客当着面利用漏洞源源不断从1.5亿美金的以太币池中拿走资金,而且还没办法。 本文面对这样的一个场景,主要是描述该场景中提到的攻击事件代码,围绕攻击的前因后果。项目进行的始末,最终通过剖析整个事件,达到历史经验借鉴,为未来利用智能合约时铭记安全意识的最终目的。...

ECNU乐扣老师——区块链、可计算情感 2万+

java通过web3j开发以太坊过滤器filter和事件event

web3j过滤器提供以太坊网络发生的某些事件的通知,对java和安卓程序员来说很有用。在Ethereum以太坊中支持三类过滤器: 块滤波器(Block filters) 未决交易过滤器(Pending transaction filters) 主题过滤器(Topic filters) 块过滤器和未决交易过滤器提供了在网络上创建新交易或块的通知。 主题过滤器更灵活。允许根据提供的特定标准创建过滤...

weixin_34099526的博客 1858

Web3j通过合约地址监听transfer事件获取以太坊交易数据

web3j通过合约地址监听transfer事件获取以太坊交易数据we3j核心特性功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注脚注释也是必不可少的KaTeX数学公式新的甘特图功能,丰富你的文章UML 图表FLowchart流程图导出与导入...

摸鱼佬的博客 1万+

智能合约Solidity教程-事件和日志(一)

简述:事件是以太坊提供的基本功能,用来将数据记录成日志,保存在区块链上,同时事件也可用于用于和外部交互,例如和前端的交互、异步调用等作用。solidity中,事件是指操作触发的行为,而日志则是触发事件后,将数据记录在区块链上形成日志。 本文主要介绍以下几点: 什么是事件event、日志log 事件event如何定义、如何触发 事件eve...

weixin_34252090的博客 2070

Vue学习之监听methods、watch及computed比较小结(十一)

一、三者之间的对比: 1、methods方法表示一个具体的操作,主要书写业务逻辑; 2、watch;一个对象,键是需要观察的表达式,值是对应回调函数。主要用来监听某些特定数据的变化,从而进行某些具体业务逻辑操作;可以看作是”computed"和“methods”的结合体; 3、computed属性的结果会被缓存,除非依赖的响应式属性变化才会重新计算。主要当作属性来使用。 二、me...

dbkfmlw338546的博客 294
上一篇: 深度探索Hyperledger技术与应用之超级账本的典型交易流程
下一篇: 应用二进制接口(ABI) 说明——Solidity中文文档(7)
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值