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 }