Skip to content

ciphermagic/eth-relay

Repository files navigation

eth-relay —— 以太坊区块中继服务(Go 实现)

一个轻量、高可靠、可扩展的以太坊区块同步与分叉检测中继服务 专为 实时监听、持久化、去重、防分叉 设计,开箱即用,适用于 DeFi、NFT、链上数据索引、监控告警等任何需要可靠链上数据的后端服务。


功能特性

特性 说明
分叉自动检测 + 回滚 实时对比 parentHash,自动标记 fork=true,确保链上数据一致性
重试机制 retryGetBlockInfoBy* 自动重试,应对节点临时不可用
批量 RPC 调用 BatchCall 提升性能,支持一次查询多个余额/交易
Nonce 管理器 内置 NonceManager,防止交易重放/丢失
数据库去重 区块/交易插入前查重,避免重复写入
协程安全 sync.Mutex 保护共享状态
完整测试用例 覆盖核心功能,接入 Sepolia/本地测试节点
模块化设计 daomodeltoolrpc 分层清晰,易扩展

项目结构

eth-relay/
├── dao/                    # 数据库模型 & 连接器
│   ├── block.go            # Block 结构体
│   ├── Transaction.go      # 交易结构体
│   └── mysql.go            # MySQL 连接封装
├── model/                  # RPC 返回数据结构
│   ├── full_block.go       # 完整区块 + 交易列表
│   ├── transaction.go      # 交易数据结构
│   └── eth_call_arg.go     # ETH Call 参数结构
├── tool/                   # 工具函数
│   ├── tool.go             # 工具函数实现
│   └── tool_test.go        # 工具函数测试
├── keystores/              # 钱包密钥存储
├── ETH_RPC_Client.go       # ETH RPC 客户端封装
├── ETH_RPC_Requester.go    # ETH RPC 请求器实现
├── block_scanner.go        # 核心:区块扫描器
├── nonce_manager.go        # Nonce 管理器
├── main.go                 # 主程序入口
├── *_test.go               # 单元测试
├── go.mod                  # Go 模块依赖
├── go.sum                  # 依赖校验
└── README.md               # 项目说明文档

核心流程图

[ETH Node] ←RPC→ [ETHRPCRequester]
                         ↓
                 [BlockScanner.Start()]
                         ↓
             init() → 获取最新已同步区块
                         ↓
                 scan() → 获取下一区块
               ┌─────────┴─────────┐
               │                   │
          [forkCheck]         [正常写入]
               ↓                   ↓
        标记 fork=true         插入 Block + Tx
               ↓
       继续扫描下一区块

关键实现解析

