github.com/bcskill/bcschain/v3@v3.4.9-beta2/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/bcskill/bcschain/v3/common"
    24  	"github.com/bcskill/bcschain/v3/core/rawdb"
    25  	"github.com/bcskill/bcschain/v3/core/types"
    26  	"github.com/bcskill/bcschain/v3/crypto"
    27  	"github.com/bcskill/bcschain/v3/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 := rawdb.ReadCanonicalHash(db, number)
    35  	if (hash != common.Hash{}) {
    36  		// if there is a canonical hash, there is a header too
    37  		header := rawdb.ReadHeader(db.HeaderTable(), 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 := rawdb.ReadCanonicalHash(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 = rawdb.ReadCanonicalHash(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 := rawdb.ReadCanonicalHash(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 := rawdb.ReadBodyRLP(odr.Database().BodyTable(), 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 := rawdb.ReadHeader(odr.Database().HeaderTable(), 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  	// Assume the receipts are already stored locally and attempt to retrieve.
   130  	receipts := rawdb.ReadRawReceipts(odr.Database().ReceiptTable(), 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 := rawdb.ReadCanonicalHash(odr.Database(), 0)
   145  		config := rawdb.ReadChainConfig(odr.Database().GlobalTable(), genesis)
   146  
   147  		if err := receipts.DeriveFields(config, block.Hash(), block.NumberU64(), block.Transactions()); err != nil {
   148  			return nil, err
   149  		}
   150  		rawdb.WriteReceipts(odr.Database().ReceiptTable(), 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, err := GetBlockReceipts(ctx, odr, hash, number)
   160  	if err != nil {
   161  		return nil, err
   162  	}
   163  	// Return the logs without deriving any computed fields on the receipts
   164  	logs := make([][]*types.Log, len(receipts))
   165  	for i, receipt := range receipts {
   166  		logs[i] = receipt.Logs
   167  	}
   168  	return logs, nil
   169  }
   170  
   171  // GetBloomBits retrieves a batch of compressed bloomBits vectors belonging to the given bit index and section indexes
   172  func GetBloomBits(ctx context.Context, odr OdrBackend, bitIdx uint, sectionIdxList []uint64) ([][]byte, error) {
   173  	db := odr.Database()
   174  	result := make([][]byte, len(sectionIdxList))
   175  	var (
   176  		reqList []uint64
   177  		reqIdx  []int
   178  	)
   179  
   180  	var (
   181  		bloomTrieCount, sectionHeadNum uint64
   182  		sectionHead                    common.Hash
   183  	)
   184  	if odr.BloomTrieIndexer() != nil {
   185  		bloomTrieCount, sectionHeadNum, sectionHead = odr.BloomTrieIndexer().Sections()
   186  		canonicalHash := rawdb.ReadCanonicalHash(db, sectionHeadNum)
   187  		// if the BloomTrie was injected as a trusted checkpoint, we have no canonical hash yet so we accept zero hash too
   188  		for bloomTrieCount > 0 && canonicalHash != sectionHead && canonicalHash != (common.Hash{}) {
   189  			bloomTrieCount--
   190  			if bloomTrieCount > 0 {
   191  				sectionHeadNum = bloomTrieCount*BloomTrieFrequency - 1
   192  				sectionHead = odr.BloomTrieIndexer().SectionHead(bloomTrieCount - 1)
   193  				canonicalHash = rawdb.ReadCanonicalHash(db, sectionHeadNum)
   194  			}
   195  		}
   196  	}
   197  
   198  	for i, sectionIdx := range sectionIdxList {
   199  		sectionHead := rawdb.ReadCanonicalHash(db, (sectionIdx+1)*BloomTrieFrequency-1)
   200  		// if we don't have the canonical hash stored for this section head number, we'll still look for
   201  		// an entry with a zero sectionHead (we store it with zero section head too if we don't know it
   202  		// at the time of the retrieval)
   203  		result[i] = rawdb.ReadBloomBits(db.GlobalTable(), bitIdx, sectionIdx, sectionHead)
   204  
   205  	}
   206  	if reqList == nil {
   207  		return result, nil
   208  	}
   209  
   210  	r := &BloomRequest{BloomTrieRoot: GetBloomTrieRoot(db, bloomTrieCount-1, sectionHead), BloomTrieNum: bloomTrieCount - 1, BitIdx: bitIdx, SectionIdxList: reqList}
   211  	if err := odr.Retrieve(ctx, r); err != nil {
   212  		return nil, err
   213  	} else {
   214  		for i, idx := range reqIdx {
   215  			result[idx] = r.BloomBits[i]
   216  		}
   217  		return result, nil
   218  	}
   219  }