| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211 |
- package service
- import (
- "context"
- "errors"
- "github.com/ethereum/go-ethereum/ethclient"
- "github.com/fbsobreira/gotron-sdk/pkg/client"
- logging "github.com/ipfs/go-log/v2"
- "google.golang.org/grpc"
- "regexp"
- "strconv"
- "time"
- )
- var log = logging.Logger("server")
- type Node struct {
- ethRpcAddrs []string
- ethBlockNumber uint64
- ethClient *ethclient.Client
- tronRpcAddrs []string
- tronBlockNumber int64
- tronClient *client.GrpcClient
- }
- func NewNode(ethRpcAddrs []string, tronRpcAddrs []string) (*Node, error) {
- ethC, ethBlockNumber, err := getBestEthNode(ethRpcAddrs)
- if err != nil {
- return nil, err
- }
- tronC, tronBlockNumber, err := getBestTronNode(tronRpcAddrs)
- if err != nil {
- return nil, err
- }
- n := &Node{
- ethRpcAddrs: ethRpcAddrs,
- ethBlockNumber: ethBlockNumber,
- ethClient: ethC,
- tronRpcAddrs: tronRpcAddrs,
- tronBlockNumber: tronBlockNumber,
- tronClient: tronC,
- }
- go n.monitor()
- return n, nil
- }
- func (n *Node) monitor() {
- ticker := time.NewTicker(time.Second * 60)
- for {
- select {
- case <-ticker.C:
- ethBlockNumber := n.keepEthClientConnect()
- tronBlockNumber := n.keepTronClientConnect()
- log.Infow("node monitor", "ethBlockNumber", ethBlockNumber, "tronBlockNumber", tronBlockNumber)
- }
- }
- }
- func (n *Node) keepEthClientConnect() uint64 {
- ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
- defer cancel()
- number, err := n.ethClient.BlockNumber(ctx)
- if err != nil || n.ethBlockNumber > number {
- ethC, ethBlockNumber, err := getBestEthNode(n.ethRpcAddrs)
- if err != nil {
- log.Errorw("keepEthClientConnect: getBestEthNode", "err", err)
- return 0
- }
- n.ethClient.Close()
- n.ethBlockNumber = ethBlockNumber
- n.ethClient = ethC
- }
- return n.ethBlockNumber
- }
- func (n *Node) keepTronClientConnect() int64 {
- num, err := getTronBlockNumber(n.tronClient)
- if err != nil || n.tronBlockNumber > num {
- tronC, tronBlockNumber, err := getBestTronNode(n.tronRpcAddrs)
- if err != nil {
- log.Errorw("keepTronClientConnect: getBestTronNode", "err", err)
- return 0
- }
- n.tronClient.Stop()
- n.tronBlockNumber = tronBlockNumber
- n.tronClient = tronC
- }
- return n.tronBlockNumber
- }
- func getBestEthNode(ethRpcAddrs []string) (*ethclient.Client, uint64, error) {
- var cs = make([]*ethclient.Client, 0, len(ethRpcAddrs))
- for _, addr := range ethRpcAddrs {
- c, err := ethclient.Dial(addr)
- if err != nil {
- log.Warnw("getBestEthNode: bad rpc", "rpc", addr)
- continue
- }
- tem := *c
- cs = append(cs, &tem)
- }
- if len(cs) == 0 {
- return nil, 0, errors.New("no active eth node")
- }
- ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
- defer cancel()
- blockNumber := uint64(0)
- bestIndex := -1
- for i, c := range cs {
- b, err := c.BlockNumber(ctx)
- if err != nil {
- log.Warnw("getBestEthNode: bad client", "err", err)
- continue
- }
- if b > blockNumber {
- bestIndex = i
- blockNumber = b
- }
- }
- if bestIndex == -1 {
- return nil, 0, errors.New("no active eth node")
- }
- for i, c := range cs {
- if i == bestIndex {
- continue
- }
- c.Close()
- }
- return cs[bestIndex], blockNumber, nil
- }
- func getBestTronNode(tronRpcAddrs []string) (*client.GrpcClient, int64, error) {
- var cs = make([]*client.GrpcClient, 0, len(tronRpcAddrs))
- for _, addr := range tronRpcAddrs {
- c := client.NewGrpcClient(addr)
- err := c.Start(grpc.WithInsecure())
- if err != nil {
- log.Warnw("getBestTronNode: bad rpc", "rpc", addr)
- continue
- }
- tem := *c
- cs = append(cs, &tem)
- }
- if len(cs) == 0 {
- return nil, 0, errors.New("no active tron node")
- }
- blockNumber := int64(0)
- bestIndex := -1
- for i, c := range cs {
- num, err := getTronBlockNumber(c)
- if err != nil {
- log.Warnw("getBestTronNode: bad client", "err", err)
- continue
- }
- if num > blockNumber {
- bestIndex = i
- blockNumber = num
- }
- }
- if bestIndex == -1 {
- return nil, 0, errors.New("no active tron node")
- }
- for i, c := range cs {
- if i == bestIndex {
- continue
- }
- c.Stop()
- }
- return cs[bestIndex], blockNumber, nil
- }
- func getTronBlockNumber(c *client.GrpcClient) (int64, error) {
- b, err := c.GetNodeInfo()
- if err != nil {
- return 0, err
- }
- re := regexp.MustCompile(`Num:(\d+)`)
- match := re.FindStringSubmatch(b.Block)
- if len(match) < 2 {
- return 0, err
- }
- num, err := strconv.ParseInt(match[1], 10, 64)
- if err != nil {
- return 0, err
- }
- return num, nil
- }
|