github.com/ccm-chain/ccmchain@v1.0.0/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/ccm-chain/ccmchain/common"
    24  	"github.com/ccm-chain/ccmchain/core/types"
    25  	"github.com/ccm-chain/ccmchain/database"
    26  	"github.com/ccm-chain/ccmchain/log"
    27  	"github.com/ccm-chain/ccmchain/params"
    28  	"github.com/ccm-chain/ccmchain/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 database.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  // WriteTxLookupEntries stores a positional metadata for every transaction from
    57  // a block, enabling hash based transaction and receipt lookups.
    58  func WriteTxLookupEntries(db database.KeyValueWriter, block *types.Block) {
    59  	number := block.Number().Bytes()
    60  	for _, tx := range block.Transactions() {
    61  		if err := db.Put(txLookupKey(tx.Hash()), number); err != nil {
    62  			log.Crit("Failed to store transaction lookup entry", "err", err)
    63  		}
    64  	}
    65  }
    66  
    67  // WriteTxLookupEntriesByHash is identical to WriteTxLookupEntries, but does not
    68  // require a full types.Block as input.
    69  func WriteTxLookupEntriesByHash(db database.KeyValueWriter, number uint64, hashes []common.Hash) {
    70  	numberBytes := new(big.Int).SetUint64(number).Bytes()
    71  	for _, hash := range hashes {
    72  		if err := db.Put(txLookupKey(hash), numberBytes); err != nil {
    73  			log.Crit("Failed to store transaction lookup entry", "err", err)
    74  		}
    75  	}
    76  }
    77  
    78  // DeleteTxLookupEntry removes all transaction data associated with a hash.
    79  func DeleteTxLookupEntry(db database.KeyValueWriter, hash common.Hash) {
    80  	if err := db.Delete(txLookupKey(hash)); err != nil {
    81  		log.Crit("Failed to delete transaction lookup entry", "err", err)
    82  	}
    83  }
    84  
    85  // DeleteTxLookupEntries removes all transaction lookups for a given block.
    86  func DeleteTxLookupEntriesByHash(db database.KeyValueWriter, hashes []common.Hash) {
    87  	for _, hash := range hashes {
    88  		if err := db.Delete(txLookupKey(hash)); err != nil {
    89  			log.Crit("Failed to delete transaction lookup entry", "err", err)
    90  		}
    91  	}
    92  }
    93  
    94  // ReadTransaction retrieves a specific transaction from the database, along with
    95  // its added positional metadata.
    96  func ReadTransaction(db database.Reader, hash common.Hash) (*types.Transaction, common.Hash, uint64, uint64) {
    97  	blockNumber := ReadTxLookupEntry(db, hash)
    98  	if blockNumber == nil {
    99  		return nil, common.Hash{}, 0, 0
   100  	}
   101  	blockHash := ReadCanonicalHash(db, *blockNumber)
   102  	if blockHash == (common.Hash{}) {
   103  		return nil, common.Hash{}, 0, 0
   104  	}
   105  	body := ReadBody(db, blockHash, *blockNumber)
   106  	if body == nil {
   107  		log.Error("Transaction referenced missing", "number", blockNumber, "hash", blockHash)
   108  		return nil, common.Hash{}, 0, 0
   109  	}
   110  	for txIndex, tx := range body.Transactions {
   111  		if tx.Hash() == hash {
   112  			return tx, blockHash, *blockNumber, uint64(txIndex)
   113  		}
   114  	}
   115  	log.Error("Transaction not found", "number", blockNumber, "hash", blockHash, "txhash", hash)
   116  	return nil, common.Hash{}, 0, 0
   117  }
   118  
   119  // ReadReceipt retrieves a specific transaction receipt from the database, along with
   120  // its added positional metadata.
   121  func ReadReceipt(db database.Reader, hash common.Hash, config *params.ChainConfig) (*types.Receipt, common.Hash, uint64, uint64) {
   122  	// Retrieve the context of the receipt based on the transaction hash
   123  	blockNumber := ReadTxLookupEntry(db, hash)
   124  	if blockNumber == nil {
   125  		return nil, common.Hash{}, 0, 0
   126  	}
   127  	blockHash := ReadCanonicalHash(db, *blockNumber)
   128  	if blockHash == (common.Hash{}) {
   129  		return nil, common.Hash{}, 0, 0
   130  	}
   131  	// Read all the receipts from the block and return the one with the matching hash
   132  	receipts := ReadReceipts(db, blockHash, *blockNumber, config)
   133  	for receiptIndex, receipt := range receipts {
   134  		if receipt.TxHash == hash {
   135  			return receipt, blockHash, *blockNumber, uint64(receiptIndex)
   136  		}
   137  	}
   138  	log.Error("Receipt not found", "number", blockNumber, "hash", blockHash, "txhash", hash)
   139  	return nil, common.Hash{}, 0, 0
   140  }
   141  
   142  // ReadBloomBits retrieves the compressed bloom bit vector belonging to the given
   143  // section and bit index from the.
   144  func ReadBloomBits(db database.KeyValueReader, bit uint, section uint64, head common.Hash) ([]byte, error) {
   145  	return db.Get(bloomBitsKey(bit, section, head))
   146  }
   147  
   148  // WriteBloomBits stores the compressed bloom bits vector belonging to the given
   149  // section and bit index.
   150  func WriteBloomBits(db database.KeyValueWriter, bit uint, section uint64, head common.Hash, bits []byte) {
   151  	if err := db.Put(bloomBitsKey(bit, section, head), bits); err != nil {
   152  		log.Crit("Failed to store bloom bits", "err", err)
   153  	}
   154  }
   155  
   156  // DeleteBloombits removes all compressed bloom bits vector belonging to the
   157  // given section range and bit index.
   158  func DeleteBloombits(db database.Database, bit uint, from uint64, to uint64) {
   159  	start, end := bloomBitsKey(bit, from, common.Hash{}), bloomBitsKey(bit, to, common.Hash{})
   160  	it := db.NewIterator(nil, start)
   161  	defer it.Release()
   162  
   163  	for it.Next() {
   164  		if bytes.Compare(it.Key(), end) >= 0 {
   165  			break
   166  		}
   167  		if len(it.Key()) != len(bloomBitsPrefix)+2+8+32 {
   168  			continue
   169  		}
   170  		db.Delete(it.Key())
   171  	}
   172  	if it.Error() != nil {
   173  		log.Crit("Failed to delete bloom bits", "err", it.Error())
   174  	}
   175  }