github.com/shrimpyuk/bor@v0.2.15-0.20220224151350-fb4ec6020bae/core/rawdb/bor_receipt.go (about)

     1  package rawdb
     2  
     3  import (
     4  	"math/big"
     5  
     6  	"github.com/ethereum/go-ethereum/common"
     7  	"github.com/ethereum/go-ethereum/core/types"
     8  	"github.com/ethereum/go-ethereum/ethdb"
     9  	"github.com/ethereum/go-ethereum/log"
    10  	"github.com/ethereum/go-ethereum/rlp"
    11  )
    12  
    13  var (
    14  	// bor receipt key
    15  	borReceiptKey = types.BorReceiptKey
    16  
    17  	// bor derived tx hash
    18  	getDerivedBorTxHash = types.GetDerivedBorTxHash
    19  
    20  	// borTxLookupPrefix + hash -> transaction/receipt lookup metadata
    21  	borTxLookupPrefix = []byte("matic-bor-tx-lookup-")
    22  
    23  	// freezerBorReceiptTable indicates the name of the freezer bor receipts table.
    24  	freezerBorReceiptTable = "matic-bor-receipts"
    25  )
    26  
    27  // borTxLookupKey = borTxLookupPrefix + bor tx hash
    28  func borTxLookupKey(hash common.Hash) []byte {
    29  	return append(borTxLookupPrefix, hash.Bytes()...)
    30  }
    31  
    32  // HasBorReceipt verifies the existence of all block receipt belonging
    33  // to a block.
    34  func HasBorReceipt(db ethdb.Reader, hash common.Hash, number uint64) bool {
    35  	if has, err := db.Ancient(freezerHashTable, number); err == nil && common.BytesToHash(has) == hash {
    36  		return true
    37  	}
    38  
    39  	if has, err := db.Has(borReceiptKey(number, hash)); !has || err != nil {
    40  		return false
    41  	}
    42  
    43  	return true
    44  }
    45  
    46  // ReadBorReceiptRLP retrieves the block receipt belonging to a block in RLP encoding.
    47  func ReadBorReceiptRLP(db ethdb.Reader, hash common.Hash, number uint64) rlp.RawValue {
    48  	// First try to look up the data in ancient database. Extra hash
    49  	// comparison is necessary since ancient database only maintains
    50  	// the canonical data.
    51  	data, _ := db.Ancient(freezerBorReceiptTable, number)
    52  	if len(data) > 0 {
    53  		h, _ := db.Ancient(freezerHashTable, number)
    54  		if common.BytesToHash(h) == hash {
    55  			return data
    56  		}
    57  	}
    58  	// Then try to look up the data in leveldb.
    59  	data, _ = db.Get(borReceiptKey(number, hash))
    60  	if len(data) > 0 {
    61  		return data
    62  	}
    63  	// In the background freezer is moving data from leveldb to flatten files.
    64  	// So during the first check for ancient db, the data is not yet in there,
    65  	// but when we reach into leveldb, the data was already moved. That would
    66  	// result in a not found error.
    67  	data, _ = db.Ancient(freezerBorReceiptTable, number)
    68  	if len(data) > 0 {
    69  		h, _ := db.Ancient(freezerHashTable, number)
    70  		if common.BytesToHash(h) == hash {
    71  			return data
    72  		}
    73  	}
    74  	return nil // Can't find the data anywhere.
    75  }
    76  
    77  // ReadRawBorReceipt retrieves the block receipt belonging to a block.
    78  // The receipt metadata fields are not guaranteed to be populated, so they
    79  // should not be used. Use ReadBorReceipt instead if the metadata is needed.
    80  func ReadRawBorReceipt(db ethdb.Reader, hash common.Hash, number uint64) *types.Receipt {
    81  	// Retrieve the flattened receipt slice
    82  	data := ReadBorReceiptRLP(db, hash, number)
    83  	if data == nil || len(data) == 0 {
    84  		return nil
    85  	}
    86  
    87  	// Convert the receipts from their storage form to their internal representation
    88  	var storageReceipt types.ReceiptForStorage
    89  	if err := rlp.DecodeBytes(data, &storageReceipt); err != nil {
    90  		log.Error("Invalid receipt array RLP", "hash", hash, "err", err)
    91  		return nil
    92  	}
    93  
    94  	return (*types.Receipt)(&storageReceipt)
    95  }
    96  
    97  // ReadBorReceipt retrieves all the bor block receipts belonging to a block, including
    98  // its correspoinding metadata fields. If it is unable to populate these metadata
    99  // fields then nil is returned.
   100  func ReadBorReceipt(db ethdb.Reader, hash common.Hash, number uint64) *types.Receipt {
   101  	// We're deriving many fields from the block body, retrieve beside the receipt
   102  	borReceipt := ReadRawBorReceipt(db, hash, number)
   103  	if borReceipt == nil {
   104  		return nil
   105  	}
   106  
   107  	// We're deriving many fields from the block body, retrieve beside the receipt
   108  	receipts := ReadRawReceipts(db, hash, number)
   109  	if receipts == nil {
   110  		return nil
   111  	}
   112  
   113  	body := ReadBody(db, hash, number)
   114  	if body == nil {
   115  		log.Error("Missing body but have bor receipt", "hash", hash, "number", number)
   116  		return nil
   117  	}
   118  
   119  	if err := types.DeriveFieldsForBorReceipt(borReceipt, hash, number, receipts); err != nil {
   120  		log.Error("Failed to derive bor receipt fields", "hash", hash, "number", number, "err", err)
   121  		return nil
   122  	}
   123  	return borReceipt
   124  }
   125  
   126  // WriteBorReceipt stores all the bor receipt belonging to a block.
   127  func WriteBorReceipt(db ethdb.KeyValueWriter, hash common.Hash, number uint64, borReceipt *types.ReceiptForStorage) {
   128  	// Convert the bor receipt into their storage form and serialize them
   129  	bytes, err := rlp.EncodeToBytes(borReceipt)
   130  	if err != nil {
   131  		log.Crit("Failed to encode bor receipt", "err", err)
   132  	}
   133  
   134  	// Store the flattened receipt slice
   135  	if err := db.Put(borReceiptKey(number, hash), bytes); err != nil {
   136  		log.Crit("Failed to store bor receipt", "err", err)
   137  	}
   138  }
   139  
   140  // DeleteBorReceipt removes receipt data associated with a block hash.
   141  func DeleteBorReceipt(db ethdb.KeyValueWriter, hash common.Hash, number uint64) {
   142  	key := borReceiptKey(number, hash)
   143  
   144  	if err := db.Delete(key); err != nil {
   145  		log.Crit("Failed to delete bor receipt", "err", err)
   146  	}
   147  }
   148  
   149  // ReadBorTransactionWithBlockHash retrieves a specific bor (fake) transaction by tx hash and block hash, along with
   150  // its added positional metadata.
   151  func ReadBorTransactionWithBlockHash(db ethdb.Reader, txHash common.Hash, blockHash common.Hash) (*types.Transaction, common.Hash, uint64, uint64) {
   152  	blockNumber := ReadBorTxLookupEntry(db, txHash)
   153  	if blockNumber == nil {
   154  		return nil, common.Hash{}, 0, 0
   155  	}
   156  
   157  	body := ReadBody(db, blockHash, *blockNumber)
   158  	if body == nil {
   159  		log.Error("Transaction referenced missing", "number", blockNumber, "hash", blockHash)
   160  		return nil, common.Hash{}, 0, 0
   161  	}
   162  
   163  	// fetch receipt and return it
   164  	return types.NewBorTransaction(), blockHash, *blockNumber, uint64(len(body.Transactions))
   165  }
   166  
   167  // ReadBorTransaction retrieves a specific bor (fake) transaction by hash, along with
   168  // its added positional metadata.
   169  func ReadBorTransaction(db ethdb.Reader, hash common.Hash) (*types.Transaction, common.Hash, uint64, uint64) {
   170  	blockNumber := ReadBorTxLookupEntry(db, hash)
   171  	if blockNumber == nil {
   172  		return nil, common.Hash{}, 0, 0
   173  	}
   174  
   175  	blockHash := ReadCanonicalHash(db, *blockNumber)
   176  	if blockHash == (common.Hash{}) {
   177  		return nil, common.Hash{}, 0, 0
   178  	}
   179  
   180  	body := ReadBody(db, blockHash, *blockNumber)
   181  	if body == nil {
   182  		log.Error("Transaction referenced missing", "number", blockNumber, "hash", blockHash)
   183  		return nil, common.Hash{}, 0, 0
   184  	}
   185  
   186  	// fetch receipt and return it
   187  	return types.NewBorTransaction(), blockHash, *blockNumber, uint64(len(body.Transactions))
   188  }
   189  
   190  //
   191  // Indexes for reverse lookup
   192  //
   193  
   194  // ReadBorTxLookupEntry retrieves the positional metadata associated with a transaction
   195  // hash to allow retrieving the bor transaction or bor receipt using tx hash.
   196  func ReadBorTxLookupEntry(db ethdb.Reader, txHash common.Hash) *uint64 {
   197  	data, _ := db.Get(borTxLookupKey(txHash))
   198  	if len(data) == 0 {
   199  		return nil
   200  	}
   201  
   202  	number := new(big.Int).SetBytes(data).Uint64()
   203  	return &number
   204  }
   205  
   206  // WriteBorTxLookupEntry stores a positional metadata for bor transaction using block hash and block number
   207  func WriteBorTxLookupEntry(db ethdb.KeyValueWriter, hash common.Hash, number uint64) {
   208  	txHash := types.GetDerivedBorTxHash(borReceiptKey(number, hash))
   209  	if err := db.Put(borTxLookupKey(txHash), big.NewInt(0).SetUint64(number).Bytes()); err != nil {
   210  		log.Crit("Failed to store bor transaction lookup entry", "err", err)
   211  	}
   212  }
   213  
   214  // DeleteBorTxLookupEntry removes bor transaction data associated with block hash and block number
   215  func DeleteBorTxLookupEntry(db ethdb.KeyValueWriter, hash common.Hash, number uint64) {
   216  	txHash := types.GetDerivedBorTxHash(borReceiptKey(number, hash))
   217  	DeleteBorTxLookupEntryByTxHash(db, txHash)
   218  }
   219  
   220  // DeleteBorTxLookupEntryByTxHash removes bor transaction data associated with a bor tx hash.
   221  func DeleteBorTxLookupEntryByTxHash(db ethdb.KeyValueWriter, txHash common.Hash) {
   222  	if err := db.Delete(borTxLookupKey(txHash)); err != nil {
   223  		log.Crit("Failed to delete bor transaction lookup entry", "err", err)
   224  	}
   225  }