使用Golang查询以太坊交易,从入门到实践

以太坊作为全球领先的智能合约平台,其上的每一笔交易都记录在公开的区块链账本上,对于开发者而言,能够以编程方式查询这些交易信息,是构建区块链应用(如钱包、浏览器、数据分析工具)的核心技能之一,Golang(Go语言)凭借其出色的并发性能、高效的执行效率和简洁的语法,成为了开发区块链应用的理想选择。

本文将详细介绍如何使用Golang来查询以太坊上的交易信息,涵盖从环境搭建、连接节点,到实际查询交易的完整流程。

准备工作:环境与工具

在开始编码之前,我们需要准备以下几项:

  1. Go环境:确保你的系统上已安装Go (建议1.15或更高版本)。

  2. 以太坊节点:查询交易需要连接到一个以太坊节点,你有以下几种选择:

    • 本地节点:运行一个全节点(如Geth或Parity),这是最完整但资源消耗最大的方式。
    • Infura等第三方服务:Infura提供了公共的以太坊节点API,无需自己维护节点,非常适合开发和测试,你需要在 Infura官网 注册并获取一个项目ID。
    • Alchemy等第三方服务:与Infura类似,Alchemy也是一个高性能的区块链节点服务,提供更丰富的开发者工具。
  3. 以太坊账户地址:你需要查询的交易哈希或发送方/接收方地址。

  4. Go-Ethereum库:我们将使用最流行的Go语言以太坊交互库 go-ethereum (也称为 geth)。

在你的Go项目目录中初始化模块并安装go-ethereum

go mod init eth-query-example
go get github.com/ethereum/go-ethereum

连接到以太坊网络

所有操作的第一步是建立一个与以太坊网络的连接,无论是连接到本地节点还是远程节点(如Infura),我们都需要使用ethclient包。

下面是一个连接到Infura节点的示例代码:

package main
import (
    "context"
    "fmt"
    "log"
    "github.com/ethereum/go-ethereum/ethclient"
)
func main() {
    // 替换成你自己的Infura项目ID
    infuraURL := "https://mainnet.infura.io/v3/YOUR_INFURA_PROJECT_ID"
    // 创建一个以太坊客户端
    client, err := ethclient.Dial(infuraURL)
    if err != nil {
        log.Fatalf("Failed to connect to the Ethereum network: %v", err)
    }
    defer client.Close()
    // 验证连接是否成功
    chainID, err := client.NetworkID(context.Background())
    if err != nil {
        log.Fatalf("Failed to get network ID: %v", err)
    }
    fmt.Printf("Successfully connected to network with Chain ID: %s\n", chainID)
}

YOUR_INFURA_PROJECT_ID 替换为你在Infura上获取的真实ID,运行此代码,如果看到成功信息,说明你已经成功连接到以太坊主网。

核心查询操作

连接建立后,我们就可以开始查询交易了。go-ethereumethclient提供了丰富的API。

根据交易哈希查询交易详情

这是最直接的方式,如果你已经知道一笔特定交易的哈希,可以获取其完整信息,包括发送方、接收方、金额、Gas消耗、日志等。

// 假设client已经成功连接
txHash := "0x5c504ed432cb51138bcf09aa5e8a410dd4a1e204ef84bfed1be16dfba1b22060" // 示例交易哈希
tx, _, err := client.TransactionByHash(context.Background(), common.HexToHash(txHash))
if err != nil {
    log.Fatalf("Failed to get transaction: %v", err)
}
fmt.Printf("Tx Hash: %s\n", tx.Hash().Hex())
fmt.Printf("Nonce: %d\n", tx.Nonce())
fmt.Printf("To: %s\n", tx.To().Hex())
fmt.Printf("Value: %s ETH\n", new(big.Float).Quo(
    new(big.Float).SetInt(tx.Value()),
    big.NewFloat(math.Pow10(18)),
)) // 以太坊精度为18,需要转换
fmt.Printf("Gas: %d\n", tx.Gas())
fmt.Printf("Gas Price: %s Gwei\n", new(big.Float).Quo(
    new(big.Float).SetInt(tx.GasPrice()),
    big.NewFloat(math.Pow10(9)),
)) // Gas Price单位是Gwei (10^9 Wei

