Skip to content

Commit

Permalink
Speed up try runtime checks for pallet-bags-list (paritytech#2151)
Browse files Browse the repository at this point in the history
closes paritytech#2020.

This improves running time for pallet-bags-list try runtime checks on
westend from ~90 minutes to 6 seconds on M2 pro.
  • Loading branch information
Ank4n authored Nov 4, 2023
1 parent 34b1b01 commit 99daa09
Showing 1 changed file with 17 additions and 10 deletions.
27 changes: 17 additions & 10 deletions substrate/frame/bags-list/src/list/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -543,7 +543,16 @@ impl<T: Config<I>, I: 'static> List<T, I> {
thresholds.into_iter().filter_map(|t| Bag::<T, I>::get(t))
};

let _ = active_bags.clone().try_for_each(|b| b.do_try_state())?;
// build map of bags and the corresponding nodes to avoid multiple lookups
let mut bags_map = BTreeMap::<T::Score, Vec<T::AccountId>>::new();

let _ = active_bags.clone().try_for_each(|b| {
bags_map.insert(
b.bag_upper,
b.iter().map(|n: Node<T, I>| n.id().clone()).collect::<Vec<_>>(),
);
b.do_try_state()
})?;

let nodes_in_bags_count =
active_bags.clone().fold(0u32, |acc, cur| acc + cur.iter().count() as u32);
Expand All @@ -554,6 +563,13 @@ impl<T: Config<I>, I: 'static> List<T, I> {
// check that all nodes are sane. We check the `ListNodes` storage item directly in case we
// have some "stale" nodes that are not in a bag.
for (_id, node) in crate::ListNodes::<T, I>::iter() {
// check that the node is in the correct bag
let expected_bag = bags_map
.get(&node.bag_upper)
.ok_or("bag not found for the node in active bags")?;
frame_support::ensure!(expected_bag.contains(node.id()), "node not found in the bag");

// verify node state
node.do_try_state()?
}

Expand Down Expand Up @@ -790,12 +806,6 @@ impl<T: Config<I>, I: 'static> Bag<T, I> {
pub fn std_iter(&self) -> impl Iterator<Item = Node<T, I>> {
sp_std::iter::successors(self.head(), |prev| prev.next())
}

/// Check if the bag contains a node with `id`.
#[cfg(any(test, feature = "try-runtime", feature = "fuzz"))]
fn contains(&self, id: &T::AccountId) -> bool {
self.iter().any(|n| n.id() == id)
}
}

/// A Node is the fundamental element comprising the doubly-linked list described by `Bag`.
Expand Down Expand Up @@ -900,11 +910,8 @@ impl<T: Config<I>, I: 'static> Node<T, I> {
#[cfg(any(test, feature = "try-runtime", feature = "fuzz"))]
fn do_try_state(&self) -> Result<(), TryRuntimeError> {
let expected_bag = Bag::<T, I>::get(self.bag_upper).ok_or("bag not found for node")?;

let id = self.id();

frame_support::ensure!(expected_bag.contains(id), "node does not exist in the bag");

let non_terminal_check = !self.is_terminal() &&
expected_bag.head.as_ref() != Some(id) &&
expected_bag.tail.as_ref() != Some(id);
Expand Down

0 comments on commit 99daa09

Please sign in to comment.