Skip to content

Commit

Permalink
indexers: flush utreexo state on prune
Browse files Browse the repository at this point in the history
For the utreexo state to be recoverable on unexpected crashes, there
must be blocks available for it to reindex on crashes. If there aren't,
the utreexo state is irrecoverable. To prevent this from happening, we
check what the last stored block on the disk is after a prune and flush
the utreexo state if the last flush happened before the last kept block.
  • Loading branch information
kcalvinalvin committed Aug 6, 2024
1 parent 46123ae commit a3b68d4
Show file tree
Hide file tree
Showing 8 changed files with 52 additions and 10 deletions.
2 changes: 1 addition & 1 deletion blockchain/indexers/addrindex.go
Original file line number Diff line number Diff line change
Expand Up @@ -816,7 +816,7 @@ func (idx *AddrIndex) DisconnectBlock(dbTx database.Tx, block *btcutil.Block,
// supported with pruning.
//
// This is part of the Indexer interface.
func (idx *AddrIndex) PruneBlock(dbTx database.Tx, blockHash *chainhash.Hash) error {
func (idx *AddrIndex) PruneBlock(_ database.Tx, _ *chainhash.Hash, _ int32) error {
return nil
}

Expand Down
2 changes: 1 addition & 1 deletion blockchain/indexers/cfindex.go
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@ func (idx *CfIndex) DisconnectBlock(dbTx database.Tx, block *btcutil.Block,
// reindexing as a pruned node.
//
// This is part of the Indexer interface.
func (idx *CfIndex) PruneBlock(dbTx database.Tx, blockHash *chainhash.Hash) error {
func (idx *CfIndex) PruneBlock(dbTx database.Tx, blockHash *chainhash.Hash, _ int32) error {
for _, key := range cfIndexKeys {
err := dbDeleteFilterIdxEntry(dbTx, key, blockHash)
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion blockchain/indexers/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ type Indexer interface {

// PruneBlock is invoked when an older block is deleted after it's been
// processed.
PruneBlock(database.Tx, *chainhash.Hash) error
PruneBlock(dbTx database.Tx, deletedBlock *chainhash.Hash, lastKeptHeight int32) error

// Flush flushes the index.
Flush(*chainhash.Hash, blockchain.FlushMode, bool) error
Expand Down
25 changes: 23 additions & 2 deletions blockchain/indexers/flatutreexoproofindex.go
Original file line number Diff line number Diff line change
Expand Up @@ -888,8 +888,29 @@ func (idx *FlatUtreexoProofIndex) DisconnectBlock(dbTx database.Tx, block *btcut
// processed.
//
// This is part of the Indexer interface.
func (idx *FlatUtreexoProofIndex) PruneBlock(dbTx database.Tx, blockHash *chainhash.Hash) error {
return nil
func (idx *FlatUtreexoProofIndex) PruneBlock(_ database.Tx, _ *chainhash.Hash, lastKeptHeight int32) error {
hash, _, err := dbFetchUtreexoStateConsistency(idx.utreexoState.utreexoStateDB)
if err != nil {
return err
}

// It's ok to call block by hash here as the utreexo state consistency hash is always
// included in the best chain.
lastFlushHeight, err := idx.chain.BlockHeightByHash(hash)
if err != nil {
return err
}

// If the last flushed utreexo state is the last or greater than the kept block,
// we can sync up to the tip so a flush is not required.
if lastKeptHeight <= lastFlushHeight {
return nil
}

// It's ok to fetch the best snapshot here as the block called on pruneblock has not
// been yet connected yet on the utreexo state. So this is indeed the correct hash.
bestHash := idx.chain.BestSnapshot().Hash
return idx.Flush(&bestHash, blockchain.FlushRequired, true)
}

// FetchUtreexoProof returns the Utreexo proof data for the given block height.
Expand Down
2 changes: 1 addition & 1 deletion blockchain/indexers/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -652,7 +652,7 @@ func (m *Manager) PruneBlocks(dbTx database.Tx, lastKeptHeight int32,
}

// Notify the indexer with the connected block so it can prune it.
err = index.PruneBlock(dbTx, blockHash)
err = index.PruneBlock(dbTx, blockHash, lastKeptHeight)
if err != nil {
return err
}
Expand Down
2 changes: 1 addition & 1 deletion blockchain/indexers/ttlindex.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ func (idx *TTLIndex) DisconnectBlock(dbTx database.Tx, block *btcutil.Block,
// supported with pruning.
//
// This is part of the Indexer interface.
func (idx *TTLIndex) PruneBlock(dbTx database.Tx, blockHash *chainhash.Hash) error {
func (idx *TTLIndex) PruneBlock(_ database.Tx, _ *chainhash.Hash, _ int32) error {
return nil
}

Expand Down
2 changes: 1 addition & 1 deletion blockchain/indexers/txindex.go
Original file line number Diff line number Diff line change
Expand Up @@ -437,7 +437,7 @@ func (idx *TxIndex) DisconnectBlock(dbTx database.Tx, block *btcutil.Block,
// supported with pruning.
//
// This is part of the Indexer interface.
func (idx *TxIndex) PruneBlock(dbTx database.Tx, blockHash *chainhash.Hash) error {
func (idx *TxIndex) PruneBlock(_ database.Tx, _ *chainhash.Hash, _ int32) error {
return nil
}

Expand Down
25 changes: 23 additions & 2 deletions blockchain/indexers/utreexoproofindex.go
Original file line number Diff line number Diff line change
Expand Up @@ -575,8 +575,29 @@ func (idx *UtreexoProofIndex) VerifyAccProof(toProve []utreexo.Hash,
// processed.
//
// This is part of the Indexer interface.
func (idx *UtreexoProofIndex) PruneBlock(dbTx database.Tx, blockHash *chainhash.Hash) error {
return nil
func (idx *UtreexoProofIndex) PruneBlock(_ database.Tx, _ *chainhash.Hash, lastKeptHeight int32) error {
hash, _, err := dbFetchUtreexoStateConsistency(idx.utreexoState.utreexoStateDB)
if err != nil {
return err
}

// It's ok to call block by hash here as the utreexo state consistency hash is always
// included in the best chain.
lastFlushHeight, err := idx.chain.BlockHeightByHash(hash)
if err != nil {
return err
}

// If the last flushed utreexo state is the last or greater than the kept block,
// we can sync up to the tip so a flush is not required.
if lastKeptHeight <= lastFlushHeight {
return nil
}

// It's ok to fetch the best snapshot here as the block called on pruneblock has not
// been yet connected yet on the utreexo state. So this is indeed the correct hash.
bestHash := idx.chain.BestSnapshot().Hash
return idx.Flush(&bestHash, blockchain.FlushRequired, true)
}

// NewUtreexoProofIndex returns a new instance of an indexer that is used to create a utreexo
Expand Down

0 comments on commit a3b68d4

Please sign in to comment.