github.com/bcskill/bcschain/v3@v3.4.9-beta2/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 23 "github.com/bcskill/bcschain/v3/common" 24 "github.com/bcskill/bcschain/v3/core/rawdb" 25 "github.com/bcskill/bcschain/v3/core/types" 26 "github.com/bcskill/bcschain/v3/crypto" 27 "github.com/bcskill/bcschain/v3/rlp" 28 ) 29 30 var sha3_nil = crypto.Keccak256Hash(nil) 31 32 func GetHeaderByNumber(ctx context.Context, odr OdrBackend, number uint64) (*types.Header, error) { 33 db := odr.Database() 34 hash := rawdb.ReadCanonicalHash(db, number) 35 if (hash != common.Hash{}) { 36 // if there is a canonical hash, there is a header too 37 header := rawdb.ReadHeader(db.HeaderTable(), hash, number) 38 if header == nil { 39 panic("Canonical hash present but header not found") 40 } 41 return header, nil 42 } 43 44 var ( 45 chtCount, sectionHeadNum uint64 46 sectionHead common.Hash 47 ) 48 if odr.ChtIndexer() != nil { 49 chtCount, sectionHeadNum, sectionHead = odr.ChtIndexer().Sections() 50 canonicalHash := rawdb.ReadCanonicalHash(db, sectionHeadNum) 51 // if the CHT was injected as a trusted checkpoint, we have no canonical hash yet so we accept zero hash too 52 for chtCount > 0 && canonicalHash != sectionHead && canonicalHash != (common.Hash{}) { 53 chtCount-- 54 if chtCount > 0 { 55 sectionHeadNum = chtCount*CHTFrequencyClient - 1 56 sectionHead = odr.ChtIndexer().SectionHead(chtCount - 1) 57 canonicalHash = rawdb.ReadCanonicalHash(db, sectionHeadNum) 58 } 59 } 60 } 61 if number >= chtCount*CHTFrequencyClient { 62 return nil, ErrNoTrustedCht 63 } 64 r := &ChtRequest{ChtRoot: GetChtRoot(db, chtCount-1, sectionHead), ChtNum: chtCount - 1, BlockNum: number} 65 if err := odr.Retrieve(ctx, r); err != nil { 66 return nil, err 67 } 68 return r.Header, nil 69 } 70 71 func GetCanonicalHash(ctx context.Context, odr OdrBackend, number uint64) (common.Hash, error) { 72 hash := rawdb.ReadCanonicalHash(odr.Database(), number) 73 if (hash != common.Hash{}) { 74 return hash, nil 75 } 76 header, err := GetHeaderByNumber(ctx, odr, number) 77 if header != nil { 78 return header.Hash(), nil 79 } 80 return common.Hash{}, err 81 } 82 83 // GetBodyRLP retrieves the block body (transactions and uncles) in RLP encoding. 84 func GetBodyRLP(ctx context.Context, odr OdrBackend, hash common.Hash, number uint64) (rlp.RawValue, error) { 85 if data := rawdb.ReadBodyRLP(odr.Database().BodyTable(), hash, number); data != nil { 86 return data, nil 87 } 88 r := &BlockRequest{Hash: hash, Number: number} 89 if err := odr.Retrieve(ctx, r); err != nil { 90 return nil, err 91 } else { 92 return r.Rlp, nil 93 } 94 } 95 96 // GetBody retrieves the block body (transactons, uncles) corresponding to the 97 // hash. 98 func GetBody(ctx context.Context, odr OdrBackend, hash common.Hash, number uint64) (*types.Body, error) { 99 data, err := GetBodyRLP(ctx, odr, hash, number) 100 if err != nil { 101 return nil, err 102 } 103 body := new(types.Body) 104 if err := rlp.Decode(bytes.NewReader(data), body); err != nil { 105 return nil, err 106 } 107 return body, nil 108 } 109 110 // GetBlock retrieves an entire block corresponding to the hash, assembling it 111 // back from the stored header and body. 112 func GetBlock(ctx context.Context, odr OdrBackend, hash common.Hash, number uint64) (*types.Block, error) { 113 // Retrieve the block header and body contents 114 header := rawdb.ReadHeader(odr.Database().HeaderTable(), hash, number) 115 if header == nil { 116 return nil, ErrNoHeader 117 } 118 body, err := GetBody(ctx, odr, hash, number) 119 if err != nil { 120 return nil, err 121 } 122 // Reassemble the block and return 123 return types.NewBlockWithHeader(header).WithBody(body.Transactions, body.Uncles), nil 124 } 125 126 // GetBlockReceipts retrieves the receipts generated by the transactions included 127 // in a block given by its hash. 128 func GetBlockReceipts(ctx context.Context, odr OdrBackend, hash common.Hash, number uint64) (types.Receipts, error) { 129 // Assume the receipts are already stored locally and attempt to retrieve. 130 receipts := rawdb.ReadRawReceipts(odr.Database().ReceiptTable(), hash, number) 131 if receipts == nil { 132 r := &ReceiptsRequest{Hash: hash, Number: number} 133 if err := odr.Retrieve(ctx, r); err != nil { 134 return nil, err 135 } 136 receipts = r.Receipts 137 } 138 // If the receipts are incomplete, fill the derived fields 139 if len(receipts) > 0 && receipts[0].TxHash == (common.Hash{}) { 140 block, err := GetBlock(ctx, odr, hash, number) 141 if err != nil { 142 return nil, err 143 } 144 genesis := rawdb.ReadCanonicalHash(odr.Database(), 0) 145 config := rawdb.ReadChainConfig(odr.Database().GlobalTable(), genesis) 146 147 if err := receipts.DeriveFields(config, block.Hash(), block.NumberU64(), block.Transactions()); err != nil { 148 return nil, err 149 } 150 rawdb.WriteReceipts(odr.Database().ReceiptTable(), hash, number, receipts) 151 } 152 return receipts, nil 153 } 154 155 // GetBlockLogs retrieves the logs generated by the transactions included in a 156 // block given by its hash. 157 func GetBlockLogs(ctx context.Context, odr OdrBackend, hash common.Hash, number uint64) ([][]*types.Log, error) { 158 // Retrieve the potentially incomplete receipts from disk or network 159 receipts, err := GetBlockReceipts(ctx, odr, hash, number) 160 if err != nil { 161 return nil, err 162 } 163 // Return the logs without deriving any computed fields on the receipts 164 logs := make([][]*types.Log, len(receipts)) 165 for i, receipt := range receipts { 166 logs[i] = receipt.Logs 167 } 168 return logs, nil 169 } 170 171 // GetBloomBits retrieves a batch of compressed bloomBits vectors belonging to the given bit index and section indexes 172 func GetBloomBits(ctx context.Context, odr OdrBackend, bitIdx uint, sectionIdxList []uint64) ([][]byte, error) { 173 db := odr.Database() 174 result := make([][]byte, len(sectionIdxList)) 175 var ( 176 reqList []uint64 177 reqIdx []int 178 ) 179 180 var ( 181 bloomTrieCount, sectionHeadNum uint64 182 sectionHead common.Hash 183 ) 184 if odr.BloomTrieIndexer() != nil { 185 bloomTrieCount, sectionHeadNum, sectionHead = odr.BloomTrieIndexer().Sections() 186 canonicalHash := rawdb.ReadCanonicalHash(db, sectionHeadNum) 187 // if the BloomTrie was injected as a trusted checkpoint, we have no canonical hash yet so we accept zero hash too 188 for bloomTrieCount > 0 && canonicalHash != sectionHead && canonicalHash != (common.Hash{}) { 189 bloomTrieCount-- 190 if bloomTrieCount > 0 { 191 sectionHeadNum = bloomTrieCount*BloomTrieFrequency - 1 192 sectionHead = odr.BloomTrieIndexer().SectionHead(bloomTrieCount - 1) 193 canonicalHash = rawdb.ReadCanonicalHash(db, sectionHeadNum) 194 } 195 } 196 } 197 198 for i, sectionIdx := range sectionIdxList { 199 sectionHead := rawdb.ReadCanonicalHash(db, (sectionIdx+1)*BloomTrieFrequency-1) 200 // if we don't have the canonical hash stored for this section head number, we'll still look for 201 // an entry with a zero sectionHead (we store it with zero section head too if we don't know it 202 // at the time of the retrieval) 203 result[i] = rawdb.ReadBloomBits(db.GlobalTable(), bitIdx, sectionIdx, sectionHead) 204 205 } 206 if reqList == nil { 207 return result, nil 208 } 209 210 r := &BloomRequest{BloomTrieRoot: GetBloomTrieRoot(db, bloomTrieCount-1, sectionHead), BloomTrieNum: bloomTrieCount - 1, BitIdx: bitIdx, SectionIdxList: reqList} 211 if err := odr.Retrieve(ctx, r); err != nil { 212 return nil, err 213 } else { 214 for i, idx := range reqIdx { 215 result[idx] = r.BloomBits[i] 216 } 217 return result, nil 218 } 219 }