github.com/ethereum/go-ethereum@v1.16.1/core/rawdb/accessors_indexes.go (about) 1 // Copyright 2018 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum 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 go-ethereum 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 go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package rawdb 18 19 import ( 20 "bytes" 21 "encoding/binary" 22 "errors" 23 "fmt" 24 "math/big" 25 26 "github.com/ethereum/go-ethereum/common" 27 "github.com/ethereum/go-ethereum/core/types" 28 "github.com/ethereum/go-ethereum/crypto" 29 "github.com/ethereum/go-ethereum/ethdb" 30 "github.com/ethereum/go-ethereum/log" 31 "github.com/ethereum/go-ethereum/params" 32 "github.com/ethereum/go-ethereum/rlp" 33 ) 34 35 // DecodeTxLookupEntry decodes the supplied tx lookup data. 36 func DecodeTxLookupEntry(data []byte, db ethdb.Reader) *uint64 { 37 // Database v6 tx lookup just stores the block number 38 if len(data) < common.HashLength { 39 number := new(big.Int).SetBytes(data).Uint64() 40 return &number 41 } 42 // Database v4-v5 tx lookup format just stores the hash 43 if len(data) == common.HashLength { 44 return ReadHeaderNumber(db, common.BytesToHash(data)) 45 } 46 // Finally try database v3 tx lookup format 47 var entry LegacyTxLookupEntry 48 if err := rlp.DecodeBytes(data, &entry); err != nil { 49 log.Error("Invalid transaction lookup entry RLP", "blob", data, "err", err) 50 return nil 51 } 52 return &entry.BlockIndex 53 } 54 55 // ReadTxLookupEntry retrieves the positional metadata associated with a transaction 56 // hash to allow retrieving the transaction or receipt by hash. 57 func ReadTxLookupEntry(db ethdb.Reader, hash common.Hash) *uint64 { 58 data, _ := db.Get(txLookupKey(hash)) 59 if len(data) == 0 { 60 return nil 61 } 62 return DecodeTxLookupEntry(data, db) 63 } 64 65 // writeTxLookupEntry stores a positional metadata for a transaction, 66 // enabling hash based transaction and receipt lookups. 67 func writeTxLookupEntry(db ethdb.KeyValueWriter, hash common.Hash, numberBytes []byte) { 68 if err := db.Put(txLookupKey(hash), numberBytes); err != nil { 69 log.Crit("Failed to store transaction lookup entry", "err", err) 70 } 71 } 72 73 // WriteTxLookupEntries is identical to WriteTxLookupEntry, but it works on 74 // a list of hashes 75 func WriteTxLookupEntries(db ethdb.KeyValueWriter, number uint64, hashes []common.Hash) { 76 numberBytes := new(big.Int).SetUint64(number).Bytes() 77 for _, hash := range hashes { 78 writeTxLookupEntry(db, hash, numberBytes) 79 } 80 } 81 82 // WriteTxLookupEntriesByBlock stores a positional metadata for every transaction from 83 // a block, enabling hash based transaction and receipt lookups. 84 func WriteTxLookupEntriesByBlock(db ethdb.KeyValueWriter, block *types.Block) { 85 numberBytes := block.Number().Bytes() 86 for _, tx := range block.Transactions() { 87 writeTxLookupEntry(db, tx.Hash(), numberBytes) 88 } 89 } 90 91 // DeleteTxLookupEntry removes all transaction data associated with a hash. 92 func DeleteTxLookupEntry(db ethdb.KeyValueWriter, hash common.Hash) { 93 if err := db.Delete(txLookupKey(hash)); err != nil { 94 log.Crit("Failed to delete transaction lookup entry", "err", err) 95 } 96 } 97 98 // DeleteTxLookupEntries removes all transaction lookups for a given block. 99 func DeleteTxLookupEntries(db ethdb.KeyValueWriter, hashes []common.Hash) { 100 for _, hash := range hashes { 101 DeleteTxLookupEntry(db, hash) 102 } 103 } 104 105 // DeleteAllTxLookupEntries purges all the transaction indexes in the database. 106 // If condition is specified, only the entry with condition as True will be 107 // removed; If condition is not specified, the entry is deleted. 108 func DeleteAllTxLookupEntries(db ethdb.KeyValueStore, condition func(common.Hash, []byte) bool) { 109 iter := NewKeyLengthIterator(db.NewIterator(txLookupPrefix, nil), common.HashLength+len(txLookupPrefix)) 110 defer iter.Release() 111 112 batch := db.NewBatch() 113 for iter.Next() { 114 txhash := common.Hash(iter.Key()[1:]) 115 if condition == nil || condition(txhash, iter.Value()) { 116 batch.Delete(iter.Key()) 117 } 118 if batch.ValueSize() >= ethdb.IdealBatchSize { 119 if err := batch.Write(); err != nil { 120 log.Crit("Failed to delete transaction lookup entries", "err", err) 121 } 122 batch.Reset() 123 } 124 } 125 if batch.ValueSize() > 0 { 126 if err := batch.Write(); err != nil { 127 log.Crit("Failed to delete transaction lookup entries", "err", err) 128 } 129 batch.Reset() 130 } 131 } 132 133 // findTxInBlockBody traverses the given RLP-encoded block body, searching for 134 // the transaction specified by its hash. 135 func findTxInBlockBody(blockbody rlp.RawValue, target common.Hash) (*types.Transaction, uint64, error) { 136 txnListRLP, _, err := rlp.SplitList(blockbody) 137 if err != nil { 138 return nil, 0, err 139 } 140 iter, err := rlp.NewListIterator(txnListRLP) 141 if err != nil { 142 return nil, 0, err 143 } 144 txIndex := uint64(0) 145 for iter.Next() { 146 if iter.Err() != nil { 147 return nil, 0, err 148 } 149 // The preimage for the hash calculation of legacy transactions 150 // is just their RLP encoding. For typed (EIP-2718) transactions, 151 // which are encoded as byte arrays, the preimage is the content of 152 // the byte array, so trim their prefix here. 153 txRLP := iter.Value() 154 kind, txHashPayload, _, err := rlp.Split(txRLP) 155 if err != nil { 156 return nil, 0, err 157 } 158 if kind == rlp.List { // Legacy transaction 159 txHashPayload = txRLP 160 } 161 if crypto.Keccak256Hash(txHashPayload) == target { 162 var tx types.Transaction 163 if err := rlp.DecodeBytes(txRLP, &tx); err != nil { 164 return nil, 0, err 165 } 166 return &tx, txIndex, nil 167 } 168 txIndex++ 169 } 170 return nil, 0, errors.New("transaction not found") 171 } 172 173 // ReadCanonicalTransaction retrieves a specific transaction from the database, along 174 // with its added positional metadata. Notably, only the transaction in the canonical 175 // chain is visible. 176 func ReadCanonicalTransaction(db ethdb.Reader, hash common.Hash) (*types.Transaction, common.Hash, uint64, uint64) { 177 blockNumber := ReadTxLookupEntry(db, hash) 178 if blockNumber == nil { 179 return nil, common.Hash{}, 0, 0 180 } 181 blockHash := ReadCanonicalHash(db, *blockNumber) 182 if blockHash == (common.Hash{}) { 183 return nil, common.Hash{}, 0, 0 184 } 185 bodyRLP := ReadCanonicalBodyRLP(db, *blockNumber, &blockHash) 186 if bodyRLP == nil { 187 log.Error("Transaction referenced missing", "number", *blockNumber, "hash", blockHash) 188 return nil, common.Hash{}, 0, 0 189 } 190 tx, txIndex, err := findTxInBlockBody(bodyRLP, hash) 191 if err != nil { 192 log.Error("Transaction not found", "number", *blockNumber, "hash", blockHash, "txhash", hash, "err", err) 193 return nil, common.Hash{}, 0, 0 194 } 195 return tx, blockHash, *blockNumber, txIndex 196 } 197 198 // ReadCanonicalReceipt retrieves a specific transaction receipt from the database, 199 // along with its added positional metadata. Notably, only the receipt in the canonical 200 // chain is visible. 201 func ReadCanonicalReceipt(db ethdb.Reader, hash common.Hash, config *params.ChainConfig) (*types.Receipt, common.Hash, uint64, uint64) { 202 // Retrieve the context of the receipt based on the transaction hash 203 blockNumber := ReadTxLookupEntry(db, hash) 204 if blockNumber == nil { 205 return nil, common.Hash{}, 0, 0 206 } 207 blockHash := ReadCanonicalHash(db, *blockNumber) 208 if blockHash == (common.Hash{}) { 209 return nil, common.Hash{}, 0, 0 210 } 211 blockHeader := ReadHeader(db, blockHash, *blockNumber) 212 if blockHeader == nil { 213 return nil, common.Hash{}, 0, 0 214 } 215 // Read all the receipts from the block and return the one with the matching hash 216 receipts := ReadReceipts(db, blockHash, *blockNumber, blockHeader.Time, config) 217 for receiptIndex, receipt := range receipts { 218 if receipt.TxHash == hash { 219 return receipt, blockHash, *blockNumber, uint64(receiptIndex) 220 } 221 } 222 log.Error("Receipt not found", "number", *blockNumber, "hash", blockHash, "txhash", hash) 223 return nil, common.Hash{}, 0, 0 224 } 225 226 // extractReceiptFields takes a raw RLP-encoded receipt blob and extracts 227 // specific fields from it. 228 func extractReceiptFields(receiptRLP rlp.RawValue) (uint64, uint, error) { 229 receiptList, _, err := rlp.SplitList(receiptRLP) 230 if err != nil { 231 return 0, 0, err 232 } 233 // Decode the field: receipt status 234 // for receipt before the byzantium fork: 235 // - bytes: post state root 236 // for receipt after the byzantium fork: 237 // - bytes: receipt status flag 238 _, _, rest, err := rlp.Split(receiptList) 239 if err != nil { 240 return 0, 0, err 241 } 242 // Decode the field: cumulative gas used (type: uint64) 243 gasUsed, rest, err := rlp.SplitUint64(rest) 244 if err != nil { 245 return 0, 0, err 246 } 247 // Decode the field: logs (type: rlp list) 248 logList, _, err := rlp.SplitList(rest) 249 if err != nil { 250 return 0, 0, err 251 } 252 logCount, err := rlp.CountValues(logList) 253 if err != nil { 254 return 0, 0, err 255 } 256 return gasUsed, uint(logCount), nil 257 } 258 259 // RawReceiptContext carries the contextual information that is needed to derive 260 // a complete receipt from a raw one. 261 type RawReceiptContext struct { 262 GasUsed uint64 // Amount of gas used by the associated transaction 263 LogIndex uint // Starting index of the logs within the block 264 } 265 266 // ReadCanonicalRawReceipt reads a raw receipt at the specified position. It also 267 // returns the gas used by the associated transaction and the starting index of 268 // the logs within the block. The main difference with ReadCanonicalReceipt is 269 // that the additional positional fields are not directly included in the receipt. 270 // Notably, only receipts from the canonical chain are visible. 271 func ReadCanonicalRawReceipt(db ethdb.Reader, blockHash common.Hash, blockNumber, txIndex uint64) (*types.Receipt, RawReceiptContext, error) { 272 receiptIt, err := rlp.NewListIterator(ReadCanonicalReceiptsRLP(db, blockNumber, &blockHash)) 273 if err != nil { 274 return nil, RawReceiptContext{}, err 275 } 276 var ( 277 cumulativeGasUsed uint64 278 logIndex uint 279 ) 280 for i := uint64(0); i <= txIndex; i++ { 281 // Unexpected iteration error 282 if receiptIt.Err() != nil { 283 return nil, RawReceiptContext{}, receiptIt.Err() 284 } 285 // Unexpected end of iteration 286 if !receiptIt.Next() { 287 return nil, RawReceiptContext{}, fmt.Errorf("receipt not found, %d, %x, %d", blockNumber, blockHash, txIndex) 288 } 289 if i == txIndex { 290 var stored types.ReceiptForStorage 291 if err := rlp.DecodeBytes(receiptIt.Value(), &stored); err != nil { 292 return nil, RawReceiptContext{}, err 293 } 294 return (*types.Receipt)(&stored), RawReceiptContext{ 295 GasUsed: stored.CumulativeGasUsed - cumulativeGasUsed, 296 LogIndex: logIndex, 297 }, nil 298 } else { 299 gas, logs, err := extractReceiptFields(receiptIt.Value()) 300 if err != nil { 301 return nil, RawReceiptContext{}, err 302 } 303 cumulativeGasUsed = gas 304 logIndex += logs 305 } 306 } 307 return nil, RawReceiptContext{}, fmt.Errorf("receipt not found, %d, %x, %d", blockNumber, blockHash, txIndex) 308 } 309 310 // ReadFilterMapExtRow retrieves a filter map row at the given mapRowIndex 311 // (see filtermaps.mapRowIndex for the storage index encoding). 312 // Note that zero length rows are not stored in the database and therefore all 313 // non-existent entries are interpreted as empty rows and return no error. 314 // Also note that the mapRowIndex indexing scheme is the same as the one 315 // proposed in EIP-7745 for tree-hashing the filter map structure and for the 316 // same data proximity reasons it is also suitable for database representation. 317 // See also: 318 // https://eips.ethereum.org/EIPS/eip-7745#hash-tree-structure 319 func ReadFilterMapExtRow(db ethdb.KeyValueReader, mapRowIndex uint64, bitLength uint) ([]uint32, error) { 320 byteLength := int(bitLength) / 8 321 if int(bitLength) != byteLength*8 { 322 panic("invalid bit length") 323 } 324 key := filterMapRowKey(mapRowIndex, false) 325 has, err := db.Has(key) 326 if err != nil { 327 return nil, err 328 } 329 if !has { 330 return nil, nil 331 } 332 encRow, err := db.Get(key) 333 if err != nil { 334 return nil, err 335 } 336 if len(encRow)%byteLength != 0 { 337 return nil, errors.New("invalid encoded extended filter row length") 338 } 339 row := make([]uint32, len(encRow)/byteLength) 340 var b [4]byte 341 for i := range row { 342 copy(b[:byteLength], encRow[i*byteLength:(i+1)*byteLength]) 343 row[i] = binary.LittleEndian.Uint32(b[:]) 344 } 345 return row, nil 346 } 347 348 func ReadFilterMapBaseRows(db ethdb.KeyValueReader, mapRowIndex uint64, rowCount uint32, bitLength uint) ([][]uint32, error) { 349 byteLength := int(bitLength) / 8 350 if int(bitLength) != byteLength*8 { 351 panic("invalid bit length") 352 } 353 key := filterMapRowKey(mapRowIndex, true) 354 has, err := db.Has(key) 355 if err != nil { 356 return nil, err 357 } 358 rows := make([][]uint32, rowCount) 359 if !has { 360 return rows, nil 361 } 362 encRows, err := db.Get(key) 363 if err != nil { 364 return nil, err 365 } 366 encLen := len(encRows) 367 var ( 368 entryCount, entriesInRow, rowIndex, headerLen, headerBits int 369 headerByte byte 370 ) 371 for headerLen+byteLength*entryCount < encLen { 372 if headerBits == 0 { 373 headerByte = encRows[headerLen] 374 headerLen++ 375 headerBits = 8 376 } 377 if headerByte&1 > 0 { 378 entriesInRow++ 379 entryCount++ 380 } else { 381 if entriesInRow > 0 { 382 rows[rowIndex] = make([]uint32, entriesInRow) 383 entriesInRow = 0 384 } 385 rowIndex++ 386 } 387 headerByte >>= 1 388 headerBits-- 389 } 390 if headerLen+byteLength*entryCount > encLen { 391 return nil, errors.New("invalid encoded base filter rows length") 392 } 393 if entriesInRow > 0 { 394 rows[rowIndex] = make([]uint32, entriesInRow) 395 } 396 nextEntry := headerLen 397 for _, row := range rows { 398 for i := range row { 399 var b [4]byte 400 copy(b[:byteLength], encRows[nextEntry:nextEntry+byteLength]) 401 row[i] = binary.LittleEndian.Uint32(b[:]) 402 nextEntry += byteLength 403 } 404 } 405 return rows, nil 406 } 407 408 // WriteFilterMapExtRow stores an extended filter map row at the given mapRowIndex 409 // or deletes any existing entry if the row is empty. 410 func WriteFilterMapExtRow(db ethdb.KeyValueWriter, mapRowIndex uint64, row []uint32, bitLength uint) { 411 byteLength := int(bitLength) / 8 412 if int(bitLength) != byteLength*8 { 413 panic("invalid bit length") 414 } 415 var err error 416 if len(row) > 0 { 417 encRow := make([]byte, len(row)*byteLength) 418 for i, c := range row { 419 var b [4]byte 420 binary.LittleEndian.PutUint32(b[:], c) 421 copy(encRow[i*byteLength:(i+1)*byteLength], b[:byteLength]) 422 } 423 err = db.Put(filterMapRowKey(mapRowIndex, false), encRow) 424 } else { 425 err = db.Delete(filterMapRowKey(mapRowIndex, false)) 426 } 427 if err != nil { 428 log.Crit("Failed to store extended filter map row", "err", err) 429 } 430 } 431 432 func WriteFilterMapBaseRows(db ethdb.KeyValueWriter, mapRowIndex uint64, rows [][]uint32, bitLength uint) { 433 byteLength := int(bitLength) / 8 434 if int(bitLength) != byteLength*8 { 435 panic("invalid bit length") 436 } 437 var entryCount, zeroBits int 438 for i, row := range rows { 439 if len(row) > 0 { 440 entryCount += len(row) 441 zeroBits = i 442 } 443 } 444 var err error 445 if entryCount > 0 { 446 headerLen := (zeroBits + entryCount + 7) / 8 447 encRows := make([]byte, headerLen+entryCount*byteLength) 448 nextEntry := headerLen 449 450 headerPtr, headerByte := 0, byte(1) 451 addHeaderBit := func(bit bool) { 452 if bit { 453 encRows[headerPtr] += headerByte 454 } 455 if headerByte += headerByte; headerByte == 0 { 456 headerPtr++ 457 headerByte = 1 458 } 459 } 460 461 for _, row := range rows { 462 for _, entry := range row { 463 var b [4]byte 464 binary.LittleEndian.PutUint32(b[:], entry) 465 copy(encRows[nextEntry:nextEntry+byteLength], b[:byteLength]) 466 nextEntry += byteLength 467 addHeaderBit(true) 468 } 469 if zeroBits == 0 { 470 break 471 } 472 addHeaderBit(false) 473 zeroBits-- 474 } 475 err = db.Put(filterMapRowKey(mapRowIndex, true), encRows) 476 } else { 477 err = db.Delete(filterMapRowKey(mapRowIndex, true)) 478 } 479 if err != nil { 480 log.Crit("Failed to store base filter map rows", "err", err) 481 } 482 } 483 484 func DeleteFilterMapRows(db ethdb.KeyValueStore, mapRows common.Range[uint64], hashScheme bool, stopCallback func(bool) bool) error { 485 return SafeDeleteRange(db, filterMapRowKey(mapRows.First(), false), filterMapRowKey(mapRows.AfterLast(), false), hashScheme, stopCallback) 486 } 487 488 // ReadFilterMapLastBlock retrieves the number of the block that generated the 489 // last log value entry of the given map. 490 func ReadFilterMapLastBlock(db ethdb.KeyValueReader, mapIndex uint32) (uint64, common.Hash, error) { 491 enc, err := db.Get(filterMapLastBlockKey(mapIndex)) 492 if err != nil { 493 return 0, common.Hash{}, err 494 } 495 if len(enc) != 40 { 496 return 0, common.Hash{}, errors.New("invalid block number and id encoding") 497 } 498 var id common.Hash 499 copy(id[:], enc[8:]) 500 return binary.BigEndian.Uint64(enc[:8]), id, nil 501 } 502 503 // WriteFilterMapLastBlock stores the number of the block that generated the 504 // last log value entry of the given map. 505 func WriteFilterMapLastBlock(db ethdb.KeyValueWriter, mapIndex uint32, blockNumber uint64, id common.Hash) { 506 var enc [40]byte 507 binary.BigEndian.PutUint64(enc[:8], blockNumber) 508 copy(enc[8:], id[:]) 509 if err := db.Put(filterMapLastBlockKey(mapIndex), enc[:]); err != nil { 510 log.Crit("Failed to store filter map last block pointer", "err", err) 511 } 512 } 513 514 // DeleteFilterMapLastBlock deletes the number of the block that generated the 515 // last log value entry of the given map. 516 func DeleteFilterMapLastBlock(db ethdb.KeyValueWriter, mapIndex uint32) { 517 if err := db.Delete(filterMapLastBlockKey(mapIndex)); err != nil { 518 log.Crit("Failed to delete filter map last block pointer", "err", err) 519 } 520 } 521 522 func DeleteFilterMapLastBlocks(db ethdb.KeyValueStore, maps common.Range[uint32], hashScheme bool, stopCallback func(bool) bool) error { 523 return SafeDeleteRange(db, filterMapLastBlockKey(maps.First()), filterMapLastBlockKey(maps.AfterLast()), hashScheme, stopCallback) 524 } 525 526 // ReadBlockLvPointer retrieves the starting log value index where the log values 527 // generated by the given block are located. 528 func ReadBlockLvPointer(db ethdb.KeyValueReader, blockNumber uint64) (uint64, error) { 529 encPtr, err := db.Get(filterMapBlockLVKey(blockNumber)) 530 if err != nil { 531 return 0, err 532 } 533 if len(encPtr) != 8 { 534 return 0, errors.New("invalid log value pointer encoding") 535 } 536 return binary.BigEndian.Uint64(encPtr), nil 537 } 538 539 // WriteBlockLvPointer stores the starting log value index where the log values 540 // generated by the given block are located. 541 func WriteBlockLvPointer(db ethdb.KeyValueWriter, blockNumber, lvPointer uint64) { 542 var encPtr [8]byte 543 binary.BigEndian.PutUint64(encPtr[:], lvPointer) 544 if err := db.Put(filterMapBlockLVKey(blockNumber), encPtr[:]); err != nil { 545 log.Crit("Failed to store block log value pointer", "err", err) 546 } 547 } 548 549 // DeleteBlockLvPointer deletes the starting log value index where the log values 550 // generated by the given block are located. 551 func DeleteBlockLvPointer(db ethdb.KeyValueWriter, blockNumber uint64) { 552 if err := db.Delete(filterMapBlockLVKey(blockNumber)); err != nil { 553 log.Crit("Failed to delete block log value pointer", "err", err) 554 } 555 } 556 557 func DeleteBlockLvPointers(db ethdb.KeyValueStore, blocks common.Range[uint64], hashScheme bool, stopCallback func(bool) bool) error { 558 return SafeDeleteRange(db, filterMapBlockLVKey(blocks.First()), filterMapBlockLVKey(blocks.AfterLast()), hashScheme, stopCallback) 559 } 560 561 // FilterMapsRange is a storage representation of the block range covered by the 562 // filter maps structure and the corresponting log value index range. 563 type FilterMapsRange struct { 564 Version uint32 565 HeadIndexed bool 566 HeadDelimiter uint64 567 BlocksFirst, BlocksAfterLast uint64 568 MapsFirst, MapsAfterLast uint32 569 TailPartialEpoch uint32 570 } 571 572 // ReadFilterMapsRange retrieves the filter maps range data. Note that if the 573 // database entry is not present, that is interpreted as a valid non-initialized 574 // state and returns a blank range structure and no error. 575 func ReadFilterMapsRange(db ethdb.KeyValueReader) (FilterMapsRange, bool, error) { 576 if has, err := db.Has(filterMapsRangeKey); err != nil || !has { 577 return FilterMapsRange{}, false, err 578 } 579 encRange, err := db.Get(filterMapsRangeKey) 580 if err != nil { 581 return FilterMapsRange{}, false, err 582 } 583 var fmRange FilterMapsRange 584 if err := rlp.DecodeBytes(encRange, &fmRange); err != nil { 585 return FilterMapsRange{}, false, err 586 } 587 588 return fmRange, true, nil 589 } 590 591 // WriteFilterMapsRange stores the filter maps range data. 592 func WriteFilterMapsRange(db ethdb.KeyValueWriter, fmRange FilterMapsRange) { 593 encRange, err := rlp.EncodeToBytes(&fmRange) 594 if err != nil { 595 log.Crit("Failed to encode filter maps range", "err", err) 596 } 597 if err := db.Put(filterMapsRangeKey, encRange); err != nil { 598 log.Crit("Failed to store filter maps range", "err", err) 599 } 600 } 601 602 // DeleteFilterMapsRange deletes the filter maps range data which is interpreted 603 // as reverting to the un-initialized state. 604 func DeleteFilterMapsRange(db ethdb.KeyValueWriter) { 605 if err := db.Delete(filterMapsRangeKey); err != nil { 606 log.Crit("Failed to delete filter maps range", "err", err) 607 } 608 } 609 610 // deletePrefixRange deletes everything with the given prefix from the database. 611 func deletePrefixRange(db ethdb.KeyValueStore, prefix []byte, hashScheme bool, stopCallback func(bool) bool) error { 612 end := bytes.Clone(prefix) 613 end[len(end)-1]++ 614 return SafeDeleteRange(db, prefix, end, hashScheme, stopCallback) 615 } 616 617 // DeleteFilterMapsDb removes the entire filter maps database 618 func DeleteFilterMapsDb(db ethdb.KeyValueStore, hashScheme bool, stopCallback func(bool) bool) error { 619 return deletePrefixRange(db, []byte(filterMapsPrefix), hashScheme, stopCallback) 620 } 621 622 // DeleteBloomBitsDb removes the old bloombits database and the associated 623 // chain indexer database. 624 func DeleteBloomBitsDb(db ethdb.KeyValueStore, hashScheme bool, stopCallback func(bool) bool) error { 625 if err := deletePrefixRange(db, bloomBitsPrefix, hashScheme, stopCallback); err != nil { 626 return err 627 } 628 return deletePrefixRange(db, bloomBitsMetaPrefix, hashScheme, stopCallback) 629 }