基于以太坊区块链的分布式支付系统
支持 充值、提现、支付 三大核心功能,实时监听链上交易,自动确认到账。
基于 Go 1.24 + Ethereum + RabbitMQ + MySQL 技术栈构建的企业级支付解决方案。
M2Pool Payment System v2 是一个基于以太坊区块链的分布式支付解决方案,提供完整的数字货币充值、提现、支付功能。
| 组件 | 技术 | 版本 |
|---|---|---|
| 语言 | Go | 1.24+ |
| 区块链 | Ethereum | go-ethereum v1.16.4 |
| 消息队列 | RabbitMQ | amqp091-go v1.10.0 |
| 数据库 | MySQL | 8.0+ |
| 网络协议 | WebSocket + RPC | - |
┌─────────────────────────────────────────────────────────────┐
│ 业务系统 │
│ (Web/App/API Server) │
└────────────┬────────────────────────────┬───────────────────┘
│ │
│ 请求 │ 响应
↓ ↑
┌─────────────────────────────────────────────────────────────┐
│ RabbitMQ │
│ ┌─────────┐ ┌──────────┐ ┌────────┐ │
│ │ topup │ │ withdraw │ │ pay │ 请求队列 │
│ └─────────┘ └──────────┘ └────────┘ │
│ ┌─────────┐ ┌──────────┐ ┌────────┐ │
│ │topup_ │ │withdraw_ │ │ pay_ │ 响应队列 │
│ │ resp │ │ resp │ │ resp │ │
│ └─────────┘ └──────────┘ └────────┘ │
└────────────┬────────────────────────────┬───────────────────┘
│ │
↓ ↑
┌─────────────────────────────────────────────────────────────┐
│ M2Pool Payment System v2 │
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ RabbitMQ │ │ Blockchain │ │ Database │ │
│ │ Consumer │─>│ Manager │─>│ (MySQL) │ │
│ └──────────────┘ └──────┬───────┘ └──────────────┘ │
│ │ │
│ │ WebSocket + RPC │
└────────────────────────────┼─────────────────────────────────┘
│
↓
┌─────────────────────────────────────────────────────────────┐
│ 以太坊区块链网络 │
│ │
│ ┌──────────────┐ ┌──────────────┐ │
│ │ 新区块 │ │ USDT Transfer │ │
│ │ (NewHead) │ │ 事件 │ │
│ └──────────────┘ └──────────────┘ │
└─────────────────────────────────────────────────────────────┘
internal/blockchain/)internal/queue/)internal/db/)internal/msg/)internal/utils/)internal/crypto/)internal/server.go)m2pool-payment-v2/
├── cmd/ # 主程序入口
│ └── main.go # 程序入口,解析命令行参数
├── internal/ # 内部包(不对外暴露)
│ ├── server.go # 服务启动和管理
│ ├── blockchain/ # 区块链交互模块
│ │ ├── blockchain.go # 统一的区块链接口定义
│ │ ├── eth/ # 以太坊实现
│ │ │ └── eth.go # USDT 监听、转账、确认
│ │ └── tron/ # TRON 实现(待开发)
│ ├── crypto/ # 加密工具
│ │ └── crypto.go # SHA256、签名验证
│ ├── db/ # 数据库
│ │ ├── db.go # MySQL 连接池管理
│ │ └── sqlite.go # SQLite 本地存储
│ ├── msg/ # 消息定义
│ │ └── msg.go # 请求/响应结构体定义
│ ├── queue/ # 消息队列
│ │ ├── rabbitmq.go # RabbitMQ 客户端封装
│ │ └── README.md # RabbitMQ 使用文档
│ ├── logger/ # 日志记录
│ │ └── transaction_logger.go # 交易日志
│ └── utils/ # 工具函数
│ └── utils.go # 类型转换、格式化
├── public/ # 公共资源
│ ├── SQLite3.sql # SQLite 表结构
│ └── migration.sql # 数据库迁移脚本
├── test/ # 测试和示例
│ ├── test.go # 测试程序(独立运行)
│ └── config.json # 配置文件
├── go.mod # Go 模块定义
├── go.sum # 依赖版本锁定
└── README.md # 项目文档(本文件)
系统同时监听两种链上事件:
① USDT Transfer 事件监听
// 检测 USDT 转账,用于充值检测和交易确认触发
e.WsClient.SubscribeFilterLogs(query, e.USDT.LogsChan)
② 新区块头监听
// 每个新区块触发交易确认检查,确保及时确认
e.WsClient.SubscribeNewHead(e.Ctx, headers)
事件驱动 + 区块驱动:
所有以太坊地址统一转换为小写:
避免大小写不一致导致的匹配失败。
sync.Map 用于高并发地址监听sync.Mutex 保护共享数据结构自动归集钱包切换:
用户钱包余额 < 转账金额
↓
自动使用归集钱包
↓
确保交易成功
转账前自动检查:
用户转账 → 实时检测 → 待确认通知 → 区块确认 → 最终通知
特点:
消息流:
提现请求 → 验证余额 → 发送交易 → 等待确认 → 返回结果
特点:
消息流:
支付请求 → 验证余额 → 发送交易 → 等待确认 → 返回结果
特点:
消息流:
# 1. 克隆项目
git clone <repository-url>
cd m2pool-payment-v2
# 2. 安装依赖
go mod download
# 3. 创建数据库
mysql -u root -p
CREATE DATABASE payment CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
USE payment;
-- 创建钱包余额表
CREATE TABLE `eth_balance` (
`id` INT AUTO_INCREMENT PRIMARY KEY,
`address` VARCHAR(42) NOT NULL UNIQUE,
`private_key` VARCHAR(255) NOT NULL COMMENT '加密后的私钥',
`balance` DECIMAL(20, 8) DEFAULT 0,
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX `idx_address` (`address`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='ETH钱包表';
# 4. 配置文件
cd test
cp config.json config.json.backup
# 编辑 config.json,填入实际配置
# 5. 编译主程序
cd ..
go build -o m2pool-payment cmd/main.go
# 6. 运行(指定通信密钥)
./m2pool-payment -key=your_secret_key
# 或者运行测试程序
cd test
go run test.go
创建 test/config.json:
{
"rmq_config": {
"sub_addr": "amqp://m2pool:m2pool@localhost:5672",
"pay": {
"queue": "pay.auto.queue",
"exchange": "pay.exchange",
"routing": ["pay.auto.routing.key"]
},
"topup": {
"queue": "pay.recharge.queue",
"exchange": "pay.exchange",
"routing": ["pay.recharge.routing.key"]
},
"withdraw": {
"queue": "pay.withdraw.queue",
"exchange": "pay.exchange",
"routing": ["pay.withdraw.routing.key"]
},
"pay_resp": {
"queue": "pay.auto.return.queue",
"exchange": "pay.exchange",
"routing": ["pay.auto.return.routing.key"]
},
"topup_resp": {
"queue": "pay.recharge.return.queue",
"exchange": "pay.exchange",
"routing": ["pay.recharge.return.routing.key"]
},
"withdraw_resp": {
"queue": "pay.withdraw.return.queue",
"exchange": "pay.exchange",
"routing": ["pay.withdraw.return.routing.key"]
}
},
"eth_config": {
"rpcUrl": "http://localhost:8545",
"wsUrl": "ws://localhost:8546",
"confirmHeight": 20,
"dbConfig": {
"user": "root",
"password": "your_password",
"host": "127.0.0.1",
"port": 3306,
"database": "payment",
"maxOpenConns": 20,
"maxIdleCoons": 20,
"connMaxLife": 120
}
}
}
| 配置项 | 说明 | 默认值 | 必填 |
|---|---|---|---|
rmq_config.sub_addr |
RabbitMQ 连接地址 | - | ✅ |
eth_config.rpcUrl |
以太坊 RPC 地址 | - | ✅ |
eth_config.wsUrl |
以太坊 WebSocket 地址 | - | ✅ |
eth_config.confirmHeight |
确认区块数 | 20 | ✅ |
dbConfig.user |
数据库用户名 | root | ✅ |
dbConfig.password |
数据库密码 | - | ✅ |
dbConfig.database |
数据库名称 | payment | ✅ |
步骤 1:业务系统发送充值请求
发送到 RabbitMQ 队列:pay.recharge.queue
{
"chain": "ETH",
"symbol": "USDT",
"address": "0x4e5b2e1dc63f6b91cb6cd759936495434c7e972f",
"timestamp": 1758610297,
"sign": "signature_hash"
}
步骤 2:用户转账
用户向指定地址转账 USDT
步骤 3:接收通知
从 RabbitMQ 队列:pay.recharge.return.queue 接收两次消息:
第一次(待确认):
{
"address": "0x4e5b2e1dc63f6b91cb6cd759936495434c7e972f",
"status": 2,
"chain": "ETH",
"symbol": "USDT",
"amount": 100.5,
"tx_hash": "0xabc..."
}
第二次(最终确认):
{
"address": "0x4e5b2e1dc63f6b91cb6cd759936495434c7e972f",
"status": 1,
"chain": "ETH",
"symbol": "USDT",
"amount": 100.5,
"tx_hash": "0xabc..."
}
步骤 1:业务系统发送提现请求
发送到 RabbitMQ 队列:pay.withdraw.queue
{
"queue_id": "withdraw_123",
"from_address": "0x1111...",
"to_address": "0x2222...",
"amount": 50.0,
"chain": "ETH",
"symbol": "USDT",
"timestamp": 1758610297,
"sign": "signature_hash"
}
步骤 2:系统处理
步骤 3:接收通知
从 RabbitMQ 队列:pay.withdraw.return.queue 接收一次消息:
{
"queue_id": "withdraw_123",
"status": 1,
"amount": 50.0,
"chain": "ETH",
"symbol": "USDT",
"tx_hash": "0xdef..."
}
步骤 1:业务系统发送支付请求
发送到 RabbitMQ 队列:pay.auto.queue
{
"queue_id": "pay_456",
"from_address": "0x1111...",
"to_address": "0x3333...",
"amount": 200.0,
"chain": "ETH",
"symbol": "USDT",
"order_id": "order_789",
"timestamp": 1758610297,
"sign": "signature_hash"
}
步骤 2:系统处理
步骤 3:接收通知
从 RabbitMQ 队列:pay.auto.return.queue 接收一次消息:
{
"queue_id": "pay_456",
"status": 1,
"amount": 200.0,
"chain": "ETH",
"symbol": "USDT",
"order_id": "order_789",
"tx_hash": "0xghi..."
}
A: 这是设计特性!
业务系统应该:
A: 因为是系统主动发起的交易,用户已经知道在处理中,不需要额外的待确认通知。
A: 系统会返回 status=0 的消息,业务系统应该:
A: 配置为 20 个区块确认,以太坊约 12 秒/块:
A:
⚠️ 重要:当前代码中的解密逻辑是占位代码,生产环境必须替换为真实的加密算法!
A: 系统会自动使用归集钱包转账。归集钱包应该:
A:
A:
建议:提现/支付时从用户金额中扣除 Gas 费
# Dockerfile
FROM golang:1.24-alpine AS builder
WORKDIR /app
COPY . .
RUN go mod download
RUN CGO_ENABLED=0 GOOS=linux go build -o m2pool-payment cmd/main.go
FROM alpine:latest
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY --from=builder /app/m2pool-payment .
COPY --from=builder /app/test/config.json .
CMD ["./m2pool-payment"]
# docker-compose.yml
version: '3.8'
services:
payment:
build: .
depends_on:
- mysql
- rabbitmq
environment:
- CONFIG_PATH=/root/config.json
volumes:
- ./config.json:/root/config.json
restart: unless-stopped
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_PASSWORD}
MYSQL_DATABASE: payment
ports:
- "3306:3306"
volumes:
- mysql_data:/var/lib/mysql
rabbitmq:
image: rabbitmq:3-management
environment:
RABBITMQ_DEFAULT_USER: m2pool
RABBITMQ_DEFAULT_PASS: m2pool
ports:
- "5672:5672"
- "15672:15672"
volumes:
- rabbitmq_data:/var/lib/rabbitmq
volumes:
mysql_data:
rabbitmq_data:
# 启动
docker-compose up -d
# 查看日志
docker-compose logs -f payment
# 停止
docker-compose down
# 1. 创建系统用户
sudo useradd -r -s /bin/false m2pool
# 2. 创建服务文件
sudo nano /etc/systemd/system/m2pool-payment.service
[Unit]
Description=M2Pool Payment System
After=network.target mysql.service rabbitmq-server.service
[Service]
Type=simple
User=m2pool
WorkingDirectory=/opt/m2pool-payment
ExecStart=/opt/m2pool-payment/m2pool-payment
Restart=on-failure
RestartSec=10
[Install]
WantedBy=multi-user.target
# 3. 启动服务
sudo systemctl daemon-reload
sudo systemctl enable m2pool-payment
sudo systemctl start m2pool-payment
# 4. 查看状态
sudo systemctl status m2pool-payment
# 5. 查看日志
sudo journalctl -u m2pool-payment -f
| 配置项 | 规格 | 说明 |
|---|---|---|
| CPU | 4核 2.4GHz | Intel/AMD x64 |
| 内存 | 8GB DDR4 | 系统 + 缓存 |
| 网络 | 100Mbps | 公网带宽 |
| 数据库 | MySQL 8.0 | 本地部署 |
| 消息队列 | RabbitMQ 3.x | 本地部署 |
| 区块链节点 | Infura/Alchemy | 云端服务 |
| 并发用户数 | TPS | 响应时间 | 成功率 | 说明 |
|---|---|---|---|---|
| 10 | 50-80 | < 2秒 | 99.9% | 轻量负载,性能优秀 |
| 50 | 200-300 | 2-5秒 | 99.5% | 中等负载,性能良好 |
| 100 | 300-500 | 5-10秒 | 99.0% | 高负载,性能稳定 |
| 200 | 400-600 | 10-20秒 | 98.5% | 极限负载,性能下降 |
| 500+ | 500-800 | > 20秒 | < 98% | 超负载,不建议 |
特点:
| 并发用户数 | TPS | 响应时间 | 成功率 | 说明 |
|---|---|---|---|---|
| 5 | 20-30 | 3-8秒 | 99.8% | 轻量负载,性能优秀 |
| 20 | 50-80 | 8-15秒 | 99.0% | 中等负载,性能良好 |
| 50 | 80-120 | 15-30秒 | 98.5% | 高负载,性能稳定 |
| 100 | 100-150 | 30-60秒 | 97.0% | 极限负载,性能下降 |
| 200+ | 120-200 | > 60秒 | < 95% | 超负载,不建议 |
特点:
| 并发用户数 | TPS | 响应时间 | 成功率 | 说明 |
|---|---|---|---|---|
| 5 | 20-30 | 3-8秒 | 99.8% | 轻量负载,性能优秀 |
| 20 | 50-80 | 8-15秒 | 99.0% | 中等负载,性能良好 |
| 50 | 80-120 | 15-30秒 | 98.5% | 高负载,性能稳定 |
| 100 | 100-150 | 30-60秒 | 97.0% | 极限负载,性能下降 |
| 200+ | 120-200 | > 60秒 | < 95% | 超负载,不建议 |
特点:
| 并发数 | 基础内存 | 峰值内存 | 说明 |
|---|---|---|---|
| 10 | 100MB | 150MB | 轻量运行 |
| 50 | 200MB | 350MB | 中等负载 |
| 100 | 300MB | 500MB | 高负载 |
| 200 | 500MB | 800MB | 极限负载 |
| 并发数 | 基础CPU | 峰值CPU | 说明 |
|---|---|---|---|
| 10 | 5% | 15% | 轻量运行 |
| 50 | 15% | 35% | 中等负载 |
| 100 | 25% | 50% | 高负载 |
| 200 | 40% | 70% | 极限负载 |
| 并发数 | 上行带宽 | 下行带宽 | 说明 |
|---|---|---|---|
| 10 | 1Mbps | 2Mbps | 轻量运行 |
| 50 | 3Mbps | 5Mbps | 中等负载 |
| 100 | 5Mbps | 8Mbps | 高负载 |
| 200 | 8Mbps | 12Mbps | 极限负载 |
| 瓶颈类型 | 影响程度 | 解决方案 |
|---|---|---|
| 区块链确认时间 | 🔴 高 | 使用Layer2或侧链 |
| 数据库查询 | 🟡 中 | 添加索引,使用缓存 |
| 私钥解密 | 🟡 中 | 优化加密算法 |
| 网络延迟 | 🟡 中 | 使用CDN,就近部署 |
| Gas费用波动 | 🟡 中 | 动态Gas价格调整 |
短期优化(1-2周):
中期优化(1-2月):
长期优化(3-6月):
# 使用 RabbitMQ 压测工具
docker run --rm -it \
-e RABBITMQ_HOST=localhost \
-e RABBITMQ_PORT=5672 \
-e RABBITMQ_USER=m2pool \
-e RABBITMQ_PASS=m2pool \
rabbitmq-perf-test:latest \
--rate 100 --time 60 --queue pay.withdraw.queue
# 使用 sysbench 压测 MySQL
sysbench mysql \
--mysql-host=localhost \
--mysql-port=3306 \
--mysql-user=root \
--mysql-password=password \
--mysql-db=payment \
--tables=1 \
--table-size=10000 \
--threads=10 \
--time=60 \
run
# 监控系统资源
htop # CPU和内存监控
iotop # 磁盘IO监控
nethogs # 网络带宽监控
| 环境 | CPU | 内存 | 并发数 | 说明 |
|---|---|---|---|---|
| 开发环境 | 2核 | 4GB | < 10 | 功能测试 |
| 测试环境 | 4核 | 8GB | < 50 | 压力测试 |
| 生产环境 | 8核 | 16GB | < 100 | 稳定运行 |
| 高可用环境 | 16核 | 32GB | < 200 | 负载均衡 |
// 关键监控指标
type Metrics struct {
TotalTransactions int64 // 总交易数
PendingTransactions int // 待确认交易数
FailedTransactions int64 // 失败交易数
ChannelUsage int // Channel使用率
LastBlockHeight uint64 // 最新区块高度
MemoryUsage int64 // 内存使用量
CPUUsage float64 // CPU使用率
}
| 指标 | 警告阈值 | 严重阈值 | 说明 |
|---|---|---|---|
| 待确认交易数 | > 100 | > 500 | 交易积压 |
| Channel使用率 | > 80% | > 95% | 消息积压 |
| 交易失败率 | > 5% | > 10% | 系统异常 |
| 内存使用率 | > 80% | > 95% | 内存不足 |
| CPU使用率 | > 70% | > 90% | CPU过载 |
问题:两笔不同的交易出现相同的 QueueId
原因:数据库表主键设计错误,使用 (from_addr, to_addr) 作为主键
修复:
queueIdpublic/migration.sql问题:提现和支付会发送两次响应
原因:转账失败时,先发送失败响应,然后仍然进入链上确认流程
修复:
return 语句| 场景 | 消息处理阶段 | 链上确认阶段 | 总发送次数 |
|---|---|---|---|
| 转账失败 | 发送失败响应 | 不进入(已return) | 1次 |
| 转账成功 | 不发送响应 | 发送成功响应 | 1次 |
欢迎贡献代码!请遵循以下步骤:
git checkout -b feature/AmazingFeature)git commit -m 'feat: Add some AmazingFeature')git push origin feature/AmazingFeature)gofmt 格式化代码# 新功能
feat: 添加 BTC 网络支持
# Bug 修复
fix: 修复充值消息重复发送问题
# 文档更新
docs: 更新 API 文档
# 性能优化
perf: 优化交易确认性能
# 代码重构
refactor: 重构数据库连接池
# 测试
test: 添加单元测试
MIT License
Copyright (c) 2025 M2Pool Team
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
⭐ 如果这个项目对你有帮助,请给一个 Star!⭐
Made with ❤️ by M2Pool Team