前言:为什么要用 Go 驱动以太坊?
当 以太坊区块链开发 遇到 高性能需求 时,JavaScript 往往显得力不从心。我最近的项目也面临同样困境:原来用 web3.js 实现的功能在低并发测试中还游刃有余,一旦流量上来,事件监听、批量签名、快速确认就出现瓶颈。于是,我将目光投向 Go,以求在读写高频、交易并发、延迟敏感等场景里获得更高吞吐与更低内存占用。
本文将通过 go-ethereum 原生库,手把手教你用 Golang 与 以太坊网络 JSON-RPC API 直接交互。示例直给、无需花哨框架,10 分钟就能跑通「查询区块高度 → 本地私钥签 → 链上广播 → 异步监控」完整链路。
假设你已装 Go 1.20+,对以太坊地址、Gas、私钥概念有基础。环境配置就留给搜索引擎啦,咱们直奔主题。
创建客户端:两行代码连入节点
go-ethereum 提供两种姿势快速接入:
方法一:直接 ethclient.Dial
client, err := ethclient.Dial("https://mainnet.infura.io/v3/YOUR_PROJECT_ID")缺点:ethclient.Client 只封装常用接口,部分冷门 JSON-RPC 方法掉链子。
方法二:rpc + ethclient 组合拳
func Connect(host string) (*Client, error) {
rpcClient, err := rpc.Dial(host)
if err != nil {
return nil, err
}
ethClient := ethclient.NewClient(rpcClient)
return &Client{rpcClient, ethClient}, nil
}- 自定义
Client结构体,把*rpc.Client与*ethclient.Client捆绑。 - 既保留自由扩展空间,又享受 go-ethereum 的标准封装,后面想调
eth_getLogs、net_listening随手就加。
👉 点此查看 ethclient 完整 API 列表,收藏不迷路
查询区块高度:迈出第一小步
项目诊断、系统告警、数据刷库,都要第一时间知道最新区块号。官方 ethclient 没有现成函数,自己封装:
func (c *Client) GetBlockNumber(ctx context.Context) (*big.Int, error) {
var result hexutil.Big
if err := c.rpcClient.CallContext(ctx, &result, "eth_blockNumber"); err != nil {
return nil, err
}
return (*big.Int)(&result), nil
}调用示例:
blockNum, _ := client.GetBlockNumber(context.TODO())
fmt.Printf("最新区块号 = %d\n", blockNum)恭喜你,正式拿到链上时间戳!
发起交易:从构造到签名广播
交易结构定义
想向节点托管的私钥发起 eth_sendTransaction,得先构造兼容 JSON-RPC 的字段:
type Message struct {
To *common.Address `json:"to"`
From common.Address `json:"from"`
Value string `json:"value"`
GasLimit string `json:"gas"`
GasPrice string `json:"gasPrice"`
Data []byte `json:"data"`
}便捷构造器
把 big.Int 转成带 0x 的十六进制字符串:
func toHexInt(i *big.Int) string { return hexutil.EncodeBig(i) }
func NewMessage(from common.Address, to *common.Address,
value *big.Int, gasLimit *big.Int, gasPrice *big.Int, data []byte) Message {
return Message{
From: from,
To: to,
Value: toHexInt(value),
GasLimit: toHexInt(gasLimit),
GasPrice: toHexInt(gasPrice),
Data: data,
}
}发起 & 返回交易哈希
func (c *Client) SendTransaction(ctx context.Context, msg *Message) (common.Hash, error) {
var txHash common.Hash
err := c.rpcClient.CallContext(ctx, &txHash, "eth_sendTransaction", msg)
return txHash, err
}实战调用:
from := common.HexToAddress("0xYourFromAddress")
to := common.HexToAddress("0xYourToAddress")
amount := big.NewInt(1000000000000000000) // 1 ETH
gasLimit := big.NewInt(21000)
gasPrice, _ := client.EthClient.SuggestGasPrice(context.TODO()) // 动态查询
msg := NewMessage(from, &to, amount, gasLimit, gasPrice, []byte{})
txHash, _ := client.SendTransaction(context.TODO(), &msg)
fmt.Println("已广播,哈希:", txHash.Hex())异步确认:让主线程不等人
监听收据
简单 for-loop 轮询,配合 Go Channel 不阻塞:
receiptChan := make(chan *types.Receipt, 1)
go func() {
ticker := time.NewTicker(2 * time.Second)
defer ticker.Stop()
for {
receipt, _ := client.EthClient.TransactionReceipt(context.TODO(), txHash)
if receipt != nil {
receiptChan <- receipt
return
}
<-ticker.C
}
}()
receipt := <-receiptChan
fmt.Printf("区块高度=%d,交易状态=%d(0成功)\n", receipt.BlockNumber.Uint64(), receipt.Status)心得
- 小批量可以用轮询,高并发建议改推 WebSocket
newHeads/logs事件。 - 如果节点返回延迟,5-10 秒轮询即可;延迟敏感,可本地缓存
nonce并并行广播多条交易。
FAQ:90% 初学者踩过的坑
Q1:私钥托管在节点会不会不安全?
A:任何“解锁账户”方式都有风险。生产环境推荐使用 离线签名 + sendRawTransaction,私钥永不出本地。
Q2:Gas 价格手填怕被抢矿被拒绝怎么办?
A:使用 SuggestGasPrice() + 乘以 1.1-1.3 系数,或订阅实时 Gas 估算服务。
Q3:一次发给多个地址必须用 for 循环吗?
A:目前单条交易只能单地址,批量场景可用 EIP-1153 多重调用合约 或打包后链下结算。
Q4:ethclient 与 go-web3/web3.go 优劣在哪?
A:后两者多年无人维护,对伦敦分叉后 EIP-1559 支持薄弱。go-ethereum 官方背书,资料最全。
Q5:本地测试能跳过同步主网吗?
A:必装 Ganache/Hardhat 或 Anvil 模拟器;对接 JSON-RPC 即可零成本调试。
Q6:如何验证交易真的进了不可篡改区?
A:拿到 receipt.BlockHash 后做 eth_getBlockByHash 校验即可;或者通过第三方区块浏览器两次校验。
写在最后
本篇只掀开 Go 与以太坊交互 的冰山一角:从区块号查询、私钥签名到交易监听,我们已能在不依赖 web3.js 的前提下完成所有核心动作。下一篇将深入 事件监听、过滤器、日志解析,并加入 离线签名 + EIP-1559,让你用 Go 打造真正的企业级区块链后端。
希望这份指南能帮你迈出坚实第一步。遇到问题欢迎在评论区留言,也可以在 GitHub repo 提 issue,一起把 以太坊 Go 语言开发 玩的更漂亮!