github.com/MetalBlockchain/subnet-evm@v0.6.3/core/rawdb/accessors_indexes.go (about)

     1  // (c) 2019-2020, Ava Labs, Inc.
     2  //
     3  // This file is a derived work, based on the go-ethereum library whose original
     4  // notices appear below.
     5  //
     6  // It is distributed under a license compatible with the licensing terms of the
     7  // original code from which it is derived.
     8  //
     9  // Much love to the original authors for their work.
    10  // **********
    11  // Copyright 2018 The go-ethereum Authors
    12  // This file is part of the go-ethereum library.
    13  //
    14  // The go-ethereum library is free software: you can redistribute it and/or modify
    15  // it under the terms of the GNU Lesser General Public License as published by
    16  // the Free Software Foundation, either version 3 of the License, or
    17  // (at your option) any later version.
    18  //
    19  // The go-ethereum library is distributed in the hope that it will be useful,
    20  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    21  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    22  // GNU Lesser General Public License for more details.
    23  //
    24  // You should have received a copy of the GNU Lesser General Public License
    25  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    26  
    27  package rawdb
    28  
    29  import (
    30  	"bytes"
    31  	"math/big"
    32  
    33  	"github.com/MetalBlockchain/subnet-evm/core/types"
    34  	"github.com/MetalBlockchain/subnet-evm/params"
    35  	"github.com/ethereum/go-ethereum/common"
    36  	"github.com/ethereum/go-ethereum/ethdb"
    37  	"github.com/ethereum/go-ethereum/log"
    38  	"github.com/ethereum/go-ethereum/rlp"
    39  )
    40  
    41  // ReadTxLookupEntry retrieves the positional metadata associated with a transaction
    42  // hash to allow retrieving the transaction or receipt by hash.
    43  func ReadTxLookupEntry(db ethdb.Reader, hash common.Hash) *uint64 {
    44  	data, _ := db.Get(txLookupKey(hash))
    45  	if len(data) == 0 {
    46  		return nil
    47  	}
    48  	// Database v6 tx lookup just stores the block number
    49  	if len(data) < common.HashLength {
    50  		number := new(big.Int).SetBytes(data).Uint64()
    51  		return &number
    52  	}
    53  	// Database v4-v5 tx lookup format just stores the hash
    54  	if len(data) == common.HashLength {
    55  		return ReadHeaderNumber(db, common.BytesToHash(data))
    56  	}
    57  	// Finally try database v3 tx lookup format
    58  	var entry LegacyTxLookupEntry
    59  	if err := rlp.DecodeBytes(data, &entry); err != nil {
    60  		log.Error("Invalid transaction lookup entry RLP", "hash", hash, "blob", data, "err", err)
    61  		return nil
    62  	}
    63  	return &entry.BlockIndex
    64  }
    65  
    66  // writeTxLookupEntry stores a positional metadata for a transaction,
    67  // enabling hash based transaction and receipt lookups.
    68  func writeTxLookupEntry(db ethdb.KeyValueWriter, hash common.Hash, numberBytes []byte) {
    69  	if err := db.Put(txLookupKey(hash), numberBytes); err != nil {
    70  		log.Crit("Failed to store transaction lookup entry", "err", err)
    71  	}
    72  }
    73  
    74  // WriteTxLookupEntries is identical to WriteTxLookupEntry, but it works on
    75  // a list of hashes
    76  func WriteTxLookupEntries(db ethdb.KeyValueWriter, number uint64, hashes []common.Hash) {
    77  	numberBytes := new(big.Int).SetUint64(number).Bytes()
    78  	for _, hash := range hashes {
    79  		writeTxLookupEntry(db, hash, numberBytes)
    80  	}
    81  }
    82  
    83  // WriteTxLookupEntriesByBlock stores a positional metadata for every transaction from
    84  // a block, enabling hash based transaction and receipt lookups.
    85  func WriteTxLookupEntriesByBlock(db ethdb.KeyValueWriter, block *types.Block) {
    86  	numberBytes := block.Number().Bytes()
    87  	for _, tx := range block.Transactions() {
    88  		writeTxLookupEntry(db, tx.Hash(), numberBytes)
    89  	}
    90  }
    91  
    92  // DeleteTxLookupEntry removes all transaction data associated with a hash.
    93  func DeleteTxLookupEntry(db ethdb.KeyValueWriter, hash common.Hash) {
    94  	if err := db.Delete(txLookupKey(hash)); err != nil {
    95  		log.Crit("Failed to delete transaction lookup entry", "err", err)
    96  	}
    97  }
    98  
    99  // DeleteTxLookupEntries removes all transaction lookups for a given block.
   100  func DeleteTxLookupEntries(db ethdb.KeyValueWriter, hashes []common.Hash) {
   101  	for _, hash := range hashes {
   102  		DeleteTxLookupEntry(db, hash)
   103  	}
   104  }
   105  
   106  // ReadTransaction retrieves a specific transaction from the database, along with
   107  // its added positional metadata.
   108  func ReadTransaction(db ethdb.Reader, hash common.Hash) (*types.Transaction, common.Hash, uint64, uint64) {
   109  	blockNumber := ReadTxLookupEntry(db, hash)
   110  	if blockNumber == nil {
   111  		return nil, common.Hash{}, 0, 0
   112  	}
   113  	blockHash := ReadCanonicalHash(db, *blockNumber)
   114  	if blockHash == (common.Hash{}) {
   115  		return nil, common.Hash{}, 0, 0
   116  	}
   117  	body := ReadBody(db, blockHash, *blockNumber)
   118  	if body == nil {
   119  		log.Error("Transaction referenced missing", "number", *blockNumber, "hash", blockHash)
   120  		return nil, common.Hash{}, 0, 0
   121  	}
   122  	for txIndex, tx := range body.Transactions {
   123  		if tx.Hash() == hash {
   124  			return tx, blockHash, *blockNumber, uint64(txIndex)
   125  		}
   126  	}
   127  	log.Error("Transaction not found", "number", *blockNumber, "hash", blockHash, "txhash", hash)
   128  	return nil, common.Hash{}, 0, 0
   129  }
   130  
   131  // ReadReceipt retrieves a specific transaction receipt from the database, along with
   132  // its added positional metadata.
   133  func ReadReceipt(db ethdb.Reader, hash common.Hash, config *params.ChainConfig) (*types.Receipt, common.Hash, uint64, uint64) {
   134  	// Retrieve the context of the receipt based on the transaction hash
   135  	blockNumber := ReadTxLookupEntry(db, hash)
   136  	if blockNumber == nil {
   137  		return nil, common.Hash{}, 0, 0
   138  	}
   139  	blockHash := ReadCanonicalHash(db, *blockNumber)
   140  	if blockHash == (common.Hash{}) {
   141  		return nil, common.Hash{}, 0, 0
   142  	}
   143  	blockHeader := ReadHeader(db, blockHash, *blockNumber)
   144  	if blockHeader == nil {
   145  		return nil, common.Hash{}, 0, 0
   146  	}
   147  	// Read all the receipts from the block and return the one with the matching hash
   148  	receipts := ReadReceipts(db, blockHash, *blockNumber, blockHeader.Time, config)
   149  	for receiptIndex, receipt := range receipts {
   150  		if receipt.TxHash == hash {
   151  			return receipt, blockHash, *blockNumber, uint64(receiptIndex)
   152  		}
   153  	}
   154  	log.Error("Receipt not found", "number", *blockNumber, "hash", blockHash, "txhash", hash)
   155  	return nil, common.Hash{}, 0, 0
   156  }
   157  
   158  // ReadBloomBits retrieves the compressed bloom bit vector belonging to the given
   159  // section and bit index from the.
   160  func ReadBloomBits(db ethdb.KeyValueReader, bit uint, section uint64, head common.Hash) ([]byte, error) {
   161  	return db.Get(bloomBitsKey(bit, section, head))
   162  }
   163  
   164  // WriteBloomBits stores the compressed bloom bits vector belonging to the given
   165  // section and bit index.
   166  func WriteBloomBits(db ethdb.KeyValueWriter, bit uint, section uint64, head common.Hash, bits []byte) {
   167  	if err := db.Put(bloomBitsKey(bit, section, head), bits); err != nil {
   168  		log.Crit("Failed to store bloom bits", "err", err)
   169  	}
   170  }
   171  
   172  // DeleteBloombits removes all compressed bloom bits vector belonging to the
   173  // given section range and bit index.
   174  func DeleteBloombits(db ethdb.Database, bit uint, from uint64, to uint64) {
   175  	start, end := bloomBitsKey(bit, from, common.Hash{}), bloomBitsKey(bit, to, common.Hash{})
   176  	it := db.NewIterator(nil, start)
   177  	defer it.Release()
   178  
   179  	for it.Next() {
   180  		if bytes.Compare(it.Key(), end) >= 0 {
   181  			break
   182  		}
   183  		if len(it.Key()) != len(bloomBitsPrefix)+2+8+32 {
   184  			continue
   185  		}
   186  		db.Delete(it.Key())
   187  	}
   188  	if it.Error() != nil {
   189  		log.Crit("Failed to delete bloom bits", "err", it.Error())
   190  	}
   191  }