aboutsummaryrefslogtreecommitdiffstats
path: root/monitor/monitor.go
diff options
context:
space:
mode:
Diffstat (limited to 'monitor/monitor.go')
-rw-r--r--monitor/monitor.go199
1 files changed, 199 insertions, 0 deletions
diff --git a/monitor/monitor.go b/monitor/monitor.go
new file mode 100644
index 0000000..5b9e350
--- /dev/null
+++ b/monitor/monitor.go
@@ -0,0 +1,199 @@
+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)
+ }
+ }
+}