Files
m2pool_payment/internal/blockchain/eth/eth.go

232 lines
6.1 KiB
Go
Raw Normal View History

2025-10-16 18:54:27 +08:00
package eth
import (
"context"
"fmt"
"log"
"m2pool-payment/internal/db"
2025-11-13 17:08:38 +08:00
"m2pool-payment/internal/listen"
2025-10-16 18:54:27 +08:00
message "m2pool-payment/internal/msg"
"math/big"
"sync"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethclient"
)
type ETHNode struct {
2025-11-13 17:08:38 +08:00
decodeKey string // 消息解密密钥用于解密RMQ消息的Sign
NetID *big.Int
2025-10-31 13:46:58 +08:00
Config message.ETHConfig
ConfirmHeight uint64
WsClient *ethclient.Client
RpcClient *ethclient.Client
2025-11-13 17:08:38 +08:00
MysqlDB *db.MySQLPool
SqliteDB *db.SQLite
USDT *USDT
NetInfo *NetInfo // 网络通用状态(当前高度、gas费用等)
// Messages map[string]any // {"queue_id": message.Topup{}, "queue_id": message.Withdraw{}, ...}
MessageServer *listen.ListenServer
UnConfirmedTxs *UnConfirmedTxs
Wallets map[string]*Wallets // {"address" : &Wallets{}, ...}
LogsChan chan *types.Header
Ctx context.Context
Cancel context.CancelFunc
mu sync.Mutex
2025-10-16 18:54:27 +08:00
}
type USDT struct {
2025-10-31 13:46:58 +08:00
Address common.Address // USDT合约地址
ListeningAddresses map[string]any // 监听的USDT转账消息
ABI abi.ABI // USDT ABI
TransferSig common.Hash // USDT函数签名
LogsChan chan types.Log
}
2025-11-13 17:08:38 +08:00
type UnConfirmedTxs struct {
mu sync.Mutex
Transactions map[string]message.Transaction // {"queue_id": message.Transactions{}, ...}
}
type NetInfo struct {
2025-10-31 13:46:58 +08:00
mu sync.Mutex
2025-11-13 17:08:38 +08:00
Height uint64
2025-10-31 13:46:58 +08:00
GasLimit uint64
GasTipCap *big.Int
GasFeeCap *big.Int
GasPrice *big.Int // 老版本转账使用的gas
2025-10-16 18:54:27 +08:00
}
2025-11-13 17:08:38 +08:00
type Wallets struct {
address string
queueId string
pk string
eth_balance *eth_balance
usdt_balance *usdt_balance
timestamp uint64
sign string
status int
mu sync.Mutex
}
type eth_balance struct {
symbol string // 默认ETH
used_gas *big.Int // 1 ETH = 1e18 WEI
balance *big.Int // 实际拥有的ETH余额
successed_tx_hash []string
failed_tx_hash []string
}
type usdt_balance struct {
symbol string
freeze_num *big.Int // 1 USDT = 1e6 WEI
balance *big.Int // 实际拥有的USDT余额
successed_tx_hash []string
failed_tx_hash []string
}
func NewETHNode(cfg message.Config, decodeKey string, l *listen.ListenServer) (*ETHNode, error) {
2025-10-16 18:54:27 +08:00
// 连入ETH节点的ws
2025-11-13 17:08:38 +08:00
ws_client, err := ethclient.Dial(cfg.ETHConfig.WsUrl)
2025-10-16 18:54:27 +08:00
if err != nil {
return nil, fmt.Errorf("failed to connect to Ethereum node: %w", err)
}
// 连入ETH节点的rpc
2025-11-13 17:08:38 +08:00
rpc_client, err := ethclient.Dial(cfg.ETHConfig.RpcUrl)
2025-10-16 18:54:27 +08:00
if err != nil {
return nil, fmt.Errorf("failed to connect to Ethereum node rpc: %w", err)
}
// 创建可取消的 context
ctx, cancel := context.WithCancel(context.Background())
2025-11-13 17:08:38 +08:00
2025-10-16 18:54:27 +08:00
// 获得net_id
netId, err := rpc_client.NetworkID(ctx)
if err != nil {
cancel()
return nil, fmt.Errorf("failed to connect to get node net_id: %w", err)
}
2025-11-13 17:08:38 +08:00
// 初始化MySQL数据库
dbConn, err := db.NewMySQLPool(cfg.MysqlConfig["wallet"])
2025-10-16 18:54:27 +08:00
if err != nil {
cancel()
return nil, fmt.Errorf("mysql connect error: %w", err)
}
2025-10-31 13:46:58 +08:00
2025-11-13 17:08:38 +08:00
// 初始化SQLite3
sqlite, err := db.NewSQLite(cfg.ETHConfig.SqlitePath)
if err != nil {
cancel()
return nil, fmt.Errorf("sqlite3 connect error: %w", err)
}
logchan := make(chan *types.Header)
// 初始化USDT
usdt := init_USDT()
ethnode := &ETHNode{
2025-10-31 13:46:58 +08:00
decodeKey: decodeKey,
NetID: netId,
2025-11-13 17:08:38 +08:00
Config: cfg.ETHConfig,
ConfirmHeight: cfg.ETHConfig.ConfirmHeight,
2025-10-31 13:46:58 +08:00
WsClient: ws_client,
RpcClient: rpc_client,
USDT: usdt,
2025-11-13 17:08:38 +08:00
MysqlDB: dbConn,
SqliteDB: sqlite,
NetInfo: &NetInfo{},
UnConfirmedTxs: &UnConfirmedTxs{
Transactions: make(map[string]message.Transaction),
},
Wallets: make(map[string]*Wallets),
MessageServer: l,
LogsChan: logchan,
2025-10-31 13:46:58 +08:00
Ctx: ctx,
Cancel: cancel,
}
// 初始化表
2025-11-18 11:10:16 +08:00
// err = ethnode.MysqlDB.ExecuteSQLFile("../public/eth_mysql.sql")
// if err != nil {
// log.Fatalf("ETH-Chain初始化数据库表失败%v", err)
// }
2025-11-13 17:08:38 +08:00
// 更新网络公共数据和加载钱包
height, err := ethnode.getHeight()
2025-10-16 18:54:27 +08:00
if err != nil {
2025-11-13 17:08:38 +08:00
return nil, fmt.Errorf("failed to get blockHeight: %v", err)
2025-10-16 18:54:27 +08:00
}
2025-11-13 17:08:38 +08:00
// 更新网络公共数据
ethnode.updateNetInfo(height)
// 加载钱包
if err := ethnode.loadWallets(); err != nil {
return nil, fmt.Errorf("[inital eth wallets]: %v", err)
2025-10-16 18:54:27 +08:00
}
2025-11-13 17:08:38 +08:00
// 加载未确认交易
if err := ethnode.loadUnConfirmedTxs(); err != nil {
return nil, fmt.Errorf("load unconfirmtxs error: %v", err)
2025-10-16 18:54:27 +08:00
}
2025-11-13 17:08:38 +08:00
log.Println("✅ ETH节点已启动")
// ethnode.handleHistoryETHEvent(23795552)
2025-11-13 17:08:38 +08:00
return ethnode, nil
2025-10-16 18:54:27 +08:00
}
2025-11-13 17:08:38 +08:00
// 转账
func (e *ETHNode) Transfer(from, to, symbol string, amount, fee float64) error {
// 执行转账
err := e.handleTx(symbol, from, to, amount)
2025-10-27 16:27:33 +08:00
if err != nil {
2025-11-13 17:08:38 +08:00
return fmt.Errorf("%s-tranfer error: %v", symbol, err)
2025-10-31 13:46:58 +08:00
}
2025-11-13 17:08:38 +08:00
return nil
2025-10-31 13:46:58 +08:00
}
2025-11-13 17:08:38 +08:00
// 监听消息
func (e *ETHNode) ListenMsg() {
log.Printf("✅ 开始监听msg...")
if e.MessageServer.ChToChainServer["ETH"] == nil {
log.Printf("ETH消息通道还未建立")
return
2025-10-16 18:54:27 +08:00
}
2025-10-27 16:27:33 +08:00
2025-11-13 17:08:38 +08:00
for msg := range e.MessageServer.ChToChainServer["ETH"] {
switch v := msg.(type) {
case message.TopupMsg_req:
go e.handleListen_Topup_req(v)
case message.WithdrawMsg_req:
go e.handleListen_Withdraw_req(v)
case message.PayMsg_req:
go e.handleListen_Pay_req(v)
case message.RemoveListenMsg_req:
go e.handleListen_Remove_req(v)
default:
log.Printf("ListenMsg error: %v", msg)
2025-10-16 18:54:27 +08:00
}
}
}
2025-11-13 17:08:38 +08:00
// 监听区块链数据
func (e *ETHNode) Listen() error {
log.Println("✅ 开始监听 ETH 和 USDT 转账事件...")
2025-10-31 13:46:58 +08:00
go func() {
2025-11-13 17:08:38 +08:00
err := e.listenETHTransactions()
if err != nil {
log.Printf("Listen ETH Transactions Error: %v", err)
2025-10-31 13:46:58 +08:00
}
}()
go func() {
2025-11-13 17:08:38 +08:00
err := e.listenUSDTTransactions()
2025-10-27 16:27:33 +08:00
if err != nil {
2025-11-13 17:08:38 +08:00
log.Printf("Listen USDT Transactions Error: %v", err)
2025-10-27 16:27:33 +08:00
}
2025-11-13 17:08:38 +08:00
}()
2025-10-27 16:27:33 +08:00
2025-10-31 13:46:58 +08:00
return nil
}
2025-10-27 16:27:33 +08:00
2025-11-13 17:08:38 +08:00
func (e *ETHNode) Stop() {
if e.Cancel != nil {
e.Cancel()
2025-10-31 13:46:58 +08:00
}
2025-11-13 17:08:38 +08:00
log.Println("🛑 停止监听...")
2025-10-16 18:54:27 +08:00
}