2020-10-18 19:44:28 +00:00
package commands
import (
"context"
"fmt"
2022-02-20 10:45:29 +00:00
"sort"
2020-10-18 19:44:28 +00:00
2022-02-20 10:45:29 +00:00
"github.com/ledgerwatch/erigon-lib/kv"
2021-05-20 18:25:53 +00:00
"github.com/ledgerwatch/erigon/common"
"github.com/ledgerwatch/erigon/core/rawdb"
"github.com/ledgerwatch/erigon/core/types"
2022-02-20 10:45:29 +00:00
"github.com/ledgerwatch/erigon/internal/ethapi"
2021-05-20 18:25:53 +00:00
"github.com/ledgerwatch/erigon/rpc"
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 ( )
2021-08-24 02:13:51 +00:00
blockNum , err := getBlockNumber ( blockNumber , tx )
if err != nil {
return nil , err
}
header := rawdb . ReadHeaderByNumber ( tx , blockNum )
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.
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 ( )
2021-05-31 10:12:48 +00:00
header , err := rawdb . ReadHeaderByHash ( 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 )
currenttHeaderTime := currentHeader . Time
highestNumber := currentHeader . Number . Uint64 ( )
firstHeader := rawdb . ReadHeaderByNumber ( tx , 0 )
firstHeaderTime := firstHeader . Time
2022-02-23 13:52:19 +00:00
if currenttHeaderTime <= uintTimestamp {
2022-02-20 10:45:29 +00:00
blockResponse , err := buildBlockResponse ( tx , highestNumber , fullTx )
if err != nil {
return nil , err
}
return blockResponse , nil
}
2022-02-23 13:52:19 +00:00
if firstHeaderTime >= uintTimestamp {
2022-02-20 10:45:29 +00:00
blockResponse , err := buildBlockResponse ( tx , 0 , fullTx )
if err != nil {
return nil , err
}
return blockResponse , nil
}
blockNum := sort . Search ( int ( currentHeader . Number . Uint64 ( ) ) , func ( blockNum int ) bool {
currentHeader := rawdb . ReadHeaderByNumber ( tx , uint64 ( blockNum ) )
2022-02-23 13:52:19 +00:00
return currentHeader . Time >= uintTimestamp
2022-02-20 10:45:29 +00:00
} )
resultingHeader := rawdb . ReadHeaderByNumber ( tx , uint64 ( blockNum ) )
2022-02-23 13:52:19 +00:00
if resultingHeader . Time > uintTimestamp {
2022-02-20 10:45:29 +00:00
response , err := buildBlockResponse ( tx , uint64 ( blockNum ) - 1 , fullTx )
if err != nil {
return nil , err
}
return response , nil
}
response , err := buildBlockResponse ( tx , uint64 ( blockNum ) , fullTx )
if err != nil {
return nil , err
}
return response , nil
}
func buildBlockResponse ( db kv . Tx , blockNum uint64 , fullTx bool ) ( map [ string ] interface { } , error ) {
block , err := rawdb . ReadBlockByNumber ( db , blockNum )
if err != nil {
return nil , err
}
if block == nil {
return nil , nil
}
response , err := ethapi . RPCMarshalBlock ( block , true , fullTx )
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
}