github.com/MetalBlockchain/subnet-evm@v0.6.3/core/rawdb/accessors_indexes.go (about) 1 // (c) 2019-2020, Ava Labs, Inc. 2 // 3 // This file is a derived work, based on the go-ethereum library whose original 4 // notices appear below. 5 // 6 // It is distributed under a license compatible with the licensing terms of the 7 // original code from which it is derived. 8 // 9 // Much love to the original authors for their work. 10 // ********** 11 // Copyright 2018 The go-ethereum Authors 12 // This file is part of the go-ethereum library. 13 // 14 // The go-ethereum library is free software: you can redistribute it and/or modify 15 // it under the terms of the GNU Lesser General Public License as published by 16 // the Free Software Foundation, either version 3 of the License, or 17 // (at your option) any later version. 18 // 19 // The go-ethereum library is distributed in the hope that it will be useful, 20 // but WITHOUT ANY WARRANTY; without even the implied warranty of 21 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 // GNU Lesser General Public License for more details. 23 // 24 // You should have received a copy of the GNU Lesser General Public License 25 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 26 27 package rawdb 28 29 import ( 30 "bytes" 31 "math/big" 32 33 "github.com/MetalBlockchain/subnet-evm/core/types" 34 "github.com/MetalBlockchain/subnet-evm/params" 35 "github.com/ethereum/go-ethereum/common" 36 "github.com/ethereum/go-ethereum/ethdb" 37 "github.com/ethereum/go-ethereum/log" 38 "github.com/ethereum/go-ethereum/rlp" 39 ) 40 41 // ReadTxLookupEntry retrieves the positional metadata associated with a transaction 42 // hash to allow retrieving the transaction or receipt by hash. 43 func ReadTxLookupEntry(db ethdb.Reader, hash common.Hash) *uint64 { 44 data, _ := db.Get(txLookupKey(hash)) 45 if len(data) == 0 { 46 return nil 47 } 48 // Database v6 tx lookup just stores the block number 49 if len(data) < common.HashLength { 50 number := new(big.Int).SetBytes(data).Uint64() 51 return &number 52 } 53 // Database v4-v5 tx lookup format just stores the hash 54 if len(data) == common.HashLength { 55 return ReadHeaderNumber(db, common.BytesToHash(data)) 56 } 57 // Finally try database v3 tx lookup format 58 var entry LegacyTxLookupEntry 59 if err := rlp.DecodeBytes(data, &entry); err != nil { 60 log.Error("Invalid transaction lookup entry RLP", "hash", hash, "blob", data, "err", err) 61 return nil 62 } 63 return &entry.BlockIndex 64 } 65 66 // writeTxLookupEntry stores a positional metadata for a transaction, 67 // enabling hash based transaction and receipt lookups. 68 func writeTxLookupEntry(db ethdb.KeyValueWriter, hash common.Hash, numberBytes []byte) { 69 if err := db.Put(txLookupKey(hash), numberBytes); err != nil { 70 log.Crit("Failed to store transaction lookup entry", "err", err) 71 } 72 } 73 74 // WriteTxLookupEntries is identical to WriteTxLookupEntry, but it works on 75 // a list of hashes 76 func WriteTxLookupEntries(db ethdb.KeyValueWriter, number uint64, hashes []common.Hash) { 77 numberBytes := new(big.Int).SetUint64(number).Bytes() 78 for _, hash := range hashes { 79 writeTxLookupEntry(db, hash, numberBytes) 80 } 81 } 82 83 // WriteTxLookupEntriesByBlock stores a positional metadata for every transaction from 84 // a block, enabling hash based transaction and receipt lookups. 85 func WriteTxLookupEntriesByBlock(db ethdb.KeyValueWriter, block *types.Block) { 86 numberBytes := block.Number().Bytes() 87 for _, tx := range block.Transactions() { 88 writeTxLookupEntry(db, tx.Hash(), numberBytes) 89 } 90 } 91 92 // DeleteTxLookupEntry removes all transaction data associated with a hash. 93 func DeleteTxLookupEntry(db ethdb.KeyValueWriter, hash common.Hash) { 94 if err := db.Delete(txLookupKey(hash)); err != nil { 95 log.Crit("Failed to delete transaction lookup entry", "err", err) 96 } 97 } 98 99 // DeleteTxLookupEntries removes all transaction lookups for a given block. 100 func DeleteTxLookupEntries(db ethdb.KeyValueWriter, hashes []common.Hash) { 101 for _, hash := range hashes { 102 DeleteTxLookupEntry(db, hash) 103 } 104 } 105 106 // ReadTransaction retrieves a specific transaction from the database, along with 107 // its added positional metadata. 108 func ReadTransaction(db ethdb.Reader, hash common.Hash) (*types.Transaction, common.Hash, uint64, uint64) { 109 blockNumber := ReadTxLookupEntry(db, hash) 110 if blockNumber == nil { 111 return nil, common.Hash{}, 0, 0 112 } 113 blockHash := ReadCanonicalHash(db, *blockNumber) 114 if blockHash == (common.Hash{}) { 115 return nil, common.Hash{}, 0, 0 116 } 117 body := ReadBody(db, blockHash, *blockNumber) 118 if body == nil { 119 log.Error("Transaction referenced missing", "number", *blockNumber, "hash", blockHash) 120 return nil, common.Hash{}, 0, 0 121 } 122 for txIndex, tx := range body.Transactions { 123 if tx.Hash() == hash { 124 return tx, blockHash, *blockNumber, uint64(txIndex) 125 } 126 } 127 log.Error("Transaction not found", "number", *blockNumber, "hash", blockHash, "txhash", hash) 128 return nil, common.Hash{}, 0, 0 129 } 130 131 // ReadReceipt retrieves a specific transaction receipt from the database, along with 132 // its added positional metadata. 133 func ReadReceipt(db ethdb.Reader, hash common.Hash, config *params.ChainConfig) (*types.Receipt, common.Hash, uint64, uint64) { 134 // Retrieve the context of the receipt based on the transaction hash 135 blockNumber := ReadTxLookupEntry(db, hash) 136 if blockNumber == nil { 137 return nil, common.Hash{}, 0, 0 138 } 139 blockHash := ReadCanonicalHash(db, *blockNumber) 140 if blockHash == (common.Hash{}) { 141 return nil, common.Hash{}, 0, 0 142 } 143 blockHeader := ReadHeader(db, blockHash, *blockNumber) 144 if blockHeader == nil { 145 return nil, common.Hash{}, 0, 0 146 } 147 // Read all the receipts from the block and return the one with the matching hash 148 receipts := ReadReceipts(db, blockHash, *blockNumber, blockHeader.Time, config) 149 for receiptIndex, receipt := range receipts { 150 if receipt.TxHash == hash { 151 return receipt, blockHash, *blockNumber, uint64(receiptIndex) 152 } 153 } 154 log.Error("Receipt not found", "number", *blockNumber, "hash", blockHash, "txhash", hash) 155 return nil, common.Hash{}, 0, 0 156 } 157 158 // ReadBloomBits retrieves the compressed bloom bit vector belonging to the given 159 // section and bit index from the. 160 func ReadBloomBits(db ethdb.KeyValueReader, bit uint, section uint64, head common.Hash) ([]byte, error) { 161 return db.Get(bloomBitsKey(bit, section, head)) 162 } 163 164 // WriteBloomBits stores the compressed bloom bits vector belonging to the given 165 // section and bit index. 166 func WriteBloomBits(db ethdb.KeyValueWriter, bit uint, section uint64, head common.Hash, bits []byte) { 167 if err := db.Put(bloomBitsKey(bit, section, head), bits); err != nil { 168 log.Crit("Failed to store bloom bits", "err", err) 169 } 170 } 171 172 // DeleteBloombits removes all compressed bloom bits vector belonging to the 173 // given section range and bit index. 174 func DeleteBloombits(db ethdb.Database, bit uint, from uint64, to uint64) { 175 start, end := bloomBitsKey(bit, from, common.Hash{}), bloomBitsKey(bit, to, common.Hash{}) 176 it := db.NewIterator(nil, start) 177 defer it.Release() 178 179 for it.Next() { 180 if bytes.Compare(it.Key(), end) >= 0 { 181 break 182 } 183 if len(it.Key()) != len(bloomBitsPrefix)+2+8+32 { 184 continue 185 } 186 db.Delete(it.Key()) 187 } 188 if it.Error() != nil { 189 log.Crit("Failed to delete bloom bits", "err", it.Error()) 190 } 191 }