Support for binance chains
This commit is contained in:
parent
25e1c64ef5
commit
7ef2efaabd
|
@ -39,10 +39,16 @@ func (api *API) CheckRecentHistoryForChainIDs(ctx context.Context, chainIDs []ui
|
||||||
|
|
||||||
// GetTransfersByAddress returns transfers for a single address
|
// GetTransfersByAddress returns transfers for a single address
|
||||||
func (api *API) GetTransfersByAddress(ctx context.Context, address common.Address, toBlock, limit *hexutil.Big, fetchMore bool) ([]transfer.View, error) {
|
func (api *API) GetTransfersByAddress(ctx context.Context, address common.Address, toBlock, limit *hexutil.Big, fetchMore bool) ([]transfer.View, error) {
|
||||||
log.Debug("[WalletAPI:: GetTransfersByAddress] get transfers for an address", "address")
|
log.Debug("[WalletAPI:: GetTransfersByAddress] get transfers for an address", "address", address)
|
||||||
return api.s.transferController.GetTransfersByAddress(ctx, api.s.rpcClient.UpstreamChainID, address, toBlock, limit, fetchMore)
|
return api.s.transferController.GetTransfersByAddress(ctx, api.s.rpcClient.UpstreamChainID, address, toBlock, limit, fetchMore)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LoadTransferByHash loads transfer to the database
|
||||||
|
func (api *API) LoadTransferByHash(ctx context.Context, address common.Address, hash common.Hash) error {
|
||||||
|
log.Debug("[WalletAPI:: LoadTransferByHash] get transfer by hash", "address", address, "hash", hash)
|
||||||
|
return api.s.transferController.LoadTransferByHash(ctx, api.s.rpcClient, address, hash)
|
||||||
|
}
|
||||||
|
|
||||||
func (api *API) GetTransfersByAddressAndChainID(ctx context.Context, chainID uint64, address common.Address, toBlock, limit *hexutil.Big, fetchMore bool) ([]transfer.View, error) {
|
func (api *API) GetTransfersByAddressAndChainID(ctx context.Context, chainID uint64, address common.Address, toBlock, limit *hexutil.Big, fetchMore bool) ([]transfer.View, error) {
|
||||||
log.Debug("[WalletAPI:: GetTransfersByAddressAndChainID] get transfers for an address", "address", address)
|
log.Debug("[WalletAPI:: GetTransfersByAddressAndChainID] get transfers for an address", "address", address)
|
||||||
return api.s.transferController.GetTransfersByAddress(ctx, chainID, address, toBlock, limit, fetchMore)
|
return api.s.transferController.GetTransfersByAddress(ctx, chainID, address, toBlock, limit, fetchMore)
|
||||||
|
|
|
@ -14,7 +14,16 @@ import (
|
||||||
"github.com/status-im/status-go/services/wallet/chain"
|
"github.com/status-im/status-go/services/wallet/chain"
|
||||||
)
|
)
|
||||||
|
|
||||||
var numberOfBlocksCheckedPerIteration = 40
|
var (
|
||||||
|
// This will work only for binance testnet as mainnet doesn't support
|
||||||
|
// archival request.
|
||||||
|
binanceChainMaxInitialRange = big.NewInt(500000)
|
||||||
|
binanceChainErc20BatchSize = big.NewInt(5000)
|
||||||
|
erc20BatchSize = big.NewInt(100000)
|
||||||
|
binancChainID = uint64(56)
|
||||||
|
binanceTestChainID = uint64(97)
|
||||||
|
numberOfBlocksCheckedPerIteration = 40
|
||||||
|
)
|
||||||
|
|
||||||
type ethHistoricalCommand struct {
|
type ethHistoricalCommand struct {
|
||||||
db *Database
|
db *Database
|
||||||
|
@ -87,12 +96,20 @@ func (c *erc20HistoricalCommand) Command() async.Command {
|
||||||
}.Run
|
}.Run
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getErc20BatchSize(chainID uint64) *big.Int {
|
||||||
|
if isBinanceChain(chainID) {
|
||||||
|
return binanceChainErc20BatchSize
|
||||||
|
}
|
||||||
|
|
||||||
|
return erc20BatchSize
|
||||||
|
}
|
||||||
|
|
||||||
func (c *erc20HistoricalCommand) Run(ctx context.Context) (err error) {
|
func (c *erc20HistoricalCommand) Run(ctx context.Context) (err error) {
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
if c.iterator == nil {
|
if c.iterator == nil {
|
||||||
c.iterator, err = SetupIterativeDownloader(
|
c.iterator, err = SetupIterativeDownloader(
|
||||||
c.db, c.chainClient, c.address,
|
c.db, c.chainClient, c.address,
|
||||||
c.erc20, erc20BatchSize, c.to, c.from)
|
c.erc20, getErc20BatchSize(c.chainClient.ChainID), c.to, c.from, !isBinanceChain(c.chainClient.ChainID))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("failed to setup historical downloader for erc20")
|
log.Error("failed to setup historical downloader for erc20")
|
||||||
return err
|
return err
|
||||||
|
@ -585,8 +602,21 @@ func loadTransfers(ctx context.Context, accounts []common.Address, block *Block,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func findFirstRange(c context.Context, account common.Address, initialTo *big.Int, client *chain.Client) (*big.Int, error) {
|
func isBinanceChain(chainID uint64) bool {
|
||||||
|
return chainID == binancChainID || chainID == binanceTestChainID
|
||||||
|
}
|
||||||
|
|
||||||
|
func getLowestFrom(chainID uint64, to *big.Int) *big.Int {
|
||||||
from := big.NewInt(0)
|
from := big.NewInt(0)
|
||||||
|
if isBinanceChain(chainID) && big.NewInt(0).Sub(to, from).Cmp(binanceChainMaxInitialRange) == 1 {
|
||||||
|
from = big.NewInt(0).Sub(to, binanceChainMaxInitialRange)
|
||||||
|
}
|
||||||
|
|
||||||
|
return from
|
||||||
|
}
|
||||||
|
|
||||||
|
func findFirstRange(c context.Context, account common.Address, initialTo *big.Int, client *chain.Client) (*big.Int, error) {
|
||||||
|
from := getLowestFrom(client.ChainID, initialTo)
|
||||||
to := initialTo
|
to := initialTo
|
||||||
goal := uint64(20)
|
goal := uint64(20)
|
||||||
|
|
||||||
|
@ -602,7 +632,7 @@ func findFirstRange(c context.Context, account common.Address, initialTo *big.In
|
||||||
}
|
}
|
||||||
|
|
||||||
if firstNonce <= goal {
|
if firstNonce <= goal {
|
||||||
return zero, nil
|
return from, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
nonceDiff := firstNonce
|
nonceDiff := firstNonce
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/event"
|
"github.com/ethereum/go-ethereum/event"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/status-im/status-go/multiaccounts/accounts"
|
"github.com/status-im/status-go/multiaccounts/accounts"
|
||||||
|
@ -169,6 +170,35 @@ func mapToList(m map[common.Address]struct{}) []common.Address {
|
||||||
return rst
|
return rst
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Controller) LoadTransferByHash(ctx context.Context, rpcClient *rpc.Client, address common.Address, hash common.Hash) error {
|
||||||
|
chainClient, err := chain.NewClient(rpcClient, rpcClient.UpstreamChainID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
signer := types.NewLondonSigner(chainClient.ToBigInt())
|
||||||
|
|
||||||
|
transfer, err := getTransferByHash(ctx, chainClient, signer, address, hash)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
transfers := []Transfer{*transfer}
|
||||||
|
|
||||||
|
err = c.db.InsertBlock(rpcClient.UpstreamChainID, address, transfer.BlockNumber, transfer.BlockHash)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
blocks := []*big.Int{transfer.BlockNumber}
|
||||||
|
err = c.db.SaveTranfers(rpcClient.UpstreamChainID, address, transfers, blocks)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Controller) GetTransfersByAddress(ctx context.Context, chainID uint64, address common.Address, toBlock, limit *hexutil.Big, fetchMore bool) ([]View, error) {
|
func (c *Controller) GetTransfersByAddress(ctx context.Context, chainID uint64, address common.Address, toBlock, limit *hexutil.Big, fetchMore bool) ([]View, error) {
|
||||||
log.Debug("[WalletAPI:: GetTransfersByAddress] get transfers for an address", "address", address)
|
log.Debug("[WalletAPI:: GetTransfersByAddress] get transfers for an address", "address", address)
|
||||||
var toBlockBN *big.Int
|
var toBlockBN *big.Int
|
||||||
|
|
|
@ -351,6 +351,31 @@ func deleteHeaders(creator statementCreator, headers []*DBHeader) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (db *Database) InsertBlock(chainID uint64, account common.Address, blockNumber *big.Int, blockHash common.Hash) error {
|
||||||
|
var (
|
||||||
|
tx *sql.Tx
|
||||||
|
)
|
||||||
|
tx, err := db.client.Begin()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
if err == nil {
|
||||||
|
err = tx.Commit()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_ = tx.Rollback()
|
||||||
|
}()
|
||||||
|
|
||||||
|
insert, err := tx.Prepare("INSERT OR IGNORE INTO blocks(network_id, address, blk_number, blk_hash, loaded) VALUES (?, ?, ?, ?, ?)")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = insert.Exec(chainID, account, (*bigint.SQLBigInt)(blockNumber), blockHash, true)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
func insertBlocksWithTransactions(chainID uint64, creator statementCreator, account common.Address, headers []*DBHeader) error {
|
func insertBlocksWithTransactions(chainID uint64, creator statementCreator, account common.Address, headers []*DBHeader) error {
|
||||||
insert, err := creator.Prepare("INSERT OR IGNORE INTO blocks(network_id, address, blk_number, blk_hash, loaded) VALUES (?, ?, ?, ?, ?)")
|
insert, err := creator.Prepare("INSERT OR IGNORE INTO blocks(network_id, address, blk_number, blk_hash, loaded) VALUES (?, ?, ?, ?, ?)")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -90,6 +90,44 @@ func (d *ETHDownloader) GetTransfersByNumber(ctx context.Context, number *big.In
|
||||||
return rst, err
|
return rst, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getTransferByHash(ctx context.Context, client *chain.Client, signer types.Signer, address common.Address, hash common.Hash) (*Transfer, error) {
|
||||||
|
transaction, _, err := client.TransactionByHash(ctx, hash)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
receipt, err := client.TransactionReceipt(ctx, hash)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
transactionLog := getTokenLog(receipt.Logs)
|
||||||
|
|
||||||
|
transferType := ethTransfer
|
||||||
|
if transactionLog != nil {
|
||||||
|
transferType = erc20Transfer
|
||||||
|
}
|
||||||
|
|
||||||
|
from, err := types.Sender(signer, transaction)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
transfer := &Transfer{Type: transferType,
|
||||||
|
ID: hash,
|
||||||
|
Address: address,
|
||||||
|
BlockNumber: receipt.BlockNumber,
|
||||||
|
BlockHash: receipt.BlockHash,
|
||||||
|
Timestamp: uint64(time.Now().Unix()),
|
||||||
|
Transaction: transaction,
|
||||||
|
From: from,
|
||||||
|
Receipt: receipt,
|
||||||
|
Log: transactionLog}
|
||||||
|
|
||||||
|
return transfer, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (d *ETHDownloader) getTransfersInBlock(ctx context.Context, blk *types.Block, accounts []common.Address) (rst []Transfer, err error) {
|
func (d *ETHDownloader) getTransfersInBlock(ctx context.Context, blk *types.Block, accounts []common.Address) (rst []Transfer, err error) {
|
||||||
for _, address := range accounts {
|
for _, address := range accounts {
|
||||||
preloadedTransfers, err := d.db.GetPreloadedTransactions(d.chainClient.ChainID, address, blk.Hash())
|
preloadedTransfers, err := d.db.GetPreloadedTransactions(d.chainClient.ChainID, address, blk.Hash())
|
||||||
|
|
|
@ -12,14 +12,14 @@ import (
|
||||||
// SetupIterativeDownloader configures IterativeDownloader with last known synced block.
|
// SetupIterativeDownloader configures IterativeDownloader with last known synced block.
|
||||||
func SetupIterativeDownloader(
|
func SetupIterativeDownloader(
|
||||||
db *Database, client HeaderReader, address common.Address,
|
db *Database, client HeaderReader, address common.Address,
|
||||||
downloader BatchDownloader, size *big.Int, to *big.Int, from *big.Int) (*IterativeDownloader, error) {
|
downloader BatchDownloader, size *big.Int, to *big.Int, from *big.Int, isBatchSizeAdjustable bool) (*IterativeDownloader, error) {
|
||||||
|
|
||||||
if to == nil || from == nil {
|
if to == nil || from == nil {
|
||||||
return nil, errors.New("to or from cannot be nil")
|
return nil, errors.New("to or from cannot be nil")
|
||||||
}
|
}
|
||||||
|
|
||||||
adjustedSize := big.NewInt(0).Div(big.NewInt(0).Sub(to, from), big.NewInt(10))
|
adjustedSize := big.NewInt(0).Div(big.NewInt(0).Sub(to, from), big.NewInt(10))
|
||||||
if adjustedSize.Cmp(size) == 1 {
|
if isBatchSizeAdjustable && adjustedSize.Cmp(size) == 1 {
|
||||||
size = adjustedSize
|
size = adjustedSize
|
||||||
}
|
}
|
||||||
log.Info("iterative downloader", "address", address, "from", from, "to", to, "size", size)
|
log.Info("iterative downloader", "address", address, "from", from, "to", to, "size", size)
|
||||||
|
|
|
@ -13,10 +13,7 @@ import (
|
||||||
"github.com/status-im/status-go/services/wallet/chain"
|
"github.com/status-im/status-go/services/wallet/chain"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var errAlreadyRunning = errors.New("already running")
|
||||||
erc20BatchSize = big.NewInt(100000)
|
|
||||||
errAlreadyRunning = errors.New("already running")
|
|
||||||
)
|
|
||||||
|
|
||||||
// HeaderReader interface for reading headers using block number or hash.
|
// HeaderReader interface for reading headers using block number or hash.
|
||||||
type HeaderReader interface {
|
type HeaderReader interface {
|
||||||
|
|
Loading…
Reference in New Issue