go-ethereum中client.BlockByHash()调用报'not found'错误求助
解决以太坊订阅新区块后通过哈希获取区块失败的问题
问题根源
当通过SubscribeNewHead接收到新区块头时,对应的完整区块数据可能还未完全同步到Infura节点的存储中,此时立刻调用BlockByHash会触发"not found"错误。而区块头的哈希能正常输出,仅说明WebSocket连接正常且收到了新区块头的广播,不代表完整区块已就绪。
解决方案
方案1:直接使用区块头获取基础信息(推荐)
如果仅需要区块号、时间、nonce这类基础字段,完全不需要额外请求完整区块——订阅返回的*types.Header对象已经包含这些数据,既避免错误又提升性能:
package main import ( "context" "fmt" "log" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethclient" ) func main() { client, err := ethclient.Dial("wss://mainnet.infura.io/ws/v3/APIKEY") 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(header.Hash().Hex()) // 区块哈希 fmt.Println(header.Number.Uint64()) // 区块号 fmt.Println(header.Time) // 区块时间 fmt.Println(header.Nonce) // Nonce // 注意:区块头不包含交易列表,若需交易必须请求完整区块 } } }
方案2:需要完整区块时添加重试逻辑
如果必须获取包含交易的完整区块,可通过重试机制等待区块数据同步完成:
package main import ( "context" "fmt" "log" "time" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethclient" ) func main() { client, err := ethclient.Dial("wss://mainnet.infura.io/ws/v3/APIKEY") 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(header.Hash().Hex()) // 重试获取完整区块,最多尝试5次,每次间隔1秒 var block *types.Block retryCount := 0 maxRetries := 5 for retryCount < maxRetries { block, err = client.BlockByHash(context.Background(), header.Hash()) if err == nil { break } retryCount++ time.Sleep(1 * time.Second) log.Printf("重试获取区块,次数:%d", retryCount) } if err != nil { log.Printf("多次重试后仍无法获取区块:%v", err) continue } fmt.Println(block.Hash().Hex()) // 区块哈希 fmt.Println(block.Number().Uint64()) // 区块号 fmt.Println(block.Time()) // 区块时间 fmt.Println(block.Nonce()) // Nonce fmt.Println(len(block.Transactions())) // 交易数量 } } }
额外提示
- 替换代码中的
APIKEY为你自己的Infura API密钥。 - 优先使用方案1,减少不必要的RPC请求能降低Infura调用频率限制风险,同时提升程序响应速度。
内容的提问来源于stack exchange,提问作者Filipe Aleixo
相关产品推荐
相关产品推荐

