github.com/SmartMeshFoundation/Spectrum@v0.0.0-20220621030607-452a266fee1e/light/odr_util.go (about) 1 // Copyright 2016 The Spectrum Authors 2 // This file is part of the Spectrum library. 3 // 4 // The Spectrum 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 Spectrum 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 Spectrum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package light 18 19 import ( 20 "bytes" 21 "context" 22 23 "github.com/SmartMeshFoundation/Spectrum/common" 24 "github.com/SmartMeshFoundation/Spectrum/core" 25 "github.com/SmartMeshFoundation/Spectrum/core/types" 26 "github.com/SmartMeshFoundation/Spectrum/crypto" 27 "github.com/SmartMeshFoundation/Spectrum/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 := core.GetCanonicalHash(db, number) 35 if (hash != common.Hash{}) { 36 // if there is a canonical hash, there is a header too 37 header := core.GetHeader(db, 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 := core.GetCanonicalHash(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*ChtFrequency - 1 56 sectionHead = odr.ChtIndexer().SectionHead(chtCount - 1) 57 canonicalHash = core.GetCanonicalHash(db, sectionHeadNum) 58 } 59 } 60 } 61 62 if number >= chtCount*ChtFrequency { 63 return nil, ErrNoTrustedCht 64 } 65 66 r := &ChtRequest{ChtRoot: GetChtRoot(db, chtCount-1, sectionHead), ChtNum: chtCount - 1, BlockNum: number} 67 if err := odr.Retrieve(ctx, r); err != nil { 68 return nil, err 69 } else { 70 return r.Header, nil 71 } 72 } 73 74 func GetCanonicalHash(ctx context.Context, odr OdrBackend, number uint64) (common.Hash, error) { 75 hash := core.GetCanonicalHash(odr.Database(), number) 76 if (hash != common.Hash{}) { 77 return hash, nil 78 } 79 header, err := GetHeaderByNumber(ctx, odr, number) 80 if header != nil { 81 return header.Hash(), nil 82 } 83 return common.Hash{}, err 84 } 85 86 // GetBodyRLP retrieves the block body (transactions and uncles) in RLP encoding. 87 func GetBodyRLP(ctx context.Context, odr OdrBackend, hash common.Hash, number uint64) (rlp.RawValue, error) { 88 if data := core.GetBodyRLP(odr.Database(), hash, number); data != nil { 89 return data, nil 90 } 91 r := &BlockRequest{Hash: hash, Number: number} 92 if err := odr.Retrieve(ctx, r); err != nil { 93 return nil, err 94 } else { 95 return r.Rlp, nil 96 } 97 } 98 99 // GetBody retrieves the block body (transactons, uncles) corresponding to the 100 // hash. 101 func GetBody(ctx context.Context, odr OdrBackend, hash common.Hash, number uint64) (*types.Body, error) { 102 data, err := GetBodyRLP(ctx, odr, hash, number) 103 if err != nil { 104 return nil, err 105 } 106 body := new(types.Body) 107 if err := rlp.Decode(bytes.NewReader(data), body); err != nil { 108 return nil, err 109 } 110 return body, nil 111 } 112 113 // GetBlock retrieves an entire block corresponding to the hash, assembling it 114 // back from the stored header and body. 115 func GetBlock(ctx context.Context, odr OdrBackend, hash common.Hash, number uint64) (*types.Block, error) { 116 // Retrieve the block header and body contents 117 header := core.GetHeader(odr.Database(), hash, number) 118 if header == nil { 119 return nil, ErrNoHeader 120 } 121 body, err := GetBody(ctx, odr, hash, number) 122 if err != nil { 123 return nil, err 124 } 125 // Reassemble the block and return 126 return types.NewBlockWithHeader(header).WithBody(body.Transactions, body.Uncles), nil 127 } 128 129 // GetBlockReceipts retrieves the receipts generated by the transactions included 130 // in a block given by its hash. 131 func GetBlockReceipts(ctx context.Context, odr OdrBackend, hash common.Hash, number uint64) (types.Receipts, error) { 132 receipts := core.GetBlockReceipts(odr.Database(), hash, number) 133 if receipts != nil { 134 return receipts, nil 135 } 136 r := &ReceiptsRequest{Hash: hash, Number: number} 137 if err := odr.Retrieve(ctx, r); err != nil { 138 return nil, err 139 } 140 return r.Receipts, nil 141 } 142 143 // GetBloomBits retrieves a batch of compressed bloomBits vectors belonging to the given bit index and section indexes 144 func GetBloomBits(ctx context.Context, odr OdrBackend, bitIdx uint, sectionIdxList []uint64) ([][]byte, error) { 145 db := odr.Database() 146 result := make([][]byte, len(sectionIdxList)) 147 var ( 148 reqList []uint64 149 reqIdx []int 150 ) 151 152 var ( 153 bloomTrieCount, sectionHeadNum uint64 154 sectionHead common.Hash 155 ) 156 if odr.BloomTrieIndexer() != nil { 157 bloomTrieCount, sectionHeadNum, sectionHead = odr.BloomTrieIndexer().Sections() 158 canonicalHash := core.GetCanonicalHash(db, sectionHeadNum) 159 // if the BloomTrie was injected as a trusted checkpoint, we have no canonical hash yet so we accept zero hash too 160 for bloomTrieCount > 0 && canonicalHash != sectionHead && canonicalHash != (common.Hash{}) { 161 bloomTrieCount-- 162 if bloomTrieCount > 0 { 163 sectionHeadNum = bloomTrieCount*BloomTrieFrequency - 1 164 sectionHead = odr.BloomTrieIndexer().SectionHead(bloomTrieCount - 1) 165 canonicalHash = core.GetCanonicalHash(db, sectionHeadNum) 166 } 167 } 168 } 169 170 for i, sectionIdx := range sectionIdxList { 171 sectionHead := core.GetCanonicalHash(db, (sectionIdx+1)*BloomTrieFrequency-1) 172 // if we don't have the canonical hash stored for this section head number, we'll still look for 173 // an entry with a zero sectionHead (we store it with zero section head too if we don't know it 174 // at the time of the retrieval) 175 bloomBits, err := core.GetBloomBits(db, bitIdx, sectionIdx, sectionHead) 176 if err == nil { 177 result[i] = bloomBits 178 } else { 179 if sectionIdx >= bloomTrieCount { 180 return nil, ErrNoTrustedBloomTrie 181 } 182 reqList = append(reqList, sectionIdx) 183 reqIdx = append(reqIdx, i) 184 } 185 } 186 if reqList == nil { 187 return result, nil 188 } 189 190 r := &BloomRequest{BloomTrieRoot: GetBloomTrieRoot(db, bloomTrieCount-1, sectionHead), BloomTrieNum: bloomTrieCount - 1, BitIdx: bitIdx, SectionIdxList: reqList} 191 if err := odr.Retrieve(ctx, r); err != nil { 192 return nil, err 193 } else { 194 for i, idx := range reqIdx { 195 result[idx] = r.BloomBits[i] 196 } 197 return result, nil 198 } 199 }