[#4087] Omit history scanning on generated multiacc creation

This commit is contained in:
Roman Volosovskyi 2023-10-18 12:02:35 +02:00
parent 74c13fd363
commit 42527723f2
No known key found for this signature in database
GPG Key ID: 0238A4B5ECEE70DE
14 changed files with 574 additions and 306 deletions

View File

@ -1 +1 @@
0.171.1
0.171.2

View File

@ -1329,6 +1329,7 @@ func (b *GethStatusBackend) generateOrImportAccount(mnemonic string, customizati
// If restoring an account, we don't set the mnemonic
if mnemonic == "" {
settings.Mnemonic = &info.Mnemonic
settings.OmitTransfersHistoryScan = true
}
nodeConfig, err := defaultNodeConfig(settings.InstallationID, request)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1 @@
ALTER TABLE settings ADD COLUMN omit_transfers_history_scan BOOLEAN NOT NULL DEFAULT FALSE;

View File

@ -447,6 +447,11 @@ var (
protobufType: protobuf.SyncSetting_URL_UNFURLING_MODE,
},
}
OmitTransfersHistoryScan = SettingField{
reactFieldName: "omit-transfers-history-scan",
dBColumnName: "omit_transfers_history_scan",
valueHandler: BoolHandler,
}
SettingFieldRegister = []SettingField{
AnonMetricsShouldSend,

View File

@ -122,10 +122,11 @@ INSERT INTO settings (
current_user_status,
profile_pictures_show_to,
profile_pictures_visibility,
url_unfurling_mode
url_unfurling_mode,
omit_transfers_history_scan
) VALUES (
?,?,?,?,?,?,?,?,?,?,?,?,?,
?,?,?,?,?,?,?,?,?,'id',?,?,?,?)`,
?,?,?,?,?,?,?,?,?,'id',?,?,?,?,?)`,
s.Address,
s.Currency,
s.CurrentNetwork,
@ -152,6 +153,7 @@ INSERT INTO settings (
s.ProfilePicturesShowTo,
s.ProfilePicturesVisibility,
s.URLUnfurlingMode,
s.OmitTransfersHistoryScan,
)
if err != nil {
return err
@ -336,7 +338,8 @@ func (db *Database) GetSettings() (Settings, error) {
profile_pictures_show_to, profile_pictures_visibility, wallet_root_address, wallet_set_up_passed, wallet_visible_tokens,
waku_bloom_filter_mode, webview_allow_permission_requests, current_user_status, send_status_updates, gif_recents,
gif_favorites, opensea_enabled, last_backup, backup_enabled, telemetry_server_url, auto_message_enabled, gif_api_key,
test_networks_enabled, mutual_contact_enabled, profile_migration_needed, is_sepolia_enabled, url_unfurling_mode
test_networks_enabled, mutual_contact_enabled, profile_migration_needed, is_sepolia_enabled, url_unfurling_mode,
omit_transfers_history_scan
FROM
settings
WHERE
@ -412,6 +415,7 @@ func (db *Database) GetSettings() (Settings, error) {
&s.ProfileMigrationNeeded,
&s.IsSepoliaEnabled,
&s.URLUnfurlingMode,
&s.OmitTransfersHistoryScan,
)
return s, err

View File

@ -143,6 +143,7 @@ type Settings struct {
MessagesFromContactsOnly bool `json:"messages-from-contacts-only"`
Mnemonic *string `json:"mnemonic,omitempty"`
MnemonicRemoved bool `json:"mnemonic-removed?,omitempty"`
OmitTransfersHistoryScan bool `json:"omit-transfers-history-scan?,omitempty"`
MutualContactEnabled bool `json:"mutual-contact-enabled?"`
Name string `json:"name,omitempty"`
Networks *json.RawMessage `json:"networks/networks"`

View File

@ -141,6 +141,7 @@ func (api *API) GetTokensBalances(ctx context.Context, accounts, addresses []com
// @deprecated
func (api *API) GetTokensBalancesForChainIDs(ctx context.Context, chainIDs []uint64, accounts, addresses []common.Address) (map[common.Address]map[common.Address]*hexutil.Big, error) {
log.Debug("wallet.api.GetTokensBalances", "accounts", accounts, "addresses", addresses)
clients, err := api.s.rpcClient.EthClients(chainIDs)
if err != nil {
return nil, err

View File

@ -97,7 +97,7 @@ func NewService(
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,
transferController := transfer.NewTransferController(db, accountsDB, rpcClient, accountFeed, feed, transactionManager, pendingTxManager,
tokenManager, balanceCacher, config.WalletConfig.LoadAllTransfers)
cryptoCompare := cryptocompare.NewClient()
coingecko := coingecko.NewClient()

View File

@ -509,7 +509,7 @@ func loadTransfersLoop(ctx context.Context, account common.Address, blockDAO *Bl
func newLoadBlocksAndTransfersCommand(account common.Address, db *Database,
blockDAO *BlockDAO, chainClient chain.ClientInterface, feed *event.Feed,
transactionManager *TransactionManager, pendingTxManager *transactions.PendingTxTracker,
tokenManager *token.Manager, balanceCacher balance.Cacher) *loadBlocksAndTransfersCommand {
tokenManager *token.Manager, balanceCacher balance.Cacher, omitHistory bool) *loadBlocksAndTransfersCommand {
return &loadBlocksAndTransfersCommand{
account: account,
@ -524,6 +524,7 @@ func newLoadBlocksAndTransfersCommand(account common.Address, db *Database,
pendingTxManager: pendingTxManager,
tokenManager: tokenManager,
blocksLoadedCh: make(chan []*DBHeader, 100),
omitHistory: omitHistory,
}
}
@ -541,6 +542,7 @@ type loadBlocksAndTransfersCommand struct {
pendingTxManager *transactions.PendingTxTracker
tokenManager *token.Manager
blocksLoadedCh chan []*DBHeader
omitHistory bool
// Not to be set by the caller
transfersLoaded bool // For event RecentHistoryReady to be sent only once per account during app lifetime
@ -591,7 +593,7 @@ func (c *loadBlocksAndTransfersCommand) startTransfersLoop(ctx context.Context)
func (c *loadBlocksAndTransfersCommand) fetchHistoryBlocks(ctx context.Context, group *async.Group, blocksLoadedCh chan []*DBHeader) error {
log.Debug("fetchHistoryBlocks start", "chainID", c.chainClient.NetworkID(), "account", c.account)
log.Debug("fetchHistoryBlocks start", "chainID", c.chainClient.NetworkID(), "account", c.account, "omit", c.omitHistory)
headNum, err := getHeadBlockNumber(ctx, c.chainClient)
if err != nil {
@ -599,6 +601,13 @@ func (c *loadBlocksAndTransfersCommand) fetchHistoryBlocks(ctx context.Context,
return err // Might need to retry a couple of times
}
if c.omitHistory {
blockRange := &BlockRange{nil, big.NewInt(0), headNum}
err := c.blockRangeDAO.upsertRange(c.chainClient.NetworkID(), c.account, blockRange)
log.Debug("fetchHistoryBlocks omit history", "chainID", c.chainClient.NetworkID(), "account", c.account, "headNum", headNum, "err", err)
return err
}
blockRange, err := loadBlockRangeInfo(c.chainClient.NetworkID(), c.account, c.blockRangeDAO)
if err != nil {
log.Error("findBlocksCommand loadBlockRangeInfo", "error", err)

View File

@ -2,6 +2,7 @@ package transfer
import (
"context"
"fmt"
"math/big"
"sort"
"strings"
@ -9,6 +10,7 @@ import (
"testing"
"time"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
"github.com/ethereum/go-ethereum"
@ -28,7 +30,9 @@ import (
"github.com/status-im/status-go/params"
statusRpc "github.com/status-im/status-go/rpc"
"github.com/status-im/status-go/rpc/network"
walletcommon "github.com/status-im/status-go/services/wallet/common"
"github.com/status-im/status-go/services/wallet/token"
"github.com/status-im/status-go/transactions"
"github.com/status-im/status-go/walletdatabase"
)
@ -45,6 +49,7 @@ type TestClient struct {
printPreparedData bool
rw sync.RWMutex
callsCounter map[string]int
currentBlock uint64
}
func (tc *TestClient) incCounter(method string) {
@ -165,6 +170,10 @@ func (tc *TestClient) tokenBalanceAt(token common.Address, blockNumber *big.Int)
func (tc *TestClient) HeaderByNumber(ctx context.Context, number *big.Int) (*types.Header, error) {
tc.incCounter("HeaderByNumber")
if number == nil {
number = big.NewInt(int64(tc.currentBlock))
}
if tc.traceAPICalls {
tc.t.Log("HeaderByNumber", number)
}
@ -804,3 +813,106 @@ func TestFindBlocksCommand(t *testing.T) {
}
}
}
type MockETHClient struct {
mock.Mock
}
func (m *MockETHClient) BatchCallContext(ctx context.Context, b []rpc.BatchElem) error {
args := m.Called(ctx, b)
return args.Error(0)
}
type MockChainClient struct {
mock.Mock
clients map[walletcommon.ChainID]*MockETHClient
}
func newMockChainClient() *MockChainClient {
return &MockChainClient{
clients: make(map[walletcommon.ChainID]*MockETHClient),
}
}
func (m *MockChainClient) AbstractEthClient(chainID walletcommon.ChainID) (chain.BatchCallClient, error) {
if _, ok := m.clients[chainID]; !ok {
panic(fmt.Sprintf("no mock client for chainID %d", chainID))
}
return m.clients[chainID], nil
}
func TestFetchTransfersForLoadedBlocks(t *testing.T) {
db, err := helpers.SetupTestMemorySQLDB(walletdatabase.DbInitializer{})
require.NoError(t, err)
tm := &TransactionManager{db, nil, nil, nil, nil, nil, nil, nil, nil, nil}
wdb := NewDB(db)
blockChannel := make(chan []*DBHeader, 100)
tc := &TestClient{
t: t,
balances: [][]int{},
outgoingERC20Transfers: []testERC20Transfer{},
incomingERC20Transfers: []testERC20Transfer{},
callsCounter: map[string]int{},
currentBlock: 100,
}
client, _ := statusRpc.NewClient(nil, 1, params.UpstreamRPCConfig{Enabled: false, URL: ""}, []params.Network{}, db)
client.SetClient(tc.NetworkID(), tc)
tokenManager := token.NewTokenManager(db, client, network.NewManager(db))
tokenManager.SetTokens([]*token.Token{
{
Address: tokenTXXAddress,
Symbol: "TXX",
Decimals: 18,
ChainID: tc.NetworkID(),
Name: "Test Token 1",
Verified: true,
},
{
Address: tokenTXYAddress,
Symbol: "TXY",
Decimals: 18,
ChainID: tc.NetworkID(),
Name: "Test Token 2",
Verified: true,
},
})
chainClient := newMockChainClient()
tracker := transactions.NewPendingTxTracker(db, chainClient, nil, &event.Feed{}, transactions.PendingCheckInterval)
cmd := &loadBlocksAndTransfersCommand{
account: common.HexToAddress("0x1234"),
db: wdb,
blockRangeDAO: &BlockRangeSequentialDAO{wdb.client},
blockDAO: &BlockDAO{db},
chainClient: tc,
feed: &event.Feed{},
balanceCacher: balance.NewCacherWithTTL(5 * time.Minute),
errorsCount: 0,
transactionManager: tm,
pendingTxManager: tracker,
tokenManager: tokenManager,
blocksLoadedCh: blockChannel,
omitHistory: true,
}
tc.prepareBalanceHistory(int(tc.currentBlock))
tc.prepareTokenBalanceHistory(int(tc.currentBlock))
tc.traceAPICalls = true
ctx := context.Background()
group := async.NewGroup(ctx)
err = cmd.fetchHistoryBlocks(ctx, group, blockChannel)
require.NoError(t, err)
select {
case <-ctx.Done():
t.Log("ERROR")
case <-group.WaitAsync():
require.Equal(t, 1, tc.getCounter())
}
}

View File

@ -10,6 +10,8 @@ import (
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/log"
statusaccounts "github.com/status-im/status-go/multiaccounts/accounts"
"github.com/status-im/status-go/multiaccounts/settings"
"github.com/status-im/status-go/rpc"
"github.com/status-im/status-go/rpc/chain"
"github.com/status-im/status-go/services/accounts/accountsevent"
@ -21,6 +23,7 @@ import (
type Controller struct {
db *Database
accountsDB *statusaccounts.Database
rpcClient *rpc.Client
blockDAO *BlockDAO
reactor *Reactor
@ -34,13 +37,14 @@ type Controller struct {
loadAllTransfers bool
}
func NewTransferController(db *sql.DB, rpcClient *rpc.Client, accountFeed *event.Feed, transferFeed *event.Feed,
func NewTransferController(db *sql.DB, accountsDB *statusaccounts.Database, rpcClient *rpc.Client, accountFeed *event.Feed, transferFeed *event.Feed,
transactionManager *TransactionManager, pendingTxManager *transactions.PendingTxTracker, tokenManager *token.Manager,
balanceCacher balance.Cacher, loadAllTransfers bool) *Controller {
blockDAO := &BlockDAO{db}
return &Controller{
db: NewDB(db),
accountsDB: accountsDB,
blockDAO: blockDAO,
rpcClient: rpcClient,
accountFeed: accountFeed,
@ -71,12 +75,10 @@ func (c *Controller) Stop() {
func (c *Controller) CheckRecentHistory(chainIDs []uint64, accounts []common.Address) error {
if len(accounts) == 0 {
log.Info("no accounts provided")
return nil
}
if len(chainIDs) == 0 {
log.Info("no chain provided")
return nil
}
@ -96,8 +98,21 @@ func (c *Controller) CheckRecentHistory(chainIDs []uint64, accounts []common.Add
return err
}
} else {
multiaccSettings, err := c.accountsDB.GetSettings()
if err != nil {
return err
}
omitHistory := multiaccSettings.OmitTransfersHistoryScan
if omitHistory {
err := c.accountsDB.SaveSettingField(settings.OmitTransfersHistoryScan, false)
if err != nil {
return err
}
}
c.reactor = NewReactor(c.db, c.blockDAO, c.TransferFeed, c.transactionManager,
c.pendingTxManager, c.tokenManager, c.balanceCacher)
c.pendingTxManager, c.tokenManager, c.balanceCacher, omitHistory)
err = c.reactor.start(chainClients, accounts, c.loadAllTransfers)
if err != nil {

View File

@ -259,11 +259,12 @@ type Reactor struct {
tokenManager *token.Manager
strategy HistoryFetcher
balanceCacher balance.Cacher
omitHistory bool
}
func NewReactor(db *Database, blockDAO *BlockDAO, feed *event.Feed, tm *TransactionManager,
pendingTxManager *transactions.PendingTxTracker, tokenManager *token.Manager,
balanceCacher balance.Cacher) *Reactor {
balanceCacher balance.Cacher, omitHistory bool) *Reactor {
return &Reactor{
db: db,
blockDAO: blockDAO,
@ -272,6 +273,7 @@ func NewReactor(db *Database, blockDAO *BlockDAO, feed *event.Feed, tm *Transact
pendingTxManager: pendingTxManager,
tokenManager: tokenManager,
balanceCacher: balanceCacher,
omitHistory: omitHistory,
}
}
@ -311,6 +313,7 @@ func (r *Reactor) createFetchStrategy(chainClients map[uint64]chain.ClientInterf
chainClients,
accounts,
r.balanceCacher,
r.omitHistory,
)
}

View File

@ -22,6 +22,7 @@ func NewSequentialFetchStrategy(db *Database, blockDAO *BlockDAO, feed *event.Fe
chainClients map[uint64]chain.ClientInterface,
accounts []common.Address,
balanceCacher balance.Cacher,
omitHistory bool,
) *SequentialFetchStrategy {
return &SequentialFetchStrategy{
@ -34,6 +35,7 @@ func NewSequentialFetchStrategy(db *Database, blockDAO *BlockDAO, feed *event.Fe
chainClients: chainClients,
accounts: accounts,
balanceCacher: balanceCacher,
omitHistory: omitHistory,
}
}
@ -49,13 +51,14 @@ type SequentialFetchStrategy struct {
chainClients map[uint64]chain.ClientInterface
accounts []common.Address
balanceCacher balance.Cacher
omitHistory bool
}
func (s *SequentialFetchStrategy) newCommand(chainClient chain.ClientInterface,
account common.Address) async.Commander {
return newLoadBlocksAndTransfersCommand(account, s.db, s.blockDAO, chainClient, s.feed,
s.transactionManager, s.pendingTxManager, s.tokenManager, s.balanceCacher)
s.transactionManager, s.pendingTxManager, s.tokenManager, s.balanceCacher, s.omitHistory)
}
func (s *SequentialFetchStrategy) start() error {