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