2020-01-17 23:16:01 +00:00
// VulcanizeDB
// Copyright © 2019 Vulcanize
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
2020-01-16 23:21:49 +00:00
package eth
import (
2022-12-19 08:42:23 +00:00
"bytes"
2020-01-16 23:21:49 +00:00
"context"
2021-04-19 10:16:59 +00:00
"database/sql"
2020-01-16 23:21:49 +00:00
"errors"
2020-10-30 03:07:39 +00:00
"fmt"
2020-01-16 23:21:49 +00:00
"math/big"
2021-09-21 12:10:55 +00:00
"time"
2020-01-16 23:21:49 +00:00
2024-05-29 12:29:55 +00:00
validator "github.com/cerc-io/eth-ipfs-state-validator/v5/pkg"
ipfsethdb "github.com/cerc-io/ipfs-ethdb/v5/postgres/v0"
ipld_direct_state "github.com/cerc-io/ipld-eth-statedb/direct_by_leaf"
ipld_sql "github.com/cerc-io/ipld-eth-statedb/sql"
ipld_trie_state "github.com/cerc-io/ipld-eth-statedb/trie_by_cid/state"
ipld_trie "github.com/cerc-io/ipld-eth-statedb/trie_by_cid/trie"
2023-09-21 06:55:26 +00:00
"github.com/cerc-io/plugeth-statediff/indexer/ipld"
"github.com/cerc-io/plugeth-statediff/utils"
2020-01-16 23:21:49 +00:00
"github.com/ethereum/go-ethereum/common"
2021-02-24 22:20:06 +00:00
"github.com/ethereum/go-ethereum/common/hexutil"
2020-10-20 20:33:18 +00:00
"github.com/ethereum/go-ethereum/consensus"
"github.com/ethereum/go-ethereum/consensus/ethash"
"github.com/ethereum/go-ethereum/core"
2020-10-28 03:04:19 +00:00
"github.com/ethereum/go-ethereum/core/bloombits"
2020-01-16 23:21:49 +00:00
"github.com/ethereum/go-ethereum/core/types"
2020-10-20 20:33:18 +00:00
"github.com/ethereum/go-ethereum/core/vm"
2020-10-30 03:07:39 +00:00
"github.com/ethereum/go-ethereum/crypto"
2020-08-11 03:53:01 +00:00
"github.com/ethereum/go-ethereum/ethdb"
2020-10-28 03:04:19 +00:00
"github.com/ethereum/go-ethereum/event"
2020-10-20 20:33:18 +00:00
"github.com/ethereum/go-ethereum/params"
2020-01-16 23:21:49 +00:00
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/rpc"
2021-02-24 22:20:06 +00:00
"github.com/ethereum/go-ethereum/trie"
2024-05-29 12:29:55 +00:00
"github.com/holiman/uint256"
2022-03-10 09:53:03 +00:00
"github.com/jmoiron/sqlx"
2023-04-14 06:26:46 +00:00
"github.com/cerc-io/ipld-eth-server/v5/pkg/log"
"github.com/cerc-io/ipld-eth-server/v5/pkg/shared"
2020-01-16 23:21:49 +00:00
)
var (
2022-07-12 08:10:45 +00:00
errPendingBlockNumber = errors . New ( "pending block number not supported" )
errNegativeBlockNumber = errors . New ( "negative block number not supported" )
errHeaderHashNotFound = errors . New ( "header for hash not found" )
errHeaderNotFound = errors . New ( "header not found" )
errMultipleHeadersForHash = errors . New ( "more than one headers for the given hash" )
errTxHashNotFound = errors . New ( "transaction for hash not found" )
errTxHashInMultipleBlocks = errors . New ( "transaction for hash found in more than one canonical block" )
2020-10-20 20:33:18 +00:00
)
2021-09-21 12:10:55 +00:00
const (
StateDBGroupCacheName = "statedb"
)
2023-04-14 06:26:46 +00:00
// Backend handles all interactions with IPLD/SQL-backed Ethereum state.
// Note that this does not contain a geth state.StateDatabase, as it is not compatible with the
// IPFS v0 blockstore nor the leaf-key indexed SQL schema.
2020-01-16 23:21:49 +00:00
type Backend struct {
2020-10-20 20:33:18 +00:00
// underlying postgres db
2022-03-10 09:53:03 +00:00
DB * sqlx . DB
2020-10-20 20:33:18 +00:00
// postgres db interfaces
2023-03-03 00:27:30 +00:00
Retriever * Retriever
2020-10-20 20:33:18 +00:00
// ethereum interfaces
2023-04-14 06:26:46 +00:00
EthDB ethdb . Database
// We use this state.Database for eth_call and any place we don't need trie access
2024-05-29 12:29:55 +00:00
IpldDirectStateDatabase ipld_direct_state . Database
2023-04-14 06:26:46 +00:00
// We use this where state must be accessed by trie
IpldTrieStateDatabase ipld_trie_state . Database
2020-10-20 20:33:18 +00:00
Config * Config
}
type Config struct {
2021-09-21 12:10:55 +00:00
ChainConfig * params . ChainConfig
VMConfig vm . Config
RPCGasCap * big . Int
GroupCacheConfig * shared . GroupCacheConfig
2020-01-16 23:21:49 +00:00
}
2023-03-13 23:23:49 +00:00
func NewEthBackend ( db * sqlx . DB , c * Config ) ( * Backend , error ) {
2021-09-21 12:10:55 +00:00
gcc := c . GroupCacheConfig
groupName := gcc . StateDB . Name
if groupName == "" {
groupName = StateDBGroupCacheName
}
2023-03-03 00:27:30 +00:00
r := NewRetriever ( db )
2022-03-10 09:53:03 +00:00
ethDB := ipfsethdb . NewDatabase ( db , ipfsethdb . CacheConfig {
2021-09-21 12:10:55 +00:00
Name : groupName ,
Size : gcc . StateDB . CacheSizeInMB * 1024 * 1024 ,
ExpiryDuration : time . Minute * time . Duration ( gcc . StateDB . CacheExpiryInMins ) ,
} )
2021-12-29 20:57:21 +00:00
logStateDBStatsOnTimer ( ethDB . ( * ipfsethdb . Database ) , gcc )
2023-04-14 06:26:46 +00:00
driver := ipld_sql . NewSQLXDriverFromPool ( context . Background ( ) , db )
2020-01-16 23:21:49 +00:00
return & Backend {
2023-04-14 06:26:46 +00:00
DB : db ,
Retriever : r ,
EthDB : ethDB ,
2024-05-29 12:29:55 +00:00
IpldDirectStateDatabase : ipld_direct_state . NewDatabase ( driver ) ,
2023-04-14 06:26:46 +00:00
IpldTrieStateDatabase : ipld_trie_state . NewDatabase ( ethDB ) ,
Config : c ,
2020-01-17 23:16:01 +00:00
} , nil
2020-01-16 23:21:49 +00:00
}
2020-10-26 13:58:37 +00:00
// ChainDb returns the backend's underlying chain database
func ( b * Backend ) ChainDb ( ) ethdb . Database {
return b . EthDB
}
2023-06-16 16:49:56 +00:00
func ( b * Backend ) NormalizeBlockNumber ( blockNumber rpc . BlockNumber ) ( int64 , error ) {
2020-01-16 23:21:49 +00:00
var err error
2020-05-01 21:25:58 +00:00
number := blockNumber . Int64 ( )
2020-01-16 23:21:49 +00:00
if blockNumber == rpc . LatestBlockNumber {
2020-02-20 22:12:52 +00:00
number , err = b . Retriever . RetrieveLastBlockNumber ( )
2020-01-16 23:21:49 +00:00
if err != nil {
2023-04-14 06:26:46 +00:00
return 0 , err
2020-01-16 23:21:49 +00:00
}
}
2020-10-20 20:33:18 +00:00
if blockNumber == rpc . EarliestBlockNumber {
number , err = b . Retriever . RetrieveFirstBlockNumber ( )
if err != nil {
2023-04-14 06:26:46 +00:00
return 0 , err
2020-10-20 20:33:18 +00:00
}
}
2020-01-16 23:21:49 +00:00
if blockNumber == rpc . PendingBlockNumber {
2023-04-14 06:26:46 +00:00
return 0 , errPendingBlockNumber
2020-01-16 23:21:49 +00:00
}
2020-10-20 20:33:18 +00:00
if number < 0 {
2023-04-14 06:26:46 +00:00
return 0 , errNegativeBlockNumber
}
return number , nil
}
// HeaderByNumber gets the canonical header for the provided block number
func ( b * Backend ) HeaderByNumber ( ctx context . Context , blockNumber rpc . BlockNumber ) ( * types . Header , error ) {
2023-06-16 16:49:56 +00:00
number , err := b . NormalizeBlockNumber ( blockNumber )
2023-04-14 06:26:46 +00:00
if err != nil {
return nil , err
2020-10-20 20:33:18 +00:00
}
_ , canonicalHeaderRLP , err := b . GetCanonicalHeader ( uint64 ( number ) )
if err != nil {
return nil , err
}
header := new ( types . Header )
return header , rlp . DecodeBytes ( canonicalHeaderRLP , header )
}
2020-05-01 21:25:58 +00:00
2020-10-20 20:33:18 +00:00
// HeaderByHash gets the header for the provided block hash
func ( b * Backend ) HeaderByHash ( ctx context . Context , hash common . Hash ) ( * types . Header , error ) {
2023-04-14 06:26:46 +00:00
_ , headerRLP , err := b . Retriever . RetrieveHeaderByHash ( hash )
2020-10-20 20:33:18 +00:00
if err != nil {
return nil , err
2020-08-11 03:53:01 +00:00
}
header := new ( types . Header )
2020-10-20 20:33:18 +00:00
return header , rlp . DecodeBytes ( headerRLP , header )
2020-01-16 23:21:49 +00:00
}
2020-10-26 13:58:37 +00:00
// HeaderByNumberOrHash gets the header for the provided block hash or number
func ( b * Backend ) HeaderByNumberOrHash ( ctx context . Context , blockNrOrHash rpc . BlockNumberOrHash ) ( * types . Header , error ) {
if blockNr , ok := blockNrOrHash . Number ( ) ; ok {
return b . HeaderByNumber ( ctx , blockNr )
}
if hash , ok := blockNrOrHash . Hash ( ) ; ok {
header , err := b . HeaderByHash ( ctx , hash )
if err != nil {
return nil , err
}
if header == nil {
2023-04-14 06:26:46 +00:00
return nil , errHeaderHashNotFound
2021-04-16 13:02:04 +00:00
}
2023-04-14 06:26:46 +00:00
if blockNrOrHash . RequireCanonical {
canonicalHash , err := b . GetCanonicalHash ( header . Number . Uint64 ( ) )
if err != nil {
return nil , err
}
if canonicalHash != hash {
return nil , errors . New ( "hash is not currently canonical" )
}
2020-10-26 13:58:37 +00:00
}
return header , nil
}
return nil , errors . New ( "invalid arguments; neither block nor hash specified" )
}
2022-06-17 14:45:54 +00:00
func ( b * Backend ) PendingBlockAndReceipts ( ) ( * types . Block , types . Receipts ) {
return nil , nil
}
2020-10-20 20:33:18 +00:00
// GetTd gets the total difficulty at the given block hash
2020-01-21 19:12:35 +00:00
func ( b * Backend ) GetTd ( blockHash common . Hash ) ( * big . Int , error ) {
var tdStr string
2020-10-26 13:58:37 +00:00
err := b . DB . Get ( & tdStr , RetrieveTD , blockHash . String ( ) )
2020-01-21 19:12:35 +00:00
if err != nil {
return nil , err
}
td , ok := new ( big . Int ) . SetString ( tdStr , 10 )
if ! ok {
return nil , errors . New ( "total difficulty retrieved from Postgres cannot be converted to an integer" )
}
return td , nil
}
2022-09-21 11:45:03 +00:00
// ChainConfig returns the active chain configuration.
func ( b * Backend ) ChainConfig ( ) * params . ChainConfig {
return b . Config . ChainConfig
}
2020-10-26 13:58:37 +00:00
// CurrentBlock returns the current block
2021-04-19 21:52:58 +00:00
func ( b * Backend ) CurrentBlock ( ) ( * types . Block , error ) {
block , err := b . BlockByNumber ( context . Background ( ) , rpc . LatestBlockNumber )
return block , err
2020-10-26 13:58:37 +00:00
}
// BlockByNumberOrHash returns block by number or hash
func ( b * Backend ) BlockByNumberOrHash ( ctx context . Context , blockNrOrHash rpc . BlockNumberOrHash ) ( * types . Block , error ) {
if blockNr , ok := blockNrOrHash . Number ( ) ; ok {
return b . BlockByNumber ( ctx , blockNr )
2020-01-21 19:12:35 +00:00
}
2020-10-26 13:58:37 +00:00
if hash , ok := blockNrOrHash . Hash ( ) ; ok {
header , err := b . HeaderByHash ( ctx , hash )
if err != nil {
2020-01-21 19:12:35 +00:00
return nil , err
}
2020-10-26 13:58:37 +00:00
if header == nil {
2023-04-14 06:26:46 +00:00
return nil , errHeaderHashNotFound
2020-10-26 13:58:37 +00:00
}
2023-04-14 06:26:46 +00:00
if blockNrOrHash . RequireCanonical {
canonicalHash , err := b . GetCanonicalHash ( header . Number . Uint64 ( ) )
if err != nil {
return nil , err
}
if canonicalHash != hash {
return nil , errors . New ( "hash is not currently canonical" )
}
2020-10-26 13:58:37 +00:00
}
block , err := b . BlockByHash ( ctx , hash )
if err != nil {
return nil , err
}
if block == nil {
return nil , errors . New ( "header found, but block body is missing" )
}
return block , nil
2020-01-21 19:12:35 +00:00
}
2020-10-26 13:58:37 +00:00
return nil , errors . New ( "invalid arguments; neither block nor hash specified" )
2020-01-16 23:21:49 +00:00
}
2020-01-26 19:55:26 +00:00
2022-08-23 07:12:19 +00:00
// BlockByNumber returns the requested canonical block
2020-01-26 19:55:26 +00:00
func ( b * Backend ) BlockByNumber ( ctx context . Context , blockNumber rpc . BlockNumber ) ( * types . Block , error ) {
2023-06-16 16:49:56 +00:00
number , err := b . NormalizeBlockNumber ( blockNumber )
2023-04-14 06:26:46 +00:00
if err != nil {
2024-05-10 09:24:34 +00:00
return nil , fmt . Errorf ( "failed to normalize block number: %w" , err )
2020-10-20 20:33:18 +00:00
}
2021-04-16 13:02:04 +00:00
canonicalHash , err := b . GetCanonicalHash ( uint64 ( number ) )
2020-10-20 20:33:18 +00:00
if err != nil {
2021-04-19 10:16:59 +00:00
if err == sql . ErrNoRows {
return nil , nil
}
2020-10-20 20:33:18 +00:00
return nil , err
}
2020-05-01 21:25:58 +00:00
2022-08-23 07:12:19 +00:00
return b . BlockByHash ( ctx , canonicalHash )
}
// BlockByHash returns the requested block
func ( b * Backend ) BlockByHash ( ctx context . Context , hash common . Hash ) ( * types . Block , error ) {
2020-05-01 21:25:58 +00:00
// Begin tx
2020-05-01 16:07:47 +00:00
tx , err := b . DB . Beginx ( )
if err != nil {
return nil , err
}
2023-05-31 22:57:42 +00:00
// we must avoid overshadowing `err` so that we update the value of the variable inside the defer
2020-05-01 21:25:58 +00:00
defer func ( ) {
if p := recover ( ) ; p != nil {
2022-03-10 12:35:19 +00:00
shared . Rollback ( tx )
2020-05-01 21:25:58 +00:00
panic ( p )
} else if err != nil {
2022-03-10 12:35:19 +00:00
shared . Rollback ( tx )
2020-05-01 21:25:58 +00:00
} else {
err = tx . Commit ( )
}
} ( )
2020-02-20 22:13:19 +00:00
2022-08-23 07:12:19 +00:00
// Fetch header
2023-05-31 22:57:42 +00:00
var header * types . Header
header , err = b . GetHeaderByBlockHash ( tx , hash )
2020-01-26 19:55:26 +00:00
if err != nil {
2022-08-23 07:12:19 +00:00
log . Error ( "error fetching header: " , err )
2021-04-19 10:16:59 +00:00
if err == sql . ErrNoRows {
return nil , nil
}
2020-01-26 19:55:26 +00:00
return nil , err
}
2022-06-28 11:10:07 +00:00
2022-11-04 04:32:09 +00:00
blockNumber := header . Number . Uint64 ( )
2022-08-23 07:12:19 +00:00
// Fetch uncles
2023-05-31 22:57:42 +00:00
var uncles [ ] * types . Header
uncles , err = b . GetUnclesByBlockHashAndNumber ( tx , hash , blockNumber )
2022-08-23 07:12:19 +00:00
if err != nil && err != sql . ErrNoRows {
log . Error ( "error fetching uncles: " , err )
2020-01-26 19:55:26 +00:00
return nil , err
}
2022-06-28 11:10:07 +00:00
2023-03-13 17:41:08 +00:00
// We should not have any non-determinism in the ordering of the uncles returned to us now
uncleHash := types . CalcUncleHash ( uncles )
// Check if uncle hash matches expected hash
if uncleHash != header . UncleHash {
log . Error ( "uncle hash mismatch for block hash: " , hash . Hex ( ) )
2023-05-31 22:57:42 +00:00
err = fmt . Errorf ( "uncle hash mismatch for block hash: %s" , hash . Hex ( ) )
return nil , err
2022-08-25 10:24:32 +00:00
}
2022-08-23 07:12:19 +00:00
// Fetch transactions
2023-05-31 22:57:42 +00:00
var transactions types . Transactions
transactions , err = b . GetTransactionsByBlockHashAndNumber ( tx , hash , blockNumber )
2022-08-23 07:12:19 +00:00
if err != nil && err != sql . ErrNoRows {
log . Error ( "error fetching transactions: " , err )
2020-01-26 19:55:26 +00:00
return nil , err
}
2022-08-23 07:12:19 +00:00
// Fetch receipts
2023-05-31 22:57:42 +00:00
var receipts types . Receipts
receipts , err = b . GetReceiptsByBlockHashAndNumber ( tx , hash , blockNumber )
2022-08-23 07:12:19 +00:00
if err != nil && err != sql . ErrNoRows {
log . Error ( "error fetching receipts: " , err )
2020-01-26 19:55:26 +00:00
return nil , err
}
2021-09-16 12:49:42 +00:00
2024-05-10 09:24:34 +00:00
// Fetch withdrawals
2024-05-29 12:29:55 +00:00
var withdrawals types . Withdrawals
if b . Config . ChainConfig . IsShanghai ( header . Number , header . Time ) {
2024-05-10 09:24:34 +00:00
withdrawals , err = b . GetWithdrawals ( tx , hash , blockNumber )
if err != nil && err != sql . ErrNoRows {
log . Error ( "error fetching withdrawals: " , err )
return nil , err
}
} else if len ( withdrawals ) > 0 {
return nil , errors . New ( "withdrawals set before Shanghai activation" )
2024-05-29 12:29:55 +00:00
}
2020-01-26 19:55:26 +00:00
// Compose everything together into a complete block
2024-05-29 12:29:55 +00:00
return types . NewBlockWithWithdrawals ( header , transactions , uncles , receipts , withdrawals , trie . NewEmpty ( nil ) ) , err
2020-01-26 19:55:26 +00:00
}
2022-08-23 07:12:19 +00:00
// GetHeaderByBlockHash retrieves header for a provided block hash
func ( b * Backend ) GetHeaderByBlockHash ( tx * sqlx . Tx , hash common . Hash ) ( * types . Header , error ) {
2023-04-14 06:26:46 +00:00
_ , headerRLP , err := b . Retriever . RetrieveHeaderByHash2 ( tx , hash )
2020-01-26 19:55:26 +00:00
if err != nil {
return nil , err
}
2020-05-01 21:25:58 +00:00
2022-08-23 07:12:19 +00:00
header := new ( types . Header )
return header , rlp . DecodeBytes ( headerRLP , header )
}
2020-05-01 21:25:58 +00:00
2023-03-31 14:25:35 +00:00
// CurrentHeader returns the current block's header
func ( b * Backend ) CurrentHeader ( ) * types . Header {
2023-04-14 06:26:46 +00:00
header , err := b . HeaderByNumber ( context . Background ( ) , rpc . LatestBlockNumber )
2023-03-31 14:25:35 +00:00
if err != nil {
return nil
}
2023-04-14 06:26:46 +00:00
return header
2023-03-31 14:25:35 +00:00
}
// GetBody returns the the body for the provided block hash and number
func ( b * Backend ) GetBody ( ctx context . Context , hash common . Hash , number rpc . BlockNumber ) ( * types . Body , error ) {
if number < 0 || hash == ( common . Hash { } ) {
return nil , errors . New ( "invalid arguments; expect hash and no special block numbers" )
}
2023-04-14 06:26:46 +00:00
block , err := b . BlockByHash ( ctx , hash )
if err != nil {
return nil , err
}
if block != nil {
2023-03-31 14:25:35 +00:00
return block . Body ( ) , nil
}
return nil , errors . New ( "block body not found" )
}
2022-08-23 07:12:19 +00:00
// GetUnclesByBlockHash retrieves uncles for a provided block hash
func ( b * Backend ) GetUnclesByBlockHash ( tx * sqlx . Tx , hash common . Hash ) ( [ ] * types . Header , error ) {
2023-03-03 00:27:30 +00:00
_ , uncleBytes , err := b . Retriever . RetrieveUnclesByBlockHash ( tx , hash )
2020-01-26 19:55:26 +00:00
if err != nil {
return nil , err
}
2022-08-23 07:12:19 +00:00
2023-03-13 17:41:08 +00:00
uncles := make ( [ ] * types . Header , 0 )
2023-04-14 06:26:46 +00:00
if err := rlp . DecodeBytes ( uncleBytes , & uncles ) ; err != nil {
2023-03-13 17:41:08 +00:00
return nil , err
2020-01-26 19:55:26 +00:00
}
2022-08-23 07:12:19 +00:00
return uncles , nil
}
2022-11-04 04:32:09 +00:00
// GetUnclesByBlockHashAndNumber retrieves uncles for a provided block hash and number
func ( b * Backend ) GetUnclesByBlockHashAndNumber ( tx * sqlx . Tx , hash common . Hash , number uint64 ) ( [ ] * types . Header , error ) {
2023-03-03 00:27:30 +00:00
_ , uncleBytes , err := b . Retriever . RetrieveUncles ( tx , hash , number )
2022-11-04 04:32:09 +00:00
if err != nil {
return nil , err
}
2023-03-13 17:41:08 +00:00
uncles := make ( [ ] * types . Header , 0 )
2023-04-14 06:26:46 +00:00
if err := rlp . DecodeBytes ( uncleBytes , & uncles ) ; err != nil {
2023-03-13 17:41:08 +00:00
return nil , err
2022-11-04 04:32:09 +00:00
}
return uncles , nil
}
2022-08-23 07:12:19 +00:00
// GetTransactionsByBlockHash retrieves transactions for a provided block hash
func ( b * Backend ) GetTransactionsByBlockHash ( tx * sqlx . Tx , hash common . Hash ) ( types . Transactions , error ) {
2023-03-03 00:27:30 +00:00
_ , transactionBytes , err := b . Retriever . RetrieveTransactionsByBlockHash ( tx , hash )
2020-01-26 19:55:26 +00:00
if err != nil {
return nil , err
}
2022-08-23 07:12:19 +00:00
txs := make ( types . Transactions , len ( transactionBytes ) )
for i , txBytes := range transactionBytes {
var tx types . Transaction
if err := tx . UnmarshalBinary ( txBytes ) ; err != nil {
2020-01-26 19:55:26 +00:00
return nil , err
}
2022-08-23 07:12:19 +00:00
txs [ i ] = & tx
2020-01-26 19:55:26 +00:00
}
2022-08-23 07:12:19 +00:00
return txs , nil
}
2022-11-04 04:32:09 +00:00
// GetTransactionsByBlockHashAndNumber retrieves transactions for a provided block hash and number
func ( b * Backend ) GetTransactionsByBlockHashAndNumber ( tx * sqlx . Tx , hash common . Hash , number uint64 ) ( types . Transactions , error ) {
2023-03-03 00:27:30 +00:00
_ , transactionBytes , err := b . Retriever . RetrieveTransactions ( tx , hash , number )
2022-11-04 04:32:09 +00:00
if err != nil {
return nil , err
}
txs := make ( types . Transactions , len ( transactionBytes ) )
for i , txBytes := range transactionBytes {
var tx types . Transaction
if err := tx . UnmarshalBinary ( txBytes ) ; err != nil {
return nil , err
}
txs [ i ] = & tx
}
return txs , nil
}
2022-08-23 07:12:19 +00:00
// GetReceiptsByBlockHash retrieves receipts for a provided block hash
func ( b * Backend ) GetReceiptsByBlockHash ( tx * sqlx . Tx , hash common . Hash ) ( types . Receipts , error ) {
2023-03-03 00:27:30 +00:00
_ , receiptBytes , txs , err := b . Retriever . RetrieveReceiptsByBlockHash ( tx , hash )
2020-01-26 19:55:26 +00:00
if err != nil {
return nil , err
}
2022-08-23 07:12:19 +00:00
rcts := make ( types . Receipts , len ( receiptBytes ) )
for i , rctBytes := range receiptBytes {
rct := new ( types . Receipt )
if err := rct . UnmarshalBinary ( rctBytes ) ; err != nil {
2020-01-26 19:55:26 +00:00
return nil , err
}
2022-08-23 07:12:19 +00:00
rct . TxHash = txs [ i ]
rcts [ i ] = rct
2020-01-26 19:55:26 +00:00
}
2022-08-23 07:12:19 +00:00
return rcts , nil
2020-01-26 19:55:26 +00:00
}
2022-11-04 04:32:09 +00:00
// GetReceiptsByBlockHashAndNumber retrieves receipts for a provided block hash and number
func ( b * Backend ) GetReceiptsByBlockHashAndNumber ( tx * sqlx . Tx , hash common . Hash , number uint64 ) ( types . Receipts , error ) {
2023-03-03 00:27:30 +00:00
_ , receiptBytes , txs , err := b . Retriever . RetrieveReceipts ( tx , hash , number )
2022-11-04 04:32:09 +00:00
if err != nil {
return nil , err
}
rcts := make ( types . Receipts , len ( receiptBytes ) )
for i , rctBytes := range receiptBytes {
rct := new ( types . Receipt )
if err := rct . UnmarshalBinary ( rctBytes ) ; err != nil {
return nil , err
}
rct . TxHash = txs [ i ]
rcts [ i ] = rct
}
return rcts , nil
}
2024-05-10 09:24:34 +00:00
// GetWithdrawals retrieves transactions for a provided block hash and number
func ( b * Backend ) GetWithdrawals ( tx * sqlx . Tx , hash common . Hash , number uint64 ) ( types . Withdrawals , error ) {
_ , rlpBytes , err := b . Retriever . RetrieveWithdrawals ( tx , hash , number )
if err != nil {
return nil , err
}
withdrawals := make ( types . Withdrawals , len ( rlpBytes ) )
for i , bytes := range rlpBytes {
withdrawals [ i ] = new ( types . Withdrawal )
if err := rlp . DecodeBytes ( bytes , withdrawals [ i ] ) ; err != nil {
return nil , err
}
}
return withdrawals , nil
}
2020-01-26 19:55:26 +00:00
// GetTransaction retrieves a tx by hash
// It also returns the blockhash, blocknumber, and tx index associated with the transaction
2024-05-29 12:29:55 +00:00
func ( b * Backend ) GetTransaction ( ctx context . Context , txHash common . Hash ) ( bool , * types . Transaction , common . Hash , uint64 , uint64 , error ) {
2022-07-12 08:10:45 +00:00
type txRes struct {
2020-08-11 03:53:01 +00:00
Data [ ] byte ` db:"data" `
2022-07-12 08:10:45 +00:00
HeaderID string ` db:"header_id" `
2020-08-11 03:53:01 +00:00
BlockNumber uint64 ` db:"block_number" `
Index uint64 ` db:"index" `
2020-05-01 16:07:47 +00:00
}
2022-07-12 08:10:45 +00:00
var res = make ( [ ] txRes , 0 )
if err := b . DB . Select ( & res , RetrieveRPCTransaction , txHash . String ( ) ) ; err != nil {
2024-05-29 12:29:55 +00:00
return false , nil , common . Hash { } , 0 , 0 , err
2020-05-01 16:07:47 +00:00
}
2022-07-12 08:10:45 +00:00
if len ( res ) == 0 {
2024-05-29 12:29:55 +00:00
return false , nil , common . Hash { } , 0 , 0 , errTxHashNotFound
2022-07-12 08:10:45 +00:00
} else if len ( res ) > 1 {
// a transaction can be part of a only one canonical block
2024-05-29 12:29:55 +00:00
return false , nil , common . Hash { } , 0 , 0 , errTxHashInMultipleBlocks
2022-07-12 08:10:45 +00:00
}
2020-02-20 22:13:19 +00:00
var transaction types . Transaction
2022-07-12 08:10:45 +00:00
if err := transaction . UnmarshalBinary ( res [ 0 ] . Data ) ; err != nil {
2024-05-29 12:29:55 +00:00
return false , nil , common . Hash { } , 0 , 0 , err
2020-01-26 19:55:26 +00:00
}
2022-07-12 08:10:45 +00:00
2024-05-29 12:29:55 +00:00
return true , & transaction , common . HexToHash ( res [ 0 ] . HeaderID ) , res [ 0 ] . BlockNumber , res [ 0 ] . Index , nil
2020-01-26 19:55:26 +00:00
}
2020-04-02 03:34:06 +00:00
2020-10-26 13:58:37 +00:00
// GetReceipts retrieves receipts for provided block hash
func ( b * Backend ) GetReceipts ( ctx context . Context , hash common . Hash ) ( types . Receipts , error ) {
2022-08-23 07:12:19 +00:00
// Begin tx
tx , err := b . DB . Beginx ( )
if err != nil {
return nil , err
}
2023-05-31 22:57:42 +00:00
// we must avoid overshadowing `err` so that we update the value of the variable inside the defer
2022-08-23 07:12:19 +00:00
defer func ( ) {
if p := recover ( ) ; p != nil {
shared . Rollback ( tx )
panic ( p )
} else if err != nil {
shared . Rollback ( tx )
} else {
err = tx . Commit ( )
}
} ( )
2023-05-31 22:57:42 +00:00
var blockNumber uint64
blockNumber , err = b . Retriever . RetrieveBlockNumberByHash ( tx , hash )
2020-10-26 13:58:37 +00:00
if err != nil {
return nil , err
2020-04-02 03:34:06 +00:00
}
2022-11-04 04:32:09 +00:00
2023-05-31 22:57:42 +00:00
var receipts types . Receipts
receipts , err = b . GetReceiptsByBlockHashAndNumber ( tx , hash , blockNumber )
return receipts , err
2020-04-02 03:34:06 +00:00
}
2020-10-26 13:58:37 +00:00
// GetLogs returns all the logs for the given block hash
2022-09-01 22:37:51 +00:00
func ( b * Backend ) GetLogs ( ctx context . Context , hash common . Hash , number uint64 ) ( [ ] [ ] * types . Log , error ) {
2022-08-23 07:12:19 +00:00
// Begin tx
tx , err := b . DB . Beginx ( )
if err != nil {
return nil , err
}
2023-05-31 22:57:42 +00:00
// we must avoid overshadowing `err` so that we update the value of the variable inside the defer
2022-08-23 07:12:19 +00:00
defer func ( ) {
if p := recover ( ) ; p != nil {
shared . Rollback ( tx )
panic ( p )
} else if err != nil {
shared . Rollback ( tx )
} else {
err = tx . Commit ( )
}
} ( )
2023-05-31 22:57:42 +00:00
var receiptBytes [ ] [ ] byte
var txs [ ] common . Hash
_ , receiptBytes , txs , err = b . Retriever . RetrieveReceipts ( tx , hash , number )
2020-04-02 03:34:06 +00:00
if err != nil {
return nil , err
}
2020-10-26 13:58:37 +00:00
logs := make ( [ ] [ ] * types . Log , len ( receiptBytes ) )
for i , rctBytes := range receiptBytes {
var rct types . Receipt
2023-05-31 22:57:42 +00:00
if err = rlp . DecodeBytes ( rctBytes , & rct ) ; err != nil {
2020-10-26 13:58:37 +00:00
return nil , err
}
2021-05-21 03:30:38 +00:00
2021-07-26 10:13:38 +00:00
for _ , log := range rct . Logs {
log . TxHash = txs [ i ]
}
2020-10-26 13:58:37 +00:00
logs [ i ] = rct . Logs
2020-04-02 03:34:06 +00:00
}
2023-05-31 22:57:42 +00:00
return logs , err
2020-04-02 03:34:06 +00:00
}
2023-04-14 06:26:46 +00:00
// IPLDStateDBAndHeaderByNumberOrHash returns the statedb and header for the provided block number or hash
func ( b * Backend ) IPLDDirectStateDBAndHeaderByNumberOrHash ( ctx context . Context , blockNrOrHash rpc . BlockNumberOrHash ) ( * ipld_direct_state . StateDB , * types . Header , error ) {
if number , ok := blockNrOrHash . Number ( ) ; ok {
// Pending state is only known by the miner
if number == rpc . PendingBlockNumber {
return nil , nil , errPendingBlockNumber
}
// Otherwise resolve the block number and return its state
header , err := b . HeaderByNumber ( ctx , number )
2020-09-25 13:58:18 +00:00
if err != nil {
return nil , nil , err
}
if header == nil {
2023-04-14 06:26:46 +00:00
return nil , nil , errHeaderNotFound
2020-09-25 13:58:18 +00:00
}
2023-04-14 06:26:46 +00:00
// TODO use GetCanonicalHeaderAndHash to avoid rehashing
statedb , err := ipld_direct_state . New ( header . Hash ( ) , b . IpldDirectStateDatabase )
return statedb , header , err
}
if hash , ok := blockNrOrHash . Hash ( ) ; ok {
header , err := b . HeaderByHash ( ctx , hash )
2021-04-16 13:02:04 +00:00
if err != nil {
return nil , nil , err
}
2023-04-14 06:26:46 +00:00
if header == nil {
return nil , nil , errHeaderHashNotFound
}
if blockNrOrHash . RequireCanonical {
canonicalHash , err := b . GetCanonicalHash ( header . Number . Uint64 ( ) )
if err != nil {
return nil , nil , err
}
if canonicalHash != hash {
return nil , nil , errors . New ( "hash is not currently canonical" )
}
2020-09-25 13:58:18 +00:00
}
2023-04-14 06:26:46 +00:00
statedb , err := ipld_direct_state . New ( header . Hash ( ) , b . IpldDirectStateDatabase )
return statedb , header , err
2020-09-25 13:58:18 +00:00
}
return nil , nil , errors . New ( "invalid arguments; neither block nor hash specified" )
}
2023-03-13 12:51:03 +00:00
// IPLDStateDBAndHeaderByNumberOrHash returns the statedb and header for the provided block number or hash
2023-04-14 06:26:46 +00:00
func ( b * Backend ) IPLDTrieStateDBAndHeaderByNumberOrHash ( ctx context . Context , blockNrOrHash rpc . BlockNumberOrHash ) ( * ipld_trie_state . StateDB , * types . Header , error ) {
var header * types . Header
if number , ok := blockNrOrHash . Number ( ) ; ok {
// Pending state is only known by the miner
if number == rpc . PendingBlockNumber {
return nil , nil , errPendingBlockNumber
}
// Otherwise resolve the block number and return its state
blockHash , err := b . GetCanonicalHash ( uint64 ( number ) )
if err != nil {
return nil , nil , err
}
header , err = b . HeaderByHash ( ctx , blockHash )
2023-03-13 12:51:03 +00:00
if err != nil {
return nil , nil , err
}
if header == nil {
2023-04-14 06:26:46 +00:00
return nil , nil , errHeaderNotFound
2023-03-13 12:51:03 +00:00
}
2023-04-14 06:26:46 +00:00
} else if hash , ok := blockNrOrHash . Hash ( ) ; ok {
var err error
header , err = b . HeaderByHash ( ctx , hash )
2023-03-13 12:51:03 +00:00
if err != nil {
return nil , nil , err
}
2023-04-14 06:26:46 +00:00
if header == nil {
return nil , nil , errHeaderHashNotFound
2023-03-13 12:51:03 +00:00
}
2023-04-14 06:26:46 +00:00
if blockNrOrHash . RequireCanonical {
canonicalHash , err := b . GetCanonicalHash ( header . Number . Uint64 ( ) )
if err != nil {
return nil , nil , err
}
if canonicalHash != hash {
return nil , nil , errors . New ( "hash is not currently canonical" )
}
}
} else {
return nil , nil , errors . New ( "invalid arguments; neither block nor hash specified" )
2020-09-25 13:58:18 +00:00
}
2023-04-14 06:26:46 +00:00
statedb , err := ipld_trie_state . New ( header . Root , b . IpldTrieStateDatabase , nil )
return statedb , header , err
2020-09-25 13:58:18 +00:00
}
2020-10-20 20:33:18 +00:00
// GetCanonicalHash gets the canonical hash for the provided number, if there is one
2021-04-16 13:02:04 +00:00
func ( b * Backend ) GetCanonicalHash ( number uint64 ) ( common . Hash , error ) {
2020-10-20 20:33:18 +00:00
var hashResult string
if err := b . DB . Get ( & hashResult , RetrieveCanonicalBlockHashByNumber , number ) ; err != nil {
2021-04-16 13:02:04 +00:00
return common . Hash { } , err
2020-10-20 20:33:18 +00:00
}
2021-04-16 13:02:04 +00:00
return common . HexToHash ( hashResult ) , nil
2020-10-20 20:33:18 +00:00
}
// GetCanonicalHeader gets the canonical header for the provided number, if there is one
func ( b * Backend ) GetCanonicalHeader ( number uint64 ) ( string , [ ] byte , error ) {
2023-04-14 06:26:46 +00:00
type rowResult struct {
CID string
Data [ ] byte
}
2020-10-20 20:33:18 +00:00
headerResult := new ( rowResult )
2023-04-14 06:26:46 +00:00
return headerResult . CID , headerResult . Data ,
b . DB . QueryRowx ( RetrieveCanonicalHeaderByNumber , number ) . StructScan ( headerResult )
}
// GetCanonicalHeader gets the canonical hash and header for the provided number, if they exist
func ( b * Backend ) GetCanonicalHeaderAndHash ( number uint64 ) ( string , [ ] byte , error ) {
type rowResult struct {
Data [ ] byte
BlockHash string
}
headerResult := new ( rowResult )
return headerResult . BlockHash , headerResult . Data ,
b . DB . QueryRowx ( RetrieveCanonicalHeaderAndHashByNumber , number ) . StructScan ( headerResult )
2020-10-20 20:33:18 +00:00
}
// GetEVM constructs and returns a vm.EVM
2023-04-14 06:26:46 +00:00
func ( b * Backend ) GetEVM ( ctx context . Context , msg * core . Message , state vm . StateDB , header * types . Header ) ( * vm . EVM , func ( ) error , error ) {
2021-09-29 05:27:11 +00:00
vmError := func ( ) error { return nil }
2021-02-19 20:23:45 +00:00
txContext := core . NewEVMTxContext ( msg )
2023-03-31 14:25:35 +00:00
evmCtx := core . NewEVMBlockContext ( header , b , nil )
return vm . NewEVM ( evmCtx , txContext , state , b . Config . ChainConfig , b . Config . VMConfig ) , vmError , nil
2020-10-20 20:33:18 +00:00
}
2020-10-30 03:07:39 +00:00
// GetAccountByNumberOrHash returns the account object for the provided address at the block corresponding to the provided number or hash
2021-10-07 09:35:11 +00:00
func ( b * Backend ) GetAccountByNumberOrHash ( ctx context . Context , address common . Address , blockNrOrHash rpc . BlockNumberOrHash ) ( * types . StateAccount , error ) {
2020-10-30 03:07:39 +00:00
if blockNr , ok := blockNrOrHash . Number ( ) ; ok {
2021-04-21 15:00:01 +00:00
return b . GetAccountByNumber ( ctx , address , blockNr )
2020-10-30 03:07:39 +00:00
}
if hash , ok := blockNrOrHash . Hash ( ) ; ok {
return b . GetAccountByHash ( ctx , address , hash )
}
return nil , errors . New ( "invalid arguments; neither block nor hash specified" )
}
// GetAccountByNumber returns the account object for the provided address at the canonical block at the provided height
2021-10-07 09:35:11 +00:00
func ( b * Backend ) GetAccountByNumber ( ctx context . Context , address common . Address , blockNumber rpc . BlockNumber ) ( * types . StateAccount , error ) {
2021-04-21 15:00:01 +00:00
var err error
number := blockNumber . Int64 ( )
if blockNumber == rpc . LatestBlockNumber {
number , err = b . Retriever . RetrieveLastBlockNumber ( )
if err != nil {
return nil , err
}
}
if blockNumber == rpc . EarliestBlockNumber {
number , err = b . Retriever . RetrieveFirstBlockNumber ( )
if err != nil {
return nil , err
}
}
if blockNumber == rpc . PendingBlockNumber {
return nil , errPendingBlockNumber
}
hash , err := b . GetCanonicalHash ( uint64 ( number ) )
2021-06-09 18:50:12 +00:00
if err == sql . ErrNoRows {
2021-06-10 06:20:25 +00:00
return nil , errHeaderNotFound
2021-06-03 16:49:48 +00:00
} else if err != nil {
return nil , err
2020-10-30 03:07:39 +00:00
}
2021-06-03 16:49:48 +00:00
2020-10-30 03:07:39 +00:00
return b . GetAccountByHash ( ctx , address , hash )
}
// GetAccountByHash returns the account object for the provided address at the block with the provided hash
2021-10-07 09:35:11 +00:00
func ( b * Backend ) GetAccountByHash ( ctx context . Context , address common . Address , hash common . Hash ) ( * types . StateAccount , error ) {
2021-06-03 16:49:48 +00:00
_ , err := b . HeaderByHash ( context . Background ( ) , hash )
if err == sql . ErrNoRows {
2021-06-10 06:20:25 +00:00
return nil , errHeaderHashNotFound
} else if err != nil {
return nil , err
2021-06-03 16:49:48 +00:00
}
2023-04-14 06:26:46 +00:00
acctRecord , err := b . Retriever . RetrieveAccountByAddressAndBlockHash ( address , hash )
2020-10-30 03:07:39 +00:00
if err != nil {
return nil , err
}
2021-06-03 16:49:48 +00:00
2023-04-14 06:26:46 +00:00
balance , ok := new ( big . Int ) . SetString ( acctRecord . Balance , 10 )
if ! ok {
return nil , fmt . Errorf ( "failed to parse balance %s" , acctRecord . Balance )
}
return & types . StateAccount {
Nonce : acctRecord . Nonce ,
2024-05-29 12:29:55 +00:00
Balance : uint256 . MustFromBig ( balance ) ,
2023-04-14 06:26:46 +00:00
Root : common . HexToHash ( acctRecord . Root ) ,
CodeHash : acctRecord . CodeHash ,
} , nil
2020-10-30 03:07:39 +00:00
}
// GetCodeByNumberOrHash returns the byte code for the contract deployed at the provided address at the block with the provided hash or block number
func ( b * Backend ) GetCodeByNumberOrHash ( ctx context . Context , address common . Address , blockNrOrHash rpc . BlockNumberOrHash ) ( [ ] byte , error ) {
if blockNr , ok := blockNrOrHash . Number ( ) ; ok {
2021-04-21 11:16:47 +00:00
return b . GetCodeByNumber ( ctx , address , blockNr )
2020-10-30 03:07:39 +00:00
}
if hash , ok := blockNrOrHash . Hash ( ) ; ok {
return b . GetCodeByHash ( ctx , address , hash )
}
return nil , errors . New ( "invalid arguments; neither block nor hash specified" )
}
// GetCodeByNumber returns the byte code for the contract deployed at the provided address at the canonical block with the provided block number
2021-04-21 15:00:01 +00:00
func ( b * Backend ) GetCodeByNumber ( ctx context . Context , address common . Address , blockNumber rpc . BlockNumber ) ( [ ] byte , error ) {
var err error
number := blockNumber . Int64 ( )
if blockNumber == rpc . LatestBlockNumber {
number , err = b . Retriever . RetrieveLastBlockNumber ( )
2021-04-21 11:16:47 +00:00
if err != nil {
return nil , err
}
}
2021-04-21 15:00:01 +00:00
if blockNumber == rpc . EarliestBlockNumber {
number , err = b . Retriever . RetrieveFirstBlockNumber ( )
if err != nil {
return nil , err
}
}
if blockNumber == rpc . PendingBlockNumber {
return nil , errPendingBlockNumber
}
hash , err := b . GetCanonicalHash ( uint64 ( number ) )
2021-04-16 13:02:04 +00:00
if err != nil {
return nil , err
}
2020-10-30 03:07:39 +00:00
if hash == ( common . Hash { } ) {
2023-04-14 06:26:46 +00:00
return nil , fmt . Errorf ( "no canonical block hash found for provided height (%d)" , number )
2020-10-30 03:07:39 +00:00
}
return b . GetCodeByHash ( ctx , address , hash )
}
// GetCodeByHash returns the byte code for the contract deployed at the provided address at the block with the provided hash
func ( b * Backend ) GetCodeByHash ( ctx context . Context , address common . Address , hash common . Hash ) ( [ ] byte , error ) {
leafKey := crypto . Keccak256Hash ( address . Bytes ( ) )
// Begin tx
tx , err := b . DB . Beginx ( )
if err != nil {
return nil , err
}
2023-05-31 22:57:42 +00:00
// we must avoid overshadowing `err` so that we update the value of the variable inside the defer
2020-10-30 03:07:39 +00:00
defer func ( ) {
if p := recover ( ) ; p != nil {
2022-03-10 12:35:19 +00:00
shared . Rollback ( tx )
2020-10-30 03:07:39 +00:00
panic ( p )
} else if err != nil {
2022-03-10 12:35:19 +00:00
shared . Rollback ( tx )
2020-10-30 03:07:39 +00:00
} else {
err = tx . Commit ( )
}
} ( )
2023-04-14 06:26:46 +00:00
var codeHash string
2021-04-19 13:42:09 +00:00
err = tx . Get ( & codeHash , RetrieveCodeHashByLeafKeyAndBlockHash , leafKey . Hex ( ) , hash . Hex ( ) )
if err != nil {
2020-10-30 03:07:39 +00:00
return nil , err
}
2023-04-14 06:26:46 +00:00
cid := ipld . Keccak256ToCid ( ipld . RawBinary , common . HexToHash ( codeHash ) . Bytes ( ) )
var code [ ] byte
err = tx . Get ( & code , RetrieveCodeByKey , cid . String ( ) )
2020-10-30 03:07:39 +00:00
return code , err
}
2020-10-30 16:54:22 +00:00
// GetStorageByNumberOrHash returns the storage value for the provided contract address an storage key at the block corresponding to the provided number or hash
2021-06-18 06:42:29 +00:00
func ( b * Backend ) GetStorageByNumberOrHash ( ctx context . Context , address common . Address , key common . Hash , blockNrOrHash rpc . BlockNumberOrHash ) ( hexutil . Bytes , error ) {
2020-10-30 16:54:22 +00:00
if blockNr , ok := blockNrOrHash . Number ( ) ; ok {
2021-06-18 06:42:29 +00:00
return b . GetStorageByNumber ( ctx , address , key , blockNr )
2020-10-30 16:54:22 +00:00
}
if hash , ok := blockNrOrHash . Hash ( ) ; ok {
2021-06-18 06:42:29 +00:00
return b . GetStorageByHash ( ctx , address , key , hash )
2020-10-30 16:54:22 +00:00
}
return nil , errors . New ( "invalid arguments; neither block nor hash specified" )
}
// GetStorageByNumber returns the storage value for the provided contract address an storage key at the block corresponding to the provided number
2021-06-18 06:42:29 +00:00
func ( b * Backend ) GetStorageByNumber ( ctx context . Context , address common . Address , key common . Hash , blockNumber rpc . BlockNumber ) ( hexutil . Bytes , error ) {
2021-04-21 15:00:01 +00:00
var err error
number := blockNumber . Int64 ( )
if blockNumber == rpc . LatestBlockNumber {
number , err = b . Retriever . RetrieveLastBlockNumber ( )
if err != nil {
return nil , err
}
}
if blockNumber == rpc . EarliestBlockNumber {
number , err = b . Retriever . RetrieveFirstBlockNumber ( )
if err != nil {
return nil , err
}
}
if blockNumber == rpc . PendingBlockNumber {
return nil , errPendingBlockNumber
}
hash , err := b . GetCanonicalHash ( uint64 ( number ) )
2021-06-10 06:20:25 +00:00
if err == sql . ErrNoRows {
return nil , errHeaderNotFound
} else if err != nil {
2021-04-16 13:02:04 +00:00
return nil , err
}
2021-06-10 06:20:25 +00:00
2021-06-18 06:42:29 +00:00
return b . GetStorageByHash ( ctx , address , key , hash )
2020-10-30 16:54:22 +00:00
}
// GetStorageByHash returns the storage value for the provided contract address an storage key at the block corresponding to the provided hash
2021-06-18 06:42:29 +00:00
func ( b * Backend ) GetStorageByHash ( ctx context . Context , address common . Address , key , hash common . Hash ) ( hexutil . Bytes , error ) {
2021-06-10 06:20:25 +00:00
_ , err := b . HeaderByHash ( context . Background ( ) , hash )
if err == sql . ErrNoRows {
return nil , errHeaderHashNotFound
} else if err != nil {
return nil , err
}
2023-04-14 06:26:46 +00:00
return b . Retriever . RetrieveStorageAtByAddressAndStorageSlotAndBlockHash ( address , key , hash )
2020-10-30 16:54:22 +00:00
}
2022-12-19 08:42:23 +00:00
func ( b * Backend ) GetSlice ( path string , depth int , root common . Hash , storage bool ) ( * GetSliceResponse , error ) {
response := new ( GetSliceResponse )
response . init ( path , depth , root )
// Metadata fields
metaData := metaDataFields { }
startTime := makeTimestamp ( )
2023-04-14 06:26:46 +00:00
var t ipld_trie_state . Trie
var err error
if storage {
2024-05-29 12:29:55 +00:00
// Note 1: once Verkle tries are used, this will be the same as state trie
// Note 2: a dummy hash is passed as owner here, and is only used to signal to ipld-eth-statedb
// that a storage, not state trie is being accessed
t , err = b . IpldTrieStateDatabase . OpenStorageTrie ( common . Hash { } , common . Hash { 1 } , root , nil )
2023-04-14 06:26:46 +00:00
} else {
t , err = b . IpldTrieStateDatabase . OpenTrie ( root )
}
if err != nil {
return nil , err
}
2022-12-19 08:42:23 +00:00
metaData . trieLoadingTime = makeTimestamp ( ) - startTime
// Convert the head hex path to a decoded byte path
headPath := common . FromHex ( path )
2024-05-29 12:29:55 +00:00
// Convert the Trie object to its concrete type for raw node access
stateTrie := t . ( * ipld_trie . StateTrie )
2022-12-19 08:42:23 +00:00
// Get Stem nodes
2024-05-29 12:29:55 +00:00
err = b . getSliceStem ( headPath , stateTrie , response , & metaData , storage )
2022-12-19 08:42:23 +00:00
if err != nil {
return nil , err
}
// Get Head node
2024-05-29 12:29:55 +00:00
err = b . getSliceHead ( headPath , stateTrie , response , & metaData , storage )
2022-12-19 08:42:23 +00:00
if err != nil {
return nil , err
}
if depth > 0 {
// Get Slice nodes
2024-05-29 12:29:55 +00:00
err = b . getSliceTrie ( headPath , stateTrie , response , & metaData , depth , storage )
2022-12-19 08:42:23 +00:00
if err != nil {
return nil , err
}
}
response . populateMetaData ( metaData )
return response , nil
}
2024-05-29 12:29:55 +00:00
func ( b * Backend ) getSliceStem ( headPath [ ] byte , t * ipld_trie . StateTrie , response * GetSliceResponse , metaData * metaDataFields , storage bool ) error {
2022-12-19 08:42:23 +00:00
leavesFetchTime := int64 ( 0 )
totalStemStartTime := makeTimestamp ( )
for i := 0 ; i < len ( headPath ) ; i ++ {
// Create path for each node along the stem
2023-04-14 06:26:46 +00:00
// nodePath := make([]byte, len(headPath[:i]))
nodePath := headPath [ : i ]
2022-12-19 08:42:23 +00:00
2024-05-29 12:29:55 +00:00
rawNode , _ , err := t . GetNode ( utils . HexToCompact ( nodePath ) )
2022-12-19 08:42:23 +00:00
if err != nil {
return err
}
// Skip if node not found
if rawNode == nil {
continue
}
2023-04-14 06:26:46 +00:00
node , nodeElements , err := ResolveNode ( nodePath , rawNode , b . IpldTrieStateDatabase . TrieDB ( ) )
2022-12-19 08:42:23 +00:00
if err != nil {
return err
}
2023-04-14 06:26:46 +00:00
leafFetchTime , err := fillSliceNodeData ( b . IpldTrieStateDatabase , response . TrieNodes . Stem , response . Leaves , node , nodeElements , storage )
2022-12-19 08:42:23 +00:00
if err != nil {
return err
}
// Update metadata
depthReached := len ( node . Path ) - len ( headPath )
if depthReached > metaData . maxDepth {
metaData . maxDepth = depthReached
}
2023-03-08 03:48:58 +00:00
if node . NodeType == Leaf {
2022-12-19 08:42:23 +00:00
metaData . leafCount ++
}
leavesFetchTime += leafFetchTime
}
// Update metadata time metrics
totalStemTime := makeTimestamp ( ) - totalStemStartTime
metaData . sliceNodesFetchTime = totalStemTime - leavesFetchTime
metaData . leavesFetchTime += leavesFetchTime
return nil
}
2024-05-29 12:29:55 +00:00
func ( b * Backend ) getSliceHead ( headPath [ ] byte , t * ipld_trie . StateTrie , response * GetSliceResponse , metaData * metaDataFields , storage bool ) error {
2022-12-19 08:42:23 +00:00
totalHeadStartTime := makeTimestamp ( )
2024-05-29 12:29:55 +00:00
rawNode , _ , err := t . GetNode ( utils . HexToCompact ( headPath ) )
2022-12-19 08:42:23 +00:00
if err != nil {
return err
}
// Skip if node not found
if rawNode == nil {
return nil
}
2023-04-14 06:26:46 +00:00
node , nodeElements , err := ResolveNode ( headPath , rawNode , b . IpldTrieStateDatabase . TrieDB ( ) )
2022-12-19 08:42:23 +00:00
if err != nil {
return err
}
2023-04-14 06:26:46 +00:00
leafFetchTime , err := fillSliceNodeData ( b . IpldTrieStateDatabase , response . TrieNodes . Head , response . Leaves , node , nodeElements , storage )
2022-12-19 08:42:23 +00:00
if err != nil {
return err
}
// Update metadata
depthReached := len ( node . Path ) - len ( headPath )
if depthReached > metaData . maxDepth {
metaData . maxDepth = depthReached
}
2023-03-08 03:48:58 +00:00
if node . NodeType == Leaf {
2022-12-19 08:42:23 +00:00
metaData . leafCount ++
}
// Update metadata time metrics
totalHeadTime := makeTimestamp ( ) - totalHeadStartTime
metaData . stemNodesFetchTime = totalHeadTime - leafFetchTime
metaData . leavesFetchTime += leafFetchTime
return nil
}
2023-04-14 06:26:46 +00:00
func ( b * Backend ) getSliceTrie ( headPath [ ] byte , t ipld_trie_state . Trie , response * GetSliceResponse , metaData * metaDataFields , depth int , storage bool ) error {
2024-05-29 12:29:55 +00:00
it , timeTaken , err := getIteratorAtPath ( t , headPath )
if err != nil {
return nil
}
2022-12-19 08:42:23 +00:00
metaData . trieLoadingTime += timeTaken
leavesFetchTime := int64 ( 0 )
totalSliceStartTime := makeTimestamp ( )
headPathLen := len ( headPath )
maxPathLen := headPathLen + depth
descend := true
for it . Next ( descend ) {
pathLen := len ( it . Path ( ) )
// End iteration on coming out of subtrie
if pathLen <= headPathLen {
break
}
// Avoid descending further if max depth reached
if pathLen >= maxPathLen {
descend = false
} else {
descend = true
}
// Skip value nodes
if it . Leaf ( ) || bytes . Equal ( nullHashBytes , it . Hash ( ) . Bytes ( ) ) {
continue
}
2023-04-14 06:26:46 +00:00
blob , err := it . NodeBlob ( ) , it . Error ( )
if err != nil {
return err
}
node , nodeElements , err := ResolveNode ( it . Path ( ) , blob , b . IpldTrieStateDatabase . TrieDB ( ) )
2022-12-19 08:42:23 +00:00
if err != nil {
return err
}
2023-04-14 06:26:46 +00:00
leafFetchTime , err := fillSliceNodeData ( b . IpldTrieStateDatabase , response . TrieNodes . Slice , response . Leaves , node , nodeElements , storage )
2022-12-19 08:42:23 +00:00
if err != nil {
return err
}
// Update metadata
depthReached := len ( node . Path ) - len ( headPath )
if depthReached > metaData . maxDepth {
metaData . maxDepth = depthReached
}
2023-03-08 03:48:58 +00:00
if node . NodeType == Leaf {
2022-12-19 08:42:23 +00:00
metaData . leafCount ++
}
leavesFetchTime += leafFetchTime
}
// Update metadata time metrics
totalSliceTime := makeTimestamp ( ) - totalSliceStartTime
metaData . sliceNodesFetchTime = totalSliceTime - leavesFetchTime
metaData . leavesFetchTime += leavesFetchTime
return nil
}
2020-10-20 20:33:18 +00:00
// Engine satisfied the ChainContext interface
func ( b * Backend ) Engine ( ) consensus . Engine {
// TODO: we need to support more than just ethash based engines
return ethash . NewFaker ( )
}
// GetHeader satisfied the ChainContext interface
func ( b * Backend ) GetHeader ( hash common . Hash , height uint64 ) * types . Header {
header , err := b . HeaderByHash ( context . Background ( ) , hash )
if err != nil {
return nil
}
return header
}
2020-10-26 13:58:37 +00:00
2021-12-29 20:57:21 +00:00
// ValidateTrie validates the trie for the given stateRoot
2021-09-21 12:10:55 +00:00
func ( b * Backend ) ValidateTrie ( stateRoot common . Hash ) error {
return validator . NewValidator ( nil , b . EthDB ) . ValidateTrie ( stateRoot )
}
2020-10-26 13:58:37 +00:00
// RPCGasCap returns the configured gas cap for the rpc server
2022-09-21 11:45:03 +00:00
func ( b * Backend ) RPCGasCap ( ) uint64 {
return b . Config . RPCGasCap . Uint64 ( )
2020-10-26 13:58:37 +00:00
}
func ( b * Backend ) SubscribeNewTxsEvent ( chan <- core . NewTxsEvent ) event . Subscription {
panic ( "implement me" )
}
func ( b * Backend ) SubscribeChainEvent ( ch chan <- core . ChainEvent ) event . Subscription {
panic ( "implement me" )
}
func ( b * Backend ) SubscribeRemovedLogsEvent ( ch chan <- core . RemovedLogsEvent ) event . Subscription {
panic ( "implement me" )
}
func ( b * Backend ) SubscribeLogsEvent ( ch chan <- [ ] * types . Log ) event . Subscription {
panic ( "implement me" )
}
func ( b * Backend ) SubscribePendingLogsEvent ( ch chan <- [ ] * types . Log ) event . Subscription {
panic ( "implement me" )
}
func ( b * Backend ) BloomStatus ( ) ( uint64 , uint64 ) {
panic ( "implement me" )
}
func ( b * Backend ) ServiceFilter ( ctx context . Context , session * bloombits . MatcherSession ) {
panic ( "implement me" )
}
2021-09-21 12:10:55 +00:00
2023-04-14 06:26:46 +00:00
// Close closes the backing DB and EthDB instances
func ( b * Backend ) Close ( ) error {
err := b . EthDB . Close ( )
if err != nil {
log . Errorf ( "error closing EthDB: %s" , err )
}
return b . DB . Close ( )
}
2021-09-21 12:10:55 +00:00
func logStateDBStatsOnTimer ( ethDB * ipfsethdb . Database , gcc * shared . GroupCacheConfig ) {
// No stats logging if interval isn't a positive integer.
if gcc . StateDB . LogStatsIntervalInSecs <= 0 {
return
}
ticker := time . NewTicker ( time . Duration ( gcc . StateDB . LogStatsIntervalInSecs ) * time . Second )
go func ( ) {
for range ticker . C {
2023-04-14 06:26:46 +00:00
log . Debugf ( "%s groupcache stats: %+v" , StateDBGroupCacheName , ethDB . GetCacheStats ( ) )
2021-09-21 12:10:55 +00:00
}
} ( )
}