github.com/ylsGit/go-ethereum@v1.6.5/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  	"errors"
    23  	"math/big"
    24  
    25  	"github.com/ethereum/go-ethereum/common"
    26  	"github.com/ethereum/go-ethereum/core"
    27  	"github.com/ethereum/go-ethereum/core/types"
    28  	"github.com/ethereum/go-ethereum/crypto"
    29  	"github.com/ethereum/go-ethereum/ethdb"
    30  	"github.com/ethereum/go-ethereum/rlp"
    31  )
    32  
    33  var sha3_nil = crypto.Keccak256Hash(nil)
    34  
    35  var (
    36  	ErrNoTrustedCht = errors.New("No trusted canonical hash trie")
    37  	ErrNoHeader     = errors.New("Header not found")
    38  
    39  	ChtFrequency     = uint64(4096)
    40  	ChtConfirmations = uint64(2048)
    41  	trustedChtKey    = []byte("TrustedCHT")
    42  )
    43  
    44  type ChtNode struct {
    45  	Hash common.Hash
    46  	Td   *big.Int
    47  }
    48  
    49  type TrustedCht struct {
    50  	Number uint64
    51  	Root   common.Hash
    52  }
    53  
    54  func GetTrustedCht(db ethdb.Database) TrustedCht {
    55  	data, _ := db.Get(trustedChtKey)
    56  	var res TrustedCht
    57  	if err := rlp.DecodeBytes(data, &res); err != nil {
    58  		return TrustedCht{0, common.Hash{}}
    59  	}
    60  	return res
    61  }
    62  
    63  func WriteTrustedCht(db ethdb.Database, cht TrustedCht) {
    64  	data, _ := rlp.EncodeToBytes(cht)
    65  	db.Put(trustedChtKey, data)
    66  }
    67  
    68  func DeleteTrustedCht(db ethdb.Database) {
    69  	db.Delete(trustedChtKey)
    70  }
    71  
    72  func GetHeaderByNumber(ctx context.Context, odr OdrBackend, number uint64) (*types.Header, error) {
    73  	db := odr.Database()
    74  	hash := core.GetCanonicalHash(db, number)
    75  	if (hash != common.Hash{}) {
    76  		// if there is a canonical hash, there is a header too
    77  		header := core.GetHeader(db, hash, number)
    78  		if header == nil {
    79  			panic("Canonical hash present but header not found")
    80  		}
    81  		return header, nil
    82  	}
    83  
    84  	cht := GetTrustedCht(db)
    85  	if number >= cht.Number*ChtFrequency {
    86  		return nil, ErrNoTrustedCht
    87  	}
    88  
    89  	r := &ChtRequest{ChtRoot: cht.Root, ChtNum: cht.Number, BlockNum: number}
    90  	if err := odr.Retrieve(ctx, r); err != nil {
    91  		return nil, err
    92  	} else {
    93  		return r.Header, nil
    94  	}
    95  }
    96  
    97  func GetCanonicalHash(ctx context.Context, odr OdrBackend, number uint64) (common.Hash, error) {
    98  	hash := core.GetCanonicalHash(odr.Database(), number)
    99  	if (hash != common.Hash{}) {
   100  		return hash, nil
   101  	}
   102  	header, err := GetHeaderByNumber(ctx, odr, number)
   103  	if header != nil {
   104  		return header.Hash(), nil
   105  	}
   106  	return common.Hash{}, err
   107  }
   108  
   109  // retrieveContractCode tries to retrieve the contract code of the given account
   110  // with the given hash from the network (id points to the storage trie belonging
   111  // to the same account)
   112  func retrieveContractCode(ctx context.Context, odr OdrBackend, id *TrieID, hash common.Hash) ([]byte, error) {
   113  	if hash == sha3_nil {
   114  		return nil, nil
   115  	}
   116  	res, _ := odr.Database().Get(hash[:])
   117  	if res != nil {
   118  		return res, nil
   119  	}
   120  	r := &CodeRequest{Id: id, Hash: hash}
   121  	if err := odr.Retrieve(ctx, r); err != nil {
   122  		return nil, err
   123  	} else {
   124  		return r.Data, nil
   125  	}
   126  }
   127  
   128  // GetBodyRLP retrieves the block body (transactions and uncles) in RLP encoding.
   129  func GetBodyRLP(ctx context.Context, odr OdrBackend, hash common.Hash, number uint64) (rlp.RawValue, error) {
   130  	if data := core.GetBodyRLP(odr.Database(), hash, number); data != nil {
   131  		return data, nil
   132  	}
   133  	r := &BlockRequest{Hash: hash, Number: number}
   134  	if err := odr.Retrieve(ctx, r); err != nil {
   135  		return nil, err
   136  	} else {
   137  		return r.Rlp, nil
   138  	}
   139  }
   140  
   141  // GetBody retrieves the block body (transactons, uncles) corresponding to the
   142  // hash.
   143  func GetBody(ctx context.Context, odr OdrBackend, hash common.Hash, number uint64) (*types.Body, error) {
   144  	data, err := GetBodyRLP(ctx, odr, hash, number)
   145  	if err != nil {
   146  		return nil, err
   147  	}
   148  	body := new(types.Body)
   149  	if err := rlp.Decode(bytes.NewReader(data), body); err != nil {
   150  		return nil, err
   151  	}
   152  	return body, nil
   153  }
   154  
   155  // GetBlock retrieves an entire block corresponding to the hash, assembling it
   156  // back from the stored header and body.
   157  func GetBlock(ctx context.Context, odr OdrBackend, hash common.Hash, number uint64) (*types.Block, error) {
   158  	// Retrieve the block header and body contents
   159  	header := core.GetHeader(odr.Database(), hash, number)
   160  	if header == nil {
   161  		return nil, ErrNoHeader
   162  	}
   163  	body, err := GetBody(ctx, odr, hash, number)
   164  	if err != nil {
   165  		return nil, err
   166  	}
   167  	// Reassemble the block and return
   168  	return types.NewBlockWithHeader(header).WithBody(body.Transactions, body.Uncles), nil
   169  }
   170  
   171  // GetBlockReceipts retrieves the receipts generated by the transactions included
   172  // in a block given by its hash.
   173  func GetBlockReceipts(ctx context.Context, odr OdrBackend, hash common.Hash, number uint64) (types.Receipts, error) {
   174  	receipts := core.GetBlockReceipts(odr.Database(), hash, number)
   175  	if receipts != nil {
   176  		return receipts, nil
   177  	}
   178  	r := &ReceiptsRequest{Hash: hash, Number: number}
   179  	if err := odr.Retrieve(ctx, r); err != nil {
   180  		return nil, err
   181  	}
   182  	return r.Receipts, nil
   183  }