2021-09-09 14:28:54 +00:00
|
|
|
package transfer
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"errors"
|
|
|
|
"math/big"
|
|
|
|
|
|
|
|
"github.com/ethereum/go-ethereum/common"
|
|
|
|
"github.com/ethereum/go-ethereum/core/types"
|
|
|
|
"github.com/ethereum/go-ethereum/event"
|
2023-02-20 09:32:45 +00:00
|
|
|
"github.com/status-im/status-go/rpc/chain"
|
2023-09-04 05:34:09 +00:00
|
|
|
"github.com/status-im/status-go/services/wallet/balance"
|
2023-06-02 20:08:45 +00:00
|
|
|
"github.com/status-im/status-go/services/wallet/token"
|
2023-06-21 14:09:55 +00:00
|
|
|
"github.com/status-im/status-go/transactions"
|
2023-05-08 06:02:00 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
ReactorNotStarted string = "reactor not started"
|
|
|
|
|
|
|
|
NonArchivalNodeBlockChunkSize = 100
|
2023-05-19 11:46:54 +00:00
|
|
|
DefaultNodeBlockChunkSize = 100000
|
2021-09-09 14:28:54 +00:00
|
|
|
)
|
|
|
|
|
2021-11-24 12:59:45 +00:00
|
|
|
var errAlreadyRunning = errors.New("already running")
|
2021-09-09 14:28:54 +00:00
|
|
|
|
2023-05-08 06:02:00 +00:00
|
|
|
type FetchStrategyType int32
|
|
|
|
|
|
|
|
const (
|
2023-11-15 14:30:56 +00:00
|
|
|
SequentialFetchStrategyType FetchStrategyType = iota
|
2023-05-08 06:02:00 +00:00
|
|
|
)
|
|
|
|
|
2021-09-09 14:28:54 +00:00
|
|
|
// HeaderReader interface for reading headers using block number or hash.
|
|
|
|
type HeaderReader interface {
|
|
|
|
HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error)
|
|
|
|
HeaderByNumber(ctx context.Context, number *big.Int) (*types.Header, error)
|
|
|
|
}
|
|
|
|
|
2023-05-08 06:02:00 +00:00
|
|
|
type HistoryFetcher interface {
|
|
|
|
start() error
|
|
|
|
stop()
|
|
|
|
kind() FetchStrategyType
|
|
|
|
|
|
|
|
getTransfersByAddress(ctx context.Context, chainID uint64, address common.Address, toBlock *big.Int,
|
2023-11-15 14:30:56 +00:00
|
|
|
limit int64) ([]Transfer, error)
|
2021-09-09 14:28:54 +00:00
|
|
|
}
|
|
|
|
|
2023-05-08 06:02:00 +00:00
|
|
|
// Reactor listens to new blocks and stores transfers into the database.
|
|
|
|
type Reactor struct {
|
|
|
|
db *Database
|
|
|
|
blockDAO *BlockDAO
|
2023-11-28 14:23:03 +00:00
|
|
|
blockRangesSeqDAO *BlockRangeSequentialDAO
|
2023-05-08 06:02:00 +00:00
|
|
|
feed *event.Feed
|
|
|
|
transactionManager *TransactionManager
|
2023-08-01 18:50:30 +00:00
|
|
|
pendingTxManager *transactions.PendingTxTracker
|
2023-06-02 20:08:45 +00:00
|
|
|
tokenManager *token.Manager
|
2023-05-08 06:02:00 +00:00
|
|
|
strategy HistoryFetcher
|
2023-09-04 05:34:09 +00:00
|
|
|
balanceCacher balance.Cacher
|
2023-10-18 10:02:35 +00:00
|
|
|
omitHistory bool
|
2023-05-08 06:02:00 +00:00
|
|
|
}
|
|
|
|
|
2023-11-28 14:23:03 +00:00
|
|
|
func NewReactor(db *Database, blockDAO *BlockDAO, blockRangesSeqDAO *BlockRangeSequentialDAO, feed *event.Feed, tm *TransactionManager,
|
2023-09-04 05:34:09 +00:00
|
|
|
pendingTxManager *transactions.PendingTxTracker, tokenManager *token.Manager,
|
2023-10-18 10:02:35 +00:00
|
|
|
balanceCacher balance.Cacher, omitHistory bool) *Reactor {
|
2023-05-08 06:02:00 +00:00
|
|
|
return &Reactor{
|
|
|
|
db: db,
|
|
|
|
blockDAO: blockDAO,
|
2023-11-28 14:23:03 +00:00
|
|
|
blockRangesSeqDAO: blockRangesSeqDAO,
|
2023-05-08 06:02:00 +00:00
|
|
|
feed: feed,
|
|
|
|
transactionManager: tm,
|
2023-06-21 14:09:55 +00:00
|
|
|
pendingTxManager: pendingTxManager,
|
2023-06-02 20:08:45 +00:00
|
|
|
tokenManager: tokenManager,
|
2023-09-04 05:34:09 +00:00
|
|
|
balanceCacher: balanceCacher,
|
2023-10-18 10:02:35 +00:00
|
|
|
omitHistory: omitHistory,
|
2023-05-08 06:02:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Start runs reactor loop in background.
|
2023-11-15 14:30:56 +00:00
|
|
|
func (r *Reactor) start(chainClients map[uint64]chain.ClientInterface, accounts []common.Address) error {
|
2023-05-08 06:02:00 +00:00
|
|
|
|
2023-11-15 14:30:56 +00:00
|
|
|
r.strategy = r.createFetchStrategy(chainClients, accounts)
|
2023-05-08 06:02:00 +00:00
|
|
|
return r.strategy.start()
|
|
|
|
}
|
|
|
|
|
|
|
|
// Stop stops reactor loop and waits till it exits.
|
|
|
|
func (r *Reactor) stop() {
|
|
|
|
if r.strategy != nil {
|
|
|
|
r.strategy.stop()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-11-15 14:30:56 +00:00
|
|
|
func (r *Reactor) restart(chainClients map[uint64]chain.ClientInterface, accounts []common.Address) error {
|
2023-05-08 06:02:00 +00:00
|
|
|
|
2021-09-09 14:28:54 +00:00
|
|
|
r.stop()
|
2023-11-15 14:30:56 +00:00
|
|
|
return r.start(chainClients, accounts)
|
2023-05-08 06:02:00 +00:00
|
|
|
}
|
|
|
|
|
2023-09-20 08:41:23 +00:00
|
|
|
func (r *Reactor) createFetchStrategy(chainClients map[uint64]chain.ClientInterface,
|
2023-11-15 14:30:56 +00:00
|
|
|
accounts []common.Address) HistoryFetcher {
|
|
|
|
|
|
|
|
return NewSequentialFetchStrategy(
|
|
|
|
r.db,
|
|
|
|
r.blockDAO,
|
2023-11-28 14:23:03 +00:00
|
|
|
r.blockRangesSeqDAO,
|
2023-11-15 14:30:56 +00:00
|
|
|
r.feed,
|
|
|
|
r.transactionManager,
|
|
|
|
r.pendingTxManager,
|
|
|
|
r.tokenManager,
|
|
|
|
chainClients,
|
|
|
|
accounts,
|
|
|
|
r.balanceCacher,
|
|
|
|
r.omitHistory,
|
|
|
|
)
|
2023-05-08 06:02:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (r *Reactor) getTransfersByAddress(ctx context.Context, chainID uint64, address common.Address, toBlock *big.Int,
|
2023-11-15 14:30:56 +00:00
|
|
|
limit int64) ([]Transfer, error) {
|
2023-05-08 06:02:00 +00:00
|
|
|
|
|
|
|
if r.strategy != nil {
|
2023-11-15 14:30:56 +00:00
|
|
|
return r.strategy.getTransfersByAddress(ctx, chainID, address, toBlock, limit)
|
2023-05-08 06:02:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return nil, errors.New(ReactorNotStarted)
|
|
|
|
}
|