mirror of
https://github.com/status-im/status-go.git
synced 2025-01-25 22:19:51 +00:00
82185b54b5
`getLogs` for multiple accounts simultaneously. For now only used for new transfers detection. Detection of `new` transfers has been changed, now they are searched from head and forward. Previously they were searched from last scanned block forward.
178 lines
6.5 KiB
Go
178 lines
6.5 KiB
Go
package transfer
|
|
|
|
import (
|
|
"database/sql"
|
|
"math/big"
|
|
|
|
"github.com/ethereum/go-ethereum/common"
|
|
"github.com/ethereum/go-ethereum/log"
|
|
"github.com/status-im/status-go/services/wallet/bigint"
|
|
)
|
|
|
|
type BlockRangeSequentialDAO struct {
|
|
db *sql.DB
|
|
}
|
|
|
|
type BlockRange struct {
|
|
Start *big.Int // Block of first transfer
|
|
FirstKnown *big.Int // Oldest scanned block
|
|
LastKnown *big.Int // Last scanned block
|
|
}
|
|
|
|
func NewBlockRange() *BlockRange {
|
|
return &BlockRange{Start: &big.Int{}, FirstKnown: &big.Int{}, LastKnown: &big.Int{}}
|
|
}
|
|
|
|
type ethTokensBlockRanges struct {
|
|
eth *BlockRange
|
|
tokens *BlockRange
|
|
}
|
|
|
|
func newEthTokensBlockRanges() *ethTokensBlockRanges {
|
|
return ðTokensBlockRanges{eth: NewBlockRange(), tokens: NewBlockRange()}
|
|
}
|
|
|
|
func (b *BlockRangeSequentialDAO) getBlockRange(chainID uint64, address common.Address) (blockRange *ethTokensBlockRanges, err error) {
|
|
query := `SELECT blk_start, blk_first, blk_last, token_blk_start, token_blk_first, token_blk_last FROM blocks_ranges_sequential
|
|
WHERE address = ?
|
|
AND network_id = ?`
|
|
|
|
rows, err := b.db.Query(query, address, chainID)
|
|
if err != nil {
|
|
return
|
|
}
|
|
defer rows.Close()
|
|
|
|
blockRange = ðTokensBlockRanges{}
|
|
if rows.Next() {
|
|
blockRange = newEthTokensBlockRanges()
|
|
err = rows.Scan((*bigint.SQLBigInt)(blockRange.eth.Start), (*bigint.SQLBigInt)(blockRange.eth.FirstKnown), (*bigint.SQLBigInt)(blockRange.eth.LastKnown),
|
|
(*bigint.SQLBigInt)(blockRange.tokens.Start), (*bigint.SQLBigInt)(blockRange.tokens.FirstKnown), (*bigint.SQLBigInt)(blockRange.tokens.LastKnown))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return blockRange, nil
|
|
}
|
|
|
|
return blockRange, nil
|
|
}
|
|
|
|
func (b *BlockRangeSequentialDAO) deleteRange(account common.Address) error {
|
|
log.Debug("delete blocks range", "account", account)
|
|
delete, err := b.db.Prepare(`DELETE FROM blocks_ranges_sequential WHERE address = ?`)
|
|
if err != nil {
|
|
log.Error("Failed to prepare deletion of sequential block range", "error", err)
|
|
return err
|
|
}
|
|
|
|
_, err = delete.Exec(account)
|
|
return err
|
|
}
|
|
|
|
func (b *BlockRangeSequentialDAO) upsertRange(chainID uint64, account common.Address, newBlockRange *ethTokensBlockRanges) (err error) {
|
|
ethTokensBlockRange, err := b.getBlockRange(chainID, account)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
ethBlockRange := prepareUpdatedBlockRange(chainID, account, ethTokensBlockRange.eth, newBlockRange.eth)
|
|
tokensBlockRange := prepareUpdatedBlockRange(chainID, account, ethTokensBlockRange.tokens, newBlockRange.tokens)
|
|
|
|
log.Debug("update eth and tokens blocks range", "account", account, "chainID", chainID,
|
|
"eth.start", ethBlockRange.Start, "eth.first", ethBlockRange.FirstKnown, "eth.last", ethBlockRange.LastKnown,
|
|
"tokens.start", tokensBlockRange.Start, "tokens.first", ethBlockRange.FirstKnown, "eth.last", ethBlockRange.LastKnown)
|
|
|
|
upsert, err := b.db.Prepare(`REPLACE INTO blocks_ranges_sequential
|
|
(network_id, address, blk_start, blk_first, blk_last, token_blk_start, token_blk_first, token_blk_last) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
_, err = upsert.Exec(chainID, account, (*bigint.SQLBigInt)(ethBlockRange.Start), (*bigint.SQLBigInt)(ethBlockRange.FirstKnown), (*bigint.SQLBigInt)(ethBlockRange.LastKnown),
|
|
(*bigint.SQLBigInt)(tokensBlockRange.Start), (*bigint.SQLBigInt)(tokensBlockRange.FirstKnown), (*bigint.SQLBigInt)(tokensBlockRange.LastKnown))
|
|
|
|
return err
|
|
}
|
|
|
|
func (b *BlockRangeSequentialDAO) upsertEthRange(chainID uint64, account common.Address,
|
|
newBlockRange *BlockRange) (err error) {
|
|
|
|
ethTokensBlockRange, err := b.getBlockRange(chainID, account)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
blockRange := prepareUpdatedBlockRange(chainID, account, ethTokensBlockRange.eth, newBlockRange)
|
|
|
|
log.Debug("update eth blocks range", "account", account, "chainID", chainID,
|
|
"start", blockRange.Start, "first", blockRange.FirstKnown, "last", blockRange.LastKnown)
|
|
|
|
upsert, err := b.db.Prepare(`REPLACE INTO blocks_ranges_sequential
|
|
(network_id, address, blk_start, blk_first, blk_last) VALUES (?, ?, ?, ?, ?)`)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
_, err = upsert.Exec(chainID, account, (*bigint.SQLBigInt)(blockRange.Start), (*bigint.SQLBigInt)(blockRange.FirstKnown),
|
|
(*bigint.SQLBigInt)(blockRange.LastKnown))
|
|
|
|
return err
|
|
}
|
|
|
|
func (b *BlockRangeSequentialDAO) upsertTokenRange(chainID uint64, account common.Address,
|
|
newBlockRange *BlockRange) (err error) {
|
|
|
|
ethTokensBlockRange, err := b.getBlockRange(chainID, account)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
blockRange := prepareUpdatedBlockRange(chainID, account, ethTokensBlockRange.tokens, newBlockRange)
|
|
|
|
log.Debug("update tokens blocks range", "account", account, "chainID", chainID,
|
|
"start", blockRange.Start, "first", blockRange.FirstKnown, "last", blockRange.LastKnown)
|
|
|
|
upsert, err := b.db.Prepare(`REPLACE INTO blocks_ranges_sequential
|
|
(network_id, address, token_blk_start, token_blk_first, token_blk_last) VALUES (?, ?, ?, ?, ?)`)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
_, err = upsert.Exec(chainID, account, (*bigint.SQLBigInt)(blockRange.Start), (*bigint.SQLBigInt)(blockRange.FirstKnown),
|
|
(*bigint.SQLBigInt)(blockRange.LastKnown))
|
|
|
|
return err
|
|
}
|
|
|
|
func prepareUpdatedBlockRange(chainID uint64, account common.Address, blockRange, newBlockRange *BlockRange) *BlockRange {
|
|
// Update existing range
|
|
if blockRange != nil {
|
|
if newBlockRange != nil {
|
|
// Ovewrite start block if there was not any or if new one is older, because it can be precised only
|
|
// to a greater value, because no history can be before some block that is considered
|
|
// as a start of history, but due to concurrent block range checks, a newer greater block
|
|
// can be found that matches criteria of a start block (nonce is zero, balances are equal)
|
|
if newBlockRange.Start != nil && (blockRange.Start == nil || blockRange.Start.Cmp(newBlockRange.Start) < 0) {
|
|
blockRange.Start = newBlockRange.Start
|
|
}
|
|
|
|
// Overwrite first known block if there was not any or if new one is older
|
|
if (blockRange.FirstKnown == nil && newBlockRange.FirstKnown != nil) ||
|
|
(blockRange.FirstKnown != nil && newBlockRange.FirstKnown != nil && blockRange.FirstKnown.Cmp(newBlockRange.FirstKnown) > 0) {
|
|
blockRange.FirstKnown = newBlockRange.FirstKnown
|
|
}
|
|
|
|
// Overwrite last known block if there was not any or if new one is newer
|
|
if (blockRange.LastKnown == nil && newBlockRange.LastKnown != nil) ||
|
|
(blockRange.LastKnown != nil && newBlockRange.LastKnown != nil && blockRange.LastKnown.Cmp(newBlockRange.LastKnown) < 0) {
|
|
blockRange.LastKnown = newBlockRange.LastKnown
|
|
}
|
|
}
|
|
} else {
|
|
blockRange = newBlockRange
|
|
}
|
|
|
|
return blockRange
|
|
}
|