Skip to content

Commit 03e5ca4

Browse files
authored
Prevent pruning potentially unfinalized mmr nodes (#191)
1 parent 3a5dc4d commit 03e5ca4

File tree

4 files changed

+34
-11
lines changed

4 files changed

+34
-11
lines changed

modules/trees/mmr/gadget/src/lib.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,8 @@ where
128128

129129
// We need to make sure all blocks leading up to current notification
130130
// have also been canonicalized.
131-
offchain_mmr.canonicalize_catch_up(&notification);
131+
let first = notification.tree_route.first().unwrap_or(&notification.hash);
132+
offchain_mmr.canonicalize_catch_up(*first);
132133
// We have to canonicalize and prune the blocks in the finality
133134
// notification that lead to building the offchain-mmr as well.
134135
offchain_mmr.canonicalize_and_prune(notification);

modules/trees/mmr/gadget/src/offchain_mmr.rs

+29-8
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
#![warn(missing_docs)]
2323

2424
use crate::{aux_schema, HashFor, MmrClient, LOG_TARGET};
25-
use log::{debug, error, info, warn};
25+
use log::{debug, error, info, trace, warn};
2626
use pallet_ismp::mmr::Leaf;
2727
use pallet_mmr_runtime_api::MmrRuntimeApi;
2828
use sc_client_api::{Backend, FinalityNotification};
@@ -168,9 +168,15 @@ where
168168
);
169169

170170
for pos in stale_nodes {
171-
let temp_key = self.node_temp_offchain_key(pos, fork_identifier);
172-
self.offchain_db.local_storage_clear(StorageKind::PERSISTENT, &temp_key);
173-
debug!(target: LOG_TARGET, "Pruned elem at pos {} fork_identifier {:?} header_hash {:?}", pos, fork_identifier, block_hash);
171+
// Only prune nodes that have been moved to the canonical path to prevent deleting nodes
172+
// from forks that share the same child trie root before they are finalized.
173+
let canon_key = self.node_canon_offchain_key(pos);
174+
if let Some(_) = self.offchain_db.local_storage_get(StorageKind::PERSISTENT, &canon_key)
175+
{
176+
let temp_key = self.node_temp_offchain_key(pos, fork_identifier);
177+
self.offchain_db.local_storage_clear(StorageKind::PERSISTENT, &temp_key);
178+
debug!(target: LOG_TARGET, "Pruned elem at pos {} fork_identifier {:?} header_hash {:?}", pos, fork_identifier, block_hash);
179+
}
174180
}
175181
}
176182

@@ -252,15 +258,16 @@ where
252258
self.best_canonicalized,
253259
header.number,
254260
);
261+
// If a block has been skipped canonicalize all blocks in between
262+
self.canonicalize_catch_up(header.parent);
255263
}
256264
self.best_canonicalized = header.number;
257265
}
258266

259267
/// In case of missed finality notifications (node restarts for example),
260268
/// make sure to also canon everything leading up to `notification.tree_route`.
261-
pub fn canonicalize_catch_up(&mut self, notification: &FinalityNotification<B>) {
262-
let first = notification.tree_route.first().unwrap_or(&notification.hash);
263-
if let Some(mut header) = self.header_metadata_or_log(*first, "canonicalize") {
269+
pub fn canonicalize_catch_up(&mut self, first: HashFor<B>) {
270+
if let Some(mut header) = self.header_metadata_or_log(first, "canonicalize") {
264271
let mut to_canon = VecDeque::<<B as Block>::Hash>::new();
265272
// Walk up the chain adding all blocks newer than `self.best_canonicalized`.
266273
loop {
@@ -304,8 +311,22 @@ where
304311
// Update the first MMR block in case of a pallet reset.
305312
self.handle_potential_pallet_reset(&notification);
306313

307-
// Move offchain MMR nodes for finalized blocks to canonical keys.
314+
// // Run catchup to just to be sure no blocks are skipped
315+
// self.canonicalize_catch_up(&notification);
308316

317+
trace!(target: LOG_TARGET, "Got new finality notification {:?}, Best Canonicalized {:?}", notification.hash, self.best_canonicalized);
318+
let mut block_nums = vec![];
319+
for hash in notification.tree_route.iter().chain(std::iter::once(&notification.hash)) {
320+
match self.header_metadata_or_log(*hash, "canonicalize") {
321+
Some(header) => {
322+
block_nums.push(header.number);
323+
},
324+
_ => {},
325+
};
326+
}
327+
328+
trace!(target: LOG_TARGET, "Canonicalizing Blocks{block_nums:?}");
329+
// Move offchain MMR nodes for finalized blocks to canonical keys.
309330
for hash in notification.tree_route.iter().chain(std::iter::once(&notification.hash)) {
310331
self.canonicalize_branch(*hash);
311332
}

parachain/chainspec/gargantua.paseo.json

+2-1
Large diffs are not rendered by default.

parachain/runtimes/gargantua/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
214214
spec_name: create_runtime_str!("gargantua"),
215215
impl_name: create_runtime_str!("gargantua"),
216216
authoring_version: 1,
217-
spec_version: 232,
217+
spec_version: 233,
218218
impl_version: 0,
219219
apis: RUNTIME_API_VERSIONS,
220220
transaction_version: 1,

0 commit comments

Comments
 (0)