根据地址查询交易列表

如果你想查看某个地址(无论是发送方还是接收方)的所有交易历史,可以使用 FilterLogsPendingTransactions 等方法,但更常见的做法是使用以太坊的JSON-RPC API中的 eth_getLogs 结合 topic 来查询。go-ethereum 提供了更高级的 Filterer 接口。

一个更简单的方法是查询一个地址发出的所有交易(作为发送方):

// 假设client已经成功连接
senderAddress := "0x742d35Cc6634C0532925a3b844Bc9e7595f8d3a6" // 示例发送方地址
// 创建一个查询过滤器,用于获取该地址作为From的所有交易
query := ethereum.FilterQuery{
    FromBlock: big.NewInt(0), // 从创世区块开始查询
    ToBlock:   nil,           // 查询到最新区块
    Addresses: []common.Address{common.HexToAddress(senderAddress)},
}
logs, err := client.FilterLogs(context.Background(), query)
if err != nil    {
    log.Fatalf("Failed to filter logs: %v", err)
}
fmt.Printf("Found %d transactions from address %s\n", len(logs), senderAddress)
for _, vLog := range logs {
    // 在以太坊中,交易本身没有直接的事件,但我们可以通过收据来关联
    // 这里简化处理,直接打印日志
    fmt.Printf("  Tx Hash: %s, Block Number: %d\n", vLog.TxHash.Hex(), vLog.BlockNumber)
}

注意:上述方法查询的是与该地址相关的“日志”(Logs),通常是合约事件,对于普通转账交易,它们本身不产生日志,更通用的方法是使用第三方API(如Etherscan)或通过订阅新交易来获取,对于精确的转账历史,通常需要结合eth_getLogstopic来过滤Transfer事件(如果涉及到ERC-20代币)。

获取交易收据

交易收据包含了交易执行后的详细信息,比如交易是否成功、消耗了多少Gas、产生了哪些日志等。

// 假设client和txHash已经定义
txHash := "0x5c504ed432cb51138bcf09aa5e8a410dd4a1e204ef84bfed1be16dfba1b22060"
receipt, err := client.TransactionReceipt(context.Background(), common.HexToHash(txHash))
if err != nil {
    log.Fatalf("Failed to get receipt: %v", err)
}
fmt.Printf("Tx Hash: %s\n", receipt.TxHash.Hex())
fmt.Printf("Status: %d (1 for success, 0 for failure)\n", receipt.Status)
fmt.Printf("Gas Used: %d\n", receipt.GasUsed)
fmt.Printf("Cumulative Gas Used: %d\n", receipt.CumulativeGasUsed)
fmt.Printf("Contract Address: %s\n", receipt.ContractAddress.Hex()) // 如果是合约创建交易,这里会有地址
fmt.Printf("Logs: %d\n", len(receipt.Logs))

完整示例代码

下面是一个整合了上述所有操作的完整示例:

package main
import (
    "context"
    "fmt"
    "log"
    "math"
    "math/big"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-eth
随机配图
ereum/ethclient" ) func main() { // 1. 连接到以太坊网络 infuraURL := "https://mainnet.infura.io/v3/YOUR_INFURA_PROJECT_ID" client, err := ethclient.Dial(infuraURL) if err != nil { log.Fatalf("Failed to connect to the Ethereum network: %v", err) } defer client.Close() fmt.Println("Successfully connected to the Ethereum network.") // 2. 根据交易哈希查询交易详情 txHash := "0x5c504ed432cb51138bcf09aa5e8a410dd4a1e204ef84bfed1be16dfba1b22060" tx, _, err := client.TransactionByHash(context.Background(), common.HexToHash(txHash)) if err != nil { log.Fatalf("Failed to get transaction: %v", err) } fmt
本文由用户投稿上传,若侵权请提供版权资料并联系删除!