github.com/aswedchain/aswed@v1.0.1/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  	"math/big"
    23  
    24  	"github.com/aswedchain/aswed/common"
    25  	"github.com/aswedchain/aswed/core"
    26  	"github.com/aswedchain/aswed/core/rawdb"
    27  	"github.com/aswedchain/aswed/core/types"
    28  	"github.com/aswedchain/aswed/crypto"
    29  	"github.com/aswedchain/aswed/rlp"
    30  )
    31  
    32  var sha3Nil = crypto.Keccak256Hash(nil)
    33  
    34  // GetHeaderByNumber retrieves the canonical block header corresponding to the
    35  // given number.
    36  func GetHeaderByNumber(ctx context.Context, odr OdrBackend, number uint64) (*types.Header, error) {
    37  	// Try to find it in the local database first.
    38  	db := odr.Database()
    39  	hash := rawdb.ReadCanonicalHash(db, number)
    40  
    41  	// If there is a canonical hash, there should have a header too.
    42  	// But if it's pruned, re-fetch from network again.
    43  	if (hash != common.Hash{}) {
    44  		if header := rawdb.ReadHeader(db, hash, number); header != nil {
    45  			return header, nil
    46  		}
    47  	}
    48  	// Retrieve the header via ODR, ensure the requested header is covered
    49  	// by local trusted CHT.
    50  	chts, _, chtHead := odr.ChtIndexer().Sections()
    51  	if number >= chts*odr.IndexerConfig().ChtSize {
    52  		return nil, errNoTrustedCht
    53  	}
    54  	r := &ChtRequest{
    55  		ChtRoot:  GetChtRoot(db, chts-1, chtHead),
    56  		ChtNum:   chts - 1,
    57  		BlockNum: number,
    58  		Config:   odr.IndexerConfig(),
    59  	}
    60  	if err := odr.Retrieve(ctx, r); err != nil {
    61  		return nil, err
    62  	}
    63  	return r.Header, nil
    64  }
    65  
    66  // GetUntrustedHeaderByNumber retrieves specified block header without
    67  // correctness checking. Note this function should only be used in light
    68  // client checkpoint syncing.
    69  func GetUntrustedHeaderByNumber(ctx context.Context, odr OdrBackend, number uint64, peerId string) (*types.Header, error) {
    70  	// todo(rjl493456442) it's a hack to retrieve headers which is not covered
    71  	// by CHT. Fix it in LES4
    72  	r := &ChtRequest{
    73  		BlockNum:  number,
    74  		ChtNum:    number / odr.IndexerConfig().ChtSize,
    75  		Untrusted: true,
    76  		PeerId:    peerId,
    77  		Config:    odr.IndexerConfig(),
    78  	}
    79  	if err := odr.Retrieve(ctx, r); err != nil {
    80  		return nil, err
    81  	}
    82  	return r.Header, nil
    83  }
    84  
    85  // GetCanonicalHash retrieves the canonical block hash corresponding to the number.
    86  func GetCanonicalHash(ctx context.Context, odr OdrBackend, number uint64) (common.Hash, error) {
    87  	hash := rawdb.ReadCanonicalHash(odr.Database(), number)
    88  	if hash != (common.Hash{}) {
    89  		return hash, nil
    90  	}
    91  	header, err := GetHeaderByNumber(ctx, odr, number)
    92  	if err != nil {
    93  		return common.Hash{}, err
    94  	}
    95  	// number -> canonical mapping already be stored in db, get it.
    96  	return header.Hash(), nil
    97  }
    98  
    99  // GetTd retrieves the total difficulty corresponding to the number and hash.
   100  func GetTd(ctx context.Context, odr OdrBackend, hash common.Hash, number uint64) (*big.Int, error) {
   101  	td := rawdb.ReadTd(odr.Database(), hash, number)
   102  	if td != nil {
   103  		return td, nil
   104  	}
   105  	_, err := GetHeaderByNumber(ctx, odr, number)
   106  	if err != nil {
   107  		return nil, err
   108  	}
   109  	// <hash, number> -> td mapping already be stored in db, get it.
   110  	return rawdb.ReadTd(odr.Database(), hash, number), nil
   111  }
   112  
   113  // GetBodyRLP retrieves the block body (transactions and uncles) in RLP encoding.
   114  func GetBodyRLP(ctx context.Context, odr OdrBackend, hash common.Hash, number uint64) (rlp.RawValue, error) {
   115  	if data := rawdb.ReadBodyRLP(odr.Database(), hash, number); data != nil {
   116  		return data, nil
   117  	}
   118  	// Retrieve the block header first and pass it for verification.
   119  	header, err := GetHeaderByNumber(ctx, odr, number)
   120  	if err != nil {
   121  		return nil, errNoHeader
   122  	}
   123  	r := &BlockRequest{Hash: hash, Number: number, Header: header}
   124  	if err := odr.Retrieve(ctx, r); err != nil {
   125  		return nil, err
   126  	}
   127  	return r.Rlp, nil
   128  }
   129  
   130  // GetBody retrieves the block body (transactions, uncles) corresponding to the
   131  // hash.
   132  func GetBody(ctx context.Context, odr OdrBackend, hash common.Hash, number uint64) (*types.Body, error) {
   133  	data, err := GetBodyRLP(ctx, odr, hash, number)
   134  	if err != nil {
   135  		return nil, err
   136  	}
   137  	body := new(types.Body)
   138  	if err := rlp.Decode(bytes.NewReader(data), body); err != nil {
   139  		return nil, err
   140  	}
   141  	return body, nil
   142  }
   143  
   144  // GetBlock retrieves an entire block corresponding to the hash, assembling it
   145  // back from the stored header and body.
   146  func GetBlock(ctx context.Context, odr OdrBackend, hash common.Hash, number uint64) (*types.Block, error) {
   147  	// Retrieve the block header and body contents
   148  	header, err := GetHeaderByNumber(ctx, odr, number)
   149  	if err != nil {
   150  		return nil, errNoHeader
   151  	}
   152  	body, err := GetBody(ctx, odr, hash, number)
   153  	if err != nil {
   154  		return nil, err
   155  	}
   156  	// Reassemble the block and return
   157  	return types.NewBlockWithHeader(header).WithBody(body.Transactions, body.Uncles), nil
   158  }
   159  
   160  // GetBlockReceipts retrieves the receipts generated by the transactions included
   161  // in a block given by its hash.
   162  func GetBlockReceipts(ctx context.Context, odr OdrBackend, hash common.Hash, number uint64) (types.Receipts, error) {
   163  	// Assume receipts are already stored locally and attempt to retrieve.
   164  	receipts := rawdb.ReadRawReceipts(odr.Database(), hash, number)
   165  	if receipts == nil {
   166  		header, err := GetHeaderByNumber(ctx, odr, number)
   167  		if err != nil {
   168  			return nil, errNoHeader
   169  		}
   170  		r := &ReceiptsRequest{Hash: hash, Number: number, Header: header}
   171  		if err := odr.Retrieve(ctx, r); err != nil {
   172  			return nil, err
   173  		}
   174  		receipts = r.Receipts
   175  	}
   176  	// If the receipts are incomplete, fill the derived fields
   177  	if len(receipts) > 0 && receipts[0].TxHash == (common.Hash{}) {
   178  		block, err := GetBlock(ctx, odr, hash, number)
   179  		if err != nil {
   180  			return nil, err
   181  		}
   182  		genesis := rawdb.ReadCanonicalHash(odr.Database(), 0)
   183  		config := rawdb.ReadChainConfig(odr.Database(), genesis)
   184  
   185  		if err := receipts.DeriveFields(config, block.Hash(), block.NumberU64(), block.Transactions()); err != nil {
   186  			return nil, err
   187  		}
   188  		rawdb.WriteReceipts(odr.Database(), hash, number, receipts)
   189  	}
   190  	return receipts, nil
   191  }
   192  
   193  // GetBlockLogs retrieves the logs generated by the transactions included in a
   194  // block given by its hash.
   195  func GetBlockLogs(ctx context.Context, odr OdrBackend, hash common.Hash, number uint64) ([][]*types.Log, error) {
   196  	// Retrieve the potentially incomplete receipts from disk or network
   197  	receipts, err := GetBlockReceipts(ctx, odr, hash, number)
   198  	if err != nil {
   199  		return nil, err
   200  	}
   201  	logs := make([][]*types.Log, len(receipts))
   202  	for i, receipt := range receipts {
   203  		logs[i] = receipt.Logs
   204  	}
   205  	return logs, nil
   206  }
   207  
   208  // GetUntrustedBlockLogs retrieves the logs generated by the transactions included in a
   209  // block. The retrieved logs are regarded as untrusted and will not be stored in the
   210  // database. This function should only be used in light client checkpoint syncing.
   211  func GetUntrustedBlockLogs(ctx context.Context, odr OdrBackend, header *types.Header) ([][]*types.Log, error) {
   212  	// Retrieve the potentially incomplete receipts from disk or network
   213  	hash, number := header.Hash(), header.Number.Uint64()
   214  	receipts := rawdb.ReadRawReceipts(odr.Database(), hash, number)
   215  	if receipts == nil {
   216  		r := &ReceiptsRequest{Hash: hash, Number: number, Header: header, Untrusted: true}
   217  		if err := odr.Retrieve(ctx, r); err != nil {
   218  			return nil, err
   219  		}
   220  		receipts = r.Receipts
   221  		// Untrusted receipts won't be stored in the database. Therefore
   222  		// derived fields computation is unnecessary.
   223  	}
   224  	// Return the logs without deriving any computed fields on the receipts
   225  	logs := make([][]*types.Log, len(receipts))
   226  	for i, receipt := range receipts {
   227  		logs[i] = receipt.Logs
   228  	}
   229  	return logs, nil
   230  }
   231  
   232  // GetBloomBits retrieves a batch of compressed bloomBits vectors belonging to
   233  // the given bit index and section indexes.
   234  func GetBloomBits(ctx context.Context, odr OdrBackend, bit uint, sections []uint64) ([][]byte, error) {
   235  	var (
   236  		reqIndex    []int
   237  		reqSections []uint64
   238  		db          = odr.Database()
   239  		result      = make([][]byte, len(sections))
   240  	)
   241  	blooms, _, sectionHead := odr.BloomTrieIndexer().Sections()
   242  	for i, section := range sections {
   243  		sectionHead := rawdb.ReadCanonicalHash(db, (section+1)*odr.IndexerConfig().BloomSize-1)
   244  		// If we don't have the canonical hash stored for this section head number,
   245  		// we'll still look for an entry with a zero sectionHead (we store it with
   246  		// zero section head too if we don't know it at the time of the retrieval)
   247  		if bloomBits, _ := rawdb.ReadBloomBits(db, bit, section, sectionHead); len(bloomBits) != 0 {
   248  			result[i] = bloomBits
   249  			continue
   250  		}
   251  		// TODO(rjl493456442) Convert sectionIndex to BloomTrie relative index
   252  		if section >= blooms {
   253  			return nil, errNoTrustedBloomTrie
   254  		}
   255  		reqSections = append(reqSections, section)
   256  		reqIndex = append(reqIndex, i)
   257  	}
   258  	// Find all bloombits in database, nothing to query via odr, return.
   259  	if reqSections == nil {
   260  		return result, nil
   261  	}
   262  	// Send odr request to retrieve missing bloombits.
   263  	r := &BloomRequest{
   264  		BloomTrieRoot:    GetBloomTrieRoot(db, blooms-1, sectionHead),
   265  		BloomTrieNum:     blooms - 1,
   266  		BitIdx:           bit,
   267  		SectionIndexList: reqSections,
   268  		Config:           odr.IndexerConfig(),
   269  	}
   270  	if err := odr.Retrieve(ctx, r); err != nil {
   271  		return nil, err
   272  	}
   273  	for i, idx := range reqIndex {
   274  		result[idx] = r.BloomBits[i]
   275  	}
   276  	return result, nil
   277  }
   278  
   279  // GetTransaction retrieves a canonical transaction by hash and also returns its position in the chain
   280  func GetTransaction(ctx context.Context, odr OdrBackend, txHash common.Hash) (*types.Transaction, common.Hash, uint64, uint64, error) {
   281  	r := &TxStatusRequest{Hashes: []common.Hash{txHash}}
   282  	if err := odr.Retrieve(ctx, r); err != nil || r.Status[0].Status != core.TxStatusIncluded {
   283  		return nil, common.Hash{}, 0, 0, err
   284  	}
   285  	pos := r.Status[0].Lookup
   286  	// first ensure that we have the header, otherwise block body retrieval will fail
   287  	// also verify if this is a canonical block by getting the header by number and checking its hash
   288  	if header, err := GetHeaderByNumber(ctx, odr, pos.BlockIndex); err != nil || header.Hash() != pos.BlockHash {
   289  		return nil, common.Hash{}, 0, 0, err
   290  	}
   291  	body, err := GetBody(ctx, odr, pos.BlockHash, pos.BlockIndex)
   292  	if err != nil || uint64(len(body.Transactions)) <= pos.Index || body.Transactions[pos.Index].Hash() != txHash {
   293  		return nil, common.Hash{}, 0, 0, err
   294  	}
   295  	return body.Transactions[pos.Index], pos.BlockHash, pos.BlockIndex, pos.Index, nil
   296  }