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