如何在 Ruby 中获取以太坊事件日志

  • quiknode
  • 发布于 2024-03-23 20:53
  • 阅读 15

本文介绍了如何使用 Ruby 语言获取以太坊事件日志,详细讲解了如何创建和部署智能合约,并使用 eth.rb gem 来连接以太坊网络并获取日志数据。

该网站在你的计算机上存储 Cookies,以收集你与我们网站的互动信息,以改善和定制你的浏览体验。要了解更多信息,请参见我们的 隐私政策

如果你拒绝,你在访问此网站时的信息将不会被跟踪。你的浏览器中将使用一个 Cookie 来记住你不希望被跟踪的偏好。

Cookies 设置

接受拒绝

跳过到主要内容

如何在 Ruby 中获取 Ethereum 事件日志

更新于

2025年1月30日

Ethereum 交易 日志 智能合约 Solidity MetaMask Remix.IDE Eth.rb Ruby

在此页面

10分钟阅读

重要通知

本指南包含对 Ropsten 测试网络的参考,该网络不再积极维护。虽然与此链相关的具体步骤可能不适用,但整体过程可能适用于其他链。我们建议你探索当前可用于实现的替代方案。如果你希望查看此指南的更新版本,请 告诉我们!

概述

以太坊日志记录对于理解和跟踪智能合约事件非常有用。在本指南中,我们将学习如何使用 eth.rb Ruby gem 在 Ruby 中获取以太坊事件日志。

