add log-system, bug fixed

This commit is contained in:
lzx
2025-11-18 11:10:16 +08:00
parent ac22db02f3
commit 74d9a114c0
13 changed files with 861 additions and 186 deletions

View File

@@ -145,10 +145,10 @@ func NewETHNode(cfg message.Config, decodeKey string, l *listen.ListenServer) (*
Cancel: cancel,
}
// 初始化表
err = ethnode.initTables()
if err != nil {
return nil, err
}
// err = ethnode.MysqlDB.ExecuteSQLFile("../public/eth_mysql.sql")
// if err != nil {
// log.Fatalf("ETH-Chain初始化数据库表失败%v", err)
// }
// 更新网络公共数据和加载钱包
height, err := ethnode.getHeight()
if err != nil {

View File

@@ -10,6 +10,7 @@ import (
"m2pool-payment/internal/utils"
"math/big"
"os"
"strconv"
"strings"
"sync"
"time"
@@ -271,6 +272,7 @@ func (e *ETHNode) checkBalance(symbol, address string, target_amount_eth, target
e.Wallets[address].mu.Lock()
defer e.Wallets[address].mu.Unlock()
if wallet, ok := e.Wallets[address]; ok {
log.Printf("需要的USDT%d钱包的USDT%d", target_amount_usdt, e.Wallets[address].usdt_balance.balance)
switch symbol {
case "ETH":
// ETH余额不足支付转账金额+GAS费用
@@ -300,29 +302,33 @@ func (e *ETHNode) loadWallets() error {
SELECT
ew.address, ew.queue_id, ew.timestamp, ew.sign, ew.status,
eb.used_gas AS eth_used_gas, eb.balance AS eth_balance,
eb.success_tx_hash AS eth_successed_tx_hash, eb.failed_tx_hash AS eth_filed_tx_hash,
eb.success_tx_hash AS eth_successed_tx_hash, eb.failed_tx_hash AS eth_failed_tx_hash,
ub.freeze_num AS usdt_freeze_num, ub.balance AS usdt_balance,
ub.success_tx_hash AS usdt_successed_tx_hash, ub.failed_tx_hash AS usdt_filed_tx_hash
ub.success_tx_hash AS usdt_successed_tx_hash, ub.failed_tx_hash AS usdt_failed_tx_hash
FROM ETH_wallets ew
LEFT JOIN ETH_balances eb ON ew.address = eb.address
LEFT JOIN USDT_balances ub ON ew.address = ub.address
WHERE ew.status = ?`
rows, err := e.SqliteDB.DB.Query(query, 1)
// 执行查询
rows, err := e.MysqlDB.Query(query, 1)
if err != nil {
return fmt.Errorf("failed to get wallets: %v", err)
}
defer rows.Close()
// 解析字段为 big.Int 类型
parseBigInt := func(val sql.NullString) *big.Int {
if val.Valid && strings.TrimSpace(val.String) != "" {
if bi, ok := new(big.Int).SetString(strings.TrimSpace(val.String), 10); ok {
return bi
}
}
return big.NewInt(0)
log.Printf("Invalid or empty string for big.Int: %s", val.String) // 添加调试日志
return big.NewInt(0) // 如果无法转换,返回 0
}
// 解析字符串为交易哈希列表
parseHashList := func(val sql.NullString) []string {
if !val.Valid || val.String == "" {
return []string{}
@@ -338,8 +344,11 @@ func (e *ETHNode) loadWallets() error {
return res
}
// 用来存储钱包信息
wallets := make(map[string]*Wallets)
addresses := []string{}
// 逐行处理查询结果
for rows.Next() {
var (
addrStr, queueID, sign sql.NullString
@@ -351,6 +360,7 @@ func (e *ETHNode) loadWallets() error {
usdtSuccess, usdtFailed sql.NullString
)
// 扫描查询结果到变量
if err := rows.Scan(
&addrStr, &queueID, &timestamp, &sign, &status,
&ethUsedGas, &ethBalance,
@@ -361,12 +371,14 @@ func (e *ETHNode) loadWallets() error {
return fmt.Errorf("failed to scan row: %v", err)
}
// 如果地址字段为空,则跳过该行
if !addrStr.Valid {
continue
}
addr := strings.ToLower(addrStr.String)
// 创建钱包对象并填充数据
wallet := &Wallets{
address: addr,
queueId: queueID.String,
@@ -385,80 +397,105 @@ func (e *ETHNode) loadWallets() error {
}(),
}
// 解析 ETH 余额和信息
ethBalanceStr := strings.TrimSpace(ethBalance.String)
log.Printf("Parsed ETH balance: %s for address: %s", ethBalanceStr, addrStr.String) // 调试日志
ethBalanceValue, err := strconv.ParseFloat(ethBalanceStr, 64)
if err != nil {
log.Printf("Failed to parse ETH balance: %v, address: %s", err, addrStr.String)
ethBalanceValue = 0 // 给一个默认值
}
wallet.eth_balance = &eth_balance{
symbol: "ETH",
used_gas: parseBigInt(ethUsedGas),
balance: parseBigInt(ethBalance),
symbol: "ETH",
used_gas: parseBigInt(ethUsedGas),
// balance: big.NewInt(int64(ethBalanceValue)), // 使用 big.Int 存储数值
balance: utils.Float64ToBigInt("ETH", ethBalanceValue),
successed_tx_hash: parseHashList(ethSuccess),
failed_tx_hash: parseHashList(ethFailed),
}
// 解析 USDT 余额和信息
usdtBalanceStr := strings.TrimSpace(usdtBalance.String)
log.Printf("Parsed USDT balance: %s for address: %s", usdtBalanceStr, addrStr.String) // 调试日志
usdtBalanceValue, err := strconv.ParseFloat(usdtBalanceStr, 64)
if err != nil {
log.Printf("Failed to parse USDT balance: %v, address: %s", err, addrStr.String)
usdtBalanceValue = 0 // 给一个默认值
}
wallet.usdt_balance = &usdt_balance{
symbol: "USDT",
freeze_num: parseBigInt(usdtFreeze),
balance: parseBigInt(usdtBalance),
balance: utils.Float64ToBigInt("USDT", usdtBalanceValue), // 使用 big.Int 存储数值
successed_tx_hash: parseHashList(usdtSuccess),
failed_tx_hash: parseHashList(usdtFailed),
}
// 添加钱包地址到列表并将钱包信息存储到 map 中
addresses = append(addresses, addr)
wallets[addr] = wallet
}
log.Printf("ETH钱包加载成功%v", addresses)
// 检查是否有查询错误
if err := rows.Err(); err != nil {
return fmt.Errorf("error occurred while iterating rows: %v", err)
}
// 打印已加载的地址
log.Printf("ETH钱包加载成功%v", addresses)
// 如果有地址,获取钱包的私钥
if len(addresses) > 0 {
pks, err := e.getAddressesPks(addresses)
if err != nil {
return fmt.Errorf("inital balance private key error: %v", err)
return fmt.Errorf("initial balance private key error: %v", err)
}
e.mu.Lock()
e.Wallets = wallets
// 将私钥绑定到钱包对象中
for address, pk := range pks {
e.Wallets[address].pk = pk
}
e.mu.Unlock()
}
// for addr, balance := range e.Wallets {
// log.Printf("钱包:%s, wallets: %v", addr, balance)
// }
// 打印每个钱包的余额
for addr, balance := range e.Wallets {
log.Printf("钱包:%s, ETH余额: %s, USDT余额: %s", addr, balance.eth_balance.balance.String(), balance.usdt_balance.balance.String())
}
return nil
}
func (e *ETHNode) loadUnConfirmedTxs() error {
query_str := "SELECT queue_id, tx_type, chain, symbol, from_addr, to_addr, tx_hash, height, amount, status FROM eth_unconfirmed_tx WHERE status = ?"
data, err := e.SqliteDB.Query_(query_str, 2)
// 查询语句
query_str := "SELECT queue_id, tx_type, chain, symbol, from_addr, to_addr, tx_hash, height, amount, status FROM ETH_unconfirmed_tx WHERE status = ?"
// 执行查询
rows, err := e.MysqlDB.Query(query_str, 2)
if err != nil {
return fmt.Errorf("failed to get columns: %v", err)
return fmt.Errorf("failed to query unconfirmed transactions: %v", err)
}
defer rows.Close() // 确保查询结束后关闭 rows
for _, row := range data {
// 提取各个字段并确保正确转换为目标类型
queueId, ok := row["queue_id"].(string)
if !ok {
return fmt.Errorf("invalid type for queue_id, expected string but got %T", row["queue_id"])
// 遍历查询结果
for rows.Next() {
var queueId, chain, symbol, fromAddr, toAddr, txHash, amount string
var txType, height, status int
// 读取当前行数据
if err := rows.Scan(&queueId, &txType, &chain, &symbol, &fromAddr, &toAddr, &txHash, &height, &amount, &status); err != nil {
return fmt.Errorf("failed to scan row: %v", err)
}
// 你可以继续提取其他字段并做类似类型转换
txType, _ := row["tx_type"].(int) // 假设 tx_type 是 int 类型
chain, _ := row["chain"].(string)
symbol, _ := row["symbol"].(string)
fromAddr, _ := row["from_addr"].(string)
toAddr, _ := row["to_addr"].(string)
tx_hash, _ := row["tx_hash"].(string)
height, _ := row["height"].(int) // 假设 height 是 int 类型
amount, _ := row["amount"].(string) // amount 是字符串类型
status, _ := row["status"].(int) // status 是 int 类型
big_amount := new(big.Int)
big_Amount, ok := big_amount.SetString(amount, 10)
if !ok {
return fmt.Errorf("amount to bigInt error: %v", err)
// 将 amount 转换为 big.Int
bigAmount := new(big.Int)
bigAmountParsed, success := bigAmount.SetString(amount, 10)
if !success {
return fmt.Errorf("failed to convert amount '%s' to big.Int", amount)
}
// 锁定并填充数据
e.UnConfirmedTxs.mu.Lock()
// 填充 Transaction 结构体
e.UnConfirmedTxs.Transactions[queueId] = message.Transaction{
QueueId: queueId,
TxType: txType,
@@ -466,13 +503,19 @@ func (e *ETHNode) loadUnConfirmedTxs() error {
Symbol: symbol,
From: fromAddr,
To: toAddr,
TxHash: tx_hash,
TxHash: txHash,
Height: uint64(height),
Amount: big_Amount,
Amount: bigAmountParsed, // 使用转换后的 big.Int
Status: status,
}
e.UnConfirmedTxs.mu.Unlock()
}
// 检查是否存在查询错误
if err := rows.Err(); err != nil {
return fmt.Errorf("error during row iteration: %v", err)
}
return nil
}
@@ -762,7 +805,16 @@ func (e *ETHNode) handleETHEvent(header *types.Header) {
Status: constant.STATUS_PENDING,
}
e.UnConfirmedTxs.mu.Unlock()
go func() {
str := "INSERT INTO ETH_unconfirmed_tx(queue_id, tx_type, chain, symbol, from_addr, to_addr, tx_hash, height, amount) VALUES (?,?,?,?,?,?,?,?,?)"
params := []any{msg.QueueId, 0, "ETH", "ETH", fromAddr, toAddr, txHash, height, amount}
_, err := e.MysqlDB.Insert(str, [][]any{params})
if err != nil {
log.Fatalf("INSERT ETH_unconfirmed_tx table error: %v", err)
return
}
}()
continue
}
// fromAddr和监听钱包一致表示(提现/支付)
@@ -807,6 +859,16 @@ func (e *ETHNode) handleETHEvent(header *types.Header) {
Status: constant.STATUS_PENDING,
}
e.UnConfirmedTxs.mu.Unlock()
go func() {
str := "INSERT INTO ETH_unconfirmed_tx(queue_id, tx_type, chain, symbol, from_addr, to_addr, tx_hash, height, amount) VALUES (?,?,?,?,?,?,?,?,?)"
params := []any{v.QueueId, 1, "ETH", "ETH", fromAddr, toAddr, txHash, height, amount}
_, err := e.MysqlDB.Insert(str, [][]any{params})
if err != nil {
log.Fatalf("INSERT ETH_unconfirmed_tx table error: %v", err)
return
}
}()
continue
}
case message.PayMsg_req:
@@ -838,6 +900,16 @@ func (e *ETHNode) handleETHEvent(header *types.Header) {
Status: constant.STATUS_PENDING,
}
e.UnConfirmedTxs.mu.Unlock()
go func() {
str := "INSERT INTO ETH_unconfirmed_tx(queue_id, tx_type, chain, symbol, from_addr, to_addr, tx_hash, height, amount) VALUES (?,?,?,?,?,?,?,?,?)"
params := []any{v.QueueId, 2, "ETH", "ETH", fromAddr, toAddr, txHash, height, amount}
_, err := e.MysqlDB.Insert(str, [][]any{params})
if err != nil {
log.Fatalf("INSERT ETH_unconfirmed_tx table error: %v", err)
return
}
}()
continue
}
default:
@@ -931,7 +1003,16 @@ func (e *ETHNode) handleUSDTEvent(vLog types.Log) {
Status: constant.STATUS_PENDING,
}
e.UnConfirmedTxs.mu.Unlock()
go func() {
str := "INSERT INTO ETH_unconfirmed_tx(queue_id, tx_type, chain, symbol, from_addr, to_addr, tx_hash, height, amount) VALUES (?,?,?,?,?,?,?,?,?)"
params := []any{msg.QueueId, 0, "ETH", "USDT", fromAddr, toAddr, txHash, height, value_float}
_, err := e.MysqlDB.Insert(str, [][]any{params})
if err != nil {
log.Fatalf("INSERT ETH_unconfirmed_tx table error: %v", err)
return
}
}()
return
}
// fromAddr和监听钱包一致表示(提现/支付)
@@ -976,6 +1057,16 @@ func (e *ETHNode) handleUSDTEvent(vLog types.Log) {
Status: constant.STATUS_PENDING,
}
e.UnConfirmedTxs.mu.Unlock()
go func() {
str := "INSERT INTO ETH_unconfirmed_tx(queue_id, tx_type, chain, symbol, from_addr, to_addr, tx_hash, height, amount) VALUES (?,?,?,?,?,?,?,?,?)"
params := []any{v.QueueId, 1, "ETH", "USDT", fromAddr, toAddr, txHash, height, value_float}
_, err := e.MysqlDB.Insert(str, [][]any{params})
if err != nil {
log.Fatalf("INSERT ETH_unconfirmed_tx table error: %v", err)
return
}
}()
return
}
case message.PayMsg_req:
@@ -1007,6 +1098,16 @@ func (e *ETHNode) handleUSDTEvent(vLog types.Log) {
Status: constant.STATUS_PENDING,
}
e.UnConfirmedTxs.mu.Unlock()
go func() {
str := "INSERT INTO ETH_unconfirmed_tx(queue_id, tx_type, chain, symbol, from_addr, to_addr, tx_hash, height, amount) VALUES (?,?,?,?,?,?,?,?,?)"
params := []any{v.QueueId, 2, "ETH", "USDT", fromAddr, toAddr, txHash, height, value_float}
_, err := e.MysqlDB.Insert(str, [][]any{params})
if err != nil {
log.Fatalf("INSERT ETH_unconfirmed_tx table error: %v", err)
return
}
}()
return
}
default:
@@ -1014,7 +1115,13 @@ func (e *ETHNode) handleUSDTEvent(vLog types.Log) {
}
}
var tableMap = map[string]string{
"ETH": "ETH_balances",
"USDT": "USDT_balances",
}
func (e *ETHNode) confirm() {
e.mu.Lock()
unconfirmedTxs := e.UnConfirmedTxs
now_height := e.NetInfo.Height
@@ -1022,6 +1129,7 @@ func (e *ETHNode) confirm() {
var responses []any
e.UnConfirmedTxs.mu.Lock()
for txHash, tx := range unconfirmedTxs.Transactions {
// 高度成熟:当前高度 >= 交易高度 + 确认高度
if now_height >= tx.Height+e.ConfirmHeight {
check_result, actual_gas, err := e.checkTransaction(txHash)
@@ -1039,6 +1147,7 @@ func (e *ETHNode) confirm() {
if ee != nil {
log.Printf("Query Message error: %v, queue_id: %s, tx_type: %d", ee, tx.QueueId, tx.TxType)
status = constant.STATUS_FAILED
// 如果找不到消息,仍然需要处理交易失败的情况
msg = nil
} else {
@@ -1061,10 +1170,7 @@ func (e *ETHNode) confirm() {
delete(e.UnConfirmedTxs.Transactions, txHash)
continue
}
var tableMap = map[string]string{
"ETH": "ETH_balances",
"USDT": "USDT_balances",
}
switch v := msg.(type) {
case message.TopupMsg_req:
if status == constant.STATUS_SUCCESS {
@@ -1091,16 +1197,31 @@ func (e *ETHNode) confirm() {
TxHash: txHash,
BlockHeight: tx.Height,
}
// 修改钱包表
go func() {
str := "UPDATE " + tableMap[tx.Symbol] + " SET success_tx_hash = success_tx_hash || ? WHERE address = ?"
params := []any{txHash + ",", v.Address}
count, err := e.SqliteDB.Update(str, params)
var str string
var params []any
if status == constant.STATUS_SUCCESS {
str = "UPDATE " + tableMap[tx.Symbol] + " SET success_tx_hash = CONCAT(success_tx_hash, ?), balance = balance + ? WHERE address = ?"
params = []any{txHash + ",", float_amount, v.Address}
} else {
str = "UPDATE " + tableMap[tx.Symbol] + " SET failed_tx_hash = CONCAT(failed_tx_hash, ?) WHERE address = ?"
params = []any{txHash + ",", v.Address}
}
_, err := e.MysqlDB.Update(str, params)
if err != nil {
// 更详细的错误日志,包括 QueueId 和 Status
log.Printf("Failed to update remove_resp_msg for queue_id %s: %v", v.QueueId, err)
} else if count != 1 {
// 如果更新的行数不是 1日志中记录详细信息
log.Printf("Unexpected update count for queue_id %s: expected 1, got %d", v.QueueId, count)
log.Printf("Failed to update success_tx_hash/failed_tx_hash for queue_id %s: %v", v.QueueId, err)
}
}()
// 修改待确认交易表
go func() {
str := "UPDATE ETH_unconfirmed_tx SET status = ? WHERE tx_hash = ?"
params := []any{status, txHash}
_, err := e.MysqlDB.Update(str, params)
if err != nil {
log.Printf("Failed to update ETH_unconfirmed_tx: %v", err)
}
}()
responses = append(responses, response) // 将消息提交至responses
@@ -1134,6 +1255,45 @@ func (e *ETHNode) confirm() {
ToAddress: tx.To,
BlockHeight: tx.Height,
}
// 修改钱包表
go func() {
var str, str1 string
var params, params1 []any
txHashWithComma := txHash + ","
if status == constant.STATUS_SUCCESS {
if tableMap[tx.Symbol] == "ETH_balances" {
str = "UPDATE ETH_balances SET success_tx_hash = CONCAT(success_tx_hash, ?), balance = balance - ?, used_gas = used_gas + ? WHERE address = ?"
params = []any{txHashWithComma, float_amount, utils.BigIntETHToFloat64(actual_gas), v.FromAddress}
str1 = ""
params1 = []any{}
} else {
str = "UPDATE USDT_balances SET success_tx_hash = CONCAT(success_tx_hash, ?), balance = balance - ?, freeze_num = freeze_num + ? WHERE address = ?"
params = []any{txHashWithComma, float_amount, v.Fee, v.FromAddress}
str1 = "UPDATE ETH_balances SET used_gas = used_gas + ? WHERE address = ?"
params1 = []any{utils.BigIntETHToFloat64(actual_gas), v.FromAddress}
}
} else {
str = "UPDATE " + tableMap[tx.Symbol] + " SET failed_tx_hash = CONCAT(failed_tx_hash, ?) WHERE address = ?"
params = []any{txHashWithComma, v.FromAddress}
str1 = ""
params1 = []any{}
}
err := e.MysqlDB.ExecuteTransactions([]string{str, str1}, [][]any{params, params1})
if err != nil {
// 更详细的错误日志,包括 QueueId 和 Status
log.Printf("Failed to update success_tx_hash/failed_tx_hash for queue_id %s: %v", v.QueueId, err)
}
}()
// 修改待确认交易表
go func() {
str := "UPDATE ETH_unconfirmed_tx SET status = ? WHERE tx_hash = ?"
params := []any{status, txHash}
_, err := e.MysqlDB.Update(str, params)
if err != nil {
log.Printf("Failed to update ETH_unconfirmed_tx: %v", err)
}
}()
responses = append(responses, response) // 将消息提交至responses
case message.PayMsg_req:
e.Wallets[tx.From].eth_balance.used_gas = new(big.Int).Add(e.Wallets[tx.From].eth_balance.used_gas, actual_gas)
@@ -1162,6 +1322,45 @@ func (e *ETHNode) confirm() {
ToAddress: tx.To,
BlockHeight: tx.Height,
}
// 修改钱包表
go func() {
var str, str1 string
var params, params1 []any
txHashWithComma := txHash + ","
if status == constant.STATUS_SUCCESS {
if tableMap[tx.Symbol] == "ETH_balances" {
str = "UPDATE ETH_balances SET success_tx_hash = CONCAT(success_tx_hash, ?), balance = balance - ?, used_gas = used_gas + ? WHERE address = ?"
params = []any{txHashWithComma, float_amount, utils.BigIntETHToFloat64(actual_gas), v.FromAddress}
str1 = ""
params1 = []any{}
} else {
str = "UPDATE USDT_balances SET success_tx_hash = CONCAT(success_tx_hash, ?), balance = balance - ?, freeze_num = freeze_num + ? WHERE address = ?"
params = []any{txHashWithComma, float_amount, v.Fee, v.FromAddress}
str1 = "UPDATE ETH_balances SET used_gas = used_gas + ? WHERE address = ?"
params1 = []any{utils.BigIntETHToFloat64(actual_gas), v.FromAddress}
}
} else {
str = "UPDATE " + tableMap[tx.Symbol] + " SET failed_tx_hash = CONCAT(failed_tx_hash, ?) WHERE address = ?"
params = []any{txHashWithComma, v.FromAddress}
str1 = ""
params1 = []any{}
}
err := e.MysqlDB.ExecuteTransactions([]string{str, str1}, [][]any{params, params1})
if err != nil {
// 更详细的错误日志,包括 QueueId 和 Status
log.Printf("Failed to update success_tx_hash/failed_tx_hash for queue_id %s: %v", v.QueueId, err)
}
}()
// 修改待确认交易表
go func() {
str := "UPDATE ETH_unconfirmed_tx SET status = ? WHERE tx_hash = ?"
params := []any{status, txHash}
_, err := e.MysqlDB.Update(str, params)
if err != nil {
log.Printf("Failed to update ETH_unconfirmed_tx: %v", err)
}
}()
responses = append(responses, response) // 将消息提交至responses
default:
log.Printf("未知的消息类型: %v, 跳过此交易", v)
@@ -1225,7 +1424,7 @@ func (e *ETHNode) handleListen_Topup_req(msg message.TopupMsg_req) {
params2 := []any{msg.Address}
str3 := "INSERT INTO USDT_balances (address) VALUES (?)"
params3 := []any{msg.Address}
err = e.SqliteDB.ExecuteTransactions([]string{str1, str2, str3}, [][]any{params1, params2, params3})
err = e.MysqlDB.ExecuteTransactions([]string{str1, str2, str3}, [][]any{params1, params2, params3})
if err != nil {
log.Printf("Received ListenServer Topup_req msg: insert sqlite3 db error: %v", err)
}
@@ -1269,6 +1468,7 @@ func (e *ETHNode) handleListen_Withdraw_req(msg message.WithdrawMsg_req) {
FromAddress: msg.FromAddress,
ToAddress: msg.ToAddress,
}
check_result, err := e.checkBalance(msg.Symbol, msg.FromAddress, target_amount_eth, target_amount_usdt)
// 余额校验错误,绕过转账,返回错误响应
if err != nil {
@@ -1383,9 +1583,9 @@ func (e *ETHNode) handleListen_Remove_req(msg message.RemoveListenMsg_req) {
}
str := "UPDATE ETH_wallets SET status = ? WHERE address = ?"
params := []any{0, msg.Address}
count, err := e.SqliteDB.Update(str, params)
if err != nil || count != 1 {
log.Printf("Remove address(%s) error: count(%d)", msg.Address, count)
_, err := e.MysqlDB.Update(str, params)
if err != nil {
log.Printf("Remove address(%s) error: %v", msg.Address, err)
// result_msg.Status = constant.STATUS_FAILED
}
go e.asyncSendMsgToListen(result_msg, 3, 5*time.Second)