github.com/kivutar/go-ethereum@v1.7.4-0.20180117074026-6fdb126e9630/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*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  }