本文介绍了以太坊客户端Geth,它是用Go语言编写的以太坊核心组件,负责处理交易执行、账户余额更新和智能合约逻辑。文章详细阐述了Geth在以太坊架构中的作用、内部组件及其功能,如网络层、区块链核心、EVM、状态存储和RPC服务器,并提供了本地运行Geth节点以及使用Go语言与之交互的示例代码和安全建议。

让我们面对现实吧,当大多数人听到“以太坊”时,他们会想到加密钱包、NFT 或在一些时髦的 DeFi 应用程序上交换代币。那是有趣的部分。但在这一切的底层,有一个机器网络不断工作以保持整个系统的活力。这些机器被称为节点,而驱动它们的最重要的软件之一就是 Geth。
Geth,是 Go Ethereum 的缩写,并不花哨。它没有用户界面。它不会向你展示价格图表或memes。它所做的是使以太坊在底层工作的所有事情——比如同步区块、验证交易、执行智能合约以及跟踪整个链的状态。并且它是完全用 Go 编写的。
顺便说一句,这个选择并非偶然。Go 提供了一些许多语言都在努力的东西——易于使用的并发性。对于一个与数百个对等方通信并处理持续数据的区块链客户端来说,这非常关键。
在这篇文章中,我将带你了解 Geth 实际是如何工作的,为什么 Go 如此适合它,以及你如何开始使用 Go 代码与它进行交互。我还将包括一些设置它的经验教训以及我在本地运行时有帮助的一些技巧。
Geth 的核心是一个执行客户端。这意味着它处理交易的执行、账户余额的更新以及合约逻辑的运行。当你在你的计算机上运行它时,它将成为以太坊网络的一部分。它下载区块链,与对等方同步数据,并通过本地 API 使所有这些都可访问。
你可以向 Geth 询问钱包的余额,发送签名的交易,甚至调用智能合约——所有这些都来自你自己的机器。你不是依赖 Infura 或某些托管端点。你正在直接与链通信。
就我个人而言,我第一次运行 Geth 只是出于好奇。我在一个 Linux 盒子上启动了它,并让它同步了几个小时。观看日志滚动使整个区块链感觉更加真实。它不再只是一些云 API。它正在那里运行,一个区块接一个区块,在我的机器上。
那么,为什么以太坊团队使用 Go 构建 Geth 呢?简而言之,它非常适合像这样的高并发、始终在线的系统。
Go 的 goroutine 使启动轻量级进程变得非常容易。Geth 在任何地方都使用它们——用于处理对等方、处理新区块、验证交易以及同时服务 JSON-RPC 请求。你不是手动处理线程。你只是编写可以很好地扩展的干净代码。
Go 也易于阅读和维护。这在贡献者来自不同背景的开源项目中很重要。你不需要成为 Go 向导才能理解 Geth 中的逻辑。
另一个很大的优势是 Go 强大的标准库。Geth 不依赖大量的外部依赖项。Go 已经提供了经过良好测试和安全的网络、文件系统访问和加密功能。
老实说,快速编译和跨平台构建使得开发更加轻松。你编写一次,它就可以在各种系统上运行。
自从以太坊转移到权益证明以来,事情变得比以前更加模块化。现在,网络分为两个主要层——共识层和执行层。
共识层处理验证者、区块提案以及就应该放入链中的内容达成一致。执行层处理区块内的所有内容:交易、智能合约逻辑、状态更新。Geth 位于执行层中。
这就是它的运作方式。像 Lighthouse 或 Prysm 这样的共识客户端提出一个区块。然后,它通过一个称为 Engine API 的协议将该区块交给 Geth。Geth 获取该区块,运行其中的所有交易,更新状态,然后将结果返回。这种职责分离保持了事物的清洁和安全。
在底层,Geth 分为几个组件。每个组件处理一个特定的作业,并且它们一起使客户端平稳运行。
这是 Geth 连接到对等网络的地方。它查找对等方,共享数据,并保持区块链同步。Go 的并发性在这里发挥作用,因为它可以管理数十个或数百个连接而不会崩溃。
这部分验证并存储新区块。它还管理 mempool,mempool 是交易在等待被包含在区块中的地方。
EVM 运行智能合约。每个节点必须执行相同的逻辑并获得相同的结果。Geth 确保以可靠、可重复的方式发生这种情况。
以太坊的状态使用一种称为 Merkle Patricia Trie 的东西来存储。这种结构允许快速更新和加密证明数据没有被篡改。
Geth 公开了一个 JSON-RPC 服务器,允许开发人员与节点交互。你可以通过 HTTP 或 WebSocket 连接查询余额、发送交易或侦听事件。
所有这些组件都由于 Go 而并发运行。这就是 Geth 保持响应的原因,即使在同步或负载下也是如此。
如果你想运行自己的 Geth 节点,则设置非常简单。这是我在测试时使用的常见命令:
geth --http --http.addr 127.0.0.1 --http.port 8545 --syncmode snap
这将启动节点,启用 HTTP API,在端口 8545 上侦听,并使用 snap sync,因此它不会花费太长时间来启动和运行。
一旦同步,你可以开始查询数据或通过其 JSON-RPC 接口推送交易。它基本上是你自己的以太坊后端。
如果你在 Go 中构建工具或脚本,则官方 Go 以太坊库中的 ethclient 包可以使你的生活更轻松。以下是我经常使用的一些示例。
package main
import (
"context"
"fmt"
"log"
"github.com/ethereum/go-ethereum/ethclient"
)
func main() {
client, err := ethclient.Dial("http://localhost:8545")
if err != nil {
log.Fatalf("Failed to connect to the node: %v", err)
}
block, err := client.BlockNumber(context.Background())
if err != nil {
log.Fatalf("Failed to get block number: %v", err)
}
fmt.Printf("Current block: %d\n", block)
}
这是一个很好的健全性检查,以确保一切正常工作。
package main
import (
"context"
"fmt"
"log"
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethclient"
)
func main() {
client, err := ethclient.Dial("http://localhost:8545")
if err != nil {
log.Fatal(err)
}
address := common.HexToAddress("0x742d35Cc6634C0532925a3b844Bc454e4438f44e")
balance, err := client.BalanceAt(context.Background(), address, nil)
if err != nil {
log.Fatal(err)
}
fmt.Println("ETH Balance:", new(big.Float).Quo(new(big.Float).SetInt(balance), big.NewFloat(1e18)))
}
这将返回地址的当前余额,单位为 Ether,而不是 Wei。
如果你有由 abigen 生成的 Go 绑定,则可以像这样调用函数:
instance, err := contract.NewStorageContract(contractAddress, client)
value, err := instance.GetValue(nil)
fmt.Println("Stored value:", value)
感觉像是调用一个普通的 Go 函数,但在底层,它使用的是 ABI 编码和 JSON-RPC。
如果你计划在本地测试之外运行 Geth,请务必小心。一些经验法则:
我早期犯的一个错误是在测试期间将 Geth 绑定到 0.0.0.0。它在本地很好,但我忘了稍后将其锁定。吸取的教训。
如果你遇到问题,你并不孤单。以下是我遇到的一些:
--http 标志--cache 2048 增加你的缓存大多数问题都可以通过一点耐心和正确的配置标志来解决。
Geth 可能没有像时髦的 DeFi 应用程序或 meme coins 那样受到关注,但它是以太坊最重要的部分之一。它使网络保持活力、准确和可访问。
运行你自己的节点可以帮助你更深入地了解以太坊。这也是建立对你的数据的信任、避免第三方限制和控制你的基础设施的好方法。
无论你是构建 dApp、探索智能合约,还是只想了解以太坊的真正工作原理,Geth 都是你的工具包中必不可少的工具。
有问题或想讨论实施细节吗?
你可以通过以下方式联系我们:hello@ancilar.com
访问我们的网站:www.ancilar.com
- 原文链接: medium.com/@ancilartech/...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!