github.com/anthdm/go-ethereum@v1.8.4-0.20180412101906-60516c83b011/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/ethereum/go-ethereum/common" 24 "github.com/ethereum/go-ethereum/core" 25 "github.com/ethereum/go-ethereum/core/types" 26 "github.com/ethereum/go-ethereum/crypto" 27 "github.com/ethereum/go-ethereum/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*CHTFrequencyClient - 1 56 sectionHead = odr.ChtIndexer().SectionHead(chtCount - 1) 57 canonicalHash = core.GetCanonicalHash(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 := core.GetCanonicalHash(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 := core.GetBodyRLP(odr.Database(), 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 := core.GetHeader(odr.Database(), 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 // Retrieve the potentially incomplete receipts from disk or network 130 receipts := core.GetBlockReceipts(odr.Database(), 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 := core.GetCanonicalHash(odr.Database(), 0) 145 config, _ := core.GetChainConfig(odr.Database(), genesis) 146 147 if err := core.SetReceiptsData(config, block, receipts); err != nil { 148 return nil, err 149 } 150 core.WriteBlockReceipts(odr.Database(), 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 := core.GetBlockReceipts(odr.Database(), hash, number) 160 if receipts == nil { 161 r := &ReceiptsRequest{Hash: hash, Number: number} 162 if err := odr.Retrieve(ctx, r); err != nil { 163 return nil, err 164 } 165 receipts = r.Receipts 166 } 167 // Return the logs without deriving any computed fields on the receipts 168 logs := make([][]*types.Log, len(receipts)) 169 for i, receipt := range receipts { 170 logs[i] = receipt.Logs 171 } 172 return logs, nil 173 } 174 175 // GetBloomBits retrieves a batch of compressed bloomBits vectors belonging to the given bit index and section indexes 176 func GetBloomBits(ctx context.Context, odr OdrBackend, bitIdx uint, sectionIdxList []uint64) ([][]byte, error) { 177 db := odr.Database() 178 result := make([][]byte, len(sectionIdxList)) 179 var ( 180 reqList []uint64 181 reqIdx []int 182 ) 183 184 var ( 185 bloomTrieCount, sectionHeadNum uint64 186 sectionHead common.Hash 187 ) 188 if odr.BloomTrieIndexer() != nil { 189 bloomTrieCount, sectionHeadNum, sectionHead = odr.BloomTrieIndexer().Sections() 190 canonicalHash := core.GetCanonicalHash(db, sectionHeadNum) 191 // if the BloomTrie was injected as a trusted checkpoint, we have no canonical hash yet so we accept zero hash too 192 for bloomTrieCount > 0 && canonicalHash != sectionHead && canonicalHash != (common.Hash{}) { 193 bloomTrieCount-- 194 if bloomTrieCount > 0 { 195 sectionHeadNum = bloomTrieCount*BloomTrieFrequency - 1 196 sectionHead = odr.BloomTrieIndexer().SectionHead(bloomTrieCount - 1) 197 canonicalHash = core.GetCanonicalHash(db, sectionHeadNum) 198 } 199 } 200 } 201 202 for i, sectionIdx := range sectionIdxList { 203 sectionHead := core.GetCanonicalHash(db, (sectionIdx+1)*BloomTrieFrequency-1) 204 // if we don't have the canonical hash stored for this section head number, we'll still look for 205 // an entry with a zero sectionHead (we store it with zero section head too if we don't know it 206 // at the time of the retrieval) 207 bloomBits, err := core.GetBloomBits(db, bitIdx, sectionIdx, sectionHead) 208 if err == nil { 209 result[i] = bloomBits 210 } else { 211 if sectionIdx >= bloomTrieCount { 212 return nil, ErrNoTrustedBloomTrie 213 } 214 reqList = append(reqList, sectionIdx) 215 reqIdx = append(reqIdx, i) 216 } 217 } 218 if reqList == nil { 219 return result, nil 220 } 221 222 r := &BloomRequest{BloomTrieRoot: GetBloomTrieRoot(db, bloomTrieCount-1, sectionHead), BloomTrieNum: bloomTrieCount - 1, BitIdx: bitIdx, SectionIdxList: reqList} 223 if err := odr.Retrieve(ctx, r); err != nil { 224 return nil, err 225 } else { 226 for i, idx := range reqIdx { 227 result[idx] = r.BloomBits[i] 228 } 229 return result, nil 230 } 231 }