github.com/MaynardMiner/ethereumprogpow@v1.8.23/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/ethereumprogpow/ethereumprogpow/common"
    24  	"github.com/ethereumprogpow/ethereumprogpow/core"
    25  	"github.com/ethereumprogpow/ethereumprogpow/core/rawdb"
    26  	"github.com/ethereumprogpow/ethereumprogpow/core/types"
    27  	"github.com/ethereumprogpow/ethereumprogpow/crypto"
    28  	"github.com/ethereumprogpow/ethereumprogpow/rlp"
    29  )
    30  
    31  var sha3_nil = crypto.Keccak256Hash(nil)
    32  
    33  func GetHeaderByNumber(ctx context.Context, odr OdrBackend, number uint64) (*types.Header, error) {
    34  	db := odr.Database()
    35  	hash := rawdb.ReadCanonicalHash(db, number)
    36  	if (hash != common.Hash{}) {
    37  		// if there is a canonical hash, there is a header too
    38  		header := rawdb.ReadHeader(db, hash, number)
    39  		if header == nil {
    40  			panic("Canonical hash present but header not found")
    41  		}
    42  		return header, nil
    43  	}
    44  
    45  	var (
    46  		chtCount, sectionHeadNum uint64
    47  		sectionHead              common.Hash
    48  	)
    49  	if odr.ChtIndexer() != nil {
    50  		chtCount, sectionHeadNum, sectionHead = odr.ChtIndexer().Sections()
    51  		canonicalHash := rawdb.ReadCanonicalHash(db, sectionHeadNum)
    52  		// if the CHT was injected as a trusted checkpoint, we have no canonical hash yet so we accept zero hash too
    53  		for chtCount > 0 && canonicalHash != sectionHead && canonicalHash != (common.Hash{}) {
    54  			chtCount--
    55  			if chtCount > 0 {
    56  				sectionHeadNum = chtCount*odr.IndexerConfig().ChtSize - 1
    57  				sectionHead = odr.ChtIndexer().SectionHead(chtCount - 1)
    58  				canonicalHash = rawdb.ReadCanonicalHash(db, sectionHeadNum)
    59  			}
    60  		}
    61  	}
    62  	if number >= chtCount*odr.IndexerConfig().ChtSize {
    63  		return nil, ErrNoTrustedCht
    64  	}
    65  	r := &ChtRequest{ChtRoot: GetChtRoot(db, chtCount-1, sectionHead), ChtNum: chtCount - 1, BlockNum: number, Config: odr.IndexerConfig()}
    66  	if err := odr.Retrieve(ctx, r); err != nil {
    67  		return nil, err
    68  	}
    69  	return r.Header, nil
    70  }
    71  
    72  func GetCanonicalHash(ctx context.Context, odr OdrBackend, number uint64) (common.Hash, error) {
    73  	hash := rawdb.ReadCanonicalHash(odr.Database(), number)
    74  	if (hash != common.Hash{}) {
    75  		return hash, nil
    76  	}
    77  	header, err := GetHeaderByNumber(ctx, odr, number)
    78  	if header != nil {
    79  		return header.Hash(), nil
    80  	}
    81  	return common.Hash{}, err
    82  }
    83  
    84  // GetBodyRLP retrieves the block body (transactions and uncles) in RLP encoding.
    85  func GetBodyRLP(ctx context.Context, odr OdrBackend, hash common.Hash, number uint64) (rlp.RawValue, error) {
    86  	if data := rawdb.ReadBodyRLP(odr.Database(), hash, number); data != nil {
    87  		return data, nil
    88  	}
    89  	r := &BlockRequest{Hash: hash, Number: number}
    90  	if err := odr.Retrieve(ctx, r); err != nil {
    91  		return nil, err
    92  	} else {
    93  		return r.Rlp, nil
    94  	}
    95  }
    96  
    97  // GetBody retrieves the block body (transactons, uncles) corresponding to the
    98  // hash.
    99  func GetBody(ctx context.Context, odr OdrBackend, hash common.Hash, number uint64) (*types.Body, error) {
   100  	data, err := GetBodyRLP(ctx, odr, hash, number)
   101  	if err != nil {
   102  		return nil, err
   103  	}
   104  	body := new(types.Body)
   105  	if err := rlp.Decode(bytes.NewReader(data), body); err != nil {
   106  		return nil, err
   107  	}
   108  	return body, nil
   109  }
   110  
   111  // GetBlock retrieves an entire block corresponding to the hash, assembling it
   112  // back from the stored header and body.
   113  func GetBlock(ctx context.Context, odr OdrBackend, hash common.Hash, number uint64) (*types.Block, error) {
   114  	// Retrieve the block header and body contents
   115  	header := rawdb.ReadHeader(odr.Database(), hash, number)
   116  	if header == nil {
   117  		return nil, ErrNoHeader
   118  	}
   119  	body, err := GetBody(ctx, odr, hash, number)
   120  	if err != nil {
   121  		return nil, err
   122  	}
   123  	// Reassemble the block and return
   124  	return types.NewBlockWithHeader(header).WithBody(body.Transactions, body.Uncles), nil
   125  }
   126  
   127  // GetBlockReceipts retrieves the receipts generated by the transactions included
   128  // in a block given by its hash.
   129  func GetBlockReceipts(ctx context.Context, odr OdrBackend, hash common.Hash, number uint64) (types.Receipts, error) {
   130  	// Retrieve the potentially incomplete receipts from disk or network
   131  	receipts := rawdb.ReadReceipts(odr.Database(), hash, number)
   132  	if receipts == nil {
   133  		r := &ReceiptsRequest{Hash: hash, Number: number}
   134  		if err := odr.Retrieve(ctx, r); err != nil {
   135  			return nil, err
   136  		}
   137  		receipts = r.Receipts
   138  	}
   139  	// If the receipts are incomplete, fill the derived fields
   140  	if len(receipts) > 0 && receipts[0].TxHash == (common.Hash{}) {
   141  		block, err := GetBlock(ctx, odr, hash, number)
   142  		if err != nil {
   143  			return nil, err
   144  		}
   145  		genesis := rawdb.ReadCanonicalHash(odr.Database(), 0)
   146  		config := rawdb.ReadChainConfig(odr.Database(), genesis)
   147  
   148  		if err := core.SetReceiptsData(config, block, receipts); err != nil {
   149  			return nil, err
   150  		}
   151  		rawdb.WriteReceipts(odr.Database(), hash, number, receipts)
   152  	}
   153  	return receipts, nil
   154  }
   155  
   156  // GetBlockLogs retrieves the logs generated by the transactions included in a
   157  // block given by its hash.
   158  func GetBlockLogs(ctx context.Context, odr OdrBackend, hash common.Hash, number uint64) ([][]*types.Log, error) {
   159  	// Retrieve the potentially incomplete receipts from disk or network
   160  	receipts := rawdb.ReadReceipts(odr.Database(), hash, number)
   161  	if receipts == nil {
   162  		r := &ReceiptsRequest{Hash: hash, Number: number}
   163  		if err := odr.Retrieve(ctx, r); err != nil {
   164  			return nil, err
   165  		}
   166  		receipts = r.Receipts
   167  	}
   168  	// Return the logs without deriving any computed fields on the receipts
   169  	logs := make([][]*types.Log, len(receipts))
   170  	for i, receipt := range receipts {
   171  		logs[i] = receipt.Logs
   172  	}
   173  	return logs, nil
   174  }
   175  
   176  // GetBloomBits retrieves a batch of compressed bloomBits vectors belonging to the given bit index and section indexes
   177  func GetBloomBits(ctx context.Context, odr OdrBackend, bitIdx uint, sectionIdxList []uint64) ([][]byte, error) {
   178  	var (
   179  		db      = odr.Database()
   180  		result  = make([][]byte, len(sectionIdxList))
   181  		reqList []uint64
   182  		reqIdx  []int
   183  	)
   184  
   185  	var (
   186  		bloomTrieCount, sectionHeadNum uint64
   187  		sectionHead                    common.Hash
   188  	)
   189  	if odr.BloomTrieIndexer() != nil {
   190  		bloomTrieCount, sectionHeadNum, sectionHead = odr.BloomTrieIndexer().Sections()
   191  		canonicalHash := rawdb.ReadCanonicalHash(db, sectionHeadNum)
   192  		// if the BloomTrie was injected as a trusted checkpoint, we have no canonical hash yet so we accept zero hash too
   193  		for bloomTrieCount > 0 && canonicalHash != sectionHead && canonicalHash != (common.Hash{}) {
   194  			bloomTrieCount--
   195  			if bloomTrieCount > 0 {
   196  				sectionHeadNum = bloomTrieCount*odr.IndexerConfig().BloomTrieSize - 1
   197  				sectionHead = odr.BloomTrieIndexer().SectionHead(bloomTrieCount - 1)
   198  				canonicalHash = rawdb.ReadCanonicalHash(db, sectionHeadNum)
   199  			}
   200  		}
   201  	}
   202  
   203  	for i, sectionIdx := range sectionIdxList {
   204  		sectionHead := rawdb.ReadCanonicalHash(db, (sectionIdx+1)*odr.IndexerConfig().BloomSize-1)
   205  		// if we don't have the canonical hash stored for this section head number, we'll still look for
   206  		// an entry with a zero sectionHead (we store it with zero section head too if we don't know it
   207  		// at the time of the retrieval)
   208  		bloomBits, err := rawdb.ReadBloomBits(db, bitIdx, sectionIdx, sectionHead)
   209  		if err == nil {
   210  			result[i] = bloomBits
   211  		} else {
   212  			// TODO(rjl493456442) Convert sectionIndex to BloomTrie relative index
   213  			if sectionIdx >= bloomTrieCount {
   214  				return nil, ErrNoTrustedBloomTrie
   215  			}
   216  			reqList = append(reqList, sectionIdx)
   217  			reqIdx = append(reqIdx, i)
   218  		}
   219  	}
   220  	if reqList == nil {
   221  		return result, nil
   222  	}
   223  
   224  	r := &BloomRequest{BloomTrieRoot: GetBloomTrieRoot(db, bloomTrieCount-1, sectionHead), BloomTrieNum: bloomTrieCount - 1,
   225  		BitIdx: bitIdx, SectionIndexList: reqList, Config: odr.IndexerConfig()}
   226  	if err := odr.Retrieve(ctx, r); err != nil {
   227  		return nil, err
   228  	} else {
   229  		for i, idx := range reqIdx {
   230  			result[idx] = r.BloomBits[i]
   231  		}
   232  		return result, nil
   233  	}
   234  }