github.com/TrueBlocks/trueblocks-core/src/apps/chifra@v0.0.0-20241022031540-b362680128f7/pkg/rpc/get_block_body.go (about) 1 // Copyright 2021 The TrueBlocks Authors. All rights reserved. 2 // Use of this source code is governed by a license that can 3 // be found in the LICENSE file. 4 5 package rpc 6 7 import ( 8 "fmt" 9 10 "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/base" 11 "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/rpc/query" 12 "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/types" 13 "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/walk" 14 "github.com/ethereum/go-ethereum" 15 ) 16 17 // GetBlockBodyByNumber fetches the block with transactions from the RPC. 18 func (conn *Connection) GetBlockBodyByNumber(bn base.Blknum) (types.Block, error) { 19 var err error 20 if conn.StoreReadable() { 21 // walk.Cache_Transactions, walk.Cache_Blocks 22 lightBlock := &types.LightBlock{ 23 BlockNumber: bn, 24 } 25 if err := conn.Store.Read(lightBlock, nil); err == nil { 26 // We need to fill in the actual transactions (from cache hopefully, but 27 // if not, then from the RPC) 28 transactions := make([]types.Transaction, 0, len(lightBlock.Transactions)) 29 for index := range lightBlock.Transactions { 30 tx, thisErr := conn.GetTransactionByNumberAndId(lightBlock.BlockNumber, base.Txnum(index)) 31 if thisErr != nil { 32 err = thisErr 33 break 34 } 35 transactions = append(transactions, *tx) 36 } 37 38 if err == nil && len(transactions) == len(lightBlock.Transactions) { 39 lightToBody := func(block *types.LightBlock) *types.Block { 40 var ret types.Block 41 ret.BaseFeePerGas = block.BaseFeePerGas 42 ret.BlockNumber = block.BlockNumber 43 ret.Difficulty = block.Difficulty 44 ret.GasLimit = block.GasLimit 45 ret.GasUsed = block.GasUsed 46 ret.Hash = block.Hash 47 ret.Miner = block.Miner 48 ret.ParentHash = block.ParentHash 49 ret.Timestamp = block.Timestamp 50 ret.Uncles = block.Uncles 51 ret.Withdrawals = block.Withdrawals 52 return &ret 53 } 54 55 ret := lightToBody(lightBlock) 56 ret.Transactions = transactions 57 // TODO: BOGUS - avoid copy 58 return *ret, err 59 } 60 } 61 } 62 63 // The block is not in the cache, or reading the cache failed. We 64 // need to fetch the block from the RPC. 65 block, err := conn.getBlockFromRpc(bn, notAHash) 66 if err != nil { 67 return types.Block{}, err 68 } 69 isFinal := base.IsFinal(conn.LatestBlockTimestamp, block.Timestamp) 70 71 _, receiptMap, _ := conn.GetReceiptsByNumber(bn, block.Timestamp) 72 for i := 0; i < len(block.Transactions); i++ { 73 receipt := receiptMap[block.Transactions[i].TransactionIndex] 74 if receipt == nil { 75 rec, err := conn.GetReceipt(bn, block.Transactions[i].TransactionIndex, block.Timestamp) 76 if err != nil { 77 return types.Block{}, err 78 } 79 receipt = &rec 80 } 81 block.Transactions[i].GasUsed = receipt.GasUsed 82 block.Transactions[i].IsError = receipt.IsError 83 block.Transactions[i].Receipt = receipt 84 block.Transactions[i].Timestamp = block.Timestamp 85 block.Transactions[i].HasToken = types.IsTokenFunction(block.Transactions[i].Input) 86 if isFinal && conn.StoreWritable() && conn.EnabledMap[walk.Cache_Transactions] { 87 _ = conn.Store.Write(&block.Transactions[i], nil) 88 } 89 } 90 91 if isFinal && conn.StoreWritable() && conn.EnabledMap[walk.Cache_Blocks] { 92 _ = conn.Store.Write(block, nil) 93 } 94 95 // TODO: BOGUS - avoid copy 96 return *block, nil 97 } 98 99 // getBlockFromRpc returns the block as received from the node 100 func (conn *Connection) getBlockFromRpc(bn base.Blknum, hash base.Hash) (*types.Block, error) { 101 method := "eth_getBlockByNumber" 102 params := query.Params{fmt.Sprintf("0x%x", bn), true} 103 if hash != notAHash { 104 method = "eth_getBlockByHash" 105 params = query.Params{hash, true} 106 } 107 108 if block, err := query.Query[types.Block](conn.Chain, method, params); err != nil { 109 return &types.Block{}, err 110 } else { 111 block.BlockNumber = block.Number 112 if bn == 0 { 113 block.Timestamp = conn.GetBlockTimestamp(0) 114 } else if block.Timestamp == 0 { 115 return &types.Block{}, fmt.Errorf("block at %s returned an error: %w", fmt.Sprintf("%d", bn), ethereum.NotFound) 116 } 117 for i := 0; i < len(block.Withdrawals); i++ { 118 block.Withdrawals[i].BlockNumber = block.BlockNumber 119 block.Withdrawals[i].Timestamp = block.Timestamp 120 } 121 return block, nil 122 } 123 }