232 lines
6.1 KiB
Go
232 lines
6.1 KiB
Go
package eth
|
||
|
||
import (
|
||
"context"
|
||
"fmt"
|
||
"log"
|
||
"m2pool-payment/internal/db"
|
||
"m2pool-payment/internal/listen"
|
||
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 {
|
||
decodeKey string // 消息解密密钥,用于解密RMQ消息的Sign
|
||
NetID *big.Int
|
||
Config message.ETHConfig
|
||
ConfirmHeight uint64
|
||
WsClient *ethclient.Client
|
||
RpcClient *ethclient.Client
|
||
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
|
||
}
|
||
|
||
type USDT struct {
|
||
Address common.Address // USDT合约地址
|
||
ListeningAddresses map[string]any // 监听的USDT转账消息
|
||
ABI abi.ABI // USDT ABI
|
||
TransferSig common.Hash // USDT函数签名
|
||
LogsChan chan types.Log
|
||
}
|
||
|
||
type UnConfirmedTxs struct {
|
||
mu sync.Mutex
|
||
Transactions map[string]message.Transaction // {"queue_id": message.Transactions{}, ...}
|
||
}
|
||
|
||
type NetInfo struct {
|
||
mu sync.Mutex
|
||
Height uint64
|
||
GasLimit uint64
|
||
GasTipCap *big.Int
|
||
GasFeeCap *big.Int
|
||
GasPrice *big.Int // 老版本转账使用的gas
|
||
}
|
||
|
||
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) {
|
||
// 连入ETH节点的ws
|
||
ws_client, err := ethclient.Dial(cfg.ETHConfig.WsUrl)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("failed to connect to Ethereum node: %w", err)
|
||
}
|
||
// 连入ETH节点的rpc
|
||
rpc_client, err := ethclient.Dial(cfg.ETHConfig.RpcUrl)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("failed to connect to Ethereum node rpc: %w", err)
|
||
}
|
||
// 创建可取消的 context
|
||
ctx, cancel := context.WithCancel(context.Background())
|
||
|
||
// 获得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)
|
||
}
|
||
|
||
// 初始化MySQL数据库
|
||
dbConn, err := db.NewMySQLPool(cfg.MysqlConfig["wallet"])
|
||
if err != nil {
|
||
cancel()
|
||
return nil, fmt.Errorf("mysql connect error: %w", err)
|
||
}
|
||
|
||
// 初始化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 := ÐNode{
|
||
decodeKey: decodeKey,
|
||
NetID: netId,
|
||
Config: cfg.ETHConfig,
|
||
ConfirmHeight: cfg.ETHConfig.ConfirmHeight,
|
||
WsClient: ws_client,
|
||
RpcClient: rpc_client,
|
||
USDT: usdt,
|
||
MysqlDB: dbConn,
|
||
SqliteDB: sqlite,
|
||
NetInfo: &NetInfo{},
|
||
UnConfirmedTxs: &UnConfirmedTxs{
|
||
Transactions: make(map[string]message.Transaction),
|
||
},
|
||
Wallets: make(map[string]*Wallets),
|
||
MessageServer: l,
|
||
LogsChan: logchan,
|
||
Ctx: ctx,
|
||
Cancel: cancel,
|
||
}
|
||
// 初始化表
|
||
// err = ethnode.MysqlDB.ExecuteSQLFile("../public/eth_mysql.sql")
|
||
// if err != nil {
|
||
// log.Fatalf("ETH-Chain初始化数据库表失败:%v", err)
|
||
// }
|
||
// 更新网络公共数据和加载钱包
|
||
height, err := ethnode.getHeight()
|
||
if err != nil {
|
||
return nil, fmt.Errorf("failed to get blockHeight: %v", err)
|
||
}
|
||
// 更新网络公共数据
|
||
ethnode.updateNetInfo(height)
|
||
// 加载钱包
|
||
if err := ethnode.loadWallets(); err != nil {
|
||
return nil, fmt.Errorf("[inital eth wallets]: %v", err)
|
||
}
|
||
// 加载未确认交易
|
||
if err := ethnode.loadUnConfirmedTxs(); err != nil {
|
||
return nil, fmt.Errorf("load unconfirmtxs error: %v", err)
|
||
}
|
||
log.Println("✅ ETH节点已启动")
|
||
// ethnode.handleHistoryETHEvent(23795552)
|
||
return ethnode, nil
|
||
}
|
||
|
||
// 转账
|
||
func (e *ETHNode) Transfer(from, to, symbol string, amount, fee float64) error {
|
||
// 执行转账
|
||
err := e.handleTx(symbol, from, to, amount)
|
||
if err != nil {
|
||
return fmt.Errorf("%s-tranfer error: %v", symbol, err)
|
||
}
|
||
return nil
|
||
}
|
||
|
||
// 监听消息
|
||
func (e *ETHNode) ListenMsg() {
|
||
log.Printf("✅ 开始监听msg...")
|
||
if e.MessageServer.ChToChainServer["ETH"] == nil {
|
||
log.Printf("ETH消息通道还未建立")
|
||
return
|
||
}
|
||
|
||
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)
|
||
}
|
||
}
|
||
}
|
||
|
||
// 监听区块链数据
|
||
func (e *ETHNode) Listen() error {
|
||
log.Println("✅ 开始监听 ETH 和 USDT 转账事件...")
|
||
go func() {
|
||
err := e.listenETHTransactions()
|
||
if err != nil {
|
||
log.Printf("Listen ETH Transactions Error: %v", err)
|
||
}
|
||
}()
|
||
|
||
go func() {
|
||
err := e.listenUSDTTransactions()
|
||
if err != nil {
|
||
log.Printf("Listen USDT Transactions Error: %v", err)
|
||
}
|
||
}()
|
||
|
||
return nil
|
||
}
|
||
|
||
func (e *ETHNode) Stop() {
|
||
if e.Cancel != nil {
|
||
e.Cancel()
|
||
}
|
||
log.Println("🛑 停止监听...")
|
||
}
|