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  }