github.com/aswedchain/aswed@v1.0.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 "bytes" 21 "context" 22 "math/big" 23 24 "github.com/aswedchain/aswed/common" 25 "github.com/aswedchain/aswed/core" 26 "github.com/aswedchain/aswed/core/rawdb" 27 "github.com/aswedchain/aswed/core/types" 28 "github.com/aswedchain/aswed/crypto" 29 "github.com/aswedchain/aswed/rlp" 30 ) 31 32 var sha3Nil = crypto.Keccak256Hash(nil) 33 34 // GetHeaderByNumber retrieves the canonical block header corresponding to the 35 // given number. 36 func GetHeaderByNumber(ctx context.Context, odr OdrBackend, number uint64) (*types.Header, error) { 37 // Try to find it in the local database first. 38 db := odr.Database() 39 hash := rawdb.ReadCanonicalHash(db, number) 40 41 // If there is a canonical hash, there should have a header too. 42 // But if it's pruned, re-fetch from network again. 43 if (hash != common.Hash{}) { 44 if header := rawdb.ReadHeader(db, hash, number); header != nil { 45 return header, nil 46 } 47 } 48 // Retrieve the header via ODR, ensure the requested header is covered 49 // by local trusted CHT. 50 chts, _, chtHead := odr.ChtIndexer().Sections() 51 if number >= chts*odr.IndexerConfig().ChtSize { 52 return nil, errNoTrustedCht 53 } 54 r := &ChtRequest{ 55 ChtRoot: GetChtRoot(db, chts-1, chtHead), 56 ChtNum: chts - 1, 57 BlockNum: number, 58 Config: odr.IndexerConfig(), 59 } 60 if err := odr.Retrieve(ctx, r); err != nil { 61 return nil, err 62 } 63 return r.Header, nil 64 } 65 66 // GetUntrustedHeaderByNumber retrieves specified block header without 67 // correctness checking. Note this function should only be used in light 68 // client checkpoint syncing. 69 func GetUntrustedHeaderByNumber(ctx context.Context, odr OdrBackend, number uint64, peerId string) (*types.Header, error) { 70 // todo(rjl493456442) it's a hack to retrieve headers which is not covered 71 // by CHT. Fix it in LES4 72 r := &ChtRequest{ 73 BlockNum: number, 74 ChtNum: number / odr.IndexerConfig().ChtSize, 75 Untrusted: true, 76 PeerId: peerId, 77 Config: odr.IndexerConfig(), 78 } 79 if err := odr.Retrieve(ctx, r); err != nil { 80 return nil, err 81 } 82 return r.Header, nil 83 } 84 85 // GetCanonicalHash retrieves the canonical block hash corresponding to the number. 86 func GetCanonicalHash(ctx context.Context, odr OdrBackend, number uint64) (common.Hash, error) { 87 hash := rawdb.ReadCanonicalHash(odr.Database(), number) 88 if hash != (common.Hash{}) { 89 return hash, nil 90 } 91 header, err := GetHeaderByNumber(ctx, odr, number) 92 if err != nil { 93 return common.Hash{}, err 94 } 95 // number -> canonical mapping already be stored in db, get it. 96 return header.Hash(), nil 97 } 98 99 // GetTd retrieves the total difficulty corresponding to the number and hash. 100 func GetTd(ctx context.Context, odr OdrBackend, hash common.Hash, number uint64) (*big.Int, error) { 101 td := rawdb.ReadTd(odr.Database(), hash, number) 102 if td != nil { 103 return td, nil 104 } 105 _, err := GetHeaderByNumber(ctx, odr, number) 106 if err != nil { 107 return nil, err 108 } 109 // <hash, number> -> td mapping already be stored in db, get it. 110 return rawdb.ReadTd(odr.Database(), hash, number), nil 111 } 112 113 // GetBodyRLP retrieves the block body (transactions and uncles) in RLP encoding. 114 func GetBodyRLP(ctx context.Context, odr OdrBackend, hash common.Hash, number uint64) (rlp.RawValue, error) { 115 if data := rawdb.ReadBodyRLP(odr.Database(), hash, number); data != nil { 116 return data, nil 117 } 118 // Retrieve the block header first and pass it for verification. 119 header, err := GetHeaderByNumber(ctx, odr, number) 120 if err != nil { 121 return nil, errNoHeader 122 } 123 r := &BlockRequest{Hash: hash, Number: number, Header: header} 124 if err := odr.Retrieve(ctx, r); err != nil { 125 return nil, err 126 } 127 return r.Rlp, nil 128 } 129 130 // GetBody retrieves the block body (transactions, uncles) corresponding to the 131 // hash. 132 func GetBody(ctx context.Context, odr OdrBackend, hash common.Hash, number uint64) (*types.Body, error) { 133 data, err := GetBodyRLP(ctx, odr, hash, number) 134 if err != nil { 135 return nil, err 136 } 137 body := new(types.Body) 138 if err := rlp.Decode(bytes.NewReader(data), body); err != nil { 139 return nil, err 140 } 141 return body, nil 142 } 143 144 // GetBlock retrieves an entire block corresponding to the hash, assembling it 145 // back from the stored header and body. 146 func GetBlock(ctx context.Context, odr OdrBackend, hash common.Hash, number uint64) (*types.Block, error) { 147 // Retrieve the block header and body contents 148 header, err := GetHeaderByNumber(ctx, odr, number) 149 if err != nil { 150 return nil, errNoHeader 151 } 152 body, err := GetBody(ctx, odr, hash, number) 153 if err != nil { 154 return nil, err 155 } 156 // Reassemble the block and return 157 return types.NewBlockWithHeader(header).WithBody(body.Transactions, body.Uncles), nil 158 } 159 160 // GetBlockReceipts retrieves the receipts generated by the transactions included 161 // in a block given by its hash. 162 func GetBlockReceipts(ctx context.Context, odr OdrBackend, hash common.Hash, number uint64) (types.Receipts, error) { 163 // Assume receipts are already stored locally and attempt to retrieve. 164 receipts := rawdb.ReadRawReceipts(odr.Database(), hash, number) 165 if receipts == nil { 166 header, err := GetHeaderByNumber(ctx, odr, number) 167 if err != nil { 168 return nil, errNoHeader 169 } 170 r := &ReceiptsRequest{Hash: hash, Number: number, Header: header} 171 if err := odr.Retrieve(ctx, r); err != nil { 172 return nil, err 173 } 174 receipts = r.Receipts 175 } 176 // If the receipts are incomplete, fill the derived fields 177 if len(receipts) > 0 && receipts[0].TxHash == (common.Hash{}) { 178 block, err := GetBlock(ctx, odr, hash, number) 179 if err != nil { 180 return nil, err 181 } 182 genesis := rawdb.ReadCanonicalHash(odr.Database(), 0) 183 config := rawdb.ReadChainConfig(odr.Database(), genesis) 184 185 if err := receipts.DeriveFields(config, block.Hash(), block.NumberU64(), block.Transactions()); err != nil { 186 return nil, err 187 } 188 rawdb.WriteReceipts(odr.Database(), hash, number, receipts) 189 } 190 return receipts, nil 191 } 192 193 // GetBlockLogs retrieves the logs generated by the transactions included in a 194 // block given by its hash. 195 func GetBlockLogs(ctx context.Context, odr OdrBackend, hash common.Hash, number uint64) ([][]*types.Log, error) { 196 // Retrieve the potentially incomplete receipts from disk or network 197 receipts, err := GetBlockReceipts(ctx, odr, hash, number) 198 if err != nil { 199 return nil, err 200 } 201 logs := make([][]*types.Log, len(receipts)) 202 for i, receipt := range receipts { 203 logs[i] = receipt.Logs 204 } 205 return logs, nil 206 } 207 208 // GetUntrustedBlockLogs retrieves the logs generated by the transactions included in a 209 // block. The retrieved logs are regarded as untrusted and will not be stored in the 210 // database. This function should only be used in light client checkpoint syncing. 211 func GetUntrustedBlockLogs(ctx context.Context, odr OdrBackend, header *types.Header) ([][]*types.Log, error) { 212 // Retrieve the potentially incomplete receipts from disk or network 213 hash, number := header.Hash(), header.Number.Uint64() 214 receipts := rawdb.ReadRawReceipts(odr.Database(), hash, number) 215 if receipts == nil { 216 r := &ReceiptsRequest{Hash: hash, Number: number, Header: header, Untrusted: true} 217 if err := odr.Retrieve(ctx, r); err != nil { 218 return nil, err 219 } 220 receipts = r.Receipts 221 // Untrusted receipts won't be stored in the database. Therefore 222 // derived fields computation is unnecessary. 223 } 224 // Return the logs without deriving any computed fields on the receipts 225 logs := make([][]*types.Log, len(receipts)) 226 for i, receipt := range receipts { 227 logs[i] = receipt.Logs 228 } 229 return logs, nil 230 } 231 232 // GetBloomBits retrieves a batch of compressed bloomBits vectors belonging to 233 // the given bit index and section indexes. 234 func GetBloomBits(ctx context.Context, odr OdrBackend, bit uint, sections []uint64) ([][]byte, error) { 235 var ( 236 reqIndex []int 237 reqSections []uint64 238 db = odr.Database() 239 result = make([][]byte, len(sections)) 240 ) 241 blooms, _, sectionHead := odr.BloomTrieIndexer().Sections() 242 for i, section := range sections { 243 sectionHead := rawdb.ReadCanonicalHash(db, (section+1)*odr.IndexerConfig().BloomSize-1) 244 // If we don't have the canonical hash stored for this section head number, 245 // we'll still look for an entry with a zero sectionHead (we store it with 246 // zero section head too if we don't know it at the time of the retrieval) 247 if bloomBits, _ := rawdb.ReadBloomBits(db, bit, section, sectionHead); len(bloomBits) != 0 { 248 result[i] = bloomBits 249 continue 250 } 251 // TODO(rjl493456442) Convert sectionIndex to BloomTrie relative index 252 if section >= blooms { 253 return nil, errNoTrustedBloomTrie 254 } 255 reqSections = append(reqSections, section) 256 reqIndex = append(reqIndex, i) 257 } 258 // Find all bloombits in database, nothing to query via odr, return. 259 if reqSections == nil { 260 return result, nil 261 } 262 // Send odr request to retrieve missing bloombits. 263 r := &BloomRequest{ 264 BloomTrieRoot: GetBloomTrieRoot(db, blooms-1, sectionHead), 265 BloomTrieNum: blooms - 1, 266 BitIdx: bit, 267 SectionIndexList: reqSections, 268 Config: odr.IndexerConfig(), 269 } 270 if err := odr.Retrieve(ctx, r); err != nil { 271 return nil, err 272 } 273 for i, idx := range reqIndex { 274 result[idx] = r.BloomBits[i] 275 } 276 return result, nil 277 } 278 279 // GetTransaction retrieves a canonical transaction by hash and also returns its position in the chain 280 func GetTransaction(ctx context.Context, odr OdrBackend, txHash common.Hash) (*types.Transaction, common.Hash, uint64, uint64, error) { 281 r := &TxStatusRequest{Hashes: []common.Hash{txHash}} 282 if err := odr.Retrieve(ctx, r); err != nil || r.Status[0].Status != core.TxStatusIncluded { 283 return nil, common.Hash{}, 0, 0, err 284 } 285 pos := r.Status[0].Lookup 286 // first ensure that we have the header, otherwise block body retrieval will fail 287 // also verify if this is a canonical block by getting the header by number and checking its hash 288 if header, err := GetHeaderByNumber(ctx, odr, pos.BlockIndex); err != nil || header.Hash() != pos.BlockHash { 289 return nil, common.Hash{}, 0, 0, err 290 } 291 body, err := GetBody(ctx, odr, pos.BlockHash, pos.BlockIndex) 292 if err != nil || uint64(len(body.Transactions)) <= pos.Index || body.Transactions[pos.Index].Hash() != txHash { 293 return nil, common.Hash{}, 0, 0, err 294 } 295 return body.Transactions[pos.Index], pos.BlockHash, pos.BlockIndex, pos.Index, nil 296 }