package monitor import ( "context" "math" "sync" "time" "github.com/gogenex/bridge-monitor/internal/eth" "github.com/gogenex/bridge-monitor/internal/genex" log "github.com/sirupsen/logrus" ) // ReconciliationResult 对账结果 type ReconciliationResult struct { EthLocked float64 `json:"ethLocked"` GenexMinted float64 `json:"genexMinted"` Discrepancy float64 `json:"discrepancy"` Healthy bool `json:"healthy"` Timestamp time.Time `json:"timestamp"` BlockEth int64 `json:"blockEth"` BlockGenex int64 `json:"blockGenex"` } // BridgeMonitor 跨链桥监控器 type BridgeMonitor struct { ethClient *eth.Client genexClient *genex.Client alerter *Alerter metrics *Metrics threshold float64 mu sync.RWMutex latest *ReconciliationResult history []ReconciliationResult } func NewBridgeMonitor( ethClient *eth.Client, genexClient *genex.Client, alerter *Alerter, metrics *Metrics, threshold float64, ) *BridgeMonitor { return &BridgeMonitor{ ethClient: ethClient, genexClient: genexClient, alerter: alerter, metrics: metrics, threshold: threshold, history: make([]ReconciliationResult, 0, 1000), } } // Reconcile 执行对账:两侧资产必须一致 func (bm *BridgeMonitor) Reconcile(ctx context.Context) (*ReconciliationResult, error) { // Ethereum 侧:查询 Axelar Gateway 合约锁定的 USDC ethLocked, ethBlock, err := bm.ethClient.GetLockedAmount("USDC") if err != nil { return nil, err } // Genex Chain 侧:查询桥铸造的 wrapped USDC 总量 genexMinted, genexBlock, err := bm.genexClient.GetBridgeTokenSupply("USDC") if err != nil { return nil, err } discrepancy := math.Abs(ethLocked - genexMinted) result := ReconciliationResult{ EthLocked: ethLocked, GenexMinted: genexMinted, Discrepancy: discrepancy, Healthy: true, Timestamp: time.Now(), BlockEth: ethBlock, BlockGenex: genexBlock, } // 更新 Prometheus 指标 bm.metrics.SetEthLocked(ethLocked) bm.metrics.SetGenexMinted(genexMinted) bm.metrics.SetDiscrepancy(discrepancy) bm.metrics.SetTVL(ethLocked) bm.metrics.IncReconciliation() // 偏差检查 if ethLocked > 0 && discrepancy > ethLocked*bm.threshold { result.Healthy = false log.WithField("ethLocked", ethLocked). WithField("genexMinted", genexMinted). WithField("discrepancy", discrepancy). Error("Bridge asset discrepancy detected!") bm.alerter.Critical("Bridge asset discrepancy detected", map[string]interface{}{ "ethLocked": ethLocked, "genexMinted": genexMinted, "discrepancy": discrepancy, }) bm.alerter.EmergencyPause() bm.metrics.IncEmergencyPause() } // 保存结果 bm.mu.Lock() bm.latest = &result bm.history = append(bm.history, result) if len(bm.history) > 1000 { bm.history = bm.history[len(bm.history)-1000:] } bm.mu.Unlock() return &result, nil } // GetLatestResult 获取最新对账结果 func (bm *BridgeMonitor) GetLatestResult() *ReconciliationResult { bm.mu.RLock() defer bm.mu.RUnlock() return bm.latest } // GetHistory 获取最近 N 条对账记录 func (bm *BridgeMonitor) GetHistory(n int) []ReconciliationResult { bm.mu.RLock() defer bm.mu.RUnlock() if n > len(bm.history) { n = len(bm.history) } return bm.history[len(bm.history)-n:] }