feat(wallet): move balance cache to a common place and make it a

parameter to share between transfers and balance history in an upcoming
commit.
Had to refactor its interface for that reason.
This commit is contained in:
Ivan Belyakov 2023-09-04 07:34:09 +02:00 committed by IvanBelyakoff
parent f73f3e9f82
commit 24bf9aada5
9 changed files with 134 additions and 96 deletions

View File

@ -1,4 +1,4 @@
package transfer
package balance
import (
"context"
@ -7,6 +7,8 @@ import (
"sync"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/status-im/status-go/rpc/chain"
)
type nonceRange struct {
@ -15,13 +17,32 @@ type nonceRange struct {
min *big.Int
}
type BalanceCache interface {
BalanceAt(ctx context.Context, client BalanceReader, account common.Address, blockNumber *big.Int) (*big.Int, error)
NonceAt(ctx context.Context, client BalanceReader, account common.Address, blockNumber *big.Int) (*int64, error)
// Reader interface for reading balance at a specified address.
type Reader interface {
BalanceAt(ctx context.Context, account common.Address, blockNumber *big.Int) (*big.Int, error)
NonceAt(ctx context.Context, account common.Address, blockNumber *big.Int) (uint64, error)
HeaderByNumber(ctx context.Context, number *big.Int) (*types.Header, error)
FullTransactionByBlockNumberAndIndex(ctx context.Context, blockNumber *big.Int, index uint) (*chain.FullTransaction, error)
}
// Cacher interface for caching balance to BalanceCache. Requires BalanceReader to fetch balance.
type Cacher interface {
BalanceAt(ctx context.Context, client Reader, account common.Address, blockNumber *big.Int) (*big.Int, error)
NonceAt(ctx context.Context, client Reader, account common.Address, blockNumber *big.Int) (*int64, error)
Clear()
Cache() CacheIface
}
// Interface for cache of balances.
type CacheIface interface {
GetBalance(account common.Address, blockNumber *big.Int) *big.Int
GetNonce(account common.Address, blockNumber *big.Int) *int64
AddBalance(account common.Address, blockNumber *big.Int, balance *big.Int)
AddNonce(account common.Address, blockNumber *big.Int, nonce *int64)
Clear()
}
type balanceCache struct {
type Cache struct {
// balances maps an address to a map of a block number and the balance of this particular address
balances map[common.Address]map[uint64]*big.Int // we don't care about block number overflow as we use cache only for comparing balances when fetching, not for UI
nonces map[common.Address]map[uint64]*int64 // we don't care about block number overflow as we use cache only for comparing balances when fetching, not for UI
@ -30,8 +51,8 @@ type balanceCache struct {
rw sync.RWMutex
}
func newBalanceCache() *balanceCache {
return &balanceCache{
func NewCache() *Cache {
return &Cache{
balances: make(map[common.Address]map[uint64]*big.Int),
nonces: make(map[common.Address]map[uint64]*int64),
nonceRanges: make(map[common.Address]map[int64]nonceRange),
@ -39,7 +60,10 @@ func newBalanceCache() *balanceCache {
}
}
func (b *balanceCache) Clear() {
func (b *Cache) Clear() {
b.rw.Lock()
defer b.rw.Unlock()
for address, cache := range b.balances {
if len(cache) == 0 {
continue
@ -84,14 +108,14 @@ func (b *balanceCache) Clear() {
b.sortedRanges = make(map[common.Address][]nonceRange)
}
func (b *balanceCache) ReadCachedBalance(account common.Address, blockNumber *big.Int) *big.Int {
func (b *Cache) GetBalance(account common.Address, blockNumber *big.Int) *big.Int {
b.rw.RLock()
defer b.rw.RUnlock()
return b.balances[account][blockNumber.Uint64()]
}
func (b *balanceCache) addBalanceToCache(account common.Address, blockNumber *big.Int, balance *big.Int) {
func (b *Cache) AddBalance(account common.Address, blockNumber *big.Int, balance *big.Int) {
b.rw.Lock()
defer b.rw.Unlock()
@ -102,8 +126,8 @@ func (b *balanceCache) addBalanceToCache(account common.Address, blockNumber *bi
b.balances[account][blockNumber.Uint64()] = balance
}
func (b *balanceCache) BalanceAt(ctx context.Context, client BalanceReader, account common.Address, blockNumber *big.Int) (*big.Int, error) {
cachedBalance := b.ReadCachedBalance(account, blockNumber)
func (b *Cache) BalanceAt(ctx context.Context, client Reader, account common.Address, blockNumber *big.Int) (*big.Int, error) {
cachedBalance := b.GetBalance(account, blockNumber)
if cachedBalance != nil {
return cachedBalance, nil
}
@ -111,19 +135,23 @@ func (b *balanceCache) BalanceAt(ctx context.Context, client BalanceReader, acco
if err != nil {
return nil, err
}
b.addBalanceToCache(account, blockNumber, balance)
b.AddBalance(account, blockNumber, balance)
return balance, nil
}
func (b *balanceCache) ReadCachedNonce(account common.Address, blockNumber *big.Int) *int64 {
func (b *Cache) GetNonce(account common.Address, blockNumber *big.Int) *int64 {
b.rw.RLock()
defer b.rw.RUnlock()
return b.nonces[account][blockNumber.Uint64()]
}
func (b *balanceCache) sortRanges(account common.Address) {
func (b *Cache) Cache() CacheIface {
return b
}
func (b *Cache) sortRanges(account common.Address) {
keys := make([]int, 0, len(b.nonceRanges[account]))
for k := range b.nonceRanges[account] {
keys = append(keys, int(k))
@ -140,7 +168,7 @@ func (b *balanceCache) sortRanges(account common.Address) {
b.sortedRanges[account] = ranges
}
func (b *balanceCache) findNonceInRange(account common.Address, block *big.Int) *int64 {
func (b *Cache) findNonceInRange(account common.Address, block *big.Int) *int64 {
b.rw.RLock()
defer b.rw.RUnlock()
@ -162,7 +190,7 @@ func (b *balanceCache) findNonceInRange(account common.Address, block *big.Int)
return nil
}
func (b *balanceCache) updateNonceRange(account common.Address, blockNumber *big.Int, nonce *int64) {
func (b *Cache) updateNonceRange(account common.Address, blockNumber *big.Int, nonce *int64) {
_, exists := b.nonceRanges[account]
if !exists {
b.nonceRanges[account] = make(map[int64]nonceRange)
@ -189,7 +217,7 @@ func (b *balanceCache) updateNonceRange(account common.Address, blockNumber *big
}
}
func (b *balanceCache) addNonceToCache(account common.Address, blockNumber *big.Int, nonce *int64) {
func (b *Cache) AddNonce(account common.Address, blockNumber *big.Int, nonce *int64) {
b.rw.Lock()
defer b.rw.Unlock()
@ -201,8 +229,8 @@ func (b *balanceCache) addNonceToCache(account common.Address, blockNumber *big.
b.updateNonceRange(account, blockNumber, nonce)
}
func (b *balanceCache) NonceAt(ctx context.Context, client BalanceReader, account common.Address, blockNumber *big.Int) (*int64, error) {
cachedNonce := b.ReadCachedNonce(account, blockNumber)
func (b *Cache) NonceAt(ctx context.Context, client Reader, account common.Address, blockNumber *big.Int) (*int64, error) {
cachedNonce := b.GetNonce(account, blockNumber)
if cachedNonce != nil {
return cachedNonce, nil
}
@ -216,7 +244,7 @@ func (b *balanceCache) NonceAt(ctx context.Context, client BalanceReader, accoun
return nil, err
}
int64Nonce := int64(nonce)
b.addNonceToCache(account, blockNumber, &int64Nonce)
b.AddNonce(account, blockNumber, &int64Nonce)
return &int64Nonce, nil
}

View File

@ -19,6 +19,7 @@ import (
"github.com/status-im/status-go/services/ens"
"github.com/status-im/status-go/services/stickers"
"github.com/status-im/status-go/services/wallet/activity"
"github.com/status-im/status-go/services/wallet/balance"
"github.com/status-im/status-go/services/wallet/collectibles"
"github.com/status-im/status-go/services/wallet/currency"
"github.com/status-im/status-go/services/wallet/history"
@ -91,11 +92,14 @@ func NewService(
ChainID: chainID,
})
})
balanceCache := balance.NewCache()
tokenManager := token.NewTokenManager(db, rpcClient, rpcClient.NetworkManager)
savedAddressesManager := &SavedAddressesManager{db: db}
transactionManager := transfer.NewTransactionManager(db, gethManager, transactor, config, accountsDB, pendingTxManager, feed)
transferController := transfer.NewTransferController(db, rpcClient, accountFeed, feed, transactionManager, pendingTxManager,
tokenManager, config.WalletConfig.LoadAllTransfers)
tokenManager, balanceCache, config.WalletConfig.LoadAllTransfers)
cryptoCompare := cryptocompare.NewClient()
coingecko := coingecko.NewClient()
marketManager := market.NewManager(cryptoCompare, coingecko, feed)

View File

@ -14,6 +14,7 @@ import (
"github.com/status-im/status-go/rpc/chain"
"github.com/status-im/status-go/services/wallet/async"
"github.com/status-im/status-go/services/wallet/balance"
w_common "github.com/status-im/status-go/services/wallet/common"
"github.com/status-im/status-go/services/wallet/token"
"github.com/status-im/status-go/services/wallet/walletevent"
@ -53,13 +54,13 @@ var (
)
type ethHistoricalCommand struct {
address common.Address
chainClient *chain.ClientWithFallback
balanceCache *balanceCache
feed *event.Feed
foundHeaders []*DBHeader
error error
noLimit bool
address common.Address
chainClient *chain.ClientWithFallback
balanceCacher balance.Cacher
feed *event.Feed
foundHeaders []*DBHeader
error error
noLimit bool
from *Block
to, resultingFrom, startBlock *big.Int
@ -81,13 +82,13 @@ func (c *ethHistoricalCommand) Run(ctx context.Context) (err error) {
start := time.Now()
if c.from.Number != nil && c.from.Balance != nil {
c.balanceCache.addBalanceToCache(c.address, c.from.Number, c.from.Balance)
c.balanceCacher.Cache().AddBalance(c.address, c.from.Number, c.from.Balance)
}
if c.from.Number != nil && c.from.Nonce != nil {
c.balanceCache.addNonceToCache(c.address, c.from.Number, c.from.Nonce)
c.balanceCacher.Cache().AddNonce(c.address, c.from.Number, c.from.Nonce)
}
from, headers, startBlock, err := findBlocksWithEthTransfers(ctx, c.chainClient,
c.balanceCache, c.address, c.from.Number, c.to, c.noLimit, c.threadLimit)
c.balanceCacher, c.address, c.from.Number, c.to, c.noLimit, c.threadLimit)
if err != nil {
c.error = err
@ -189,6 +190,7 @@ type controlCommand struct {
transactionManager *TransactionManager
pendingTxManager *transactions.PendingTxTracker
tokenManager *token.Manager
balanceCacher balance.Cacher
}
func (c *controlCommand) LoadTransfers(ctx context.Context, limit int) error {
@ -258,13 +260,12 @@ func (c *controlCommand) Run(parent context.Context) error {
toByAddress[address] = target
}
bCache := newBalanceCache()
cmnd := &findAndCheckBlockRangeCommand{
accounts: c.accounts,
db: c.db,
blockDAO: c.blockDAO,
chainClient: c.chainClient,
balanceCache: bCache,
balanceCacher: c.balanceCacher,
feed: c.feed,
fromByAddress: fromByAddress,
toByAddress: toByAddress,
@ -285,7 +286,7 @@ func (c *controlCommand) Run(parent context.Context) error {
return cmnd.error
}
bCache.Clear()
c.balanceCacher.Clear()
err = c.LoadTransfers(parent, numberOfBlocksCheckedPerIteration)
if err != nil {
if c.NewError(err) {
@ -618,7 +619,7 @@ type findAndCheckBlockRangeCommand struct {
db *Database
blockDAO *BlockDAO
chainClient *chain.ClientWithFallback
balanceCache *balanceCache
balanceCacher balance.Cacher
feed *event.Feed
fromByAddress map[common.Address]*Block
toByAddress map[common.Address]*big.Int
@ -637,7 +638,7 @@ func (c *findAndCheckBlockRangeCommand) Command() async.Command {
func (c *findAndCheckBlockRangeCommand) Run(parent context.Context) error {
log.Debug("start findAndCHeckBlockRangeCommand")
newFromByAddress, ethHeadersByAddress, err := c.fastIndex(parent, c.balanceCache, c.fromByAddress, c.toByAddress)
newFromByAddress, ethHeadersByAddress, err := c.fastIndex(parent, c.balanceCacher, c.fromByAddress, c.toByAddress)
if err != nil {
c.error = err
// return err // In case c.noLimit is true, hystrix "max concurrency" may be reached and we will not be able to index ETH transfers. But if we return error, we will get stuck in inifinite loop.
@ -679,12 +680,12 @@ func (c *findAndCheckBlockRangeCommand) Run(parent context.Context) error {
lastBlockNumber := c.toByAddress[address]
log.Debug("saving headers", "len", len(uniqHeaders), "lastBlockNumber", lastBlockNumber,
"balance", c.balanceCache.ReadCachedBalance(address, lastBlockNumber), "nonce", c.balanceCache.ReadCachedNonce(address, lastBlockNumber))
"balance", c.balanceCacher.Cache().GetBalance(address, lastBlockNumber), "nonce", c.balanceCacher.Cache().GetNonce(address, lastBlockNumber))
to := &Block{
Number: lastBlockNumber,
Balance: c.balanceCache.ReadCachedBalance(address, lastBlockNumber),
Nonce: c.balanceCache.ReadCachedNonce(address, lastBlockNumber),
Balance: c.balanceCacher.Cache().GetBalance(address, lastBlockNumber),
Nonce: c.balanceCacher.Cache().GetNonce(address, lastBlockNumber),
}
log.Debug("uniqHeaders found for account", "address", address, "uniqHeaders.len", len(uniqHeaders))
err = c.db.ProcessBlocks(c.chainClient.ChainID, address, newFromByAddress[address], to, uniqHeaders)
@ -701,7 +702,7 @@ func (c *findAndCheckBlockRangeCommand) Run(parent context.Context) error {
// run fast indexing for every accont up to canonical chain head minus safety depth.
// every account will run it from last synced header.
func (c *findAndCheckBlockRangeCommand) fastIndex(ctx context.Context, bCache *balanceCache,
func (c *findAndCheckBlockRangeCommand) fastIndex(ctx context.Context, bCacher balance.Cacher,
fromByAddress map[common.Address]*Block, toByAddress map[common.Address]*big.Int) (map[common.Address]*big.Int,
map[common.Address][]*DBHeader, error) {
@ -713,14 +714,14 @@ func (c *findAndCheckBlockRangeCommand) fastIndex(ctx context.Context, bCache *b
commands := make([]*ethHistoricalCommand, len(c.accounts))
for i, address := range c.accounts {
eth := &ethHistoricalCommand{
chainClient: c.chainClient,
balanceCache: bCache,
address: address,
feed: c.feed,
from: fromByAddress[address],
to: toByAddress[address],
noLimit: c.noLimit,
threadLimit: NoThreadLimit,
chainClient: c.chainClient,
balanceCacher: bCacher,
address: address,
feed: c.feed,
from: fromByAddress[address],
to: toByAddress[address],
noLimit: c.noLimit,
threadLimit: NoThreadLimit,
}
commands[i] = eth
group.Add(eth.Command())

View File

@ -11,6 +11,7 @@ import (
"github.com/ethereum/go-ethereum/log"
"github.com/status-im/status-go/rpc/chain"
"github.com/status-im/status-go/services/wallet/async"
"github.com/status-im/status-go/services/wallet/balance"
"github.com/status-im/status-go/services/wallet/token"
"github.com/status-im/status-go/services/wallet/walletevent"
"github.com/status-im/status-go/transactions"
@ -69,7 +70,7 @@ type findBlocksCommand struct {
db *Database
blockRangeDAO *BlockRangeSequentialDAO
chainClient *chain.ClientWithFallback
balanceCache *balanceCache
balanceCacher balance.Cacher
feed *event.Feed
noLimit bool
transactionManager *TransactionManager
@ -112,8 +113,8 @@ func (c *findBlocksCommand) Run(parent context.Context) (err error) {
if len(headers) > 0 {
log.Debug("findBlocksCommand saving headers", "len", len(headers), "lastBlockNumber", to,
"balance", c.balanceCache.ReadCachedBalance(c.account, to),
"nonce", c.balanceCache.ReadCachedNonce(c.account, to))
"balance", c.balanceCacher.Cache().GetBalance(c.account, to),
"nonce", c.balanceCacher.Cache().GetNonce(c.account, to))
err = c.db.SaveBlocks(c.chainClient.ChainID, c.account, headers)
if err != nil {
@ -145,7 +146,7 @@ func (c *findBlocksCommand) Run(parent context.Context) (err error) {
}
func (c *findBlocksCommand) blocksFound(headers []*DBHeader) {
c.blocksLoadedCh <- headers
c.blocksLoadedCh <- headers // TODO Use notifyOfNewBlocksLoaded instead ??
}
func (c *findBlocksCommand) upsertBlockRange(blockRange *BlockRange) error {
@ -167,7 +168,7 @@ func (c *findBlocksCommand) checkRange(parent context.Context, from *big.Int, to
fromBlock := &Block{Number: from}
newFromBlock, ethHeaders, startBlock, err := c.fastIndex(parent, c.balanceCache, fromBlock, to)
newFromBlock, ethHeaders, startBlock, err := c.fastIndex(parent, c.balanceCacher, fromBlock, to)
if err != nil {
log.Error("findBlocksCommand checkRange fastIndex", "err", err, "account", c.account,
"chain", c.chainClient.ChainID)
@ -247,7 +248,7 @@ func areAllHistoryBlocksLoadedForAddress(blockRangeDAO *BlockRangeSequentialDAO,
// run fast indexing for every accont up to canonical chain head minus safety depth.
// every account will run it from last synced header.
func (c *findBlocksCommand) fastIndex(ctx context.Context, bCache *balanceCache,
func (c *findBlocksCommand) fastIndex(ctx context.Context, bCacher balance.Cacher,
fromBlock *Block, toBlockNumber *big.Int) (resultingFrom *Block, headers []*DBHeader,
startBlock *big.Int, err error) {
@ -258,14 +259,14 @@ func (c *findBlocksCommand) fastIndex(ctx context.Context, bCache *balanceCache,
group := async.NewGroup(ctx)
command := &ethHistoricalCommand{
chainClient: c.chainClient,
balanceCache: bCache,
address: c.account,
feed: c.feed,
from: fromBlock,
to: toBlockNumber,
noLimit: c.noLimit,
threadLimit: SequentialThreadLimit,
chainClient: c.chainClient,
balanceCacher: bCacher,
address: c.account,
feed: c.feed,
from: fromBlock,
to: toBlockNumber,
noLimit: c.noLimit,
threadLimit: SequentialThreadLimit,
}
group.Add(command.Command())
@ -349,7 +350,7 @@ func loadTransfersLoop(ctx context.Context, account common.Address, blockDAO *Bl
func newLoadBlocksAndTransfersCommand(account common.Address, db *Database,
blockDAO *BlockDAO, chainClient *chain.ClientWithFallback, feed *event.Feed,
transactionManager *TransactionManager, pendingTxManager *transactions.PendingTxTracker,
tokenManager *token.Manager) *loadBlocksAndTransfersCommand {
tokenManager *token.Manager, balanceCacher balance.Cacher) *loadBlocksAndTransfersCommand {
return &loadBlocksAndTransfersCommand{
account: account,
@ -358,6 +359,7 @@ func newLoadBlocksAndTransfersCommand(account common.Address, db *Database,
blockDAO: blockDAO,
chainClient: chainClient,
feed: feed,
balanceCacher: balanceCacher,
errorsCount: 0,
transactionManager: transactionManager,
pendingTxManager: pendingTxManager,
@ -373,7 +375,7 @@ type loadBlocksAndTransfersCommand struct {
blockDAO *BlockDAO
chainClient *chain.ClientWithFallback
feed *event.Feed
balanceCache *balanceCache
balanceCacher balance.Cacher
errorsCount int
// nonArchivalRPCNode bool // TODO Make use of it
transactionManager *TransactionManager
@ -389,11 +391,6 @@ func (c *loadBlocksAndTransfersCommand) Run(parent context.Context) error {
log.Debug("start load all transfers command", "chain", c.chainClient.ChainID, "account", c.account)
ctx := parent
if c.balanceCache == nil {
c.balanceCache = newBalanceCache() // TODO - need to keep balanceCache in memory??? What about sharing it with other packages?
}
group := async.NewGroup(ctx)
err := c.fetchTransfersForLoadedBlocks(group)
@ -414,7 +411,7 @@ func (c *loadBlocksAndTransfersCommand) Run(parent context.Context) error {
select {
case <-ctx.Done():
c.balanceCache.Clear()
c.balanceCacher.Clear()
return ctx.Err()
case <-group.WaitAsync():
log.Debug("end loadBlocksAndTransfers command", "chain", c.chainClient.ChainID, "account", c.account)
@ -462,7 +459,7 @@ func (c *loadBlocksAndTransfersCommand) fetchHistoryBlocks(ctx context.Context,
db: c.db,
blockRangeDAO: c.blockRangeDAO,
chainClient: c.chainClient,
balanceCache: c.balanceCache,
balanceCacher: c.balanceCacher,
feed: c.feed,
noLimit: false,
fromBlockNumber: big.NewInt(0),
@ -500,7 +497,7 @@ func (c *loadBlocksAndTransfersCommand) startFetchingNewBlocks(group *async.Grou
db: c.db,
blockRangeDAO: c.blockRangeDAO,
chainClient: c.chainClient,
balanceCache: c.balanceCache,
balanceCacher: c.balanceCacher,
feed: c.feed,
noLimit: false,
transactionManager: c.transactionManager,

View File

@ -12,6 +12,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/log"
"github.com/status-im/status-go/services/wallet/async"
"github.com/status-im/status-go/services/wallet/balance"
)
const (
@ -93,7 +94,7 @@ type Downloader interface {
// Returns new block ranges that contain transfers and found block headers that contain transfers, and a block where
// beginning of trasfers history detected
func checkRangesWithStartBlock(parent context.Context, client BalanceReader, cache BalanceCache,
func checkRangesWithStartBlock(parent context.Context, client balance.Reader, cache balance.Cacher,
account common.Address, ranges [][]*big.Int, threadLimit uint32, startBlock *big.Int) (
resRanges [][]*big.Int, headers []*DBHeader, newStartBlock *big.Int, err error) {
@ -214,7 +215,7 @@ func checkRangesWithStartBlock(parent context.Context, client BalanceReader, cac
return c.GetRanges(), c.GetHeaders(), newStartBlock, nil
}
func findBlocksWithEthTransfers(parent context.Context, client BalanceReader, cache BalanceCache,
func findBlocksWithEthTransfers(parent context.Context, client balance.Reader, cache balance.Cacher,
account common.Address, low, high *big.Int, noLimit bool, threadLimit uint32) (
from *big.Int, headers []*DBHeader, resStartBlock *big.Int, err error) {

View File

@ -9,6 +9,7 @@ import (
"time"
"github.com/status-im/status-go/rpc/chain"
"github.com/status-im/status-go/services/wallet/balance"
"github.com/stretchr/testify/require"
@ -142,7 +143,7 @@ func TestConcurrentEthDownloader(t *testing.T) {
defer cancel()
concurrent := NewConcurrentDownloader(ctx, 0)
_, headers, _, _ := findBlocksWithEthTransfers(
ctx, tc.options.balances, newBalanceCache(),
ctx, tc.options.balances, balance.NewCache(),
common.Address{}, zero, tc.options.last, false, NoThreadLimit)
concurrent.Wait()
require.NoError(t, concurrent.Error())

View File

@ -14,6 +14,7 @@ import (
"github.com/status-im/status-go/rpc/chain"
"github.com/status-im/status-go/services/accounts/accountsevent"
"github.com/status-im/status-go/services/wallet/async"
"github.com/status-im/status-go/services/wallet/balance"
"github.com/status-im/status-go/services/wallet/token"
"github.com/status-im/status-go/transactions"
)
@ -29,11 +30,13 @@ type Controller struct {
transactionManager *TransactionManager
pendingTxManager *transactions.PendingTxTracker
tokenManager *token.Manager
balanceCacher balance.Cacher
loadAllTransfers bool
}
func NewTransferController(db *sql.DB, rpcClient *rpc.Client, accountFeed *event.Feed, transferFeed *event.Feed,
transactionManager *TransactionManager, pendingTxManager *transactions.PendingTxTracker, tokenManager *token.Manager, loadAllTransfers bool) *Controller {
transactionManager *TransactionManager, pendingTxManager *transactions.PendingTxTracker, tokenManager *token.Manager,
balanceCacher balance.Cacher, loadAllTransfers bool) *Controller {
blockDAO := &BlockDAO{db}
return &Controller{
@ -45,6 +48,7 @@ func NewTransferController(db *sql.DB, rpcClient *rpc.Client, accountFeed *event
transactionManager: transactionManager,
pendingTxManager: pendingTxManager,
tokenManager: tokenManager,
balanceCacher: balanceCacher,
loadAllTransfers: loadAllTransfers,
}
}
@ -93,7 +97,7 @@ func (c *Controller) CheckRecentHistory(chainIDs []uint64, accounts []common.Add
}
} else {
c.reactor = NewReactor(c.db, c.blockDAO, c.TransferFeed, c.transactionManager,
c.pendingTxManager, c.tokenManager)
c.pendingTxManager, c.tokenManager, c.balanceCacher)
err = c.reactor.start(chainClients, accounts, c.loadAllTransfers)
if err != nil {

View File

@ -13,6 +13,7 @@ import (
"github.com/ethereum/go-ethereum/log"
"github.com/status-im/status-go/rpc/chain"
"github.com/status-im/status-go/services/wallet/async"
"github.com/status-im/status-go/services/wallet/balance"
"github.com/status-im/status-go/services/wallet/token"
"github.com/status-im/status-go/services/wallet/walletevent"
"github.com/status-im/status-go/transactions"
@ -40,14 +41,6 @@ type HeaderReader interface {
HeaderByNumber(ctx context.Context, number *big.Int) (*types.Header, error)
}
// BalanceReader interface for reading balance at a specifeid address.
type BalanceReader interface {
BalanceAt(ctx context.Context, account common.Address, blockNumber *big.Int) (*big.Int, error)
NonceAt(ctx context.Context, account common.Address, blockNumber *big.Int) (uint64, error)
HeaderByNumber(ctx context.Context, number *big.Int) (*types.Header, error)
FullTransactionByBlockNumberAndIndex(ctx context.Context, blockNumber *big.Int, index uint) (*chain.FullTransaction, error)
}
type HistoryFetcher interface {
start() error
stop()
@ -66,11 +59,13 @@ func NewOnDemandFetchStrategy(
tokenManager *token.Manager,
chainClients map[uint64]*chain.ClientWithFallback,
accounts []common.Address,
balanceCacher balance.Cacher,
) *OnDemandFetchStrategy {
strategy := &OnDemandFetchStrategy{
db: db,
blockDAO: blockDAO,
feed: feed,
balanceCacher: balanceCacher,
transactionManager: transactionManager,
pendingTxManager: pendingTxManager,
tokenManager: tokenManager,
@ -87,7 +82,7 @@ type OnDemandFetchStrategy struct {
feed *event.Feed
mu sync.Mutex
group *async.Group
balanceCache *balanceCache
balanceCacher balance.Cacher
transactionManager *TransactionManager
pendingTxManager *transactions.PendingTxTracker
tokenManager *token.Manager
@ -114,6 +109,7 @@ func (s *OnDemandFetchStrategy) newControlCommand(chainClient *chain.ClientWithF
transactionManager: s.transactionManager,
pendingTxManager: s.pendingTxManager,
tokenManager: s.tokenManager,
balanceCacher: s.balanceCacher,
}
return ctl
@ -207,14 +203,11 @@ func (s *OnDemandFetchStrategy) getTransfersByAddress(ctx context.Context, chain
}}
toByAddress := map[common.Address]*big.Int{address: block}
if s.balanceCache == nil {
s.balanceCache = newBalanceCache()
}
blocksCommand := &findAndCheckBlockRangeCommand{
accounts: []common.Address{address},
db: s.db,
chainClient: chainClient,
balanceCache: s.balanceCache,
balanceCacher: s.balanceCacher,
feed: s.feed,
fromByAddress: fromByAddress,
toByAddress: toByAddress,
@ -223,7 +216,7 @@ func (s *OnDemandFetchStrategy) getTransfersByAddress(ctx context.Context, chain
if err = blocksCommand.Command()(ctx); err != nil {
return nil, err
}
s.balanceCache.Clear()
s.balanceCacher.Clear()
blocks, err := s.blockDAO.GetBlocksToLoadByAddress(chainID, address, numberOfBlocksCheckedPerIteration)
if err != nil {
@ -266,10 +259,12 @@ type Reactor struct {
pendingTxManager *transactions.PendingTxTracker
tokenManager *token.Manager
strategy HistoryFetcher
balanceCacher balance.Cacher
}
func NewReactor(db *Database, blockDAO *BlockDAO, feed *event.Feed, tm *TransactionManager,
pendingTxManager *transactions.PendingTxTracker, tokenManager *token.Manager) *Reactor {
pendingTxManager *transactions.PendingTxTracker, tokenManager *token.Manager,
balanceCacher balance.Cacher) *Reactor {
return &Reactor{
db: db,
blockDAO: blockDAO,
@ -277,6 +272,7 @@ func NewReactor(db *Database, blockDAO *BlockDAO, feed *event.Feed, tm *Transact
transactionManager: tm,
pendingTxManager: pendingTxManager,
tokenManager: tokenManager,
balanceCacher: balanceCacher,
}
}
@ -315,10 +311,11 @@ func (r *Reactor) createFetchStrategy(chainClients map[uint64]*chain.ClientWithF
r.tokenManager,
chainClients,
accounts,
r.balanceCacher,
)
}
return NewOnDemandFetchStrategy(r.db, r.blockDAO, r.feed, r.transactionManager, r.pendingTxManager, r.tokenManager, chainClients, accounts)
return NewOnDemandFetchStrategy(r.db, r.blockDAO, r.feed, r.transactionManager, r.pendingTxManager, r.tokenManager, chainClients, accounts, r.balanceCacher)
}
func (r *Reactor) getTransfersByAddress(ctx context.Context, chainID uint64, address common.Address, toBlock *big.Int,

View File

@ -10,6 +10,7 @@ import (
"github.com/ethereum/go-ethereum/log"
"github.com/status-im/status-go/rpc/chain"
"github.com/status-im/status-go/services/wallet/async"
"github.com/status-im/status-go/services/wallet/balance"
"github.com/status-im/status-go/services/wallet/token"
"github.com/status-im/status-go/services/wallet/walletevent"
"github.com/status-im/status-go/transactions"
@ -19,7 +20,9 @@ func NewSequentialFetchStrategy(db *Database, blockDAO *BlockDAO, feed *event.Fe
transactionManager *TransactionManager, pendingTxManager *transactions.PendingTxTracker,
tokenManager *token.Manager,
chainClients map[uint64]*chain.ClientWithFallback,
accounts []common.Address) *SequentialFetchStrategy {
accounts []common.Address,
balanceCacher balance.Cacher,
) *SequentialFetchStrategy {
return &SequentialFetchStrategy{
db: db,
@ -30,6 +33,7 @@ func NewSequentialFetchStrategy(db *Database, blockDAO *BlockDAO, feed *event.Fe
tokenManager: tokenManager,
chainClients: chainClients,
accounts: accounts,
balanceCacher: balanceCacher,
}
}
@ -44,13 +48,14 @@ type SequentialFetchStrategy struct {
tokenManager *token.Manager
chainClients map[uint64]*chain.ClientWithFallback
accounts []common.Address
balanceCacher balance.Cacher
}
func (s *SequentialFetchStrategy) newCommand(chainClient *chain.ClientWithFallback,
account common.Address) async.Commander {
return newLoadBlocksAndTransfersCommand(account, s.db, s.blockDAO, chainClient, s.feed,
s.transactionManager, s.pendingTxManager, s.tokenManager)
s.transactionManager, s.pendingTxManager, s.tokenManager, s.balanceCacher)
}
func (s *SequentialFetchStrategy) start() error {