2021-11-14 04:08:52 +00:00
package snapshotsync
import (
2021-11-21 03:32:14 +00:00
"bytes"
2021-11-14 04:08:52 +00:00
"context"
2022-05-20 07:12:12 +00:00
"encoding/binary"
2021-11-18 14:07:55 +00:00
"fmt"
2021-11-14 04:08:52 +00:00
2023-01-13 18:12:18 +00:00
libcommon "github.com/ledgerwatch/erigon-lib/common"
2022-06-28 04:31:44 +00:00
"github.com/ledgerwatch/erigon-lib/common/dbg"
2021-11-21 03:32:14 +00:00
"github.com/ledgerwatch/erigon-lib/gointerfaces"
"github.com/ledgerwatch/erigon-lib/gointerfaces/remote"
2021-11-14 04:08:52 +00:00
"github.com/ledgerwatch/erigon-lib/kv"
2022-01-24 23:12:25 +00:00
"github.com/ledgerwatch/erigon-lib/recsplit"
2023-01-13 18:12:18 +00:00
2021-11-14 04:08:52 +00:00
"github.com/ledgerwatch/erigon/core/rawdb"
"github.com/ledgerwatch/erigon/core/types"
2021-11-21 03:32:14 +00:00
"github.com/ledgerwatch/erigon/rlp"
2021-11-14 04:08:52 +00:00
)
// BlockReader can read blocks from db and snapshots
type BlockReader struct {
}
func NewBlockReader ( ) * BlockReader {
return & BlockReader { }
}
2023-01-13 18:12:18 +00:00
func ( back * BlockReader ) CanonicalHash ( ctx context . Context , tx kv . Getter , blockHeight uint64 ) ( libcommon . Hash , error ) {
2022-01-04 08:46:22 +00:00
return rawdb . ReadCanonicalHash ( tx , blockHeight )
}
2022-08-11 14:06:41 +00:00
func ( back * BlockReader ) Snapshots ( ) * RoSnapshots { return nil }
2023-01-13 18:12:18 +00:00
func ( back * BlockReader ) Header ( ctx context . Context , tx kv . Getter , hash libcommon . Hash , blockHeight uint64 ) ( * types . Header , error ) {
2021-11-29 03:43:19 +00:00
h := rawdb . ReadHeader ( tx , hash , blockHeight )
return h , nil
}
2023-01-13 18:12:18 +00:00
func ( back * BlockReader ) Body ( ctx context . Context , tx kv . Getter , hash libcommon . Hash , blockHeight uint64 ) ( body * types . Body , txAmount uint32 , err error ) {
2022-08-04 11:49:53 +00:00
body , _ , txAmount = rawdb . ReadBody ( tx , hash , blockHeight )
return body , txAmount , nil
2021-12-14 10:13:17 +00:00
}
2023-01-13 18:12:18 +00:00
func ( back * BlockReader ) BodyWithTransactions ( ctx context . Context , tx kv . Getter , hash libcommon . Hash , blockHeight uint64 ) ( body * types . Body , err error ) {
2022-01-07 13:52:38 +00:00
return rawdb . ReadBodyWithTransactions ( tx , hash , blockHeight )
}
2023-01-13 18:12:18 +00:00
func ( back * BlockReader ) BodyRlp ( ctx context . Context , tx kv . Getter , hash libcommon . Hash , blockHeight uint64 ) ( bodyRlp rlp . RawValue , err error ) {
2022-08-04 11:49:53 +00:00
body , _ , err := back . Body ( ctx , tx , hash , blockHeight )
2021-12-14 10:13:17 +00:00
if err != nil {
return nil , err
}
bodyRlp , err = rlp . EncodeToBytes ( body )
if err != nil {
return nil , err
}
return bodyRlp , nil
}
2021-12-05 02:03:08 +00:00
func ( back * BlockReader ) HeaderByNumber ( ctx context . Context , tx kv . Getter , blockHeight uint64 ) ( * types . Header , error ) {
2021-11-29 03:43:19 +00:00
h := rawdb . ReadHeaderByNumber ( tx , blockHeight )
return h , nil
}
2023-01-13 18:12:18 +00:00
func ( back * BlockReader ) HeaderByHash ( ctx context . Context , tx kv . Getter , hash libcommon . Hash ) ( * types . Header , error ) {
2022-01-04 08:46:22 +00:00
return rawdb . ReadHeaderByHash ( tx , hash )
}
2023-01-13 18:12:18 +00:00
func ( back * BlockReader ) BlockWithSenders ( ctx context . Context , tx kv . Getter , hash libcommon . Hash , blockHeight uint64 ) ( block * types . Block , senders [ ] libcommon . Address , err error ) {
2021-11-18 14:07:55 +00:00
canonicalHash , err := rawdb . ReadCanonicalHash ( tx , blockHeight )
2021-11-14 04:08:52 +00:00
if err != nil {
2021-11-18 14:07:55 +00:00
return nil , nil , fmt . Errorf ( "requested non-canonical hash %x. canonical=%x" , hash , canonicalHash )
2021-11-14 04:08:52 +00:00
}
2021-11-18 14:07:55 +00:00
if canonicalHash == hash {
block , senders , err = rawdb . ReadBlockWithSenders ( tx , hash , blockHeight )
if err != nil {
return nil , nil , err
}
return block , senders , nil
}
return rawdb . NonCanonicalBlockWithSenders ( tx , hash , blockHeight )
2021-11-14 04:08:52 +00:00
}
2021-11-21 03:32:14 +00:00
2023-01-13 18:12:18 +00:00
func ( back * BlockReader ) TxnLookup ( ctx context . Context , tx kv . Getter , txnHash libcommon . Hash ) ( uint64 , bool , error ) {
2022-01-06 11:22:59 +00:00
n , err := rawdb . ReadTxLookupEntry ( tx , txnHash )
if err != nil {
return 0 , false , err
}
if n == nil {
return 0 , false , nil
}
return * n , true , nil
}
2022-05-20 07:12:12 +00:00
func ( back * BlockReader ) TxnByIdxInBlock ( ctx context . Context , tx kv . Getter , blockNum uint64 , i int ) ( txn types . Transaction , err error ) {
canonicalHash , err := rawdb . ReadCanonicalHash ( tx , blockNum )
if err != nil {
return nil , err
}
var k [ 8 + 32 ] byte
binary . BigEndian . PutUint64 ( k [ : ] , blockNum )
copy ( k [ 8 : ] , canonicalHash [ : ] )
b , err := rawdb . ReadBodyForStorageByKey ( tx , k [ : ] )
if err != nil {
return nil , err
}
if b == nil {
return nil , nil
}
txn , err = rawdb . CanonicalTxnByID ( tx , b . BaseTxId + 1 + uint64 ( i ) )
if err != nil {
return nil , err
}
return txn , nil
}
2022-01-06 11:22:59 +00:00
2021-11-21 03:32:14 +00:00
type RemoteBlockReader struct {
client remote . ETHBACKENDClient
}
2022-06-01 02:57:12 +00:00
func ( back * RemoteBlockReader ) HeaderByNumber ( ctx context . Context , tx kv . Getter , blockHeight uint64 ) ( * types . Header , error ) {
canonicalHash , err := rawdb . ReadCanonicalHash ( tx , blockHeight )
if err != nil {
return nil , err
}
block , _ , err := back . BlockWithSenders ( ctx , tx , canonicalHash , blockHeight )
if err != nil {
return nil , err
}
return block . Header ( ) , nil
}
2022-08-11 14:06:41 +00:00
func ( back * RemoteBlockReader ) Snapshots ( ) * RoSnapshots { return nil }
2023-01-13 18:12:18 +00:00
func ( back * RemoteBlockReader ) HeaderByHash ( ctx context . Context , tx kv . Getter , hash libcommon . Hash ) ( * types . Header , error ) {
2022-06-01 02:57:12 +00:00
blockNum := rawdb . ReadHeaderNumber ( tx , hash )
if blockNum == nil {
return nil , nil
}
block , _ , err := back . BlockWithSenders ( ctx , tx , hash , * blockNum )
if err != nil {
return nil , err
}
return block . Header ( ) , nil
}
2023-01-13 18:12:18 +00:00
func ( back * RemoteBlockReader ) CanonicalHash ( ctx context . Context , tx kv . Getter , blockHeight uint64 ) ( libcommon . Hash , error ) {
2022-06-01 02:57:12 +00:00
return rawdb . ReadCanonicalHash ( tx , blockHeight )
}
2021-11-21 03:32:14 +00:00
func NewRemoteBlockReader ( client remote . ETHBACKENDClient ) * RemoteBlockReader {
return & RemoteBlockReader { client }
}
2023-01-13 18:12:18 +00:00
func ( back * RemoteBlockReader ) TxnLookup ( ctx context . Context , tx kv . Getter , txnHash libcommon . Hash ) ( uint64 , bool , error ) {
2022-01-07 13:52:38 +00:00
reply , err := back . client . TxnLookup ( ctx , & remote . TxnLookupRequest { TxnHash : gointerfaces . ConvertHashToH256 ( txnHash ) } )
if err != nil {
return 0 , false , err
}
if reply == nil {
return 0 , false , nil
}
return reply . BlockNumber , true , nil
}
2022-05-20 07:12:12 +00:00
func ( back * RemoteBlockReader ) TxnByIdxInBlock ( ctx context . Context , tx kv . Getter , blockNum uint64 , i int ) ( txn types . Transaction , err error ) {
2022-12-22 05:54:07 +00:00
canonicalHash , err := rawdb . ReadCanonicalHash ( tx , blockNum )
if err != nil {
return nil , err
}
b , err := back . BodyWithTransactions ( ctx , tx , canonicalHash , blockNum )
if err != nil {
return nil , err
}
if b == nil {
return nil , nil
}
2022-12-24 06:11:15 +00:00
if i < 0 {
return nil , nil
}
if len ( b . Transactions ) <= i {
return nil , nil
}
return b . Transactions [ i ] , nil
2022-05-20 07:12:12 +00:00
}
2023-01-13 18:12:18 +00:00
func ( back * RemoteBlockReader ) BlockWithSenders ( ctx context . Context , _ kv . Getter , hash libcommon . Hash , blockHeight uint64 ) ( block * types . Block , senders [ ] libcommon . Address , err error ) {
2021-11-21 03:32:14 +00:00
reply , err := back . client . Block ( ctx , & remote . BlockRequest { BlockHash : gointerfaces . ConvertHashToH256 ( hash ) , BlockHeight : blockHeight } )
if err != nil {
return nil , nil , err
}
block = & types . Block { }
err = rlp . Decode ( bytes . NewReader ( reply . BlockRlp ) , block )
if err != nil {
return nil , nil , err
}
2023-01-13 18:12:18 +00:00
senders = make ( [ ] libcommon . Address , len ( reply . Senders ) / 20 )
2021-11-21 03:32:14 +00:00
for i := range senders {
senders [ i ] . SetBytes ( reply . Senders [ i * 20 : ( i + 1 ) * 20 ] )
}
if len ( senders ) == block . Transactions ( ) . Len ( ) { //it's fine if no senders provided - they can be lazy recovered
block . SendersToTxs ( senders )
}
return block , senders , nil
}
2023-01-13 18:12:18 +00:00
func ( back * RemoteBlockReader ) Header ( ctx context . Context , tx kv . Getter , hash libcommon . Hash , blockHeight uint64 ) ( * types . Header , error ) {
2021-11-29 03:43:19 +00:00
block , _ , err := back . BlockWithSenders ( ctx , tx , hash , blockHeight )
if err != nil {
return nil , err
}
if block == nil {
return nil , nil
}
return block . Header ( ) , nil
}
2023-01-13 18:12:18 +00:00
func ( back * RemoteBlockReader ) Body ( ctx context . Context , tx kv . Getter , hash libcommon . Hash , blockHeight uint64 ) ( body * types . Body , txAmount uint32 , err error ) {
2022-01-07 13:52:38 +00:00
block , _ , err := back . BlockWithSenders ( ctx , tx , hash , blockHeight )
if err != nil {
2022-08-04 11:49:53 +00:00
return nil , 0 , err
2022-01-07 13:52:38 +00:00
}
if block == nil {
2022-08-04 11:49:53 +00:00
return nil , 0 , nil
2022-01-07 13:52:38 +00:00
}
2022-08-04 11:49:53 +00:00
return block . Body ( ) , uint32 ( len ( block . Body ( ) . Transactions ) ) , nil
2022-01-07 13:52:38 +00:00
}
2023-01-13 18:12:18 +00:00
func ( back * RemoteBlockReader ) BodyWithTransactions ( ctx context . Context , tx kv . Getter , hash libcommon . Hash , blockHeight uint64 ) ( body * types . Body , err error ) {
2021-12-14 10:13:17 +00:00
block , _ , err := back . BlockWithSenders ( ctx , tx , hash , blockHeight )
if err != nil {
return nil , err
}
if block == nil {
return nil , nil
}
return block . Body ( ) , nil
}
2023-01-13 18:12:18 +00:00
func ( back * RemoteBlockReader ) BodyRlp ( ctx context . Context , tx kv . Getter , hash libcommon . Hash , blockHeight uint64 ) ( bodyRlp rlp . RawValue , err error ) {
2022-01-07 13:52:38 +00:00
body , err := back . BodyWithTransactions ( ctx , tx , hash , blockHeight )
2021-12-14 10:13:17 +00:00
if err != nil {
return nil , err
}
bodyRlp , err = rlp . EncodeToBytes ( body )
if err != nil {
return nil , err
}
return bodyRlp , nil
}
2021-11-29 03:43:19 +00:00
2021-11-21 03:32:14 +00:00
// BlockReaderWithSnapshots can read blocks from db and snapshots
type BlockReaderWithSnapshots struct {
2022-03-16 02:57:48 +00:00
sn * RoSnapshots
2021-11-21 03:32:14 +00:00
}
2022-02-18 02:24:17 +00:00
func NewBlockReaderWithSnapshots ( snapshots * RoSnapshots ) * BlockReaderWithSnapshots {
2021-11-21 03:32:14 +00:00
return & BlockReaderWithSnapshots { sn : snapshots }
}
2022-05-10 02:29:44 +00:00
2022-08-11 14:06:41 +00:00
func ( back * BlockReaderWithSnapshots ) Snapshots ( ) * RoSnapshots { return back . sn }
2022-03-16 02:57:48 +00:00
func ( back * BlockReaderWithSnapshots ) HeaderByNumber ( ctx context . Context , tx kv . Getter , blockHeight uint64 ) ( h * types . Header , err error ) {
ok , err := back . sn . ViewHeaders ( blockHeight , func ( segment * HeaderSegment ) error {
2022-05-10 02:29:44 +00:00
h , _ , err = back . headerFromSnapshot ( blockHeight , segment , nil )
2022-03-16 02:57:48 +00:00
if err != nil {
return err
}
return nil
} )
if err != nil {
return nil , err
}
if ok {
2021-11-29 03:43:19 +00:00
return h , nil
}
2022-07-05 08:49:39 +00:00
h = rawdb . ReadHeaderByNumber ( tx , blockHeight )
return h , nil
2021-11-29 03:43:19 +00:00
}
2021-12-14 10:13:17 +00:00
2022-01-04 08:46:22 +00:00
// HeaderByHash - will search header in all snapshots starting from recent
2023-01-13 18:12:18 +00:00
func ( back * BlockReaderWithSnapshots ) HeaderByHash ( ctx context . Context , tx kv . Getter , hash libcommon . Hash ) ( h * types . Header , err error ) {
2022-03-16 02:57:48 +00:00
h , err = rawdb . ReadHeaderByHash ( tx , hash )
2022-01-04 08:46:22 +00:00
if err != nil {
return nil , err
}
if h != nil {
return h , nil
}
2022-01-07 13:52:38 +00:00
buf := make ( [ ] byte , 128 )
2022-03-16 02:57:48 +00:00
if err := back . sn . Headers . View ( func ( segments [ ] * HeaderSegment ) error {
for i := len ( segments ) - 1 ; i >= 0 ; i -- {
2022-03-21 13:36:03 +00:00
if segments [ i ] . idxHeaderHash == nil {
continue
}
2022-03-16 02:57:48 +00:00
h , err = back . headerFromSnapshotByHash ( hash , segments [ i ] , buf )
if err != nil {
return err
}
2022-08-09 08:03:39 +00:00
if h != nil {
break
}
2022-01-04 08:46:22 +00:00
}
2022-03-16 02:57:48 +00:00
return nil
} ) ; err != nil {
return nil , err
2022-01-04 08:46:22 +00:00
}
2022-03-16 02:57:48 +00:00
return h , nil
2022-01-04 08:46:22 +00:00
}
2023-01-13 18:12:18 +00:00
func ( back * BlockReaderWithSnapshots ) CanonicalHash ( ctx context . Context , tx kv . Getter , blockHeight uint64 ) ( h libcommon . Hash , err error ) {
2022-03-16 02:57:48 +00:00
ok , err := back . sn . ViewHeaders ( blockHeight , func ( segment * HeaderSegment ) error {
2022-05-10 02:29:44 +00:00
header , _ , err := back . headerFromSnapshot ( blockHeight , segment , nil )
2022-03-16 02:57:48 +00:00
if err != nil {
return err
}
if header == nil {
return nil
}
h = header . Hash ( )
return nil
} )
2022-01-04 08:46:22 +00:00
if err != nil {
2022-03-16 02:57:48 +00:00
return h , err
2022-01-04 08:46:22 +00:00
}
2022-03-16 02:57:48 +00:00
if ok {
return h , nil
2022-01-04 08:46:22 +00:00
}
2022-03-16 02:57:48 +00:00
return rawdb . ReadCanonicalHash ( tx , blockHeight )
2022-01-04 08:46:22 +00:00
}
2023-01-13 18:12:18 +00:00
func ( back * BlockReaderWithSnapshots ) Header ( ctx context . Context , tx kv . Getter , hash libcommon . Hash , blockHeight uint64 ) ( h * types . Header , err error ) {
2022-03-16 02:57:48 +00:00
ok , err := back . sn . ViewHeaders ( blockHeight , func ( segment * HeaderSegment ) error {
2022-05-10 02:29:44 +00:00
h , _ , err = back . headerFromSnapshot ( blockHeight , segment , nil )
2022-03-16 02:57:48 +00:00
if err != nil {
return err
}
return nil
} )
2022-07-02 19:48:42 +00:00
if err != nil {
return h , err
}
2022-03-16 02:57:48 +00:00
if ok {
2021-11-29 03:43:19 +00:00
return h , nil
}
2022-03-16 02:57:48 +00:00
h = rawdb . ReadHeader ( tx , hash , blockHeight )
return h , nil
2021-11-29 03:43:19 +00:00
}
2023-01-13 18:12:18 +00:00
func ( back * BlockReaderWithSnapshots ) BodyWithTransactions ( ctx context . Context , tx kv . Getter , hash libcommon . Hash , blockHeight uint64 ) ( body * types . Body , err error ) {
2022-03-16 02:57:48 +00:00
var baseTxnID uint64
var txsAmount uint32
2022-05-10 02:29:44 +00:00
var buf [ ] byte
2022-03-16 02:57:48 +00:00
ok , err := back . sn . ViewBodies ( blockHeight , func ( seg * BodySegment ) error {
2022-05-10 02:29:44 +00:00
body , baseTxnID , txsAmount , buf , err = back . bodyFromSnapshot ( blockHeight , seg , buf )
2022-03-16 02:57:48 +00:00
if err != nil {
return err
}
return nil
} )
if err != nil {
return nil , err
}
if ok {
ok , err = back . sn . ViewTxs ( blockHeight , func ( seg * TxnSegment ) error {
2022-05-10 02:29:44 +00:00
txs , senders , err := back . txsFromSnapshot ( baseTxnID , txsAmount , seg , buf )
2022-03-16 02:57:48 +00:00
if err != nil {
return err
}
2022-05-10 02:29:44 +00:00
if txs == nil {
return nil
}
2022-03-16 02:57:48 +00:00
body . Transactions = txs
body . SendersToTxs ( senders )
return nil
} )
2021-12-14 10:13:17 +00:00
if err != nil {
return nil , err
}
2022-03-16 02:57:48 +00:00
if ok {
return body , nil
}
2021-12-14 10:13:17 +00:00
}
2022-03-16 02:57:48 +00:00
body , err = rawdb . ReadBodyWithTransactions ( tx , hash , blockHeight )
2021-12-14 10:13:17 +00:00
if err != nil {
return nil , err
}
return body , nil
}
2023-01-13 18:12:18 +00:00
func ( back * BlockReaderWithSnapshots ) BodyRlp ( ctx context . Context , tx kv . Getter , hash libcommon . Hash , blockHeight uint64 ) ( bodyRlp rlp . RawValue , err error ) {
2022-01-07 13:52:38 +00:00
body , err := back . BodyWithTransactions ( ctx , tx , hash , blockHeight )
2021-12-14 10:13:17 +00:00
if err != nil {
return nil , err
}
bodyRlp , err = rlp . EncodeToBytes ( body )
if err != nil {
return nil , err
}
return bodyRlp , nil
}
2023-01-13 18:12:18 +00:00
func ( back * BlockReaderWithSnapshots ) Body ( ctx context . Context , tx kv . Getter , hash libcommon . Hash , blockHeight uint64 ) ( body * types . Body , txAmount uint32 , err error ) {
2022-03-16 02:57:48 +00:00
ok , err := back . sn . ViewBodies ( blockHeight , func ( seg * BodySegment ) error {
2022-08-04 11:49:53 +00:00
body , _ , txAmount , _ , err = back . bodyFromSnapshot ( blockHeight , seg , nil )
2022-03-16 02:57:48 +00:00
if err != nil {
return err
}
return nil
} )
2022-01-07 13:52:38 +00:00
if err != nil {
2022-08-04 11:49:53 +00:00
return nil , 0 , err
2022-01-07 13:52:38 +00:00
}
2022-03-16 02:57:48 +00:00
if ok {
2022-08-04 11:49:53 +00:00
return body , txAmount , nil
2022-03-16 02:57:48 +00:00
}
2022-08-04 11:49:53 +00:00
body , _ , txAmount = rawdb . ReadBody ( tx , hash , blockHeight )
return body , txAmount , nil
2022-01-07 13:52:38 +00:00
}
2023-01-13 18:12:18 +00:00
func ( back * BlockReaderWithSnapshots ) BlockWithSenders ( ctx context . Context , tx kv . Getter , hash libcommon . Hash , blockHeight uint64 ) ( block * types . Block , senders [ ] libcommon . Address , err error ) {
2022-03-16 02:57:48 +00:00
var buf [ ] byte
var h * types . Header
ok , err := back . sn . ViewHeaders ( blockHeight , func ( seg * HeaderSegment ) error {
2022-05-10 02:29:44 +00:00
h , buf , err = back . headerFromSnapshot ( blockHeight , seg , buf )
if err != nil {
2022-03-16 02:57:48 +00:00
return err
}
return nil
} )
if err != nil {
2022-07-06 13:10:12 +00:00
return nil , nil , err
2022-03-16 02:57:48 +00:00
}
2022-05-10 02:29:44 +00:00
if ok && h != nil {
var b * types . Body
var baseTxnId uint64
var txsAmount uint32
2022-03-16 02:57:48 +00:00
ok , err = back . sn . ViewBodies ( blockHeight , func ( seg * BodySegment ) error {
2022-05-10 02:29:44 +00:00
b , baseTxnId , txsAmount , buf , err = back . bodyFromSnapshot ( blockHeight , seg , buf )
if err != nil {
2022-03-16 02:57:48 +00:00
return err
}
return nil
} )
2021-11-21 03:32:14 +00:00
if err != nil {
2022-07-06 13:10:12 +00:00
return nil , nil , err
2021-11-21 03:32:14 +00:00
}
2022-05-10 02:29:44 +00:00
if ok && b != nil {
if txsAmount == 0 {
2022-12-01 08:15:01 +00:00
block = types . NewBlockFromStorage ( hash , h , nil , b . Uncles , b . Withdrawals )
2022-03-16 02:57:48 +00:00
if len ( senders ) != block . Transactions ( ) . Len ( ) {
return block , senders , nil // no senders is fine - will recover them on the fly
}
block . SendersToTxs ( senders )
return block , senders , nil
}
2022-05-10 02:29:44 +00:00
var txs [ ] types . Transaction
2023-01-13 18:12:18 +00:00
var senders [ ] libcommon . Address
2022-03-16 02:57:48 +00:00
ok , err = back . sn . ViewTxs ( blockHeight , func ( seg * TxnSegment ) error {
2022-05-10 02:29:44 +00:00
txs , senders , err = back . txsFromSnapshot ( baseTxnId , txsAmount , seg , buf )
if err != nil {
return err
2022-03-16 02:57:48 +00:00
}
return nil
} )
2021-11-21 03:32:14 +00:00
if err != nil {
return nil , nil , err
}
2022-03-16 02:57:48 +00:00
if ok {
2022-12-01 08:15:01 +00:00
block = types . NewBlockFromStorage ( hash , h , txs , b . Uncles , b . Withdrawals )
2022-03-16 02:57:48 +00:00
if len ( senders ) != block . Transactions ( ) . Len ( ) {
return block , senders , nil // no senders is fine - will recover them on the fly
}
block . SendersToTxs ( senders )
return block , senders , nil
}
2021-11-21 03:32:14 +00:00
}
}
2022-03-16 02:57:48 +00:00
canonicalHash , err := rawdb . ReadCanonicalHash ( tx , blockHeight )
if err != nil {
return nil , nil , fmt . Errorf ( "requested non-canonical hash %x. canonical=%x" , hash , canonicalHash )
2021-11-29 03:43:19 +00:00
}
2022-03-16 02:57:48 +00:00
if canonicalHash == hash {
block , senders , err = rawdb . ReadBlockWithSenders ( tx , hash , blockHeight )
if err != nil {
return nil , nil , err
2021-11-21 03:32:14 +00:00
}
2022-03-16 02:57:48 +00:00
return block , senders , nil
2021-11-21 03:32:14 +00:00
}
2022-03-16 02:57:48 +00:00
return rawdb . NonCanonicalBlockWithSenders ( tx , hash , blockHeight )
2021-11-21 03:32:14 +00:00
}
2021-11-29 03:43:19 +00:00
2022-05-10 02:29:44 +00:00
func ( back * BlockReaderWithSnapshots ) headerFromSnapshot ( blockHeight uint64 , sn * HeaderSegment , buf [ ] byte ) ( * types . Header , [ ] byte , error ) {
if sn . idxHeaderHash == nil {
return nil , buf , nil
}
2022-06-17 12:40:49 +00:00
headerOffset := sn . idxHeaderHash . OrdinalLookup ( blockHeight - sn . idxHeaderHash . BaseDataID ( ) )
2022-03-16 02:57:48 +00:00
gg := sn . seg . MakeGetter ( )
2021-11-29 03:43:19 +00:00
gg . Reset ( headerOffset )
2022-06-28 04:31:44 +00:00
if ! gg . HasNext ( ) {
2022-09-18 10:41:01 +00:00
return nil , buf , nil
2022-06-28 04:31:44 +00:00
}
2021-11-29 03:43:19 +00:00
buf , _ = gg . Next ( buf [ : 0 ] )
2022-04-25 03:24:37 +00:00
if len ( buf ) == 0 {
2022-05-10 02:29:44 +00:00
return nil , buf , nil
2022-04-25 03:24:37 +00:00
}
2021-11-29 03:43:19 +00:00
h := & types . Header { }
2022-01-04 08:46:22 +00:00
if err := rlp . DecodeBytes ( buf [ 1 : ] , h ) ; err != nil {
2022-05-10 02:29:44 +00:00
return nil , buf , err
2022-01-04 08:46:22 +00:00
}
2022-05-10 02:29:44 +00:00
return h , buf , nil
2022-01-04 08:46:22 +00:00
}
// headerFromSnapshotByHash - getting header by hash AND ensure that it has correct hash
// because HeaderByHash method will search header in all snapshots - and may request header which doesn't exists
// but because our indices are based on PerfectHashMap, no way to know is given key exists or not, only way -
// to make sure is to fetch it and compare hash
2023-01-13 18:12:18 +00:00
func ( back * BlockReaderWithSnapshots ) headerFromSnapshotByHash ( hash libcommon . Hash , sn * HeaderSegment , buf [ ] byte ) ( * types . Header , error ) {
2022-06-28 04:31:44 +00:00
defer func ( ) {
if rec := recover ( ) ; rec != nil {
2022-07-19 12:27:54 +00:00
panic ( fmt . Errorf ( "%+v, snapshot: %d-%d, trace: %s" , rec , sn . ranges . from , sn . ranges . to , dbg . Stack ( ) ) )
2022-06-28 04:31:44 +00:00
}
} ( ) // avoid crash because Erigon's core does many things
2022-05-10 02:29:44 +00:00
if sn . idxHeaderHash == nil {
return nil , nil
}
2022-03-16 02:57:48 +00:00
reader := recsplit . NewIndexReader ( sn . idxHeaderHash )
2022-01-24 23:12:25 +00:00
localID := reader . Lookup ( hash [ : ] )
2022-06-17 12:40:49 +00:00
headerOffset := sn . idxHeaderHash . OrdinalLookup ( localID )
2022-03-16 02:57:48 +00:00
gg := sn . seg . MakeGetter ( )
2022-01-04 08:46:22 +00:00
gg . Reset ( headerOffset )
2022-06-28 04:31:44 +00:00
if ! gg . HasNext ( ) {
return nil , nil
}
2022-01-04 08:46:22 +00:00
buf , _ = gg . Next ( buf [ : 0 ] )
2022-04-25 03:24:37 +00:00
if len ( buf ) > 1 && hash [ 0 ] != buf [ 0 ] {
2022-01-04 08:46:22 +00:00
return nil , nil
}
h := & types . Header { }
if err := rlp . DecodeBytes ( buf [ 1 : ] , h ) ; err != nil {
2021-11-29 03:43:19 +00:00
return nil , err
}
2022-01-04 08:46:22 +00:00
if h . Hash ( ) != hash {
return nil , nil
}
2021-11-29 03:43:19 +00:00
return h , nil
}
2021-12-14 10:13:17 +00:00
2022-05-10 02:29:44 +00:00
func ( back * BlockReaderWithSnapshots ) bodyFromSnapshot ( blockHeight uint64 , sn * BodySegment , buf [ ] byte ) ( * types . Body , uint64 , uint32 , [ ] byte , error ) {
2022-05-20 07:12:12 +00:00
b , buf , err := back . bodyForStorageFromSnapshot ( blockHeight , sn , buf )
if err != nil {
return nil , 0 , 0 , buf , err
}
body := new ( types . Body )
body . Uncles = b . Uncles
var txsAmount uint32
if b . TxAmount >= 2 {
txsAmount = b . TxAmount - 2
}
return body , b . BaseTxId + 1 , txsAmount , buf , nil // empty txs in the beginning and end of block
}
func ( back * BlockReaderWithSnapshots ) bodyForStorageFromSnapshot ( blockHeight uint64 , sn * BodySegment , buf [ ] byte ) ( * types . BodyForStorage , [ ] byte , error ) {
2022-06-28 04:31:44 +00:00
defer func ( ) {
if rec := recover ( ) ; rec != nil {
2022-07-19 12:27:54 +00:00
panic ( fmt . Errorf ( "%+v, snapshot: %d-%d, trace: %s" , rec , sn . ranges . from , sn . ranges . to , dbg . Stack ( ) ) )
2022-06-28 04:31:44 +00:00
}
} ( ) // avoid crash because Erigon's core does many things
2022-05-10 02:29:44 +00:00
if sn . idxBodyNumber == nil {
2022-05-20 07:12:12 +00:00
return nil , buf , nil
2022-05-10 02:29:44 +00:00
}
2022-06-17 12:40:49 +00:00
bodyOffset := sn . idxBodyNumber . OrdinalLookup ( blockHeight - sn . idxBodyNumber . BaseDataID ( ) )
2021-12-14 10:13:17 +00:00
2022-03-16 02:57:48 +00:00
gg := sn . seg . MakeGetter ( )
2021-12-14 10:13:17 +00:00
gg . Reset ( bodyOffset )
2022-06-28 04:31:44 +00:00
if ! gg . HasNext ( ) {
2022-09-18 10:41:01 +00:00
return nil , buf , nil
2022-06-28 04:31:44 +00:00
}
2021-12-14 10:13:17 +00:00
buf , _ = gg . Next ( buf [ : 0 ] )
2022-04-25 03:24:37 +00:00
if len ( buf ) == 0 {
2022-09-18 10:41:01 +00:00
return nil , buf , nil
2022-04-25 03:24:37 +00:00
}
2021-12-14 10:13:17 +00:00
b := & types . BodyForStorage { }
reader := bytes . NewReader ( buf )
if err := rlp . Decode ( reader , b ) ; err != nil {
2022-05-20 07:12:12 +00:00
return nil , buf , err
2021-12-14 10:13:17 +00:00
}
2022-03-16 02:57:48 +00:00
if b . BaseTxId < sn . idxBodyNumber . BaseDataID ( ) {
2022-05-20 07:12:12 +00:00
return nil , buf , fmt . Errorf ( ".idx file has wrong baseDataID? %d<%d, %s" , b . BaseTxId , sn . idxBodyNumber . BaseDataID ( ) , sn . seg . FilePath ( ) )
2021-12-14 10:13:17 +00:00
}
2022-05-20 07:12:12 +00:00
return b , buf , nil
2022-01-07 13:52:38 +00:00
}
2023-01-13 18:12:18 +00:00
func ( back * BlockReaderWithSnapshots ) txsFromSnapshot ( baseTxnID uint64 , txsAmount uint32 , txsSeg * TxnSegment , buf [ ] byte ) ( txs [ ] types . Transaction , senders [ ] libcommon . Address , err error ) {
2022-06-28 04:31:44 +00:00
defer func ( ) {
if rec := recover ( ) ; rec != nil {
2022-07-19 12:27:54 +00:00
panic ( fmt . Errorf ( "%+v, snapshot: %d-%d, trace: %s" , rec , txsSeg . ranges . from , txsSeg . ranges . to , dbg . Stack ( ) ) )
2022-06-28 04:31:44 +00:00
}
} ( ) // avoid crash because Erigon's core does many things
2022-05-10 02:29:44 +00:00
if txsSeg . IdxTxnHash == nil {
return nil , nil , nil
}
if baseTxnID < txsSeg . IdxTxnHash . BaseDataID ( ) {
return nil , nil , fmt . Errorf ( ".idx file has wrong baseDataID? %d<%d, %s" , baseTxnID , txsSeg . IdxTxnHash . BaseDataID ( ) , txsSeg . Seg . FilePath ( ) )
}
txs = make ( [ ] types . Transaction , txsAmount )
2023-01-13 18:12:18 +00:00
senders = make ( [ ] libcommon . Address , txsAmount )
2022-05-10 02:29:44 +00:00
if txsAmount == 0 {
return txs , senders , nil
}
2022-06-17 12:40:49 +00:00
txnOffset := txsSeg . IdxTxnHash . OrdinalLookup ( baseTxnID - txsSeg . IdxTxnHash . BaseDataID ( ) )
2022-05-10 02:29:44 +00:00
gg := txsSeg . Seg . MakeGetter ( )
gg . Reset ( txnOffset )
2022-09-09 07:40:25 +00:00
reader := bytes . NewReader ( buf )
2022-05-10 02:29:44 +00:00
stream := rlp . NewStream ( reader , 0 )
for i := uint32 ( 0 ) ; i < txsAmount ; i ++ {
2022-06-28 04:31:44 +00:00
if ! gg . HasNext ( ) {
return nil , nil , nil
}
2022-05-10 02:29:44 +00:00
buf , _ = gg . Next ( buf [ : 0 ] )
if len ( buf ) < 1 + 20 {
return nil , nil , fmt . Errorf ( "segment %s has too short record: len(buf)=%d < 21" , txsSeg . Seg . FilePath ( ) , len ( buf ) )
2021-12-14 10:13:17 +00:00
}
2022-05-10 02:29:44 +00:00
senders [ i ] . SetBytes ( buf [ 1 : 1 + 20 ] )
txRlp := buf [ 1 + 20 : ]
reader . Reset ( txRlp )
stream . Reset ( reader , 0 )
txs [ i ] , err = types . DecodeTransaction ( stream )
if err != nil {
return nil , nil , err
}
txs [ i ] . SetSender ( senders [ i ] )
2021-12-14 10:13:17 +00:00
}
2022-03-16 02:57:48 +00:00
return txs , senders , nil
2021-12-14 10:13:17 +00:00
}
2022-01-06 11:22:59 +00:00
2022-05-20 07:12:12 +00:00
func ( back * BlockReaderWithSnapshots ) txnByID ( txnID uint64 , sn * TxnSegment , buf [ ] byte ) ( txn types . Transaction , err error ) {
2022-06-17 12:40:49 +00:00
offset := sn . IdxTxnHash . OrdinalLookup ( txnID - sn . IdxTxnHash . BaseDataID ( ) )
2022-05-20 07:12:12 +00:00
gg := sn . Seg . MakeGetter ( )
gg . Reset ( offset )
2022-06-28 04:31:44 +00:00
if ! gg . HasNext ( ) {
return nil , nil
}
2022-05-20 07:12:12 +00:00
buf , _ = gg . Next ( buf [ : 0 ] )
sender , txnRlp := buf [ 1 : 1 + 20 ] , buf [ 1 + 20 : ]
txn , err = types . DecodeTransaction ( rlp . NewStream ( bytes . NewReader ( txnRlp ) , uint64 ( len ( txnRlp ) ) ) )
if err != nil {
return
}
2023-01-13 18:12:18 +00:00
txn . SetSender ( * ( * libcommon . Address ) ( sender ) ) // see: https://tip.golang.org/ref/spec#Conversions_from_slice_to_array_pointer
2022-05-20 07:12:12 +00:00
return
}
2023-01-13 18:12:18 +00:00
func ( back * BlockReaderWithSnapshots ) txnByHash ( txnHash libcommon . Hash , segments [ ] * TxnSegment , buf [ ] byte ) ( txn types . Transaction , blockNum , txnID uint64 , err error ) {
2022-03-16 02:57:48 +00:00
for i := len ( segments ) - 1 ; i >= 0 ; i -- {
sn := segments [ i ]
2022-04-07 04:27:57 +00:00
if sn . IdxTxnHash == nil || sn . IdxTxnHash2BlockNum == nil {
2022-03-21 13:36:03 +00:00
continue
}
2022-01-06 11:22:59 +00:00
2022-03-16 02:57:48 +00:00
reader := recsplit . NewIndexReader ( sn . IdxTxnHash )
2022-04-07 04:27:57 +00:00
txnId := reader . Lookup ( txnHash [ : ] )
2022-06-17 12:40:49 +00:00
offset := sn . IdxTxnHash . OrdinalLookup ( txnId )
2022-03-16 02:57:48 +00:00
gg := sn . Seg . MakeGetter ( )
2022-01-06 11:22:59 +00:00
gg . Reset ( offset )
2022-01-24 06:47:05 +00:00
// first byte txnHash check - reducing false-positives 256 times. Allows don't store and don't calculate full hash of entity - when checking many snapshots.
2022-05-17 02:40:45 +00:00
if ! gg . MatchPrefix ( [ ] byte { txnHash [ 0 ] } ) {
2022-01-06 11:22:59 +00:00
continue
}
2022-05-17 02:40:45 +00:00
buf , _ = gg . Next ( buf [ : 0 ] )
2022-09-02 14:41:58 +00:00
senderByte , txnRlp := buf [ 1 : 1 + 20 ] , buf [ 1 + 20 : ]
2023-01-13 18:12:18 +00:00
sender := * ( * libcommon . Address ) ( senderByte )
2022-01-06 11:22:59 +00:00
2022-05-17 02:40:45 +00:00
txn , err = types . DecodeTransaction ( rlp . NewStream ( bytes . NewReader ( txnRlp ) , uint64 ( len ( txnRlp ) ) ) )
2022-01-07 13:52:38 +00:00
if err != nil {
return
}
2022-09-02 14:41:58 +00:00
txn . SetSender ( sender ) // see: https://tip.golang.org/ref/spec#Conversions_from_slice_to_array_pointer
2022-05-17 02:40:45 +00:00
reader2 := recsplit . NewIndexReader ( sn . IdxTxnHash2BlockNum )
blockNum = reader2 . Lookup ( txnHash [ : ] )
2022-01-07 13:52:38 +00:00
// final txnHash check - completely avoid false-positives
2022-01-24 06:47:05 +00:00
if txn . Hash ( ) == txnHash {
2022-01-07 13:52:38 +00:00
return
}
2022-01-06 11:22:59 +00:00
}
2022-01-07 13:52:38 +00:00
return
}
2022-01-06 11:22:59 +00:00
2022-09-20 12:09:24 +00:00
// TxnByIdxInBlock - doesn't include system-transactions in the begin/end of block
2023-01-11 05:04:22 +00:00
// return nil if 0 < i < body.TxAmount
2022-05-20 07:12:12 +00:00
func ( back * BlockReaderWithSnapshots ) TxnByIdxInBlock ( ctx context . Context , tx kv . Getter , blockNum uint64 , i int ) ( txn types . Transaction , err error ) {
var b * types . BodyForStorage
ok , err := back . sn . ViewBodies ( blockNum , func ( segment * BodySegment ) error {
b , _ , err = back . bodyForStorageFromSnapshot ( blockNum , segment , nil )
if err != nil {
return err
}
if b == nil {
return nil
}
return nil
} )
2022-09-20 12:09:24 +00:00
if err != nil {
return nil , err
}
2022-05-20 07:12:12 +00:00
if ok {
2022-09-20 12:09:24 +00:00
// if block has no transactions, or requested txNum out of non-system transactions length
if b . TxAmount == 2 || i == - 1 || i >= int ( b . TxAmount - 2 ) {
return nil , nil
}
2022-05-20 07:12:12 +00:00
ok , err = back . sn . Txs . ViewSegment ( blockNum , func ( segment * TxnSegment ) error {
// +1 because block has system-txn in the beginning of block
txn , err = back . txnByID ( b . BaseTxId + 1 + uint64 ( i ) , segment , nil )
if err != nil {
return err
}
if txn == nil {
return nil
}
return nil
} )
if err != nil {
return nil , err
}
if ok {
return txn , nil
}
return nil , nil
}
canonicalHash , err := rawdb . ReadCanonicalHash ( tx , blockNum )
if err != nil {
return nil , err
}
var k [ 8 + 32 ] byte
binary . BigEndian . PutUint64 ( k [ : ] , blockNum )
copy ( k [ 8 : ] , canonicalHash [ : ] )
b , err = rawdb . ReadBodyForStorageByKey ( tx , k [ : ] )
if err != nil {
return nil , err
}
if b == nil {
return nil , nil
}
txn , err = rawdb . CanonicalTxnByID ( tx , b . BaseTxId + 1 + uint64 ( i ) )
if err != nil {
return nil , err
}
return txn , nil
}
2022-01-07 13:52:38 +00:00
// TxnLookup - find blockNumber and txnID by txnHash
2023-01-13 18:12:18 +00:00
func ( back * BlockReaderWithSnapshots ) TxnLookup ( ctx context . Context , tx kv . Getter , txnHash libcommon . Hash ) ( uint64 , bool , error ) {
2022-01-07 13:52:38 +00:00
n , err := rawdb . ReadTxLookupEntry ( tx , txnHash )
if err != nil {
return 0 , false , err
}
if n != nil {
return * n , true , nil
}
2022-03-16 02:57:48 +00:00
var txn types . Transaction
var blockNum uint64
if err := back . sn . Txs . View ( func ( segments [ ] * TxnSegment ) error {
txn , blockNum , _ , err = back . txnByHash ( txnHash , segments , nil )
if err != nil {
return err
}
if txn == nil {
return nil
}
return nil
} ) ; err != nil {
2022-01-07 13:52:38 +00:00
return 0 , false , err
}
if txn == nil {
return 0 , false , nil
}
return blockNum , true , nil
2022-01-06 11:22:59 +00:00
}