package monitor import ( "log" "math" "math/big" "strconv" "time" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/ethclient" ) type node struct { owner common.Address email string fined *big.Int name string publicKey []byte nodeKeyAddress common.Address } // NetworkConfig represents the network config. type NetworkConfig struct { WSEndpoint string HTTPEndpoint string EthHTTPEndpoint string GovAddress common.Address Network string } // GovAddress is governance address. var GovAddress = common.HexToAddress("0x246FcDE58581e2754f215A523C0718C4BFc8041F") // Fifty is 50 * 10^18 var Fifty *big.Int // OneHundred is 100 * 10^18 var OneHundred *big.Int func init() { Fifty, _ = big.NewInt(0).SetString("50000000000000000000", 10) OneHundred, _ = big.NewInt(0).SetString("100000000000000000000", 10) } // NetworkConfigMap represents the system network config mapping. var NetworkConfigMap = map[int64]NetworkConfig{ 373: { WSEndpoint: "wss://mainnet-rpc.tangerine-network.io/ws", HTTPEndpoint: "https://mainnet-rpc.tangerine-network.io", EthHTTPEndpoint: "https://mainnet.infura.io/v3/4eb07139b29d41c59b352f21c4c9f526", Network: "Mainnet", }, 374: { WSEndpoint: "wss://testnet-rpc.tangerine-network.io/ws", HTTPEndpoint: "https://testnet-rpc.tangerine-network.io", EthHTTPEndpoint: "https://rinkeby.infura.io/v3/4eb07139b29d41c59b352f21c4c9f526", Network: "Testnet", }, } // Monitor is the object to monitor tangerine network. type Monitor struct { networkID int notifiers []Notifier backend backendIntf tanBalancesCache map[common.Address]*big.Int ethBalancesCache map[common.Address]*big.Int ethThreshold *big.Int // in wei ethThresholdString string // in ETH checkBalanceDuration time.Duration } // NewMonitor is the constructor for monitor object. func NewMonitor(networkID int, backend backendIntf, threshold string) *Monitor { tanBalance := make(map[common.Address]*big.Int) ethBalance := make(map[common.Address]*big.Int) t, err := strconv.ParseFloat(threshold, 64) if err != nil { panic(err) } t = t * math.Pow(10, 18) ethThreshold := new(big.Int) ethThreshold.SetString( strconv.FormatFloat(t, 'f', 0, 64), 10, ) m := Monitor{ networkID: networkID, backend: backend, tanBalancesCache: tanBalance, ethBalancesCache: ethBalance, checkBalanceDuration: time.Duration(10 * 60 * 1000 * 1000 * 1000), ethThresholdString: threshold, ethThreshold: ethThreshold, } return &m } // Run is the entry point for running monitor. func (m *Monitor) Run() { done := make(chan bool) finedNodeChan := make(chan node) go m.fetchFinedNodes(finedNodeChan) go m.sendNotifications(finedNodeChan, FINED) go m.checkTanBalance() go m.checkEthBalance() <-done } func (m *Monitor) checkEthBalance() { ethNodeChan := make(chan node) go m.sendNotifications(ethNodeChan, INSUFFICIENT_ETH) for { nc := NetworkConfigMap[int64(m.networkID)] conn, err := ethclient.Dial(nc.EthHTTPEndpoint) if err != nil { log.Println("Get Tan balance fail at") continue } nodes := m.backend.NodeSet() for i := range nodes { n := nodes[i] address := n.nodeKeyAddress balance := m.backend.BalanceFromAddress(conn, address) if balance.Cmp(m.ethThreshold) < 0 { if cacheBalance, exist := m.ethBalancesCache[address]; exist { if cacheBalance.Cmp(m.ethThreshold) >= 0 { ethNodeChan <- n } } else { ethNodeChan <- n } } m.ethBalancesCache[address] = balance } time.Sleep(m.checkBalanceDuration) } } func (m *Monitor) checkTanBalance() { tanNodeChan := make(chan node) go m.sendNotifications(tanNodeChan, INSUFFICIENT_TAN) for { nodes := m.backend.NodeSet() nc := NetworkConfigMap[int64(m.networkID)] conn, err := ethclient.Dial(nc.HTTPEndpoint) if err != nil { log.Println("Get Eth balance fail") continue } for i := range nodes { n := nodes[i] balance := m.backend.BalanceFromAddress(conn, n.nodeKeyAddress) if balance.Cmp(Fifty) < 0 { if cacheBalance, exist := m.tanBalancesCache[n.nodeKeyAddress]; exist { if cacheBalance.Cmp(Fifty) >= 0 { tanNodeChan <- n } } else { tanNodeChan <- n } } else if balance.Cmp(OneHundred) < 0 { if cacheBalance, exist := m.tanBalancesCache[n.nodeKeyAddress]; exist { if cacheBalance.Cmp(OneHundred) >= 0 { tanNodeChan <- n } } else { tanNodeChan <- n } } m.tanBalancesCache[n.nodeKeyAddress] = balance } time.Sleep(m.checkBalanceDuration) } } // Register registries the notifiers. func (m *Monitor) Register(n Notifier) { m.notifiers = append(m.notifiers, n) } func (m *Monitor) fetchFinedNodes(nodeChan chan node) { m.backend.FetchFinedNodes(nodeChan) } func (m *Monitor) sendNotifications(nodeChan chan node, notifyType uint) { nc := NetworkConfigMap[int64(m.networkID)] for { node, open := <-nodeChan if !open { return } for _, notifier := range m.notifiers { notifier.notify(node, nc.Network, notifyType, m.ethThresholdString) } } }