先决条件

  • 系统上已安装 Ruby(版本 >= 2.6, < 4.0)

  • Remix IDE

  • Metamask 钱包

  • 一个文本编辑器(例如 Sublime Text

  • Ethereum RPC 节点/端点

  • 终端即命令行

什么是 Ruby?

Ruby 是一种开源的、解释型的、面向对象的编程语言,由松本行弘(Yukihiro Matsumoto,简称 Matz)创建,他选择了宝石的名称,意味着 Ruby 是“一种珍宝语言”。Ruby 旨在简单、完整、可扩展和可移植。主要在 Linux 上开发的 Ruby 可以在大多数平台上运行,例如大多数基于 UNIX 的平台、DOS、Windows 和 Mac。根据倡导者的说法,Ruby 的简单语法(部分受 Ada 和 Eiffel 的启发)使任何熟悉现代编程语言的人都能阅读。Ruby 被认为与 Smalltalk 和 Perl 类似。

什么是 Ethereum 日志?

在像 JavaScript 这样的事件驱动语言中,我们常常监听事件以执行其他操作。Solidity(以太坊的智能合约编程语言)提供了相同的范例。除了通过 WebSockets 发送实时事件外,EVM(以太坊虚拟机)实际上还存储特定智能合约产生的事件日志,以供通过 HTTP 检索。这些日志通常用于调试目的,捕获事件,或者告诉记录的查看者发生了某些事情。

日志记录通常用于描述智能合约事件,例如所有权变更或 Token 转移。每条日志记录都有主题和数据。主题是 32 字节(256 位)单词,描述事件中发生的情况。不同类型的操作码(LOG0 … LOG1)描述了需要添加到日志记录中的主题数量。例如,LOG1 可以有一个主题,而 LOG4 可以有四个主题。因此,单个日志记录的主题最大数量为四个。日志记录的第一部分包含主题数组,而日志记录的第二部分则包含附加数据。

主题和数据最佳配合使用,因为单独使用各自都有利弊。例如,虽然主题是可搜索的,但数据则不是。包含数据比包含主题便宜。主题限制为 4 * 32 字节,而事件数据没有限制,这意味着它可以由大型或复杂数据(如数组或字符串)组成。事件为你提供了一种将相关日志数据添加到区块日志的方法。

合约不能读取由智能合约生成的事件;然而,它们可以在区块链外读取,并且由于事件是不可变的,因此可以用于跟踪数据变化。

日志需要解码才能在区块链外使用。因此,我们将使用 eth.rb gem 来获取和解码智能合约事件的日志。

什么是 eth.rb?

eth.rb 是一个 Ruby gem,使得使用 Ruby 与以太坊区块链进行交互变得简单。使用此 gem,我们可以与以太坊客户端建立连接,进行直接的 JSON RPC 调用等。如果这是你第一次使用 eth.rb,我们建议你在我们的入门指南中熟悉它,了解 如何使用 eth.rb 连接到以太坊网络

创建和部署智能合约

我们将首先部署一个将发出事件的智能合约,然后编写一小段 Ruby 代码来获取该事件的日志。

我们将在 Ropsten 测试网络上部署我们的合约。首先,你需要 Metamask 浏览器扩展以创建 ETH 钱包。你还需要一些测试 ETH,你可以通过访问 Ropsten 水龙头 来获取。你需要在 Metamask 钱包上选择 Ropsten 测试网络,并将钱包地址复制粘贴到水龙头的文本框中,然后点击“发送我测试以太币”(具体略有不同,取决于你使用的水龙头)。

前往 Ethereum Remix IDE 并创建一个新的 Solidity 文件 event.sol

将以下代码粘贴到你的新 Solidity 脚本中:

以上代码的解释

  • 第 1 行:指定 SPDX 许可证 类型,这是在 Solidity ^0.6.8 后添加的;每当智能合约的源代码对公众可用时,这些许可证可以帮助解决/避免版权问题。如果你不希望指定任何许可证类型,你可以使用特殊值 UNLICENSED 或简单地跳过整个注释(这不会导致错误,只是一个警告)。

  • 第 2 行:声明 Solidity 版本。

  • 第 4 行:启动名为 Counter 的合约。

  • 第 6 行:创建一个名为 ValueChanged 的事件,包含两个参数,oldValue 将是计数的输入值,而 newValue 将是计数的输出值。

  • 第 9 行:声明私有变量 count,初始值为零。

  • 第 12-15 行:创建公共函数 increment,将计数的值增加 1,并发出事件 ValueChanged,其中 oldValue = 当前计数值减 1,newValue = 当前计数值。

  • 第 18-19 行:创建公共函数 getCount 以返回计数的值。

编译智能合约并使用 Injected Web3 部署它;确保在部署合约之前在你的 Metamask 插件上选择 Ropsten 网络。

同时,从编译选项卡中复制合约的 ABI。我们稍后会用到它。

你将在 Remix 的“已部署合约”部分看到你的合约。打开已部署的合约并点击 getCount;你会看到返回的值为零,这是预期的结果。

现在点击 increment 以将计数的值增加 1,确认交易,并在收到交易确认通知后再次点击 getCount。这一次你会看到计数的值已经改变。

我们将为该交易获取日志。从“已部署合约”部分中合同名称附近的复制按钮中复制合约地址。通过查看 QuickNode 指南,了解有关智能合约和 Solidity 的更多信息。

与你的 RPC 建立连接

我们今天几乎可以使用任何以太坊客户端。由于这对于获取日志来说稍微复杂,我们将从 QuickNode 获取一个端点,以便简化这个过程。如果你还没有 QuickNode 端点,你可以在 这里 创建一个免费帐户。我们需要一个 Ropsten 端点来获取链上的数据,因为我们在 Ropsten 测试网络上部署了合约。创建以太坊端点后,复制你的 HTTP Provider 端点:

Quicknode Ropsten 端点截图

你将稍后需要这个,因此请复制并保存。

在 Ruby 中获取日志

安装 eth.rb gem

让我们首先确保系统上已安装 Ruby。要检查,只需复制粘贴并在终端/命令提示符中运行以下命令:

ruby -v

简化调试的日志记录

现在你可以访问用于你的 RPC 端点的日志,帮助你更有效地排查问题。如果你在 RPC 调用中遇到问题,只需检查你 QuickNode 仪表板中的日志,快速识别并解决问题。了解更多关于日志历史限制的信息,请访问 我们的定价页面。

如果此命令返回的版本晚于 2.6,则一切正常!如果该命令未被识别,则需要安装 Ruby。如果被识别但版本低于 2.6,则需要升级到更新版本。

注意: macOS 附带的 Ruby 版本通常是供 Apple 自用,最好不要更改。你可以对此版本进行更改,但我们建议使用 rbenv 或 RVM(Ruby 版本管理器)管理单独的 Ruby 版本,该版本将在你的主目录的沙箱中安装。这样你可以更改此版本而不影响系统上的 Ruby 版本。有关更多信息,请阅读 来自 mac.install 的外部指南

一旦你准备好继续,我们就可以安装 eth.rb gem。这个 gem 将允许我们使用 Ruby 语言连接到以太坊区块链网络。我们可以使用 RubyGems 包管理器从命令行安装它:

让我们继续并安装 eth.rb gem,你可以使用 Ruby 的包管理器 RubyGems 从命令行进行安装。

gem install eth

你还需要安装一个名为 forwardable 的 gem:

gem install forwardable

创建和运行 Ruby 脚本以提取日志

打开你的文本编辑器并创建一个 Ruby 文件 log.rb,将以下内容复制粘贴到其中。

require 'eth'
require 'forwardable'

client = Eth::Client.create 'QUICKNODE_HTTP_PROVIDER_LINK'
contract_address = "CONTRACT_ADDRESS_FROM_REMIX"
contract_name = "Increment"
contract_abi = '[\
    {\
      "inputs": [],\
      "name": "increment",\
      "outputs": [],\
      "stateMutability": "nonpayable",\
      "type": "function"\
    },\
    {\
      "anonymous": false,\
      "inputs": [\
        {\
          "indexed": false,\
          "internalType": "uint256",\
          "name": "oldValue",\
          "type": "uint256"\
        },\
        {\
          "indexed": false,\
          "internalType": "uint256",\
          "name": "newValue",\
          "type": "uint256"\
        }\
      ],\
      "name": "ValueChanged",\
      "type": "event"\
    },\
\
    {\
      "inputs": [],\
      "name": "getCount",\
      "outputs": [\
        {\
          "internalType": "uint256",\
          "name": "",\
          "type": "uint256"\
        }\
      ],\
      "stateMutability": "view",\
      "type": "function"\
    }\
  ]'
contract = Eth::Contract.from_abi(name: contract_name, address: contract_address, abi: contract_abi)

params =
  {
    address: contract.address,
    fromBlock: "earliest",
    toBlock: "latest",
    topics: []
  }
events = client.eth_get_logs(params)["result"]

event_abi = contract.abi.find {|a| a['name'] == 'ValueChanged'}
event_inputs = event_abi['inputs'].map {|i| i["type"]}

events.each_with_index do |event, index|
  transaction_id = event["transactionHash"]
  transaction = client.eth_get_transaction_receipt(transaction_id)
  logs = transaction.dig('result', 'logs').find { |d| d['data'] != "0x" }
  data = logs.fetch('data')
  eventlogs = transaction.inspect
  block = logs.fetch('blockNumber')
  contract_values = Eth::Abi.decode(event_inputs, data )
  puts "Transaction: #{index+1}"
  puts "Transaction ID: #{transaction_id}"
  puts "The Transaction was added to block: #{block.to_i(16)}"
  puts "Contract Logs:"
  event_abi['inputs'].each_with_index do |value,index|
    puts "#{" "* 3} #{value["name"]}: #{contract_values[index]}"
  end
  puts "Event Logs:"
  puts eventlogs
  puts "-" * 20
end

确保将 QUICKNODE_HTTP_PROVIDER_LINK 替换为 Ropsten HTTP Provider,将 CONTRACT_ADDRESS_FROM_REMIX 替换为上节中部署合约的地址,并将 contract_abi 替换为你从 Remix 复制的 ABI 值。

以上代码的解释

  • 第 1-2 行:导入所需的 gem。

  • 第 4 行:使用来自 QuickNode 的 Ropsten 端点定义客户端。

  • 第 5-6 行:定义你的合约地址(从 Remix 复制)和合约名称,“Increment”。

  • 第 7-48 行:将 contract_abi 替换为你的 ABI,你在前面的部分中复制的内容(如果你使用的是相同的智能合约,则使用相同的 ABI)。

  • 第 49 行: 实例化我们的 contract 对象并获取合约。

  • 第 51-57 行:使用合约地址以及最早和最新块定义搜索参数。

  • 第 58 行:根据我们的搜索参数获取日志,并将其存储在 events 变量中。

  • 第 60 行:从 ABI 中查找事件 ValueChanged 并将其存储在 event_abi 变量中。

  • 第 61 行:映射我们的 event_abi 以查找输入类型并将数组存储在 event_inputs 变量中(我们将用其解码我们的智能合约)。

对于日志中的每个交易:

  • 第 64 行:获取交易哈希并将其存储在 transaction_id 变量中。

  • 第 65 行:通过我们的节点使用 eth_get_transaction_receipt 方法获取交易详情。

  • 第 66 行:检查结果和日志并将其存储在 logs 变量中。

  • 第 67 行:从日志中提取数据并存储在 data 变量中。

  • 第 68 行:使用 inspect 方法获取交易详情并将其存储在 eventlogs 变量中。

  • 第 69 行:从日志中提取 blockNumber 并将其存储在 block 变量中。

  • 第 70 行:解码 event_inputs 和数据,并将其存储在 contract_values 变量中。

  • 第 71-80 行:打印搜索结果。

  • 第 75-77 行:对于每笔交易,我们打印智能合约返回的解码值(在本例中,即在创建智能合约时定义的 oldValuenewValue)。

现在,保存 log.rb 并按以下方式运行:

$ ruby log.rb

如果一切顺利,你的输出应该如下所示:

Ruby ETH 交易日志结果

输出包含交易、块号、合约日志和事件详细信息。

结论

恭喜你!你已经了解了以太坊事件日志以及如何使用 Ruby 过滤和提取其中的信息。

订阅我们的 电子邮件通知,获取更多有关以太坊的文章和指南。如果你有任何反馈,欢迎通过 Twitter 联系我们。你也可以随时在我们的 Discord 社区服务器上与我们聊天,与一些你会遇到的最酷的开发人员交流 :)

  • 原文链接: quicknode.com/guides/eth...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
quiknode
quiknode
江湖只有他的大名,没有他的介绍。