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
2022-09-20 15:52:06 +00:00
validator "github.com/cerc-io/eth-ipfs-state-validator/v4/pkg"
ipfsethdb "github.com/cerc-io/ipfs-ethdb/v4/postgres"
2023-01-21 01:39:26 +00:00
"github.com/cerc-io/ipld-eth-server/v4/pkg/log"
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-10-20 20:33:18 +00:00
"github.com/ethereum/go-ethereum/core/state"
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"
2022-12-19 08:42:23 +00:00
ethServerShared "github.com/ethereum/go-ethereum/statediff/indexer/shared"
sdtrie "github.com/ethereum/go-ethereum/statediff/trie_helpers"
sdtypes "github.com/ethereum/go-ethereum/statediff/types"
2021-02-24 22:20:06 +00:00
"github.com/ethereum/go-ethereum/trie"
2022-03-10 09:53:03 +00:00
"github.com/jmoiron/sqlx"
2021-09-21 12:10:55 +00:00
2022-09-20 15:52:06 +00:00
"github.com/cerc-io/ipld-eth-server/v4/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
)
const (
2022-07-12 08:10:45 +00:00
RetrieveCanonicalBlockHashByNumber = ` SELECT block_hash
FROM canonical_header_hash ( $ 1 ) AS block_hash
WHERE block_hash IS NOT NULL `
2020-10-20 20:33:18 +00:00
RetrieveCanonicalHeaderByNumber = ` SELECT cid , data FROM eth . header_cids
2023-03-02 23:59:13 +00:00
INNER JOIN public . blocks ON (
header_cids . cid = blocks . key
2022-04-26 14:10:06 +00:00
AND header_cids . block_number = blocks . block_number
)
2022-03-14 09:57:58 +00:00
WHERE block_hash = ( SELECT canonical_header_hash ( $ 1 ) ) `
2023-03-02 23:41:44 +00:00
RetrieveTD = ` SELECT CAST ( td as TEXT ) FROM eth . header_cids
2020-10-26 13:58:37 +00:00
WHERE header_cids . block_hash = $ 1 `
2022-07-12 08:10:45 +00:00
RetrieveRPCTransaction = ` SELECT blocks . data , header_id , transaction_cids . block_number , index
2023-03-02 23:41:44 +00:00
FROM ipld . blocks , eth . transaction_cids
2023-03-02 23:59:13 +00:00
WHERE blocks . key = transaction_cids . cid
2022-04-26 14:10:06 +00:00
AND blocks . block_number = transaction_cids . block_number
2022-07-12 08:10:45 +00:00
AND transaction_cids . tx_hash = $ 1
AND transaction_cids . header_id = ( SELECT canonical_header_hash ( transaction_cids . block_number ) ) `
2020-10-30 03:07:39 +00:00
RetrieveCodeHashByLeafKeyAndBlockHash = ` SELECT code_hash FROM eth . state_accounts , eth . state_cids , eth . header_cids
2022-04-26 14:10:06 +00:00
WHERE state_accounts . header_id = state_cids . header_id
AND state_accounts . state_path = state_cids . state_path
AND state_accounts . block_number = state_cids . block_number
2022-03-10 12:35:19 +00:00
AND state_cids . header_id = header_cids . block_hash
2022-04-26 14:10:06 +00:00
AND state_cids . block_number = header_cids . block_number
2020-10-30 03:07:39 +00:00
AND state_leaf_key = $ 1
2022-04-26 14:10:06 +00:00
AND header_cids . block_number <= ( SELECT block_number
2020-10-30 03:08:26 +00:00
FROM eth . header_cids
WHERE block_hash = $ 2 )
2022-04-26 14:10:06 +00:00
AND header_cids . block_hash = ( SELECT canonical_header_hash ( header_cids . block_number ) )
ORDER BY header_cids . block_number DESC
2020-10-30 03:08:26 +00:00
LIMIT 1 `
2023-03-02 23:59:13 +00:00
RetrieveCodeByMhKey = ` SELECT data FROM public.blocks WHERE key = $1 `
2020-01-16 23:21:49 +00:00
)
2021-09-21 12:10:55 +00:00
const (
StateDBGroupCacheName = "statedb"
)
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
Retriever * CIDRetriever
IPLDRetriever * IPLDRetriever
// ethereum interfaces
EthDB ethdb . Database
StateDatabase state . Database
Config * Config
}
type Config struct {
2021-09-21 12:10:55 +00:00
ChainConfig * params . ChainConfig
VMConfig vm . Config
DefaultSender * common . Address
RPCGasCap * big . Int
GroupCacheConfig * shared . GroupCacheConfig
2020-01-16 23:21:49 +00:00
}
2022-03-10 09:53:03 +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
}
2020-01-17 23:16:01 +00:00
r := NewCIDRetriever ( 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 )
2021-08-20 07:37:11 +00:00
2020-01-16 23:21:49 +00:00
return & Backend {
2020-10-20 20:33:18 +00:00
DB : db ,
Retriever : r ,
IPLDRetriever : NewIPLDRetriever ( db ) ,
EthDB : ethDB ,
StateDatabase : 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
}
2020-10-20 20:33:18 +00:00
// HeaderByNumber gets the canonical header for the provided block number
2020-01-16 23:21:49 +00:00
func ( b * Backend ) HeaderByNumber ( ctx context . Context , blockNumber rpc . BlockNumber ) ( * types . Header , error ) {
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 {
return nil , err
}
}
2020-10-20 20:33:18 +00:00
if blockNumber == rpc . EarliestBlockNumber {
number , err = b . Retriever . RetrieveFirstBlockNumber ( )
if err != nil {
return nil , err
}
}
2020-01-16 23:21:49 +00:00
if blockNumber == rpc . PendingBlockNumber {
return nil , errPendingBlockNumber
}
2020-10-20 20:33:18 +00:00
if number < 0 {
return nil , errNegativeBlockNumber
}
_ , 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 ) {
2022-08-23 07:12:19 +00:00
// Begin tx
tx , err := b . DB . Beginx ( )
if err != nil {
return nil , err
}
defer func ( ) {
if p := recover ( ) ; p != nil {
shared . Rollback ( tx )
panic ( p )
} else if err != nil {
shared . Rollback ( tx )
} else {
err = tx . Commit ( )
}
} ( )
_ , headerRLP , err := b . IPLDRetriever . RetrieveHeaderByHash ( tx , 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 {
return nil , errors . New ( "header for hash not found" )
}
2021-04-16 13:02:04 +00:00
canonicalHash , err := b . GetCanonicalHash ( header . Number . Uint64 ( ) )
if err != nil {
return nil , err
}
if blockNrOrHash . RequireCanonical && canonicalHash != hash {
2020-10-26 13:58:37 +00:00
return nil , errors . New ( "hash is not currently canonical" )
}
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 {
return nil , errors . New ( "header for hash not found" )
}
2021-04-16 13:02:04 +00:00
canonicalHash , err := b . GetCanonicalHash ( header . Number . Uint64 ( ) )
if err != nil {
return nil , err
}
if blockNrOrHash . RequireCanonical && canonicalHash != hash {
2020-10-26 13:58:37 +00:00
return nil , errors . New ( "hash is not currently canonical" )
}
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 ) {
var err error
2020-05-01 21:25:58 +00:00
number := blockNumber . Int64 ( )
2020-01-26 19:55:26 +00:00
if blockNumber == rpc . LatestBlockNumber {
2020-02-20 22:12:52 +00:00
number , err = b . Retriever . RetrieveLastBlockNumber ( )
2020-01-26 19:55:26 +00:00
if err != nil {
return nil , err
}
}
2020-10-20 20:33:18 +00:00
if blockNumber == rpc . EarliestBlockNumber {
number , err = b . Retriever . RetrieveFirstBlockNumber ( )
if err != nil {
return nil , err
}
}
2020-01-26 19:55:26 +00:00
if blockNumber == rpc . PendingBlockNumber {
return nil , errPendingBlockNumber
}
2020-10-20 20:33:18 +00:00
if number < 0 {
return nil , errNegativeBlockNumber
}
2022-08-23 07:12:19 +00:00
2020-10-20 20:33:18 +00:00
// Get the canonical hash
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
}
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
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
2022-11-04 04:32:09 +00:00
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
2022-08-25 10:24:32 +00:00
// When num. of uncles = 2,
// Check if calculated uncle hash matches the one in header
// If not, re-order the two uncles
// Assumption: Max num. of uncles in mainnet = 2
if len ( uncles ) == 2 {
uncleHash := types . CalcUncleHash ( uncles )
if uncleHash != header . UncleHash {
uncles [ 0 ] , uncles [ 1 ] = uncles [ 1 ] , uncles [ 0 ]
uncleHash = types . CalcUncleHash ( uncles )
// Check if uncle hash matches after re-ordering
if uncleHash != header . UncleHash {
log . Error ( "uncle hash mismatch for block hash: " , hash . Hex ( ) )
}
}
}
2022-08-23 07:12:19 +00:00
// Fetch transactions
2022-11-04 04:32:09 +00:00
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
2022-11-04 04:32:09 +00:00
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
2020-01-26 19:55:26 +00:00
// Compose everything together into a complete block
2022-08-23 07:12:19 +00:00
return types . NewBlock ( header , transactions , uncles , receipts , new ( trie . Trie ) ) , 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 ) {
_ , headerRLP , err := b . IPLDRetriever . RetrieveHeaderByHash ( 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
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 ) {
_ , uncleBytes , err := b . IPLDRetriever . 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
uncles := make ( [ ] * types . Header , len ( uncleBytes ) )
for i , bytes := range uncleBytes {
2020-02-20 22:13:19 +00:00
var uncle types . Header
2022-08-23 07:12:19 +00:00
err = rlp . DecodeBytes ( bytes , & uncle )
2021-04-19 13:42:09 +00:00
if err != nil {
2020-01-26 19:55:26 +00:00
return nil , err
}
2022-08-23 07:12:19 +00:00
uncles [ i ] = & uncle
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 ) {
_ , uncleBytes , err := b . IPLDRetriever . RetrieveUncles ( tx , hash , number )
if err != nil {
return nil , err
}
uncles := make ( [ ] * types . Header , len ( uncleBytes ) )
for i , bytes := range uncleBytes {
var uncle types . Header
err = rlp . DecodeBytes ( bytes , & uncle )
if err != nil {
return nil , err
}
uncles [ i ] = & uncle
}
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 ) {
_ , transactionBytes , err := b . IPLDRetriever . 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 ) {
_ , transactionBytes , err := b . IPLDRetriever . RetrieveTransactions ( tx , hash , number )
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 ) {
_ , receiptBytes , txs , err := b . IPLDRetriever . 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 ) {
_ , receiptBytes , txs , err := b . IPLDRetriever . RetrieveReceipts ( tx , hash , number )
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
}
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
func ( b * Backend ) GetTransaction ( ctx context . Context , txHash common . Hash ) ( * 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 {
2020-05-01 16:07:47 +00:00
return nil , common . Hash { } , 0 , 0 , err
}
2022-07-12 08:10:45 +00:00
if len ( res ) == 0 {
return nil , common . Hash { } , 0 , 0 , errTxHashNotFound
} else if len ( res ) > 1 {
// a transaction can be part of a only one canonical block
return nil , common . Hash { } , 0 , 0 , errTxHashInMultipleBlocks
}
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 {
2020-01-26 19:55:26 +00:00
return nil , common . Hash { } , 0 , 0 , err
}
2022-07-12 08:10:45 +00:00
return & 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
}
defer func ( ) {
if p := recover ( ) ; p != nil {
shared . Rollback ( tx )
panic ( p )
} else if err != nil {
shared . Rollback ( tx )
} else {
err = tx . Commit ( )
}
} ( )
2023-03-02 23:59:13 +00:00
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
return b . GetReceiptsByBlockHashAndNumber ( tx , hash , blockNumber )
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
}
defer func ( ) {
if p := recover ( ) ; p != nil {
shared . Rollback ( tx )
panic ( p )
} else if err != nil {
shared . Rollback ( tx )
} else {
err = tx . Commit ( )
}
} ( )
2022-11-04 04:32:09 +00:00
_ , receiptBytes , txs , err := b . IPLDRetriever . 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
if err := rlp . DecodeBytes ( rctBytes , & rct ) ; err != nil {
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
}
2020-10-26 13:58:37 +00:00
return logs , nil
2020-04-02 03:34:06 +00:00
}
2020-09-25 13:58:18 +00:00
// StateAndHeaderByNumberOrHash returns the statedb and header for the provided block number or hash
func ( b * Backend ) StateAndHeaderByNumberOrHash ( ctx context . Context , blockNrOrHash rpc . BlockNumberOrHash ) ( * state . StateDB , * types . Header , error ) {
if blockNr , ok := blockNrOrHash . Number ( ) ; ok {
return b . StateAndHeaderByNumber ( ctx , blockNr )
}
if hash , ok := blockNrOrHash . Hash ( ) ; ok {
header , err := b . HeaderByHash ( ctx , hash )
if err != nil {
return nil , nil , err
}
if header == nil {
return nil , nil , errors . New ( "header for hash not found" )
}
2021-04-16 13:02:04 +00:00
canonicalHash , err := b . GetCanonicalHash ( header . Number . Uint64 ( ) )
if err != nil {
return nil , nil , err
}
if blockNrOrHash . RequireCanonical && canonicalHash != hash {
2020-09-25 13:58:18 +00:00
return nil , nil , errors . New ( "hash is not currently canonical" )
}
2021-02-19 20:23:45 +00:00
stateDb , err := state . New ( header . Root , b . StateDatabase , nil )
2020-09-25 13:58:18 +00:00
return stateDb , header , err
}
return nil , nil , errors . New ( "invalid arguments; neither block nor hash specified" )
}
// StateAndHeaderByNumber returns the statedb and header for a provided block number
func ( b * Backend ) StateAndHeaderByNumber ( ctx context . Context , number rpc . BlockNumber ) ( * state . StateDB , * types . Header , error ) {
// Pending state is only known by the miner
if number == rpc . PendingBlockNumber {
2020-10-20 20:33:18 +00:00
return nil , nil , errPendingBlockNumber
2020-09-25 13:58:18 +00:00
}
// Otherwise resolve the block number and return its state
header , err := b . HeaderByNumber ( ctx , number )
if err != nil {
return nil , nil , err
}
if header == nil {
return nil , nil , errors . New ( "header not found" )
}
2021-02-19 20:23:45 +00:00
stateDb , err := state . New ( header . Root , b . StateDatabase , nil )
2020-09-25 13:58:18 +00:00
return stateDb , header , err
}
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
}
type rowResult struct {
CID string
Data [ ] byte
}
// GetCanonicalHeader gets the canonical header for the provided number, if there is one
func ( b * Backend ) GetCanonicalHeader ( number uint64 ) ( string , [ ] byte , error ) {
headerResult := new ( rowResult )
return headerResult . CID , headerResult . Data , b . DB . QueryRowx ( RetrieveCanonicalHeaderByNumber , number ) . StructScan ( headerResult )
}
// GetEVM constructs and returns a vm.EVM
2021-09-29 05:27:11 +00:00
func ( b * Backend ) GetEVM ( ctx context . Context , msg core . Message , state * state . StateDB , header * types . Header ) ( * vm . EVM , func ( ) error , error ) {
vmError := func ( ) error { return nil }
2021-02-19 20:23:45 +00:00
txContext := core . NewEVMTxContext ( msg )
2021-09-29 05:27:11 +00:00
context := core . NewEVMBlockContext ( header , b , nil )
return vm . NewEVM ( context , 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
}
2020-10-30 03:07:39 +00:00
_ , accountRlp , err := b . IPLDRetriever . RetrieveAccountByAddressAndBlockHash ( address , hash )
if err != nil {
return nil , err
}
2021-06-03 16:49:48 +00:00
2021-10-07 09:35:11 +00:00
acct := new ( types . StateAccount )
2020-10-30 03:07:39 +00:00
return acct , rlp . DecodeBytes ( accountRlp , acct )
}
// 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 { } ) {
return nil , fmt . Errorf ( "no canoncial block hash found for provided height (%d)" , number )
}
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 ) {
codeHash := make ( [ ] byte , 0 )
leafKey := crypto . Keccak256Hash ( address . Bytes ( ) )
// Begin tx
tx , err := b . DB . Beginx ( )
if err != nil {
return nil , err
}
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 ( )
}
} ( )
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
}
2021-04-19 13:42:09 +00:00
var mhKey string
2021-09-21 12:10:55 +00:00
mhKey , err = ethServerShared . MultihashKeyFromKeccak256 ( common . BytesToHash ( codeHash ) )
2020-10-30 03:07:39 +00:00
if err != nil {
return nil , err
}
code := make ( [ ] byte , 0 )
err = tx . Get ( & code , RetrieveCodeByMhKey , mhKey )
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
}
2021-05-26 11:37:25 +00:00
_ , _ , storageRlp , err := b . IPLDRetriever . RetrieveStorageAtByAddressAndStorageSlotAndBlockHash ( address , key , hash )
2020-10-30 16:54:22 +00:00
return storageRlp , err
}
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 ( )
t , _ := b . StateDatabase . OpenTrie ( root )
metaData . trieLoadingTime = makeTimestamp ( ) - startTime
// Convert the head hex path to a decoded byte path
headPath := common . FromHex ( path )
// Get Stem nodes
err := b . getSliceStem ( headPath , t , response , & metaData , storage )
if err != nil {
return nil , err
}
// Get Head node
err = b . getSliceHead ( headPath , t , response , & metaData , storage )
if err != nil {
return nil , err
}
if depth > 0 {
// Get Slice nodes
err = b . getSliceTrie ( headPath , t , response , & metaData , depth , storage )
if err != nil {
return nil , err
}
}
response . populateMetaData ( metaData )
return response , nil
}
func ( b * Backend ) getSliceStem ( headPath [ ] byte , t state . Trie , response * GetSliceResponse , metaData * metaDataFields , storage bool ) error {
leavesFetchTime := int64 ( 0 )
totalStemStartTime := makeTimestamp ( )
for i := 0 ; i < len ( headPath ) ; i ++ {
// Create path for each node along the stem
nodePath := make ( [ ] byte , len ( headPath [ : i ] ) )
copy ( nodePath , headPath [ : i ] )
rawNode , _ , err := t . ( * trie . StateTrie ) . TryGetNode ( trie . HexToCompact ( nodePath ) )
if err != nil {
return err
}
// Skip if node not found
if rawNode == nil {
continue
}
node , nodeElements , err := ResolveNode ( nodePath , rawNode , b . StateDatabase . TrieDB ( ) )
if err != nil {
return err
}
leafFetchTime , err := fillSliceNodeData ( b . EthDB , response . TrieNodes . Stem , response . Leaves , node , nodeElements , storage )
if err != nil {
return err
}
// Update metadata
depthReached := len ( node . Path ) - len ( headPath )
if depthReached > metaData . maxDepth {
metaData . maxDepth = depthReached
}
if node . NodeType == sdtypes . Leaf {
metaData . leafCount ++
}
leavesFetchTime += leafFetchTime
}
// Update metadata time metrics
totalStemTime := makeTimestamp ( ) - totalStemStartTime
metaData . sliceNodesFetchTime = totalStemTime - leavesFetchTime
metaData . leavesFetchTime += leavesFetchTime
return nil
}
func ( b * Backend ) getSliceHead ( headPath [ ] byte , t state . Trie , response * GetSliceResponse , metaData * metaDataFields , storage bool ) error {
totalHeadStartTime := makeTimestamp ( )
rawNode , _ , err := t . ( * trie . StateTrie ) . TryGetNode ( trie . HexToCompact ( headPath ) )
if err != nil {
return err
}
// Skip if node not found
if rawNode == nil {
return nil
}
node , nodeElements , err := ResolveNode ( headPath , rawNode , b . StateDatabase . TrieDB ( ) )
if err != nil {
return err
}
leafFetchTime , err := fillSliceNodeData ( b . EthDB , response . TrieNodes . Head , response . Leaves , node , nodeElements , storage )
if err != nil {
return err
}
// Update metadata
depthReached := len ( node . Path ) - len ( headPath )
if depthReached > metaData . maxDepth {
metaData . maxDepth = depthReached
}
if node . NodeType == sdtypes . Leaf {
metaData . leafCount ++
}
// Update metadata time metrics
totalHeadTime := makeTimestamp ( ) - totalHeadStartTime
metaData . stemNodesFetchTime = totalHeadTime - leafFetchTime
metaData . leavesFetchTime += leafFetchTime
return nil
}
func ( b * Backend ) getSliceTrie ( headPath [ ] byte , t state . Trie , response * GetSliceResponse , metaData * metaDataFields , depth int , storage bool ) error {
it , timeTaken := getIteratorAtPath ( t , headPath )
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
}
node , nodeElements , err := sdtrie . ResolveNode ( it , b . StateDatabase . TrieDB ( ) )
if err != nil {
return err
}
leafFetchTime , err := fillSliceNodeData ( b . EthDB , response . TrieNodes . Slice , response . Leaves , node , nodeElements , storage )
if err != nil {
return err
}
// Update metadata
depthReached := len ( node . Path ) - len ( headPath )
if depthReached > metaData . maxDepth {
metaData . maxDepth = depthReached
}
if node . NodeType == sdtypes . Leaf {
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
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 {
log . Infof ( "%s groupcache stats: %+v" , StateDBGroupCacheName , ethDB . GetCacheStats ( ) )
}
} ( )
}