diff --git a/.changelog/unreleased/bug-fixes/2264-fix-bp-tree-pruning.md b/.changelog/unreleased/bug-fixes/2264-fix-bp-tree-pruning.md new file mode 100644 index 0000000000..d309f1dbc2 --- /dev/null +++ b/.changelog/unreleased/bug-fixes/2264-fix-bp-tree-pruning.md @@ -0,0 +1,2 @@ +- Fix to skip pruning BridgePool Merkle trees when no signed nonce + ([\#2264](https://github.com/anoma/namada/issues/2264)) \ No newline at end of file diff --git a/apps/src/lib/node/ledger/storage/mod.rs b/apps/src/lib/node/ledger/storage/mod.rs index e17ff0db9a..4a02b2bcf9 100644 --- a/apps/src/lib/node/ledger/storage/mod.rs +++ b/apps/src/lib/node/ledger/storage/mod.rs @@ -591,11 +591,8 @@ mod tests { ); let new_epoch_start = BlockHeight(1); let signed_root_key = bridge_pool::get_signed_root_key(); + // the first nonce isn't written for a test skipping pruning let nonce = Uint::default(); - let root_proof = - BridgePoolRootProof::new((KeccakHash::default(), nonce)); - let bytes = types::encode(&root_proof); - storage.write(&signed_root_key, bytes).unwrap(); storage .begin_block(BlockHash::default(), new_epoch_start) @@ -622,11 +619,8 @@ mod tests { .write(&key, types::encode(&value)) .expect("write failed"); + // the second nonce isn't written for a test skipping pruning let nonce = nonce + 1; - let root_proof = - BridgePoolRootProof::new((KeccakHash::default(), nonce)); - let bytes = types::encode(&root_proof); - storage.write(&signed_root_key, bytes).unwrap(); storage.block.epoch = storage.block.epoch.next(); storage.block.pred_epochs.new_epoch(new_epoch_start); diff --git a/apps/src/lib/node/ledger/storage/rocksdb.rs b/apps/src/lib/node/ledger/storage/rocksdb.rs index a1a26b272f..7b2df4dc40 100644 --- a/apps/src/lib/node/ledger/storage/rocksdb.rs +++ b/apps/src/lib/node/ledger/storage/rocksdb.rs @@ -1453,17 +1453,21 @@ impl DB for RocksDB { &self, height: BlockHeight, last_height: BlockHeight, - ) -> Result { + ) -> Result> { let nonce_key = bridge_pool::get_signed_root_key(); let bytes = if height == BlockHeight(0) || height >= last_height { self.read_subspace_val(&nonce_key)? } else { self.read_subspace_val_with_height(&nonce_key, height, last_height)? }; - let bytes = bytes.expect("Signed root should exist"); - let bp_root_proof = BridgePoolRootProof::try_from_slice(&bytes) - .map_err(Error::BorshCodingError)?; - Ok(bp_root_proof.data.1) + match bytes { + Some(bytes) => { + let bp_root_proof = BridgePoolRootProof::try_from_slice(&bytes) + .map_err(Error::BorshCodingError)?; + Ok(Some(bp_root_proof.data.1)) + } + None => Ok(None), + } } fn write_replay_protection_entry( diff --git a/core/src/ledger/storage/mockdb.rs b/core/src/ledger/storage/mockdb.rs index a60c6ccd2e..94d949fa51 100644 --- a/core/src/ledger/storage/mockdb.rs +++ b/core/src/ledger/storage/mockdb.rs @@ -593,8 +593,8 @@ impl DB for MockDB { &self, _height: BlockHeight, _last_height: BlockHeight, - ) -> Result { - Ok(Uint::default()) + ) -> Result> { + Ok(None) } fn write_replay_protection_entry( diff --git a/core/src/ledger/storage/mod.rs b/core/src/ledger/storage/mod.rs index e40cbcc017..6a51b207a8 100644 --- a/core/src/ledger/storage/mod.rs +++ b/core/src/ledger/storage/mod.rs @@ -363,7 +363,7 @@ pub trait DB: std::fmt::Debug { &self, height: BlockHeight, last_height: BlockHeight, - ) -> Result; + ) -> Result>; /// Write a replay protection entry fn write_replay_protection_entry( @@ -1178,7 +1178,10 @@ where } // Prune the BridgePool subtree stores with invalid nonce - let mut epoch = self.get_oldest_epoch_with_valid_nonce()?; + let mut epoch = match self.get_oldest_epoch_with_valid_nonce()? { + Some(epoch) => epoch, + None => return Ok(()), + }; while oldest_epoch < epoch { epoch = epoch.prev(); self.db.prune_merkle_tree_store( @@ -1216,11 +1219,15 @@ where } /// Get oldest epoch which has the valid signed nonce of the bridge pool - pub fn get_oldest_epoch_with_valid_nonce(&self) -> Result { + fn get_oldest_epoch_with_valid_nonce(&self) -> Result> { let last_height = self.get_last_block_height(); - let current_nonce = self + let current_nonce = match self .db - .read_bridge_pool_signed_nonce(last_height, last_height)?; + .read_bridge_pool_signed_nonce(last_height, last_height)? + { + Some(nonce) => nonce, + None => return Ok(None), + }; let (mut epoch, _) = self.get_last_epoch(); // We don't need to check the older epochs because their Merkle tree // snapshots have been already removed @@ -1235,13 +1242,19 @@ where Some(h) => h, None => continue, }; - let nonce = - self.db.read_bridge_pool_signed_nonce(height, last_height)?; + let nonce = match self + .db + .read_bridge_pool_signed_nonce(height, last_height)? + { + Some(nonce) => nonce, + // skip pruning when the old epoch doesn't have the signed nonce + None => break, + }; if nonce < current_nonce { break; } } - Ok(epoch) + Ok(Some(epoch)) } /// Check it the given transaction's hash is already present in storage