2021-09-09 14:28:54 +00:00
|
|
|
package transfer
|
|
|
|
|
|
|
|
import (
|
2023-04-21 11:59:29 +00:00
|
|
|
"context"
|
2021-09-09 14:28:54 +00:00
|
|
|
"database/sql"
|
|
|
|
"database/sql/driver"
|
|
|
|
"encoding/json"
|
|
|
|
"errors"
|
|
|
|
"math/big"
|
|
|
|
"reflect"
|
|
|
|
|
|
|
|
"github.com/ethereum/go-ethereum/common"
|
|
|
|
"github.com/ethereum/go-ethereum/core/types"
|
|
|
|
"github.com/ethereum/go-ethereum/log"
|
2023-05-19 15:31:45 +00:00
|
|
|
|
2021-09-09 14:28:54 +00:00
|
|
|
"github.com/status-im/status-go/services/wallet/bigint"
|
2023-05-19 15:31:45 +00:00
|
|
|
w_common "github.com/status-im/status-go/services/wallet/common"
|
|
|
|
"github.com/status-im/status-go/sqlite"
|
2021-09-09 14:28:54 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// DBHeader fields from header that are stored in database.
|
|
|
|
type DBHeader struct {
|
2023-06-02 20:08:45 +00:00
|
|
|
Number *big.Int
|
|
|
|
Hash common.Hash
|
|
|
|
Timestamp uint64
|
|
|
|
PreloadedTransactions []*PreloadedTransaction
|
|
|
|
Network uint64
|
|
|
|
Address common.Address
|
2021-09-09 14:28:54 +00:00
|
|
|
// Head is true if the block was a head at the time it was pulled from chain.
|
|
|
|
Head bool
|
2023-05-19 15:31:45 +00:00
|
|
|
// Loaded is true if transfers from this block have been already fetched
|
2021-09-09 14:28:54 +00:00
|
|
|
Loaded bool
|
|
|
|
}
|
|
|
|
|
2023-06-01 17:16:50 +00:00
|
|
|
func toDBHeader(header *types.Header, blockHash common.Hash) *DBHeader {
|
2021-09-09 14:28:54 +00:00
|
|
|
return &DBHeader{
|
2023-06-01 17:16:50 +00:00
|
|
|
Hash: blockHash,
|
2021-09-09 14:28:54 +00:00
|
|
|
Number: header.Number,
|
|
|
|
Timestamp: header.Time,
|
|
|
|
Loaded: false,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// SyncOption is used to specify that application processed transfers for that block.
|
|
|
|
type SyncOption uint
|
|
|
|
|
|
|
|
// JSONBlob type for marshaling/unmarshaling inner type to json.
|
|
|
|
type JSONBlob struct {
|
|
|
|
data interface{}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Scan implements interface.
|
|
|
|
func (blob *JSONBlob) Scan(value interface{}) error {
|
|
|
|
if value == nil || reflect.ValueOf(blob.data).IsNil() {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
bytes, ok := value.([]byte)
|
|
|
|
if !ok {
|
|
|
|
return errors.New("not a byte slice")
|
|
|
|
}
|
|
|
|
if len(bytes) == 0 {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
err := json.Unmarshal(bytes, blob.data)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Value implements interface.
|
|
|
|
func (blob *JSONBlob) Value() (driver.Value, error) {
|
|
|
|
if blob.data == nil || reflect.ValueOf(blob.data).IsNil() {
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
return json.Marshal(blob.data)
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewDB(client *sql.DB) *Database {
|
|
|
|
return &Database{client: client}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Database sql wrapper for operations with wallet objects.
|
|
|
|
type Database struct {
|
|
|
|
client *sql.DB
|
|
|
|
}
|
|
|
|
|
|
|
|
// Close closes database.
|
|
|
|
func (db *Database) Close() error {
|
|
|
|
return db.client.Close()
|
|
|
|
}
|
|
|
|
|
2023-05-08 06:02:00 +00:00
|
|
|
func (db *Database) ProcessBlocks(chainID uint64, account common.Address, from *big.Int, to *Block, headers []*DBHeader) (err error) {
|
2021-09-09 14:28:54 +00:00
|
|
|
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()
|
|
|
|
}()
|
|
|
|
|
|
|
|
err = insertBlocksWithTransactions(chainID, tx, account, headers)
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
err = upsertRange(chainID, tx, account, from, to)
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
func (db *Database) SaveBlocks(chainID uint64, account common.Address, headers []*DBHeader) (err 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()
|
|
|
|
}()
|
|
|
|
|
|
|
|
err = insertBlocksWithTransactions(chainID, tx, account, headers)
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2023-02-15 12:28:19 +00:00
|
|
|
// ProcessTransfers atomically adds/removes blocks and adds new transfers.
|
|
|
|
func (db *Database) ProcessTransfers(chainID uint64, transfers []Transfer, removed []*DBHeader) (err error) {
|
2021-09-09 14:28:54 +00:00
|
|
|
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()
|
|
|
|
}()
|
2023-02-15 12:28:19 +00:00
|
|
|
|
2021-09-09 14:28:54 +00:00
|
|
|
err = deleteHeaders(tx, removed)
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
2023-02-15 12:28:19 +00:00
|
|
|
|
2021-09-09 14:28:54 +00:00
|
|
|
err = updateOrInsertTransfers(chainID, tx, transfers)
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2023-05-08 06:02:00 +00:00
|
|
|
// SaveTransfersMarkBlocksLoaded
|
|
|
|
func (db *Database) SaveTransfersMarkBlocksLoaded(chainID uint64, address common.Address, transfers []Transfer, blocks []*big.Int) (err error) {
|
|
|
|
err = db.SaveTransfers(chainID, address, transfers)
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2023-02-15 12:28:19 +00:00
|
|
|
var tx *sql.Tx
|
2021-09-09 14:28:54 +00:00
|
|
|
tx, err = db.client.Begin()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer func() {
|
|
|
|
if err == nil {
|
|
|
|
err = tx.Commit()
|
|
|
|
return
|
|
|
|
}
|
|
|
|
_ = tx.Rollback()
|
|
|
|
}()
|
2023-05-08 06:02:00 +00:00
|
|
|
err = markBlocksAsLoaded(chainID, tx, address, blocks)
|
2021-09-09 14:28:54 +00:00
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2023-05-08 06:02:00 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// SaveTransfers
|
|
|
|
func (db *Database) SaveTransfers(chainID uint64, address common.Address, transfers []Transfer) (err 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()
|
|
|
|
}()
|
|
|
|
|
|
|
|
err = updateOrInsertTransfers(chainID, tx, transfers)
|
2021-09-09 14:28:54 +00:00
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetTransfersInRange loads transfers for a given address between two blocks.
|
|
|
|
func (db *Database) GetTransfersInRange(chainID uint64, address common.Address, start, end *big.Int) (rst []Transfer, err error) {
|
|
|
|
query := newTransfersQuery().FilterNetwork(chainID).FilterAddress(address).FilterStart(start).FilterEnd(end).FilterLoaded(1)
|
|
|
|
rows, err := db.client.Query(query.String(), query.Args()...)
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
defer rows.Close()
|
2023-06-02 20:08:45 +00:00
|
|
|
return query.TransferScan(rows)
|
2021-09-09 14:28:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// GetTransfersByAddress loads transfers for a given address between two blocks.
|
|
|
|
func (db *Database) GetTransfersByAddress(chainID uint64, address common.Address, toBlock *big.Int, limit int64) (rst []Transfer, err error) {
|
|
|
|
query := newTransfersQuery().
|
|
|
|
FilterNetwork(chainID).
|
|
|
|
FilterAddress(address).
|
|
|
|
FilterEnd(toBlock).
|
|
|
|
FilterLoaded(1).
|
|
|
|
Limit(limit)
|
|
|
|
|
|
|
|
rows, err := db.client.Query(query.String(), query.Args()...)
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
defer rows.Close()
|
2023-06-02 20:08:45 +00:00
|
|
|
return query.TransferScan(rows)
|
2021-09-09 14:28:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// GetTransfersByAddressAndBlock loads transfers for a given address and block.
|
|
|
|
func (db *Database) GetTransfersByAddressAndBlock(chainID uint64, address common.Address, block *big.Int, limit int64) (rst []Transfer, err error) {
|
|
|
|
query := newTransfersQuery().
|
|
|
|
FilterNetwork(chainID).
|
|
|
|
FilterAddress(address).
|
|
|
|
FilterBlockNumber(block).
|
|
|
|
FilterLoaded(1).
|
|
|
|
Limit(limit)
|
|
|
|
|
|
|
|
rows, err := db.client.Query(query.String(), query.Args()...)
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
defer rows.Close()
|
2023-06-02 20:08:45 +00:00
|
|
|
return query.TransferScan(rows)
|
2021-09-09 14:28:54 +00:00
|
|
|
}
|
|
|
|
|
2023-04-21 11:59:29 +00:00
|
|
|
// GetTransfers load transfers transfer between two blocks.
|
2021-09-09 14:28:54 +00:00
|
|
|
func (db *Database) GetTransfers(chainID uint64, start, end *big.Int) (rst []Transfer, err error) {
|
|
|
|
query := newTransfersQuery().FilterNetwork(chainID).FilterStart(start).FilterEnd(end).FilterLoaded(1)
|
|
|
|
rows, err := db.client.Query(query.String(), query.Args()...)
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
defer rows.Close()
|
2023-06-02 20:08:45 +00:00
|
|
|
return query.TransferScan(rows)
|
2021-09-09 14:28:54 +00:00
|
|
|
}
|
|
|
|
|
2023-04-21 11:59:29 +00:00
|
|
|
func (db *Database) GetTransfersForIdentities(ctx context.Context, identities []TransactionIdentity) (rst []Transfer, err error) {
|
|
|
|
query := newTransfersQuery()
|
|
|
|
for _, identity := range identities {
|
|
|
|
subQuery := newSubQuery()
|
|
|
|
// TODO optimization: consider using tuples in sqlite and IN operator
|
2023-05-11 07:50:07 +00:00
|
|
|
subQuery = subQuery.FilterNetwork(uint64(identity.ChainID)).FilterTransactionHash(identity.Hash).FilterAddress(identity.Address)
|
2023-04-21 11:59:29 +00:00
|
|
|
query.addSubQuery(subQuery, OrSeparator)
|
|
|
|
}
|
|
|
|
rows, err := db.client.QueryContext(ctx, query.String(), query.Args()...)
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
defer rows.Close()
|
2023-06-02 20:08:45 +00:00
|
|
|
return query.TransferScan(rows)
|
2023-04-21 11:59:29 +00:00
|
|
|
}
|
|
|
|
|
2023-06-02 20:08:45 +00:00
|
|
|
func (db *Database) GetTransactionsToLoad(chainID uint64, address common.Address, blockNumber *big.Int) (rst []PreloadedTransaction, err error) {
|
2021-09-09 14:28:54 +00:00
|
|
|
query := newTransfersQuery().
|
|
|
|
FilterNetwork(chainID).
|
|
|
|
FilterAddress(address).
|
2023-05-08 15:14:46 +00:00
|
|
|
FilterBlockNumber(blockNumber).
|
2021-09-09 14:28:54 +00:00
|
|
|
FilterLoaded(0)
|
|
|
|
|
|
|
|
rows, err := db.client.Query(query.String(), query.Args()...)
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
defer rows.Close()
|
2023-06-02 20:08:45 +00:00
|
|
|
return query.PreloadedTransactionScan(rows)
|
2021-09-09 14:28:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// statementCreator allows to pass transaction or database to use in consumer.
|
|
|
|
type statementCreator interface {
|
|
|
|
Prepare(query string) (*sql.Stmt, error)
|
|
|
|
}
|
|
|
|
|
|
|
|
func deleteHeaders(creator statementCreator, headers []*DBHeader) error {
|
|
|
|
delete, err := creator.Prepare("DELETE FROM blocks WHERE blk_hash = ?")
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
deleteTransfers, err := creator.Prepare("DELETE FROM transfers WHERE blk_hash = ?")
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
for _, h := range headers {
|
|
|
|
_, err = delete.Exec(h.Hash)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
_, err = deleteTransfers.Exec(h.Hash)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2023-06-02 20:08:45 +00:00
|
|
|
// Only used by status-mobile
|
2021-11-24 12:59:45 +00:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2021-09-09 14:28:54 +00:00
|
|
|
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 (?, ?, ?, ?, ?)")
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
updateTx, err := creator.Prepare(`UPDATE transfers
|
2023-05-19 15:31:45 +00:00
|
|
|
SET log = ?, log_index = ?
|
2021-09-09 14:28:54 +00:00
|
|
|
WHERE network_id = ? AND address = ? AND hash = ?`)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2021-11-24 12:59:45 +00:00
|
|
|
insertTx, err := creator.Prepare(`INSERT OR IGNORE
|
2023-05-19 15:31:45 +00:00
|
|
|
INTO transfers (network_id, address, sender, hash, blk_number, blk_hash, type, timestamp, log, loaded, log_index)
|
|
|
|
VALUES (?, ?, ?, ?, ?, ?, ?, 0, ?, 0, ?)`)
|
2021-09-09 14:28:54 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, header := range headers {
|
|
|
|
_, err = insert.Exec(chainID, account, (*bigint.SQLBigInt)(header.Number), header.Hash, header.Loaded)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2023-06-02 20:08:45 +00:00
|
|
|
for _, transaction := range header.PreloadedTransactions {
|
2023-05-19 15:31:45 +00:00
|
|
|
var logIndex *uint
|
|
|
|
if transaction.Log != nil {
|
|
|
|
logIndex = new(uint)
|
|
|
|
*logIndex = transaction.Log.Index
|
|
|
|
}
|
|
|
|
res, err := updateTx.Exec(&JSONBlob{transaction.Log}, logIndex, chainID, account, transaction.ID)
|
2023-06-02 20:08:45 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
affected, err := res.RowsAffected()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if affected > 0 {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2023-05-19 15:31:45 +00:00
|
|
|
_, err = insertTx.Exec(chainID, account, account, transaction.ID, (*bigint.SQLBigInt)(header.Number), header.Hash, w_common.Erc20Transfer, &JSONBlob{transaction.Log}, logIndex)
|
2023-06-02 20:08:45 +00:00
|
|
|
if err != nil {
|
2023-05-19 15:31:45 +00:00
|
|
|
log.Error("error saving Erc20transfer", "err", err)
|
2023-06-02 20:08:45 +00:00
|
|
|
return err
|
2021-09-09 14:28:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func updateOrInsertTransfers(chainID uint64, creator statementCreator, transfers []Transfer) error {
|
2023-06-02 20:08:45 +00:00
|
|
|
insert, err := creator.Prepare(`INSERT OR REPLACE INTO transfers
|
2023-05-19 15:31:45 +00:00
|
|
|
(network_id, hash, blk_hash, blk_number, timestamp, address, tx, sender, receipt, log, type, loaded, base_gas_fee, multi_transaction_id,
|
|
|
|
status, receipt_type, tx_hash, log_index, block_hash, cumulative_gas_used, contract_address, gas_used, tx_index,
|
|
|
|
tx_type, protected, gas_limit, gas_price_clamped64, gas_tip_cap_clamped64, gas_fee_cap_clamped64, amount_padded128hex, account_nonce, size, token_address, token_id)
|
2021-09-09 14:28:54 +00:00
|
|
|
VALUES
|
2023-05-19 15:31:45 +00:00
|
|
|
(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`)
|
2021-09-09 14:28:54 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
for _, t := range transfers {
|
2023-05-19 15:31:45 +00:00
|
|
|
var receiptType *uint8
|
|
|
|
var txHash, blockHash *common.Hash
|
|
|
|
var receiptStatus, cumulativeGasUsed, gasUsed *uint64
|
|
|
|
var contractAddress *common.Address
|
|
|
|
var transactionIndex, logIndex *uint
|
|
|
|
|
|
|
|
if t.Receipt != nil {
|
|
|
|
receiptType = &t.Receipt.Type
|
|
|
|
receiptStatus = &t.Receipt.Status
|
|
|
|
txHash = &t.Receipt.TxHash
|
|
|
|
if t.Log != nil {
|
|
|
|
logIndex = new(uint)
|
|
|
|
*logIndex = t.Log.Index
|
|
|
|
}
|
|
|
|
blockHash = &t.Receipt.BlockHash
|
|
|
|
cumulativeGasUsed = &t.Receipt.CumulativeGasUsed
|
|
|
|
contractAddress = &t.Receipt.ContractAddress
|
|
|
|
gasUsed = &t.Receipt.GasUsed
|
|
|
|
transactionIndex = &t.Receipt.TransactionIndex
|
|
|
|
}
|
|
|
|
|
|
|
|
var txProtected *bool
|
|
|
|
var txGas, txNonce, txSize *uint64
|
|
|
|
var txGasPrice, txGasTipCap, txGasFeeCap *int64
|
|
|
|
var txType *uint8
|
|
|
|
var txValue *string
|
|
|
|
var tokenAddress *common.Address
|
|
|
|
var tokenID *big.Int
|
|
|
|
if t.Transaction != nil {
|
|
|
|
var value *big.Int
|
|
|
|
if t.Log != nil {
|
|
|
|
_, tokenAddress, tokenID, value = w_common.ExtractTokenIdentity(t.Type, t.Log, t.Transaction)
|
|
|
|
} else {
|
|
|
|
value = new(big.Int).Set(t.Transaction.Value())
|
|
|
|
}
|
|
|
|
|
|
|
|
txType = new(uint8)
|
|
|
|
*txType = t.Transaction.Type()
|
|
|
|
txProtected = new(bool)
|
|
|
|
*txProtected = t.Transaction.Protected()
|
|
|
|
txGas = new(uint64)
|
|
|
|
*txGas = t.Transaction.Gas()
|
|
|
|
txGasPrice = sqlite.BigIntToClampedInt64(t.Transaction.GasPrice())
|
|
|
|
txGasTipCap = sqlite.BigIntToClampedInt64(t.Transaction.GasTipCap())
|
|
|
|
txGasFeeCap = sqlite.BigIntToClampedInt64(t.Transaction.GasFeeCap())
|
|
|
|
txValue = sqlite.BigIntToPadded128BitsStr(value)
|
|
|
|
txNonce = new(uint64)
|
|
|
|
*txNonce = t.Transaction.Nonce()
|
|
|
|
txSize = new(uint64)
|
|
|
|
*txSize = uint64(t.Transaction.Size())
|
|
|
|
}
|
|
|
|
|
|
|
|
_, err = insert.Exec(chainID, t.ID, t.BlockHash, (*bigint.SQLBigInt)(t.BlockNumber), t.Timestamp, t.Address, &JSONBlob{t.Transaction}, t.From, &JSONBlob{t.Receipt}, &JSONBlob{t.Log}, t.Type, t.BaseGasFees, t.MultiTransactionID,
|
|
|
|
receiptStatus, receiptType, txHash, logIndex, blockHash, cumulativeGasUsed, contractAddress, gasUsed, transactionIndex,
|
|
|
|
txType, txProtected, txGas, txGasPrice, txGasTipCap, txGasFeeCap, txValue, txNonce, txSize, &sqlite.JSONBlob{Data: tokenAddress}, (*bigint.SQLBigIntBytes)(tokenID))
|
2021-09-09 14:28:54 +00:00
|
|
|
if err != nil {
|
|
|
|
log.Error("can't save transfer", "b-hash", t.BlockHash, "b-n", t.BlockNumber, "a", t.Address, "h", t.ID)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2022-12-29 06:16:19 +00:00
|
|
|
// markBlocksAsLoaded(tx, address, chainID, blocks)
|
2021-09-09 14:28:54 +00:00
|
|
|
func markBlocksAsLoaded(chainID uint64, creator statementCreator, address common.Address, blocks []*big.Int) error {
|
|
|
|
update, err := creator.Prepare("UPDATE blocks SET loaded=? WHERE address=? AND blk_number=? AND network_id=?")
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, block := range blocks {
|
|
|
|
_, err := update.Exec(true, address, (*bigint.SQLBigInt)(block), chainID)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|