1. 分叉检测机制(forkCheck

if s.lastBlock.BlockHash != currentBlock.ParentHash {
    // 触发分叉 → 递归查找分叉起点 → 标记区间内所有区块为 fork
}
  • 递归查找 getStartForkBlock 直到找到主链交点
  • 使用 UPDATE ... WHERE block_number > X AND <= Y 批量标记
  • 避免数据不一致,适合索引服务

2. 重试 + 防空块

Retry:
    fullBlock, err := GetBlockInfoByNumber(targetNumber)
    if err != nil && strings.Contains(err.Error(), "empty") {
        s.log("获取区块信息,重试一次......", targetNumber.String())
        goto Retry
    }
  • 防止节点同步延迟导致空响应
  • 配合 time.Sleep(1s) 轮询,稳定可靠

3. 批量查询优化

client.GetRpc().BatchCall(reqs)
  • GetEthBalances, GetERC20Balances, GetTransactions 均支持批量
  • 减少 RTT,提升性能 3~5 倍

4. Nonce 管理器

nonceManager.GetNonce(addr) → *big.Int
nonceManager.PlusNonce(addr)
  • 内存缓存 + RPC 兜底
  • 防止 nonce too low / replacement transaction underpriced

快速启动

1. 环境要求

Go ≥ 1.23
MySQL ≥ 5.7
Ethereum Node (Infura / Alchemy / Self-hosted / Local)

2. 克隆并编译

git clone https://github.com/ciphermagic/eth-relay.git
cd eth-relay
go mod tidy
go build -o eth-relay

3. 配置数据库

CREATE DATABASE eth_relay CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

4. 启动服务

# 使用命令行参数
./eth-relay \
  --rpc https://sepolia.infura.io/v3/YOUR_INFURA_KEY \
  --mysql "root:password@tcp(localhost:3306)/eth_relay?charset=utf8mb4&parseTime=true"

# 或使用环境变量
export ETH_RPC_URL="https://sepolia.infura.io/v3/YOUR_INFURA_KEY"
export MYSQL_DSN="root:password@tcp(localhost:3306)/eth_relay?charset=utf8mb4&parseTime=true"
go run main.go

5. 钱包管理

项目支持以太坊钱包的创建和管理:

# 程序将自动在 keystores/ 目录下创建和管理钱包文件

数据库表结构

-- 区块表
CREATE TABLE eth_block (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    block_number VARCHAR(66) NOT NULL,
    block_hash VARCHAR(66) NOT NULL UNIQUE,
    parent_hash VARCHAR(66),
    create_time BIGINT NOT NULL,
    fork TINYINT(1) DEFAULT 0,
    INDEX idx_number (block_number),
    INDEX idx_fork (fork)
);

-- 交易表
CREATE TABLE eth_transaction (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    hash VARCHAR(66) NOT NULL UNIQUE,
    nonce VARCHAR(20),
    block_hash VARCHAR(66),
    block_number VARCHAR(66),
    transaction_index VARCHAR(20),
    from_addr VARCHAR(42),
    to_addr VARCHAR(42),
    value VARCHAR(78),
    gas_price VARCHAR(50),
    gas VARCHAR(50),
    input TEXT,
    INDEX idx_block_hash (block_hash),
    INDEX idx_from_addr (from_addr),
    INDEX idx_to_addr (to_addr)
);

测试用例

# 运行所有测试
go test -v ./...

# 运行特定测试
go test -v -run TestBlockScanner_Start
go test -v -run TestETHRPCRequester_
测试 功能
TestBlockScanner_Start 启动扫描器,监听 Sepolia
TestETHRPCRequester_GetTransactionByHash 单交易查询
TestETHRPCRequester_GetTransactions 批量交易查询
TestETHRPCRequester_GetETHBalance ETH余额查询
TestETHRPCRequester_GetEthBalances 批量ETH余额查询
TestETHRPCRequester_GetERC20Balance ERC20代币余额查询
TestETHRPCRequester_GetLastestBlockNumber 获取最新区块号
TestETHRPCRequester_GetBlockInfoByNumber 完整区块信息
TestETHRPCRequester_GetBlockInfoByHash 通过哈希获取区块
TestETHRPCRequester_CreateETHWallet 创建以太坊钱包
TestETHRPCRequester_SendETHTransaction 发送ETH交易
TestETHRPCRequester_SendERC20Transaction 发送ERC20代币交易

性能指标(Sepolia 测试)

指标 数据
同步延迟 < 3 秒
分叉检测时间 < 1 秒
QPS(批量查询) > 50
内存占用 ~30MB
CPU 单核 < 10%

扩展方向

方向 实现
WebSocket 订阅 替换轮询,使用 eth_subscribe
事件解析 集成 abi.Decode 解析 Transfer 事件
Prometheus 监控 暴露 /metrics
Docker 部署 Dockerfile + docker-compose.yml
多链支持 抽象 ChainConfig,支持 BSC/Polygon
GraphQL API 提供 GraphQL 接口查询链上数据
缓存层 集成 Redis 缓存热点数据
分布式部署 支持多个节点协同工作

贡献指南

# 克隆项目
git clone https://github.com/ciphermagic/eth-relay.git
cd eth-relay

# 运行测试
go test -v ./...

# 运行特定包的测试
go test -v ./dao/
go test -v ./model/
go test -v ./tool/

# 代码格式化
go fmt ./...
go vet ./...

# 提交代码
git add .
git commit -m "feat: add new feature"
git push origin main

欢迎 PR!我们遵循 Conventional Commits.


许可证

MIT License © 2025 www.ciphermagic.cn

Star me on GitHub https://github.com/ciphermagic/eth-relay

About

一个轻量、高可靠、可扩展的以太坊区块同步与分叉检测中继服务

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages