golang实现以太坊协议官方Go语言插件库go-ethereum的使用

Golang实现以太坊协议官方Go语言插件库go-ethereum的使用

Go Ethereum介绍

Go Ethereum是以太坊协议的Golang执行层实现。它是进入以太坊网络(主网、测试网或私有网络)的主要入口点,可以作为全节点(默认)、归档节点(保留所有历史状态)或轻节点(实时检索数据)运行。

构建源代码

构建geth需要Go(1.23或更高版本)和C编译器。安装依赖后运行:

make geth

或者构建完整的实用程序套件:

make all

可执行文件

go-ethereum项目提供了几个可执行文件:

命令 描述
geth 主要的以太坊CLI客户端
clef 独立的签名工具,可作为geth的后端签名器
devp2p 与网络层节点交互的实用程序
abigen 将以太坊合约定义转换为易于使用的Go包的源代码生成器
evm EVM的开发工具版本
rlpdump 将二进制RLP转储转换为用户友好的层次表示的工具

运行geth

硬件要求

最低配置:

  • 4核以上CPU
  • 8GB内存
  • 1TB可用存储空间
  • 8Mbps下载带宽

推荐配置:

  • 8核以上快速CPU
  • 16GB以上内存
  • 高性能SSD,至少1TB可用空间
  • 25Mbps以上下载带宽

主网全节点

最常见的场景是用户希望简单地与以太坊网络交互:

geth console

Holesky测试网络节点

geth --holesky console

配置

可以通过配置文件传递配置:

geth --config /path/to/your_config.toml

Docker快速启动

docker run -d --name ethereum-node -v /Users/alice/ethereum:/root \
           -p 8545:8545 -p 30303:30303 \
           ethereum/client-go

编程接口

geth内置支持基于JSON-RPC的API,可以通过HTTP、WebSockets和IPC暴露。

HTTP JSON-RPC API选项:

  • --http 启用HTTP-RPC服务器
  • --http.addr HTTP-RPC服务器监听接口
  • --http.port HTTP-RPC服务器监听端口
  • --http.api 通过HTTP-RPC接口提供的API
  • --http.corsdomain 接受跨域请求的域列表

私有网络

维护自己的私有网络需要更多配置。有三种解决方案:

  1. 使用模拟后端测试智能合约
  2. 使用开发模式进行单节点测试
  3. 使用Kurtosis设置多节点测试网络

示例代码

以下是一个使用go-ethereum连接以太坊节点并查询区块高度的简单示例:

package main

import (
	"context"
	"fmt"
	"log"

	"github.com/ethereum/go-ethereum/ethclient"
)

func main() {
	// 连接到本地geth节点
	client, err := ethclient.Dial("http://localhost:8545")
	if err != nil {
		log.Fatal(err)
	}

	// 获取最新区块号
	blockNumber, err := client.BlockNumber(context.Background())
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println("Latest block number:", blockNumber)
}

贡献

欢迎任何人为go-ethereum贡献代码。请遵循以下准则:

  • 代码必须符合Go官方格式指南
  • 代码必须文档化
  • 提交消息应前缀修改的包名

许可证

go-ethereum库(即cmd目录外的所有代码)在GNU Lesser General Public License v3.0下授权。go-ethereum二进制文件(即cmd目录内的所有代码)在GNU General Public License v3.0下授权。


更多关于golang实现以太坊协议官方Go语言插件库go-ethereum的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang实现以太坊协议官方Go语言插件库go-ethereum的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


go-ethereum 使用指南

go-ethereum (简称 Geth) 是以太坊协议的官方 Go 语言实现,它提供了与以太坊区块链交互的全套功能。下面我将介绍如何使用 go-ethereum 进行常见的区块链操作。

1. 安装 go-ethereum

首先需要安装 go-ethereum 库:

go get -u github.com/ethereum/go-ethereum

2. 连接以太坊节点

连接到本地节点

package main

import (
	"context"
	"fmt"
	"log"

	"github.com/ethereum/go-ethereum/ethclient"
)

func main() {
	// 连接到本地节点 (默认IPC路径)
	client, err := ethclient.Dial("/home/user/.ethereum/geth.ipc")
	if err != nil {
		log.Fatal(err)
	}

	// 或者连接到远程节点
	// client, err := ethclient.Dial("https://mainnet.infura.io/v3/YOUR_PROJECT_ID")
	
	// 获取最新区块号
	header, err := client.HeaderByNumber(context.Background(), nil)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println("Latest block number:", header.Number.String())
}

3. 查询账户余额

func checkBalance() {
	client, err := ethclient.Dial("https://mainnet.infura.io/v3/YOUR_PROJECT_ID")
	if err != nil {
		log.Fatal(err)
	}

	// 替换为你要查询的地址
	account := common.HexToAddress("0x71c7656ec7ab88b098defb751b7401b5f6d8976f")
	
	balance, err := client.BalanceAt(context.Background(), account, nil)
	if err != nil {
		log.Fatal(err)
	}

	// 将wei转换为ether
	ethBalance := new(big.Float).Quo(new(big.Float).SetInt(balance), big.NewFloat(math.Pow10(18)))
	fmt.Printf("Balance: %f ETH\n", ethBalance)
}

4. 发送交易

func sendTransaction() {
	// 连接到节点
	client, err := ethclient.Dial("https://ropsten.infura.io/v3/YOUR_PROJECT_ID")
	if err != nil {
		log.Fatal(err)
	}

	// 加载私钥 (实际应用中应从安全的地方获取)
	privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY")
	if err != nil {
		log.Fatal(err)
	}

	// 获取账户地址
	publicKey := privateKey.Public()
	publicKeyECDSA, ok := publicKey.(*ecdsa.PublicKey)
	if !ok {
		log.Fatal("cannot assert type: publicKey is not of type *ecdsa.PublicKey")
	}
	fromAddress := crypto.PubkeyToAddress(*publicKeyECDSA)

	// 获取nonce
	nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
	if err != nil {
		log.Fatal(err)
	}

	// 设置转账金额 (1 ETH)
	value := big.NewInt(1000000000000000000) // in wei (1 eth)
	gasLimit := uint64(21000)                // in units
	gasPrice, err := client.SuggestGasPrice(context.Background())
	if err != nil {
		log.Fatal(err)
	}

	// 目标地址
	toAddress := common.HexToAddress("0xRecipientAddress")

	// 创建交易
	tx := types.NewTransaction(nonce, toAddress, value, gasLimit, gasPrice, nil)

	// 获取链ID
	chainID, err := client.NetworkID(context.Background())
	if err != nil {
		log.Fatal(err)
	}

	// 签名交易
	signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)
	if err != nil {
		log.Fatal(err)
	}

	// 发送交易
	err = client.SendTransaction(context.Background(), signedTx)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Printf("tx sent: %s", signedTx.Hash().Hex())
}

5. 与智能合约交互

读取合约数据

func readContract() {
	// 连接到节点
	client, err := ethclient.Dial("https://mainnet.infura.io/v3/YOUR_PROJECT_ID")
	if err != nil {
		log.Fatal(err)
	}

	// 合约地址 (这里使用USDT合约作为示例)
	contractAddress := common.HexToAddress("0xdac17f958d2ee523a2206206994597c13d831ec7")
	
	// 合约ABI (简化版)
	contractABI := `[{"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"name":"balance","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"}]`
	
	// 创建合约实例
	contract, err := abi.JSON(strings.NewReader(contractABI))
	if err != nil {
		log.Fatal(err)
	}

	// 要查询的地址
	account := common.HexToAddress("0xAddressToQuery")

	// 调用balanceOf方法
	data, err := contract.Pack("balanceOf", account)
	if err != nil {
		log.Fatal(err)
	}

	// 执行call
	msg := ethereum.CallMsg{
		To:   &contractAddress,
		Data: data,
	}
	result, err := client.CallContract(context.Background(), msg, nil)
	if err != nil {
		log.Fatal(err)
	}

	// 解析结果
	var balance *big.Int
	err = contract.UnpackIntoInterface(&balance, "balanceOf", result)
	if err != nil {
		log.Fatal(err)
	}

	// USDT有6位小数
	usdtBalance := new(big.Float).Quo(new(big.Float).SetInt(balance), big.NewFloat(math.Pow10(6)))
	fmt.Printf("USDT Balance: %f\n", usdtBalance)
}

