github.com/etherbanking/go-etherbanking@v1.7.1-0.20181009210156-cf649bca5aba/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/etherbanking/go-etherbanking/common"
    26  	"github.com/etherbanking/go-etherbanking/core"
    27  	"github.com/etherbanking/go-etherbanking/core/types"
    28  	"github.com/etherbanking/go-etherbanking/crypto"
    29  	"github.com/etherbanking/go-etherbanking/ethdb"
    30  	"github.com/etherbanking/go-etherbanking/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  // GetBodyRLP retrieves the block body (transactions and uncles) in RLP encoding.
   110  func GetBodyRLP(ctx context.Context, odr OdrBackend, hash common.Hash, number uint64) (rlp.RawValue, error) {
   111  	if data := core.GetBodyRLP(odr.Database(), hash, number); data != nil {
   112  		return data, nil
   113  	}
   114  	r := &BlockRequest{Hash: hash, Number: number}
   115  	if err := odr.Retrieve(ctx, r); err != nil {
   116  		return nil, err
   117  	} else {
   118  		return r.Rlp, nil
   119  	}
   120  }
   121  
   122  // GetBody retrieves the block body (transactons, uncles) corresponding to the
   123  // hash.
   124  func GetBody(ctx context.Context, odr OdrBackend, hash common.Hash, number uint64) (*types.Body, error) {
   125  	data, err := GetBodyRLP(ctx, odr, hash, number)
   126  	if err != nil {
   127  		return nil, err
   128  	}
   129  	body := new(types.Body)
   130  	if err := rlp.Decode(bytes.NewReader(data), body); err != nil {
   131  		return nil, err
   132  	}
   133  	return body, nil
   134  }
   135  
   136  // GetBlock retrieves an entire block corresponding to the hash, assembling it
   137  // back from the stored header and body.
   138  func GetBlock(ctx context.Context, odr OdrBackend, hash common.Hash, number uint64) (*types.Block, error) {
   139  	// Retrieve the block header and body contents
   140  	header := core.GetHeader(odr.Database(), hash, number)
   141  	if header == nil {
   142  		return nil, ErrNoHeader
   143  	}
   144  	body, err := GetBody(ctx, odr, hash, number)
   145  	if err != nil {
   146  		return nil, err
   147  	}
   148  	// Reassemble the block and return
   149  	return types.NewBlockWithHeader(header).WithBody(body.Transactions, body.Uncles), nil
   150  }
   151  
   152  // GetBlockReceipts retrieves the receipts generated by the transactions included
   153  // in a block given by its hash.
   154  func GetBlockReceipts(ctx context.Context, odr OdrBackend, hash common.Hash, number uint64) (types.Receipts, error) {
   155  	receipts := core.GetBlockReceipts(odr.Database(), hash, number)
   156  	if receipts != nil {
   157  		return receipts, nil
   158  	}
   159  	r := &ReceiptsRequest{Hash: hash, Number: number}
   160  	if err := odr.Retrieve(ctx, r); err != nil {
   161  		return nil, err
   162  	}
   163  	return r.Receipts, nil
   164  }