github.com/core-coin/go-core/v2@v2.1.9/core/rawdb/accessors_indexes.go (about)

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