github.com/amazechain/amc@v0.1.3/modules/rawdb/accessors_indexes.go (about)

     1  // Copyright 2023 The AmazeChain Authors
     2  // This file is part of the AmazeChain library.
     3  //
     4  // The AmazeChain 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 AmazeChain 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 AmazeChain library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package rawdb
    18  
    19  import (
    20  	"github.com/amazechain/amc/common/block"
    21  	"github.com/amazechain/amc/common/transaction"
    22  	"github.com/amazechain/amc/common/types"
    23  	"github.com/amazechain/amc/log"
    24  	"github.com/amazechain/amc/modules"
    25  	"github.com/holiman/uint256"
    26  	"github.com/ledgerwatch/erigon-lib/kv"
    27  )
    28  
    29  // TxLookupEntry is a positional metadata to help looking up the data content of
    30  // a transaction or receipt given only its hash.
    31  type TxLookupEntry struct {
    32  	BlockHash  types.Hash
    33  	BlockIndex uint64
    34  	Index      uint64
    35  }
    36  
    37  // ReadTxLookupEntry retrieves the positional metadata associated with a transaction
    38  // hash to allow retrieving the transaction or receipt by hash.
    39  func ReadTxLookupEntry(db kv.Getter, txnHash types.Hash) (*uint64, error) {
    40  	data, err := db.GetOne(modules.TxLookup, txnHash.Bytes())
    41  	if err != nil {
    42  		return nil, err
    43  	}
    44  	if len(data) == 0 {
    45  		return nil, nil
    46  	}
    47  	// number := new(big.Int).SetBytes(data).Uint64()
    48  	number := uint256.NewInt(0).SetBytes(data).Uint64()
    49  	return &number, nil
    50  }
    51  
    52  // WriteTxLookupEntries stores a positional metadata for every transaction from
    53  // a block, enabling hash based transaction and receipt lookups.
    54  func WriteTxLookupEntries(db kv.Putter, block *block.Block) {
    55  	for _, tx := range block.Transactions() {
    56  		data := block.Number64().Bytes()
    57  		h := tx.Hash()
    58  		if err := db.Put(modules.TxLookup, h.Bytes(), data); err != nil {
    59  			log.Crit("Failed to store transaction lookup entry", "err", err)
    60  		}
    61  	}
    62  }
    63  
    64  // DeleteTxLookupEntry removes all transaction data associated with a hash.
    65  func DeleteTxLookupEntry(db kv.Deleter, hash types.Hash) error {
    66  	return db.Delete(modules.TxLookup, hash.Bytes())
    67  }
    68  
    69  // ReadTransactionByHash retrieves a specific transaction from the database, along with
    70  // its added positional metadata.
    71  func ReadTransactionByHash(db kv.Tx, hash types.Hash) (*transaction.Transaction, types.Hash, uint64, uint64, error) {
    72  	blockNumber, err := ReadTxLookupEntry(db, hash)
    73  	if err != nil {
    74  		return nil, types.Hash{}, 0, 0, err
    75  	}
    76  	if blockNumber == nil {
    77  		return nil, types.Hash{}, 0, 0, nil
    78  	}
    79  	blockHash, err := ReadCanonicalHash(db, *blockNumber)
    80  	if err != nil {
    81  		return nil, types.Hash{}, 0, 0, err
    82  	}
    83  	if blockHash == (types.Hash{}) {
    84  		return nil, types.Hash{}, 0, 0, nil
    85  	}
    86  	body := ReadCanonicalBodyWithTransactions(db, blockHash, *blockNumber)
    87  	if body == nil {
    88  		log.Error("Transaction referenced missing", "number", blockNumber, "hash", blockHash)
    89  		return nil, types.Hash{}, 0, 0, nil
    90  	}
    91  	senders, err1 := ReadSenders(db, blockHash, *blockNumber)
    92  	if err1 != nil {
    93  		return nil, types.Hash{}, 0, 0, err1
    94  	}
    95  	body.SendersToTxs(senders)
    96  	for txIndex, tx := range body.Txs {
    97  		h := tx.Hash()
    98  		if h == hash {
    99  			return tx, blockHash, *blockNumber, uint64(txIndex), nil
   100  		}
   101  	}
   102  	log.Error("Transaction not found", "number", blockNumber, "hash", blockHash, "txhash", hash)
   103  	return nil, types.Hash{}, 0, 0, nil
   104  }
   105  
   106  // ReadTransaction retrieves a specific transaction from the database, along with
   107  // its added positional metadata.
   108  func ReadTransaction(db kv.Tx, hash types.Hash, blockNumber uint64) (*transaction.Transaction, types.Hash, uint64, uint64, error) {
   109  	blockHash, err := ReadCanonicalHash(db, blockNumber)
   110  	if err != nil {
   111  		return nil, types.Hash{}, 0, 0, err
   112  	}
   113  	if blockHash == (types.Hash{}) {
   114  		return nil, types.Hash{}, 0, 0, nil
   115  	}
   116  	body := ReadCanonicalBodyWithTransactions(db, blockHash, blockNumber)
   117  	if body == nil {
   118  		log.Error("Transaction referenced missing", "number", blockNumber, "hash", blockHash)
   119  		return nil, types.Hash{}, 0, 0, nil
   120  	}
   121  	senders, err1 := ReadSenders(db, blockHash, blockNumber)
   122  	if err1 != nil {
   123  		return nil, types.Hash{}, 0, 0, err1
   124  	}
   125  	body.SendersToTxs(senders)
   126  	for txIndex, tx := range body.Txs {
   127  		h := tx.Hash()
   128  		if h == hash {
   129  			return tx, blockHash, blockNumber, uint64(txIndex), nil
   130  		}
   131  	}
   132  	log.Error("Transaction not found", "number", blockNumber, "hash", blockHash, "txhash", hash)
   133  	return nil, types.Hash{}, 0, 0, nil
   134  }
   135  
   136  func ReadReceipt(db kv.Tx, txHash types.Hash) (*block.Receipt, types.Hash, uint64, uint64, error) {
   137  	// Retrieve the context of the receipt based on the transaction hash
   138  	blockNumber, err := ReadTxLookupEntry(db, txHash)
   139  	if err != nil {
   140  		return nil, types.Hash{}, 0, 0, err
   141  	}
   142  	if blockNumber == nil {
   143  		return nil, types.Hash{}, 0, 0, nil
   144  	}
   145  	blockHash, err := ReadCanonicalHash(db, *blockNumber)
   146  	if err != nil {
   147  		return nil, types.Hash{}, 0, 0, err
   148  	}
   149  	if blockHash == (types.Hash{}) {
   150  		return nil, types.Hash{}, 0, 0, nil
   151  	}
   152  	b, senders, err := ReadBlockWithSenders(db, blockHash, *blockNumber)
   153  	if err != nil {
   154  		return nil, types.Hash{}, 0, 0, err
   155  	}
   156  	// Read all the receipts from the block and return the one with the matching hash
   157  	receipts := ReadReceipts(db, b, senders)
   158  	for receiptIndex, receipt := range receipts {
   159  		if receipt.TxHash == txHash {
   160  			return receipt, blockHash, *blockNumber, uint64(receiptIndex), nil
   161  		}
   162  	}
   163  	log.Error("Receipt not found", "number", blockNumber, "hash", blockHash, "txhash", txHash)
   164  	return nil, types.Hash{}, 0, 0, nil
   165  }