github.com/jimmyx0x/go-ethereum@v1.10.28/core/rawdb/accessors_indexes.go (about)

     1  // Copyright 2018 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 rawdb
    18  
    19  import (
    20  	"bytes"
    21  	"math/big"
    22  
    23  	"github.com/ethereum/go-ethereum/common"
    24  	"github.com/ethereum/go-ethereum/core/types"
    25  	"github.com/ethereum/go-ethereum/ethdb"
    26  	"github.com/ethereum/go-ethereum/log"
    27  	"github.com/ethereum/go-ethereum/params"
    28  	"github.com/ethereum/go-ethereum/rlp"
    29  )
    30  
    31  // ReadTxLookupEntry retrieves the positional metadata associated with a transaction
    32  // hash to allow retrieving the transaction or receipt by hash.
    33  func ReadTxLookupEntry(db ethdb.Reader, hash common.Hash) *uint64 {
    34  	data, _ := db.Get(txLookupKey(hash))
    35  	if len(data) == 0 {
    36  		return nil
    37  	}
    38  	// Database v6 tx lookup just stores the block number
    39  	if len(data) < common.HashLength {
    40  		number := new(big.Int).SetBytes(data).Uint64()
    41  		return &number
    42  	}
    43  	// Database v4-v5 tx lookup format just stores the hash
    44  	if len(data) == common.HashLength {
    45  		return ReadHeaderNumber(db, common.BytesToHash(data))
    46  	}
    47  	// Finally try database v3 tx lookup format
    48  	var entry LegacyTxLookupEntry
    49  	if err := rlp.DecodeBytes(data, &entry); err != nil {
    50  		log.Error("Invalid transaction lookup entry RLP", "hash", hash, "blob", data, "err", err)
    51  		return nil
    52  	}
    53  	return &entry.BlockIndex
    54  }
    55  
    56  // writeTxLookupEntry stores a positional metadata for a transaction,
    57  // enabling hash based transaction and receipt lookups.
    58  func writeTxLookupEntry(db ethdb.KeyValueWriter, hash common.Hash, numberBytes []byte) {
    59  	if err := db.Put(txLookupKey(hash), numberBytes); err != nil {
    60  		log.Crit("Failed to store transaction lookup entry", "err", err)
    61  	}
    62  }
    63  
    64  // WriteTxLookupEntries is identical to WriteTxLookupEntry, but it works on
    65  // a list of hashes
    66  func WriteTxLookupEntries(db ethdb.KeyValueWriter, number uint64, hashes []common.Hash) {
    67  	numberBytes := new(big.Int).SetUint64(number).Bytes()
    68  	for _, hash := range hashes {
    69  		writeTxLookupEntry(db, hash, numberBytes)
    70  	}
    71  }
    72  
    73  // WriteTxLookupEntriesByBlock stores a positional metadata for every transaction from
    74  // a block, enabling hash based transaction and receipt lookups.
    75  func WriteTxLookupEntriesByBlock(db ethdb.KeyValueWriter, block *types.Block) {
    76  	numberBytes := block.Number().Bytes()
    77  	for _, tx := range block.Transactions() {
    78  		writeTxLookupEntry(db, tx.Hash(), numberBytes)
    79  	}
    80  }
    81  
    82  // DeleteTxLookupEntry removes all transaction data associated with a hash.
    83  func DeleteTxLookupEntry(db ethdb.KeyValueWriter, hash common.Hash) {
    84  	if err := db.Delete(txLookupKey(hash)); err != nil {
    85  		log.Crit("Failed to delete transaction lookup entry", "err", err)
    86  	}
    87  }
    88  
    89  // DeleteTxLookupEntries removes all transaction lookups for a given block.
    90  func DeleteTxLookupEntries(db ethdb.KeyValueWriter, hashes []common.Hash) {
    91  	for _, hash := range hashes {
    92  		DeleteTxLookupEntry(db, hash)
    93  	}
    94  }
    95  
    96  // ReadTransaction retrieves a specific transaction from the database, along with
    97  // its added positional metadata.
    98  func ReadTransaction(db ethdb.Reader, hash common.Hash) (*types.Transaction, common.Hash, uint64, uint64) {
    99  	blockNumber := ReadTxLookupEntry(db, hash)
   100  	if blockNumber == nil {
   101  		return nil, common.Hash{}, 0, 0
   102  	}
   103  	blockHash := ReadCanonicalHash(db, *blockNumber)
   104  	if blockHash == (common.Hash{}) {
   105  		return nil, common.Hash{}, 0, 0
   106  	}
   107  	body := ReadBody(db, blockHash, *blockNumber)
   108  	if body == nil {
   109  		log.Error("Transaction referenced missing", "number", *blockNumber, "hash", blockHash)
   110  		return nil, common.Hash{}, 0, 0
   111  	}
   112  	for txIndex, tx := range body.Transactions {
   113  		if tx.Hash() == hash {
   114  			return tx, blockHash, *blockNumber, uint64(txIndex)
   115  		}
   116  	}
   117  	log.Error("Transaction not found", "number", *blockNumber, "hash", blockHash, "txhash", hash)
   118  	return nil, common.Hash{}, 0, 0
   119  }
   120  
   121  // ReadReceipt retrieves a specific transaction receipt from the database, along with
   122  // its added positional metadata.
   123  func ReadReceipt(db ethdb.Reader, hash common.Hash, config *params.ChainConfig) (*types.Receipt, common.Hash, uint64, uint64) {
   124  	// Retrieve the context of the receipt based on the transaction hash
   125  	blockNumber := ReadTxLookupEntry(db, hash)
   126  	if blockNumber == nil {
   127  		return nil, common.Hash{}, 0, 0
   128  	}
   129  	blockHash := ReadCanonicalHash(db, *blockNumber)
   130  	if blockHash == (common.Hash{}) {
   131  		return nil, common.Hash{}, 0, 0
   132  	}
   133  	// Read all the receipts from the block and return the one with the matching hash
   134  	receipts := ReadReceipts(db, blockHash, *blockNumber, config)
   135  	for receiptIndex, receipt := range receipts {
   136  		if receipt.TxHash == hash {
   137  			return receipt, blockHash, *blockNumber, uint64(receiptIndex)
   138  		}
   139  	}
   140  	log.Error("Receipt not found", "number", *blockNumber, "hash", blockHash, "txhash", hash)
   141  	return nil, common.Hash{}, 0, 0
   142  }
   143  
   144  // ReadBloomBits retrieves the compressed bloom bit vector belonging to the given
   145  // section and bit index from the.
   146  func ReadBloomBits(db ethdb.KeyValueReader, bit uint, section uint64, head common.Hash) ([]byte, error) {
   147  	return db.Get(bloomBitsKey(bit, section, head))
   148  }
   149  
   150  // WriteBloomBits stores the compressed bloom bits vector belonging to the given
   151  // section and bit index.
   152  func WriteBloomBits(db ethdb.KeyValueWriter, bit uint, section uint64, head common.Hash, bits []byte) {
   153  	if err := db.Put(bloomBitsKey(bit, section, head), bits); err != nil {
   154  		log.Crit("Failed to store bloom bits", "err", err)
   155  	}
   156  }
   157  
   158  // DeleteBloombits removes all compressed bloom bits vector belonging to the
   159  // given section range and bit index.
   160  func DeleteBloombits(db ethdb.Database, bit uint, from uint64, to uint64) {
   161  	start, end := bloomBitsKey(bit, from, common.Hash{}), bloomBitsKey(bit, to, common.Hash{})
   162  	it := db.NewIterator(nil, start)
   163  	defer it.Release()
   164  
   165  	for it.Next() {
   166  		if bytes.Compare(it.Key(), end) >= 0 {
   167  			break
   168  		}
   169  		if len(it.Key()) != len(bloomBitsPrefix)+2+8+32 {
   170  			continue
   171  		}
   172  		db.Delete(it.Key())
   173  	}
   174  	if it.Error() != nil {
   175  		log.Crit("Failed to delete bloom bits", "err", it.Error())
   176  	}
   177  }