6. 监听新区块和事件

func watchBlocks() {
	client, err := ethclient.Dial("wss://mainnet.infura.io/ws/v3/YOUR_PROJECT_ID")
	if err != nil {
		log.Fatal(err)
	}

	headers := make(chan *types.Header)
	sub, err := client.SubscribeNewHead(context.Background(), headers)
	if err != nil {
		log.Fatal(err)
	}

	for {
		select {
		case err := <-sub.Err():
			log.Fatal(err)
		case header := <-headers:
			fmt.Println("New block:", header.Number.String())
			
			// 获取完整区块信息
			block, err := client.BlockByHash(context.Background(), header.Hash())
			if err != nil {
				log.Fatal(err)
			}
			
			fmt.Println("Block hash:", block.Hash().Hex())
			fmt.Println("Block transactions:", len(block.Transactions()))
		}
	}
}

7. 部署智能合约

func deployContract() {
	// 连接到测试网络
	client, err := ethclient.Dial("https://ropsten.infura.io/v3/YOUR_PROJECT_ID")
	if err != nil {
		log.Fatal(err)
	}

	// 加载私钥
	privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY")
	if err != nil {
		log.Fatal(err)
	}

	// 获取账户地址和nonce
	publicKey := privateKey.Public()
	publicKeyECDSA, ok := publicKey.(*ecdsa.PublicKey)
	if !ok {
		log.Fatal("cannot assert type: publicKey is not of type *ecdsa.PublicKey")
	}
	fromAddress := crypto.PubkeyToAddress(*publicKeyECDSA)
	nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
	if err != nil {
		log.Fatal(err)
	}

	// 设置gas价格和限制
	gasPrice, err := client.SuggestGasPrice(context.Background())
	if err != nil {
		log.Fatal(err)
	}
	auth := bind.NewKeyedTransactor(privateKey)
	auth.Nonce = big.NewInt(int64(nonce))
	auth.Value = big.NewInt(0)     // in wei
	auth.GasLimit = uint64(300000) // in units
	auth.GasPrice = gasPrice

	// 编译合约 (这里使用简单示例)
	// 实际项目中应该使用solc编译合约获取bytecode和abi
	contractBytecode := "0x606060...合约字节码..."
	contractABI := `[{"constant":false,"inputs":[{"name":"x","type":"uint256"}],"name":"set","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"get","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[{"name":"_x","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"}]`

	// 解析ABI
	parsedABI, err := abi.JSON(strings.NewReader(contractABI))
	if err != nil {
		log.Fatal(err)
	}

	// 部署合约
	address, tx, _, err := bind.DeployContract(auth, parsedABI, common.FromHex(contractBytecode), client, big.NewInt(123)) // 123是构造函数参数
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println("Contract deployed at:", address.Hex())
	fmt.Println("Transaction hash:", tx.Hash().Hex())
}

注意事项

  1. 私钥管理:实际应用中不应将私钥硬编码在代码中,应使用安全的存储方式
  2. 错误处理:生产代码中需要更完善的错误处理
  3. 网络选择:开发时建议使用测试网络(Ropsten, Rinkeby等)而非主网
  4. 资源管理:记得关闭连接和释放资源
  5. 异步处理:大量数据查询时考虑使用goroutine提高效率

go-ethereum 提供了丰富的功能,以上只是基础用法。根据你的具体需求,可以进一步探索其文档和源码实现更复杂的功能。

回到顶部