2023-11-28 14:23:03 +00:00
|
|
|
package transfer
|
|
|
|
|
|
|
|
import (
|
|
|
|
"math/big"
|
|
|
|
"testing"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
|
|
|
|
"github.com/ethereum/go-ethereum/common"
|
|
|
|
"github.com/ethereum/go-ethereum/event"
|
|
|
|
"github.com/status-im/status-go/appdatabase"
|
|
|
|
"github.com/status-im/status-go/eth-node/types"
|
|
|
|
"github.com/status-im/status-go/multiaccounts/accounts"
|
|
|
|
"github.com/status-im/status-go/services/accounts/accountsevent"
|
2024-01-25 12:05:59 +00:00
|
|
|
"github.com/status-im/status-go/services/wallet/blockchainstate"
|
2023-11-28 14:23:03 +00:00
|
|
|
"github.com/status-im/status-go/t/helpers"
|
|
|
|
"github.com/status-im/status-go/walletdatabase"
|
|
|
|
)
|
|
|
|
|
|
|
|
func TestController_watchAccountsChanges(t *testing.T) {
|
|
|
|
appDB, err := helpers.SetupTestMemorySQLDB(appdatabase.DbInitializer{})
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
accountsDB, err := accounts.NewDB(appDB)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
walletDB, err := helpers.SetupTestMemorySQLDB(walletdatabase.DbInitializer{})
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
accountFeed := &event.Feed{}
|
|
|
|
|
2024-01-25 12:05:59 +00:00
|
|
|
bcstate := blockchainstate.NewBlockChainState()
|
2023-11-28 14:23:03 +00:00
|
|
|
c := NewTransferController(
|
|
|
|
walletDB,
|
|
|
|
accountsDB,
|
|
|
|
nil, // rpcClient
|
|
|
|
accountFeed,
|
|
|
|
nil, // transferFeed
|
|
|
|
nil, // transactionManager
|
|
|
|
nil, // pendingTxManager
|
|
|
|
nil, // tokenManager
|
|
|
|
nil, // balanceCacher
|
2024-01-25 12:05:59 +00:00
|
|
|
bcstate,
|
2023-11-28 14:23:03 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
address := common.HexToAddress("0x1234")
|
|
|
|
chainID := uint64(777)
|
|
|
|
// Insert blocks
|
|
|
|
database := NewDB(walletDB)
|
2023-11-27 10:08:17 +00:00
|
|
|
err = database.SaveBlocks(chainID, []*DBHeader{
|
2023-11-28 14:23:03 +00:00
|
|
|
{
|
|
|
|
Number: big.NewInt(1),
|
|
|
|
Hash: common.Hash{1},
|
|
|
|
Network: chainID,
|
|
|
|
Address: address,
|
|
|
|
Loaded: false,
|
|
|
|
},
|
|
|
|
})
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
// Insert transfers
|
|
|
|
err = saveTransfersMarkBlocksLoaded(walletDB, chainID, address, []Transfer{
|
|
|
|
{
|
|
|
|
ID: common.Hash{1},
|
|
|
|
BlockHash: common.Hash{1},
|
|
|
|
BlockNumber: big.NewInt(1),
|
|
|
|
Address: address,
|
|
|
|
NetworkID: chainID,
|
|
|
|
},
|
|
|
|
}, []*big.Int{big.NewInt(1)})
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
// Insert block ranges
|
|
|
|
blockRangesDAO := &BlockRangeSequentialDAO{walletDB}
|
2023-11-27 10:08:17 +00:00
|
|
|
err = blockRangesDAO.upsertRange(chainID, address, newEthTokensBlockRanges())
|
2023-11-28 14:23:03 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
2024-02-19 15:50:07 +00:00
|
|
|
ranges, _, err := blockRangesDAO.getBlockRange(chainID, address)
|
2023-11-28 14:23:03 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
require.NotNil(t, ranges)
|
|
|
|
|
2024-03-03 07:59:21 +00:00
|
|
|
c.accWatcher = accountsevent.NewWatcher(c.accountsDB, c.accountFeed, func(changedAddresses []common.Address, eventType accountsevent.EventType, currentAddresses []common.Address) {
|
|
|
|
c.onAccountsChanged(changedAddresses, eventType, currentAddresses, []uint64{chainID})
|
|
|
|
|
|
|
|
// Quit channel event handler before destroying the channel
|
|
|
|
go func() {
|
|
|
|
time.Sleep(1 * time.Millisecond)
|
|
|
|
// Wait for DB to be cleaned up
|
|
|
|
c.accWatcher.Stop()
|
|
|
|
|
|
|
|
// Check that transfers, blocks and block ranges were deleted
|
|
|
|
transfers, err := database.GetTransfersByAddress(chainID, address, big.NewInt(2), 1)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Len(t, transfers, 0)
|
|
|
|
|
|
|
|
blocksDAO := &BlockDAO{walletDB}
|
|
|
|
block, err := blocksDAO.GetLastBlockByAddress(chainID, address, 1)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Nil(t, block)
|
|
|
|
|
|
|
|
ranges, _, err = blockRangesDAO.getBlockRange(chainID, address)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Nil(t, ranges.eth.FirstKnown)
|
|
|
|
require.Nil(t, ranges.eth.LastKnown)
|
|
|
|
require.Nil(t, ranges.eth.Start)
|
|
|
|
require.Nil(t, ranges.tokens.FirstKnown)
|
|
|
|
require.Nil(t, ranges.tokens.LastKnown)
|
|
|
|
require.Nil(t, ranges.tokens.Start)
|
|
|
|
}()
|
|
|
|
})
|
|
|
|
c.startAccountWatcher([]uint64{chainID})
|
2023-11-28 14:23:03 +00:00
|
|
|
|
|
|
|
// Watching accounts must start before sending event.
|
2024-03-03 07:59:21 +00:00
|
|
|
// To avoid running goroutine immediately and let the controller subscribe first,
|
|
|
|
// use any delay.
|
2023-11-28 14:23:03 +00:00
|
|
|
go func() {
|
|
|
|
time.Sleep(1 * time.Millisecond)
|
|
|
|
|
|
|
|
accountFeed.Send(accountsevent.Event{
|
|
|
|
Type: accountsevent.EventTypeRemoved,
|
|
|
|
Accounts: []common.Address{address},
|
|
|
|
})
|
|
|
|
}()
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestController_cleanupAccountLeftovers(t *testing.T) {
|
|
|
|
appDB, err := helpers.SetupTestMemorySQLDB(appdatabase.DbInitializer{})
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
walletDB, err := helpers.SetupTestMemorySQLDB(walletdatabase.DbInitializer{})
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
accountsDB, err := accounts.NewDB(appDB)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
removedAddr := common.HexToAddress("0x5678")
|
|
|
|
existingAddr := types.HexToAddress("0x1234")
|
|
|
|
accounts := []*accounts.Account{
|
|
|
|
{Address: existingAddr, Chat: false, Wallet: true},
|
|
|
|
}
|
|
|
|
err = accountsDB.SaveOrUpdateAccounts(accounts, false)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
storedAccs, err := accountsDB.GetWalletAddresses()
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Len(t, storedAccs, 1)
|
|
|
|
|
2024-01-25 12:05:59 +00:00
|
|
|
bcstate := blockchainstate.NewBlockChainState()
|
2023-11-28 14:23:03 +00:00
|
|
|
c := NewTransferController(
|
|
|
|
walletDB,
|
|
|
|
accountsDB,
|
|
|
|
nil, // rpcClient
|
|
|
|
nil, // accountFeed
|
|
|
|
nil, // transferFeed
|
|
|
|
nil, // transactionManager
|
|
|
|
nil, // pendingTxManager
|
|
|
|
nil, // tokenManager
|
|
|
|
nil, // balanceCacher
|
2024-01-25 12:05:59 +00:00
|
|
|
bcstate,
|
2023-11-28 14:23:03 +00:00
|
|
|
)
|
|
|
|
chainID := uint64(777)
|
|
|
|
// Insert blocks
|
|
|
|
database := NewDB(walletDB)
|
2023-11-27 10:08:17 +00:00
|
|
|
err = database.SaveBlocks(chainID, []*DBHeader{
|
2023-11-28 14:23:03 +00:00
|
|
|
{
|
|
|
|
Number: big.NewInt(1),
|
|
|
|
Hash: common.Hash{1},
|
|
|
|
Network: chainID,
|
|
|
|
Address: removedAddr,
|
|
|
|
Loaded: false,
|
|
|
|
},
|
|
|
|
})
|
|
|
|
require.NoError(t, err)
|
2023-11-27 10:08:17 +00:00
|
|
|
err = database.SaveBlocks(chainID, []*DBHeader{
|
2023-11-28 14:23:03 +00:00
|
|
|
{
|
|
|
|
Number: big.NewInt(2),
|
|
|
|
Hash: common.Hash{2},
|
|
|
|
Network: chainID,
|
|
|
|
Address: common.Address(existingAddr),
|
|
|
|
Loaded: false,
|
|
|
|
},
|
|
|
|
})
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
blocksDAO := &BlockDAO{walletDB}
|
|
|
|
block, err := blocksDAO.GetLastBlockByAddress(chainID, removedAddr, 1)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.NotNil(t, block)
|
|
|
|
block, err = blocksDAO.GetLastBlockByAddress(chainID, common.Address(existingAddr), 1)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.NotNil(t, block)
|
|
|
|
|
|
|
|
// Insert transfers
|
|
|
|
err = saveTransfersMarkBlocksLoaded(walletDB, chainID, removedAddr, []Transfer{
|
|
|
|
{
|
|
|
|
ID: common.Hash{1},
|
|
|
|
BlockHash: common.Hash{1},
|
|
|
|
BlockNumber: big.NewInt(1),
|
|
|
|
Address: removedAddr,
|
|
|
|
NetworkID: chainID,
|
|
|
|
},
|
|
|
|
}, []*big.Int{big.NewInt(1)})
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
err = saveTransfersMarkBlocksLoaded(walletDB, chainID, common.Address(existingAddr), []Transfer{
|
|
|
|
{
|
|
|
|
ID: common.Hash{2},
|
|
|
|
BlockHash: common.Hash{2},
|
|
|
|
BlockNumber: big.NewInt(2),
|
|
|
|
Address: common.Address(existingAddr),
|
|
|
|
NetworkID: chainID,
|
|
|
|
},
|
|
|
|
}, []*big.Int{big.NewInt(2)})
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
err = c.cleanupAccountsLeftovers()
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
// Check that transfers and blocks of removed account were deleted
|
|
|
|
transfers, err := database.GetTransfers(chainID, big.NewInt(1), big.NewInt(2))
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Len(t, transfers, 1)
|
|
|
|
require.Equal(t, transfers[0].Address, common.Address(existingAddr))
|
|
|
|
|
|
|
|
block, err = blocksDAO.GetLastBlockByAddress(chainID, removedAddr, 1)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Nil(t, block)
|
|
|
|
|
|
|
|
// Make sure that transfers and blocks of existing account were not deleted
|
|
|
|
existingBlock, err := blocksDAO.GetLastBlockByAddress(chainID, common.Address(existingAddr), 1)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.NotNil(t, existingBlock)
|
|
|
|
}
|