2023-07-08 17:01:26 +00:00
package jsonrpc
2020-10-18 19:44:28 +00:00
import (
2022-07-15 14:04:23 +00:00
"bytes"
2020-10-18 19:44:28 +00:00
"context"
2022-07-01 14:36:44 +00:00
"errors"
2020-10-18 19:44:28 +00:00
"fmt"
2023-10-21 23:17:18 +00:00
"github.com/ledgerwatch/erigon-lib/common/hexutil"
2022-02-20 10:45:29 +00:00
"sort"
2020-10-18 19:44:28 +00:00
2022-07-15 14:04:23 +00:00
"github.com/holiman/uint256"
2023-01-27 04:39:34 +00:00
"github.com/ledgerwatch/erigon-lib/common"
2023-01-13 18:12:18 +00:00
"github.com/ledgerwatch/erigon-lib/common/hexutility"
2022-02-20 10:45:29 +00:00
"github.com/ledgerwatch/erigon-lib/kv"
2023-06-11 04:49:53 +00:00
"github.com/ledgerwatch/erigon-lib/kv/order"
"github.com/ledgerwatch/erigon-lib/kv/rawdbv3"
2022-12-19 08:38:54 +00:00
"github.com/ledgerwatch/erigon-lib/kv/temporal/historyv2"
2023-05-25 05:46:11 +00:00
"github.com/ledgerwatch/erigon/turbo/services"
2023-01-13 18:12:18 +00:00
2021-05-20 18:25:53 +00:00
"github.com/ledgerwatch/erigon/core/rawdb"
"github.com/ledgerwatch/erigon/core/types"
2022-07-15 14:04:23 +00:00
"github.com/ledgerwatch/erigon/core/types/accounts"
2021-05-20 18:25:53 +00:00
"github.com/ledgerwatch/erigon/rpc"
2022-10-25 02:58:25 +00:00
"github.com/ledgerwatch/erigon/turbo/adapter/ethapi"
2022-06-14 13:29:49 +00:00
"github.com/ledgerwatch/erigon/turbo/rpchelper"
2020-10-18 19:44:28 +00:00
)
2021-05-26 10:35:39 +00:00
// GetHeaderByNumber implements erigon_getHeaderByNumber. Returns a block's header given a block number ignoring the block's transaction and uncle list (may be faster).
func ( api * ErigonImpl ) GetHeaderByNumber ( ctx context . Context , blockNumber rpc . BlockNumber ) ( * types . Header , error ) {
2021-03-30 07:09:00 +00:00
// Pending block is only known by the miner
if blockNumber == rpc . PendingBlockNumber {
2021-05-17 12:15:19 +00:00
block := api . pendingBlock ( )
if block == nil {
return nil , nil
}
2021-03-30 07:09:00 +00:00
return block . Header ( ) , nil
}
2021-04-03 06:26:00 +00:00
tx , err := api . db . BeginRo ( ctx )
2020-10-18 19:44:28 +00:00
if err != nil {
return nil , err
}
defer tx . Rollback ( )
2022-06-14 13:29:49 +00:00
blockNum , _ , _ , err := rpchelper . GetBlockNumber ( rpc . BlockNumberOrHashWithNumber ( blockNumber ) , tx , api . filters )
2021-08-24 02:13:51 +00:00
if err != nil {
return nil , err
}
2022-07-01 14:36:44 +00:00
header , err := api . _blockReader . HeaderByNumber ( ctx , tx , blockNum )
if err != nil {
return nil , err
}
2020-10-18 19:44:28 +00:00
if header == nil {
2021-08-24 02:13:51 +00:00
return nil , fmt . Errorf ( "block header not found: %d" , blockNum )
2020-10-18 19:44:28 +00:00
}
return header , nil
}
2021-05-26 10:35:39 +00:00
// GetHeaderByHash implements erigon_getHeaderByHash. Returns a block's header given a block's hash.
2023-01-27 04:39:34 +00:00
func ( api * ErigonImpl ) GetHeaderByHash ( ctx context . Context , hash common . Hash ) ( * types . Header , error ) {
2021-04-03 06:26:00 +00:00
tx , err := api . db . BeginRo ( ctx )
2020-10-18 19:44:28 +00:00
if err != nil {
return nil , err
}
defer tx . Rollback ( )
2022-07-01 14:36:44 +00:00
header , err := api . _blockReader . HeaderByHash ( ctx , tx , hash )
2020-10-24 06:57:09 +00:00
if err != nil {
return nil , err
}
2020-10-18 19:44:28 +00:00
if header == nil {
return nil , fmt . Errorf ( "block header not found: %s" , hash . String ( ) )
}
return header , nil
}
2022-02-20 10:45:29 +00:00
2022-02-23 13:52:19 +00:00
func ( api * ErigonImpl ) GetBlockByTimestamp ( ctx context . Context , timeStamp rpc . Timestamp , fullTx bool ) ( map [ string ] interface { } , error ) {
2022-02-20 10:45:29 +00:00
tx , err := api . db . BeginRo ( ctx )
if err != nil {
return nil , err
}
defer tx . Rollback ( )
2022-02-23 13:52:19 +00:00
uintTimestamp := timeStamp . TurnIntoUint64 ( )
2022-02-20 10:45:29 +00:00
currentHeader := rawdb . ReadCurrentHeader ( tx )
2023-01-22 19:31:57 +00:00
currentHeaderTime := currentHeader . Time
2022-02-20 10:45:29 +00:00
highestNumber := currentHeader . Number . Uint64 ( )
2022-07-01 14:36:44 +00:00
firstHeader , err := api . _blockReader . HeaderByNumber ( ctx , tx , 0 )
if err != nil {
return nil , err
}
if firstHeader == nil {
return nil , errors . New ( "no genesis header found" )
}
2022-02-20 10:45:29 +00:00
firstHeaderTime := firstHeader . Time
2023-01-22 19:31:57 +00:00
if currentHeaderTime <= uintTimestamp {
2023-05-25 05:46:11 +00:00
blockResponse , err := buildBlockResponse ( api . _blockReader , tx , highestNumber , fullTx )
2022-02-20 10:45:29 +00:00
if err != nil {
return nil , err
}
return blockResponse , nil
}
2022-02-23 13:52:19 +00:00
if firstHeaderTime >= uintTimestamp {
2023-05-25 05:46:11 +00:00
blockResponse , err := buildBlockResponse ( api . _blockReader , tx , 0 , fullTx )
2022-02-20 10:45:29 +00:00
if err != nil {
return nil , err
}
return blockResponse , nil
}
blockNum := sort . Search ( int ( currentHeader . Number . Uint64 ( ) ) , func ( blockNum int ) bool {
2022-07-01 14:36:44 +00:00
currentHeader , err := api . _blockReader . HeaderByNumber ( ctx , tx , uint64 ( blockNum ) )
if err != nil {
return false
}
if currentHeader == nil {
return false
}
2022-02-20 10:45:29 +00:00
2022-02-23 13:52:19 +00:00
return currentHeader . Time >= uintTimestamp
2022-02-20 10:45:29 +00:00
} )
2022-07-01 14:36:44 +00:00
resultingHeader , err := api . _blockReader . HeaderByNumber ( ctx , tx , uint64 ( blockNum ) )
if err != nil {
return nil , err
}
if resultingHeader == nil {
return nil , fmt . Errorf ( "no header found with header number: %d" , blockNum )
}
2022-02-20 10:45:29 +00:00
2023-01-22 19:31:57 +00:00
for resultingHeader . Time > uintTimestamp {
beforeHeader , err := api . _blockReader . HeaderByNumber ( ctx , tx , uint64 ( blockNum ) - 1 )
2022-02-20 10:45:29 +00:00
if err != nil {
return nil , err
}
2023-01-22 19:31:57 +00:00
if beforeHeader == nil || beforeHeader . Time < uintTimestamp {
break
}
blockNum --
resultingHeader = beforeHeader
2022-02-20 10:45:29 +00:00
}
2023-05-25 05:46:11 +00:00
response , err := buildBlockResponse ( api . _blockReader , tx , uint64 ( blockNum ) , fullTx )
2022-02-20 10:45:29 +00:00
if err != nil {
return nil , err
}
return response , nil
}
2023-05-25 05:46:11 +00:00
func buildBlockResponse ( br services . FullBlockReader , db kv . Tx , blockNum uint64 , fullTx bool ) ( map [ string ] interface { } , error ) {
header , err := br . HeaderByNumber ( context . Background ( ) , db , blockNum )
2022-02-20 10:45:29 +00:00
if err != nil {
return nil , err
}
2023-05-25 05:46:11 +00:00
if header == nil {
return nil , nil
}
2022-02-20 10:45:29 +00:00
2023-05-25 05:46:11 +00:00
block , _ , err := br . BlockWithSenders ( context . Background ( ) , db , header . Hash ( ) , blockNum )
if err != nil {
return nil , err
}
2022-02-20 10:45:29 +00:00
if block == nil {
return nil , nil
}
2022-11-18 00:15:00 +00:00
additionalFields := make ( map [ string ] interface { } )
2023-05-25 05:46:11 +00:00
td , err := rawdb . ReadTd ( db , header . Hash ( ) , header . Number . Uint64 ( ) )
2022-11-18 00:15:00 +00:00
if err != nil {
return nil , err
}
if td != nil {
additionalFields [ "totalDifficulty" ] = ( * hexutil . Big ) ( td )
}
2023-01-27 04:39:34 +00:00
response , err := ethapi . RPCMarshalBlockEx ( block , true , fullTx , nil , common . Hash { } , additionalFields )
2022-02-20 10:45:29 +00:00
if err == nil && rpc . BlockNumber ( block . NumberU64 ( ) ) == rpc . PendingBlockNumber {
// Pending blocks need to nil out a few fields
for _ , field := range [ ] string { "hash" , "nonce" , "miner" } {
response [ field ] = nil
}
}
return response , err
}
2022-07-15 14:04:23 +00:00
2023-01-27 04:39:34 +00:00
func ( api * ErigonImpl ) GetBalanceChangesInBlock ( ctx context . Context , blockNrOrHash rpc . BlockNumberOrHash ) ( map [ common . Address ] * hexutil . Big , error ) {
2022-07-15 14:04:23 +00:00
tx , err := api . db . BeginRo ( ctx )
if err != nil {
return nil , err
}
defer tx . Rollback ( )
2023-06-11 04:49:53 +00:00
balancesMapping := make ( map [ common . Address ] * hexutil . Big )
latestState , err := rpchelper . CreateStateReader ( ctx , tx , blockNrOrHash , 0 , api . filters , api . stateCache , api . historyV3 ( tx ) , "" )
if err != nil {
return nil , err
}
2022-07-15 14:04:23 +00:00
blockNumber , _ , _ , err := rpchelper . GetBlockNumber ( blockNrOrHash , tx , api . filters )
if err != nil {
return nil , err
}
2023-06-11 04:49:53 +00:00
if api . historyV3 ( tx ) {
minTxNum , _ := rawdbv3 . TxNums . Min ( tx , blockNumber )
2023-06-11 14:12:05 +00:00
it , err := tx . ( kv . TemporalTx ) . HistoryRange ( kv . AccountsHistory , int ( minTxNum ) , - 1 , order . Asc , - 1 )
2023-06-11 04:49:53 +00:00
if err != nil {
return nil , err
}
for it . HasNext ( ) {
addressBytes , v , err := it . Next ( )
if err != nil {
return nil , err
}
var oldAcc accounts . Account
if len ( v ) > 0 {
if err = accounts . DeserialiseV3 ( & oldAcc , v ) ; err != nil {
return nil , err
}
}
oldBalance := oldAcc . Balance
address := common . BytesToAddress ( addressBytes )
newAcc , err := latestState . ReadAccountData ( address )
if err != nil {
return nil , err
}
newBalance := uint256 . NewInt ( 0 )
if newAcc != nil {
newBalance = & newAcc . Balance
}
if ! oldBalance . Eq ( newBalance ) {
newBalanceDesc := ( * hexutil . Big ) ( newBalance . ToBig ( ) )
balancesMapping [ address ] = newBalanceDesc
}
}
}
2022-07-15 14:04:23 +00:00
c , err := tx . Cursor ( kv . AccountChangeSet )
if err != nil {
return nil , err
}
defer c . Close ( )
2023-01-13 18:12:18 +00:00
startkey := hexutility . EncodeTs ( blockNumber )
2022-07-15 14:04:23 +00:00
2022-12-19 08:38:54 +00:00
decodeFn := historyv2 . Mapper [ kv . AccountChangeSet ] . Decode
2022-07-15 14:04:23 +00:00
2022-09-05 14:31:00 +00:00
for dbKey , dbValue , err := c . Seek ( startkey ) ; bytes . Equal ( dbKey , startkey ) && dbKey != nil ; dbKey , dbValue , err = c . Next ( ) {
if err != nil {
return nil , err
}
2022-07-15 14:04:23 +00:00
_ , addressBytes , v , err := decodeFn ( dbKey , dbValue )
if err != nil {
return nil , err
}
var oldAcc accounts . Account
if err = oldAcc . DecodeForStorage ( v ) ; err != nil {
return nil , err
}
oldBalance := oldAcc . Balance
2023-01-27 04:39:34 +00:00
address := common . BytesToAddress ( addressBytes )
2022-07-15 14:04:23 +00:00
2023-06-11 04:49:53 +00:00
newAcc , err := latestState . ReadAccountData ( address )
2022-07-15 14:04:23 +00:00
if err != nil {
return nil , err
}
newBalance := uint256 . NewInt ( 0 )
if newAcc != nil {
newBalance = & newAcc . Balance
}
if ! oldBalance . Eq ( newBalance ) {
newBalanceDesc := ( * hexutil . Big ) ( newBalance . ToBig ( ) )
balancesMapping [ address ] = newBalanceDesc
}
}
return balancesMapping , nil
}