github.com/status-im/status-go@v1.1.0/services/wallet/transfer/reactor.go (about)

     1  package transfer
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"math/big"
     7  
     8  	"github.com/ethereum/go-ethereum/common"
     9  	"github.com/ethereum/go-ethereum/core/types"
    10  	"github.com/ethereum/go-ethereum/event"
    11  	"github.com/status-im/status-go/multiaccounts/accounts"
    12  	"github.com/status-im/status-go/rpc/chain"
    13  	"github.com/status-im/status-go/services/wallet/balance"
    14  	"github.com/status-im/status-go/services/wallet/blockchainstate"
    15  	"github.com/status-im/status-go/services/wallet/token"
    16  	"github.com/status-im/status-go/transactions"
    17  )
    18  
    19  const (
    20  	ReactorNotStarted string = "reactor not started"
    21  
    22  	NonArchivalNodeBlockChunkSize = 100
    23  	DefaultNodeBlockChunkSize     = 100000
    24  )
    25  
    26  var errAlreadyRunning = errors.New("already running")
    27  
    28  type FetchStrategyType int32
    29  
    30  const (
    31  	SequentialFetchStrategyType FetchStrategyType = iota
    32  )
    33  
    34  // HeaderReader interface for reading headers using block number or hash.
    35  type HeaderReader interface {
    36  	HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error)
    37  	HeaderByNumber(ctx context.Context, number *big.Int) (*types.Header, error)
    38  }
    39  
    40  type HistoryFetcher interface {
    41  	start() error
    42  	stop()
    43  	kind() FetchStrategyType
    44  
    45  	getTransfersByAddress(ctx context.Context, chainID uint64, address common.Address, toBlock *big.Int,
    46  		limit int64) ([]Transfer, error)
    47  }
    48  
    49  // Reactor listens to new blocks and stores transfers into the database.
    50  type Reactor struct {
    51  	db                 *Database
    52  	blockDAO           *BlockDAO
    53  	blockRangesSeqDAO  *BlockRangeSequentialDAO
    54  	accountsDB         *accounts.Database
    55  	feed               *event.Feed
    56  	transactionManager *TransactionManager
    57  	pendingTxManager   *transactions.PendingTxTracker
    58  	tokenManager       *token.Manager
    59  	strategy           HistoryFetcher
    60  	balanceCacher      balance.Cacher
    61  	omitHistory        bool
    62  	blockChainState    *blockchainstate.BlockChainState
    63  	chainIDs           []uint64
    64  }
    65  
    66  func NewReactor(db *Database, blockDAO *BlockDAO, blockRangesSeqDAO *BlockRangeSequentialDAO, accountsDB *accounts.Database, feed *event.Feed, tm *TransactionManager,
    67  	pendingTxManager *transactions.PendingTxTracker, tokenManager *token.Manager,
    68  	balanceCacher balance.Cacher, omitHistory bool, blockChainState *blockchainstate.BlockChainState) *Reactor {
    69  	return &Reactor{
    70  		db:                 db,
    71  		accountsDB:         accountsDB,
    72  		blockDAO:           blockDAO,
    73  		blockRangesSeqDAO:  blockRangesSeqDAO,
    74  		feed:               feed,
    75  		transactionManager: tm,
    76  		pendingTxManager:   pendingTxManager,
    77  		tokenManager:       tokenManager,
    78  		balanceCacher:      balanceCacher,
    79  		omitHistory:        omitHistory,
    80  		blockChainState:    blockChainState,
    81  	}
    82  }
    83  
    84  // Start runs reactor loop in background.
    85  func (r *Reactor) start(chainClients map[uint64]chain.ClientInterface, accounts []common.Address) error {
    86  	chainIDs := []uint64{}
    87  	for _, client := range chainClients {
    88  		chainIDs = append(chainIDs, client.NetworkID())
    89  	}
    90  	r.chainIDs = chainIDs
    91  	r.strategy = r.createFetchStrategy(chainClients, accounts)
    92  	return r.strategy.start()
    93  }
    94  
    95  // Stop stops reactor loop and waits till it exits.
    96  func (r *Reactor) stop() {
    97  	if r.strategy != nil {
    98  		r.strategy.stop()
    99  	}
   100  }
   101  
   102  func (r *Reactor) restart(chainClients map[uint64]chain.ClientInterface, accounts []common.Address) error {
   103  
   104  	r.stop()
   105  	return r.start(chainClients, accounts)
   106  }
   107  
   108  func (r *Reactor) createFetchStrategy(chainClients map[uint64]chain.ClientInterface,
   109  	accounts []common.Address) HistoryFetcher {
   110  
   111  	return NewSequentialFetchStrategy(
   112  		r.db,
   113  		r.blockDAO,
   114  		r.blockRangesSeqDAO,
   115  		r.accountsDB,
   116  		r.feed,
   117  		r.transactionManager,
   118  		r.pendingTxManager,
   119  		r.tokenManager,
   120  		chainClients,
   121  		accounts,
   122  		r.balanceCacher,
   123  		r.omitHistory,
   124  		r.blockChainState,
   125  	)
   126  }
   127  
   128  func (r *Reactor) getTransfersByAddress(ctx context.Context, chainID uint64, address common.Address, toBlock *big.Int,
   129  	limit int64) ([]Transfer, error) {
   130  
   131  	if r.strategy != nil {
   132  		return r.strategy.getTransfersByAddress(ctx, chainID, address, toBlock, limit)
   133  	}
   134  
   135  	return nil, errors.New(ReactorNotStarted)
   136  }