github.com/theQRL/go-zond@v0.1.1/light/odr_util.go (about) 1 // Copyright 2016 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package light 18 19 import ( 20 "context" 21 "errors" 22 "math/big" 23 24 "github.com/theQRL/go-zond/common" 25 "github.com/theQRL/go-zond/consensus/misc/eip4844" 26 "github.com/theQRL/go-zond/core/rawdb" 27 "github.com/theQRL/go-zond/core/txpool" 28 "github.com/theQRL/go-zond/core/types" 29 "github.com/theQRL/go-zond/rlp" 30 ) 31 32 // errNonCanonicalHash is returned if the requested chain data doesn't belong 33 // to the canonical chain. ODR can only retrieve the canonical chain data covered 34 // by the CHT or Bloom trie for verification. 35 var errNonCanonicalHash = errors.New("hash is not currently canonical") 36 37 // GetHeaderByNumber retrieves the canonical block header corresponding to the 38 // given number. The returned header is proven by local CHT. 39 func GetHeaderByNumber(ctx context.Context, odr OdrBackend, number uint64) (*types.Header, error) { 40 // Try to find it in the local database first. 41 db := odr.Database() 42 hash := rawdb.ReadCanonicalHash(db, number) 43 44 // If there is a canonical hash, there should have a header too. 45 // But if it's pruned, re-fetch from network again. 46 if (hash != common.Hash{}) { 47 if header := rawdb.ReadHeader(db, hash, number); header != nil { 48 return header, nil 49 } 50 } 51 // Retrieve the header via ODR, ensure the requested header is covered 52 // by local trusted CHT. 53 chts, _, chtHead := odr.ChtIndexer().Sections() 54 if number >= chts*odr.IndexerConfig().ChtSize { 55 return nil, errNoTrustedCht 56 } 57 r := &ChtRequest{ 58 ChtRoot: GetChtRoot(db, chts-1, chtHead), 59 ChtNum: chts - 1, 60 BlockNum: number, 61 Config: odr.IndexerConfig(), 62 } 63 if err := odr.Retrieve(ctx, r); err != nil { 64 return nil, err 65 } 66 return r.Header, nil 67 } 68 69 // GetCanonicalHash retrieves the canonical block hash corresponding to the number. 70 func GetCanonicalHash(ctx context.Context, odr OdrBackend, number uint64) (common.Hash, error) { 71 hash := rawdb.ReadCanonicalHash(odr.Database(), number) 72 if hash != (common.Hash{}) { 73 return hash, nil 74 } 75 header, err := GetHeaderByNumber(ctx, odr, number) 76 if err != nil { 77 return common.Hash{}, err 78 } 79 // number -> canonical mapping already be stored in db, get it. 80 return header.Hash(), nil 81 } 82 83 // GetTd retrieves the total difficulty corresponding to the number and hash. 84 func GetTd(ctx context.Context, odr OdrBackend, hash common.Hash, number uint64) (*big.Int, error) { 85 td := rawdb.ReadTd(odr.Database(), hash, number) 86 if td != nil { 87 return td, nil 88 } 89 header, err := GetHeaderByNumber(ctx, odr, number) 90 if err != nil { 91 return nil, err 92 } 93 if header.Hash() != hash { 94 return nil, errNonCanonicalHash 95 } 96 // <hash, number> -> td mapping already be stored in db, get it. 97 return rawdb.ReadTd(odr.Database(), hash, number), nil 98 } 99 100 // GetBodyRLP retrieves the block body (transactions and uncles) in RLP encoding. 101 func GetBodyRLP(ctx context.Context, odr OdrBackend, hash common.Hash, number uint64) (rlp.RawValue, error) { 102 if data := rawdb.ReadBodyRLP(odr.Database(), hash, number); data != nil { 103 return data, nil 104 } 105 // Retrieve the block header first and pass it for verification. 106 header, err := GetHeaderByNumber(ctx, odr, number) 107 if err != nil { 108 return nil, errNoHeader 109 } 110 if header.Hash() != hash { 111 return nil, errNonCanonicalHash 112 } 113 r := &BlockRequest{Hash: hash, Number: number, Header: header} 114 if err := odr.Retrieve(ctx, r); err != nil { 115 return nil, err 116 } 117 return r.Rlp, nil 118 } 119 120 // GetBody retrieves the block body (transactions, uncles) corresponding to the 121 // hash. 122 func GetBody(ctx context.Context, odr OdrBackend, hash common.Hash, number uint64) (*types.Body, error) { 123 data, err := GetBodyRLP(ctx, odr, hash, number) 124 if err != nil { 125 return nil, err 126 } 127 body := new(types.Body) 128 if err := rlp.DecodeBytes(data, body); err != nil { 129 return nil, err 130 } 131 return body, nil 132 } 133 134 // GetBlock retrieves an entire block corresponding to the hash, assembling it 135 // back from the stored header and body. 136 func GetBlock(ctx context.Context, odr OdrBackend, hash common.Hash, number uint64) (*types.Block, error) { 137 // Retrieve the block header and body contents 138 header, err := GetHeaderByNumber(ctx, odr, number) 139 if err != nil { 140 return nil, errNoHeader 141 } 142 body, err := GetBody(ctx, odr, hash, number) 143 if err != nil { 144 return nil, err 145 } 146 // Reassemble the block and return 147 return types.NewBlockWithHeader(header).WithBody(body.Transactions, body.Uncles), nil 148 } 149 150 // GetBlockReceipts retrieves the receipts generated by the transactions included 151 // in a block given by its hash. Receipts will be filled in with context data. 152 func GetBlockReceipts(ctx context.Context, odr OdrBackend, hash common.Hash, number uint64) (types.Receipts, error) { 153 // Assume receipts are already stored locally and attempt to retrieve. 154 receipts := rawdb.ReadRawReceipts(odr.Database(), hash, number) 155 if receipts == nil { 156 header, err := GetHeaderByNumber(ctx, odr, number) 157 if err != nil { 158 return nil, errNoHeader 159 } 160 if header.Hash() != hash { 161 return nil, errNonCanonicalHash 162 } 163 r := &ReceiptsRequest{Hash: hash, Number: number, Header: header} 164 if err := odr.Retrieve(ctx, r); err != nil { 165 return nil, err 166 } 167 receipts = r.Receipts 168 } 169 // If the receipts are incomplete, fill the derived fields 170 if len(receipts) > 0 && receipts[0].TxHash == (common.Hash{}) { 171 block, err := GetBlock(ctx, odr, hash, number) 172 if err != nil { 173 return nil, err 174 } 175 genesis := rawdb.ReadCanonicalHash(odr.Database(), 0) 176 config := rawdb.ReadChainConfig(odr.Database(), genesis) 177 178 var blobGasPrice *big.Int 179 excessBlobGas := block.ExcessBlobGas() 180 if excessBlobGas != nil { 181 blobGasPrice = eip4844.CalcBlobFee(*excessBlobGas) 182 } 183 184 if err := receipts.DeriveFields(config, block.Hash(), block.NumberU64(), block.Time(), block.BaseFee(), blobGasPrice, block.Transactions()); err != nil { 185 return nil, err 186 } 187 rawdb.WriteReceipts(odr.Database(), hash, number, receipts) 188 } 189 return receipts, nil 190 } 191 192 // GetBlockLogs retrieves the logs generated by the transactions included in a 193 // block given by its hash. Logs will be filled in with context data. 194 func GetBlockLogs(ctx context.Context, odr OdrBackend, hash common.Hash, number uint64) ([][]*types.Log, error) { 195 receipts, err := GetBlockReceipts(ctx, odr, hash, number) 196 if err != nil { 197 return nil, err 198 } 199 logs := make([][]*types.Log, len(receipts)) 200 for i, receipt := range receipts { 201 logs[i] = receipt.Logs 202 } 203 return logs, nil 204 } 205 206 // GetBloomBits retrieves a batch of compressed bloomBits vectors belonging to 207 // the given bit index and section indexes. 208 func GetBloomBits(ctx context.Context, odr OdrBackend, bit uint, sections []uint64) ([][]byte, error) { 209 var ( 210 reqIndex []int 211 reqSections []uint64 212 db = odr.Database() 213 result = make([][]byte, len(sections)) 214 ) 215 blooms, _, sectionHead := odr.BloomTrieIndexer().Sections() 216 for i, section := range sections { 217 sectionHead := rawdb.ReadCanonicalHash(db, (section+1)*odr.IndexerConfig().BloomSize-1) 218 // If we don't have the canonical hash stored for this section head number, 219 // we'll still look for an entry with a zero sectionHead (we store it with 220 // zero section head too if we don't know it at the time of the retrieval) 221 if bloomBits, _ := rawdb.ReadBloomBits(db, bit, section, sectionHead); len(bloomBits) != 0 { 222 result[i] = bloomBits 223 continue 224 } 225 // TODO(rjl493456442) Convert sectionIndex to BloomTrie relative index 226 if section >= blooms { 227 return nil, errNoTrustedBloomTrie 228 } 229 reqSections = append(reqSections, section) 230 reqIndex = append(reqIndex, i) 231 } 232 // Find all bloombits in database, nothing to query via odr, return. 233 if reqSections == nil { 234 return result, nil 235 } 236 // Send odr request to retrieve missing bloombits. 237 r := &BloomRequest{ 238 BloomTrieRoot: GetBloomTrieRoot(db, blooms-1, sectionHead), 239 BloomTrieNum: blooms - 1, 240 BitIdx: bit, 241 SectionIndexList: reqSections, 242 Config: odr.IndexerConfig(), 243 } 244 if err := odr.Retrieve(ctx, r); err != nil { 245 return nil, err 246 } 247 for i, idx := range reqIndex { 248 result[idx] = r.BloomBits[i] 249 } 250 return result, nil 251 } 252 253 // GetTransaction retrieves a canonical transaction by hash and also returns 254 // its position in the chain. There is no guarantee in the LES protocol that 255 // the mined transaction will be retrieved back for sure because of different 256 // reasons(the transaction is unindexed, the malicious server doesn't reply it 257 // deliberately, etc). Therefore, unretrieved transactions will receive a certain 258 // number of retries, thus giving a weak guarantee. 259 func GetTransaction(ctx context.Context, odr OdrBackend, txHash common.Hash) (*types.Transaction, common.Hash, uint64, uint64, error) { 260 r := &TxStatusRequest{Hashes: []common.Hash{txHash}} 261 if err := odr.RetrieveTxStatus(ctx, r); err != nil || r.Status[0].Status != txpool.TxStatusIncluded { 262 return nil, common.Hash{}, 0, 0, err 263 } 264 pos := r.Status[0].Lookup 265 // first ensure that we have the header, otherwise block body retrieval will fail 266 // also verify if this is a canonical block by getting the header by number and checking its hash 267 if header, err := GetHeaderByNumber(ctx, odr, pos.BlockIndex); err != nil || header.Hash() != pos.BlockHash { 268 return nil, common.Hash{}, 0, 0, err 269 } 270 body, err := GetBody(ctx, odr, pos.BlockHash, pos.BlockIndex) 271 if err != nil || uint64(len(body.Transactions)) <= pos.Index || body.Transactions[pos.Index].Hash() != txHash { 272 return nil, common.Hash{}, 0, 0, err 273 } 274 return body.Transactions[pos.Index], pos.BlockHash, pos.BlockIndex, pos.Index, nil 275 }