From 3a12a693e95af722e90085d17649696cd27e7d41 Mon Sep 17 00:00:00 2001 From: Brian Picciano Date: Wed, 15 Apr 2026 17:38:43 +0000 Subject: [PATCH 1/6] perf(trie): skip DB seek on exact overlay hits Amp-Thread-ID: https://ampcode.com/threads/T-019d9227-11c0-70b9-a0c2-7ad1dc6151ff Co-authored-by: Amp --- crates/trie/trie/src/trie_cursor/in_memory.rs | 36 +++++++++++++------ 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/crates/trie/trie/src/trie_cursor/in_memory.rs b/crates/trie/trie/src/trie_cursor/in_memory.rs index 7951a6b791c..6a7bd63a589 100644 --- a/crates/trie/trie/src/trie_cursor/in_memory.rs +++ b/crates/trie/trie/src/trie_cursor/in_memory.rs @@ -60,6 +60,8 @@ pub struct InMemoryTrieCursor<'a, C> { cursor_wiped: bool, /// Entry that `cursor` is currently pointing to. cursor_entry: Option<(Nibbles, BranchNodeCompact)>, + /// Whether the DB cursor has been positioned at least once. + cursor_seeked: bool, /// Forward-only in-memory cursor over storage trie nodes. in_memory_cursor: ForwardInMemoryCursor<'a, Nibbles, Option>, /// The key most recently returned from the Cursor. @@ -78,6 +80,7 @@ impl<'a, C: TrieCursor> InMemoryTrieCursor<'a, C> { cursor, cursor_wiped: false, cursor_entry: None, + cursor_seeked: false, in_memory_cursor, last_key: None, seeked: false, @@ -98,6 +101,7 @@ impl<'a, C: TrieCursor> InMemoryTrieCursor<'a, C> { cursor, cursor_wiped, cursor_entry: None, + cursor_seeked: false, in_memory_cursor, last_key: None, seeked: false, @@ -139,14 +143,15 @@ impl<'a, C: TrieCursor> InMemoryTrieCursor<'a, C> { fn cursor_seek(&mut self, key: Nibbles) -> Result<(), DatabaseError> { // Only seek if: // 1. We have a cursor entry and need to seek forward (entry.0 < key), OR - // 2. We have no cursor entry and haven't seeked yet (!self.seeked) + // 2. We have no cursor entry and haven't positioned the DB cursor yet. let should_seek = match self.cursor_entry.as_ref() { Some(entry) => entry.0 < key, - None => !self.seeked, + None => !self.cursor_seeked, }; if should_seek { self.cursor_entry = self.get_cursor_mut().map(|c| c.seek(key)).transpose()?.flatten(); + self.cursor_seeked = true; } Ok(()) @@ -209,16 +214,24 @@ impl TrieCursor for InMemoryTrieCursor<'_, C> { &mut self, key: Nibbles, ) -> Result, DatabaseError> { - self.cursor_seek(key)?; let mem_entry = self.in_memory_cursor.seek(&key); + if let Some((mem_key, entry_inner)) = mem_entry && + *mem_key == key + { + self.seeked = true; + + let entry = entry_inner.clone().map(|node| (key, node)); + self.set_last_key(&entry); + return Ok(entry) + } + + self.cursor_seek(key)?; + self.seeked = true; - let entry = match (mem_entry, &self.cursor_entry) { - (Some((mem_key, entry_inner)), _) if *mem_key == key => { - entry_inner.clone().map(|node| (key, node)) - } - (_, Some((db_key, node))) if db_key == &key => Some((key, node.clone())), + let entry = match &self.cursor_entry { + Some((db_key, node)) if db_key == &key => Some((key, node.clone())), _ => None, }; @@ -279,6 +292,7 @@ impl TrieCursor for InMemoryTrieCursor<'_, C> { cursor, cursor_wiped, cursor_entry, + cursor_seeked, in_memory_cursor, last_key, seeked, @@ -290,6 +304,7 @@ impl TrieCursor for InMemoryTrieCursor<'_, C> { *cursor_wiped = false; *cursor_entry = None; + *cursor_seeked = false; *last_key = None; *seeked = false; } @@ -323,7 +338,7 @@ mod tests { test_case.db_nodes.into_iter().collect(); let db_nodes_arc = Arc::new(db_nodes_map); let visited_keys = Arc::new(Mutex::new(Vec::new())); - let mock_cursor = MockTrieCursor::new(db_nodes_arc, visited_keys); + let mock_cursor = MockTrieCursor::new(db_nodes_arc, visited_keys.clone()); let trie_updates = TrieUpdatesSorted::new(test_case.in_memory_nodes, Default::default()); let mut cursor = InMemoryTrieCursor::new_account(mock_cursor, &trie_updates); @@ -507,7 +522,7 @@ mod tests { let db_nodes_map: BTreeMap = db_nodes.into_iter().collect(); let db_nodes_arc = Arc::new(db_nodes_map); let visited_keys = Arc::new(Mutex::new(Vec::new())); - let mock_cursor = MockTrieCursor::new(db_nodes_arc, visited_keys); + let mock_cursor = MockTrieCursor::new(db_nodes_arc, visited_keys.clone()); let trie_updates = TrieUpdatesSorted::new(in_memory_nodes, Default::default()); let mut cursor = InMemoryTrieCursor::new_account(mock_cursor, &trie_updates); @@ -520,6 +535,7 @@ mod tests { BranchNodeCompact::new(0b0010, 0b0010, 0, vec![], None) )) ); + assert!(visited_keys.lock().is_empty(), "exact overlay hit should not touch the DB cursor"); let result = cursor.seek_exact(Nibbles::from_nibbles([0x3])).unwrap(); assert_eq!( From a41e157e5e18de8009b250994d11a3bba5e14773 Mon Sep 17 00:00:00 2001 From: Brian Picciano <933154+mediocregopher@users.noreply.github.com> Date: Thu, 16 Apr 2026 09:31:00 +0000 Subject: [PATCH 2/6] refactor(trie): model db cursor state with enum Co-Authored-By: Brian Picciano <933154+mediocregopher@users.noreply.github.com> --- crates/trie/trie/src/trie_cursor/in_memory.rs | 114 +++++++++++------- 1 file changed, 72 insertions(+), 42 deletions(-) diff --git a/crates/trie/trie/src/trie_cursor/in_memory.rs b/crates/trie/trie/src/trie_cursor/in_memory.rs index 6a7bd63a589..3d3c12d7350 100644 --- a/crates/trie/trie/src/trie_cursor/in_memory.rs +++ b/crates/trie/trie/src/trie_cursor/in_memory.rs @@ -56,12 +56,8 @@ where pub struct InMemoryTrieCursor<'a, C> { /// The underlying cursor. cursor: C, - /// Whether the underlying cursor should be ignored (when storage trie was wiped). - cursor_wiped: bool, - /// Entry that `cursor` is currently pointing to. - cursor_entry: Option<(Nibbles, BranchNodeCompact)>, - /// Whether the DB cursor has been positioned at least once. - cursor_seeked: bool, + /// Tracks whether the DB cursor is available, positioned, or exhausted. + db_cursor_state: DbCursorState, /// Forward-only in-memory cursor over storage trie nodes. in_memory_cursor: ForwardInMemoryCursor<'a, Nibbles, Option>, /// The key most recently returned from the Cursor. @@ -72,15 +68,45 @@ pub struct InMemoryTrieCursor<'a, C> { trie_updates: &'a TrieUpdatesSorted, } +#[derive(Debug)] +enum DbCursorState { + NeedsPosition, + Positioned((Nibbles, BranchNodeCompact)), + Exhausted, + Wiped, +} + +impl DbCursorState { + const fn new(cursor_wiped: bool) -> Self { + if cursor_wiped { + Self::Wiped + } else { + Self::NeedsPosition + } + } + + const fn entry(&self) -> Option<&(Nibbles, BranchNodeCompact)> { + match self { + Self::Positioned(entry) => Some(entry), + Self::NeedsPosition | Self::Exhausted | Self::Wiped => None, + } + } + + fn set_entry(&mut self, entry: Option<(Nibbles, BranchNodeCompact)>) { + *self = match entry { + Some(entry) => Self::Positioned(entry), + None => Self::Exhausted, + }; + } +} + impl<'a, C: TrieCursor> InMemoryTrieCursor<'a, C> { /// Create new account trie cursor which combines a DB cursor and the trie updates. pub fn new_account(cursor: C, trie_updates: &'a TrieUpdatesSorted) -> Self { let in_memory_cursor = ForwardInMemoryCursor::new(trie_updates.account_nodes_ref()); Self { cursor, - cursor_wiped: false, - cursor_entry: None, - cursor_seeked: false, + db_cursor_state: DbCursorState::NeedsPosition, in_memory_cursor, last_key: None, seeked: false, @@ -99,9 +125,7 @@ impl<'a, C: TrieCursor> InMemoryTrieCursor<'a, C> { Self::get_storage_overlay(trie_updates, hashed_address); Self { cursor, - cursor_wiped, - cursor_entry: None, - cursor_seeked: false, + db_cursor_state: DbCursorState::new(cursor_wiped), in_memory_cursor, last_key: None, seeked: false, @@ -123,7 +147,7 @@ impl<'a, C: TrieCursor> InMemoryTrieCursor<'a, C> { /// Returns a mutable reference to the underlying cursor if it's not wiped, None otherwise. fn get_cursor_mut(&mut self) -> Option<&mut C> { - (!self.cursor_wiped).then_some(&mut self.cursor) + (!matches!(self.db_cursor_state, DbCursorState::Wiped)).then_some(&mut self.cursor) } /// Asserts that the next entry to be returned from the cursor is not previous to the last entry @@ -139,32 +163,33 @@ impl<'a, C: TrieCursor> InMemoryTrieCursor<'a, C> { self.last_key = next_key; } - /// Seeks the `cursor_entry` field of the struct using the cursor. + /// Positions the DB cursor state using the underlying cursor when needed. fn cursor_seek(&mut self, key: Nibbles) -> Result<(), DatabaseError> { // Only seek if: // 1. We have a cursor entry and need to seek forward (entry.0 < key), OR - // 2. We have no cursor entry and haven't positioned the DB cursor yet. - let should_seek = match self.cursor_entry.as_ref() { + // 2. The DB cursor needs to be positioned. + let should_seek = match self.db_cursor_state.entry() { Some(entry) => entry.0 < key, - None => !self.cursor_seeked, + None => matches!(self.db_cursor_state, DbCursorState::NeedsPosition), }; if should_seek { - self.cursor_entry = self.get_cursor_mut().map(|c| c.seek(key)).transpose()?.flatten(); - self.cursor_seeked = true; + let entry = self.get_cursor_mut().map(|c| c.seek(key)).transpose()?.flatten(); + self.db_cursor_state.set_entry(entry); } Ok(()) } - /// Seeks the `cursor_entry` field of the struct to the subsequent entry using the cursor. + /// Advances the DB cursor state to the subsequent entry using the underlying cursor. fn cursor_next(&mut self) -> Result<(), DatabaseError> { debug_assert!(self.seeked); // If the previous entry is `None`, and we've done a seek previously, then the cursor is // exhausted and we shouldn't call `next` again. - if self.cursor_entry.is_some() { - self.cursor_entry = self.get_cursor_mut().map(|c| c.next()).transpose()?.flatten(); + if matches!(self.db_cursor_state, DbCursorState::Positioned(_)) { + let entry = self.get_cursor_mut().map(|c| c.next()).transpose()?.flatten(); + self.db_cursor_state.set_entry(entry); } Ok(()) @@ -177,9 +202,9 @@ impl<'a, C: TrieCursor> InMemoryTrieCursor<'a, C> { /// node. fn choose_next_entry(&mut self) -> Result, DatabaseError> { loop { - match (self.in_memory_cursor.current().cloned(), &self.cursor_entry) { + match (self.in_memory_cursor.current().cloned(), self.db_cursor_state.entry()) { (Some((mem_key, None)), _) - if self.cursor_entry.as_ref().is_none_or(|(db_key, _)| &mem_key < db_key) => + if self.db_cursor_state.entry().is_none_or(|(db_key, _)| &mem_key < db_key) => { // If overlay has a removed node but DB cursor is exhausted or ahead of the // in-memory cursor then move ahead in-memory, as there might be further @@ -193,7 +218,10 @@ impl<'a, C: TrieCursor> InMemoryTrieCursor<'a, C> { self.cursor_next()?; } (Some((mem_key, Some(node))), _) - if self.cursor_entry.as_ref().is_none_or(|(db_key, _)| &mem_key <= db_key) => + if self + .db_cursor_state + .entry() + .is_none_or(|(db_key, _)| &mem_key <= db_key) => { // If overlay returns a node prior to the DB's node, or the DB is exhausted, // then we return the overlay's node. @@ -203,7 +231,7 @@ impl<'a, C: TrieCursor> InMemoryTrieCursor<'a, C> { // - mem_key > db_key // - overlay is exhausted // Return the db_entry. If DB is also exhausted then this returns None. - _ => return Ok(self.cursor_entry.clone()), + _ => return Ok(self.db_cursor_state.entry().cloned()), } } } @@ -221,6 +249,12 @@ impl TrieCursor for InMemoryTrieCursor<'_, C> { { self.seeked = true; + if self.db_cursor_state.entry().is_some_and(|(db_key, _)| db_key < &key) || + matches!(self.db_cursor_state, DbCursorState::NeedsPosition) + { + self.db_cursor_state = DbCursorState::NeedsPosition; + } + let entry = entry_inner.clone().map(|node| (key, node)); self.set_last_key(&entry); return Ok(entry) @@ -230,7 +264,7 @@ impl TrieCursor for InMemoryTrieCursor<'_, C> { self.seeked = true; - let entry = match &self.cursor_entry { + let entry = match self.db_cursor_state.entry() { Some((db_key, node)) if db_key == &key => Some((key, node.clone())), _ => None, }; @@ -269,7 +303,11 @@ impl TrieCursor for InMemoryTrieCursor<'_, C> { self.in_memory_cursor.first_after(&last_key); } - if let Some((key, _)) = &self.cursor_entry && + if matches!(self.db_cursor_state, DbCursorState::NeedsPosition) { + self.cursor_seek(last_key)?; + } + + if let Some((key, _)) = self.db_cursor_state.entry() && key == &last_key { self.cursor_next()?; @@ -288,23 +326,13 @@ impl TrieCursor for InMemoryTrieCursor<'_, C> { } fn reset(&mut self) { - let Self { - cursor, - cursor_wiped, - cursor_entry, - cursor_seeked, - in_memory_cursor, - last_key, - seeked, - trie_updates: _, - } = self; + let Self { cursor, db_cursor_state, in_memory_cursor, last_key, seeked, trie_updates: _ } = + self; cursor.reset(); in_memory_cursor.reset(); - *cursor_wiped = false; - *cursor_entry = None; - *cursor_seeked = false; + *db_cursor_state = DbCursorState::NeedsPosition; *last_key = None; *seeked = false; } @@ -314,8 +342,10 @@ impl TrieStorageCursor for InMemoryTrieCursor<'_, C> { fn set_hashed_address(&mut self, hashed_address: B256) { self.reset(); self.cursor.set_hashed_address(hashed_address); - (self.in_memory_cursor, self.cursor_wiped) = + let (in_memory_cursor, cursor_wiped) = Self::get_storage_overlay(self.trie_updates, hashed_address); + self.in_memory_cursor = in_memory_cursor; + self.db_cursor_state = DbCursorState::new(cursor_wiped); } } From 673cafa4e10a4e5a1aa469be11f43338f7173df0 Mon Sep 17 00:00:00 2001 From: Brian Picciano <933154+mediocregopher@users.noreply.github.com> Date: Thu, 16 Apr 2026 09:52:55 +0000 Subject: [PATCH 3/6] refactor(trie): address in-memory cursor review feedback Co-Authored-By: Brian Picciano <933154+mediocregopher@users.noreply.github.com> --- crates/trie/trie/src/trie_cursor/in_memory.rs | 32 +++++++++++-------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/crates/trie/trie/src/trie_cursor/in_memory.rs b/crates/trie/trie/src/trie_cursor/in_memory.rs index 3d3c12d7350..95af0d100c3 100644 --- a/crates/trie/trie/src/trie_cursor/in_memory.rs +++ b/crates/trie/trie/src/trie_cursor/in_memory.rs @@ -168,9 +168,10 @@ impl<'a, C: TrieCursor> InMemoryTrieCursor<'a, C> { // Only seek if: // 1. We have a cursor entry and need to seek forward (entry.0 < key), OR // 2. The DB cursor needs to be positioned. - let should_seek = match self.db_cursor_state.entry() { - Some(entry) => entry.0 < key, - None => matches!(self.db_cursor_state, DbCursorState::NeedsPosition), + let should_seek = match &self.db_cursor_state { + DbCursorState::NeedsPosition => true, + DbCursorState::Positioned((entry_key, _)) => entry_key < &key, + DbCursorState::Exhausted | DbCursorState::Wiped => false, }; if should_seek { @@ -184,9 +185,10 @@ impl<'a, C: TrieCursor> InMemoryTrieCursor<'a, C> { /// Advances the DB cursor state to the subsequent entry using the underlying cursor. fn cursor_next(&mut self) -> Result<(), DatabaseError> { debug_assert!(self.seeked); + debug_assert!(!matches!(self.db_cursor_state, DbCursorState::NeedsPosition)); - // If the previous entry is `None`, and we've done a seek previously, then the cursor is - // exhausted and we shouldn't call `next` again. + // Exhausted and wiped states are stable; only advance if the DB cursor currently points to + // an entry. if matches!(self.db_cursor_state, DbCursorState::Positioned(_)) { let entry = self.get_cursor_mut().map(|c| c.next()).transpose()?.flatten(); self.db_cursor_state.set_entry(entry); @@ -202,9 +204,12 @@ impl<'a, C: TrieCursor> InMemoryTrieCursor<'a, C> { /// node. fn choose_next_entry(&mut self) -> Result, DatabaseError> { loop { - match (self.in_memory_cursor.current().cloned(), self.db_cursor_state.entry()) { + let mem_entry = self.in_memory_cursor.current().cloned(); + let db_entry = self.db_cursor_state.entry().cloned(); + + match (mem_entry, db_entry.as_ref()) { (Some((mem_key, None)), _) - if self.db_cursor_state.entry().is_none_or(|(db_key, _)| &mem_key < db_key) => + if db_entry.as_ref().is_none_or(|(db_key, _)| &mem_key < db_key) => { // If overlay has a removed node but DB cursor is exhausted or ahead of the // in-memory cursor then move ahead in-memory, as there might be further @@ -218,10 +223,7 @@ impl<'a, C: TrieCursor> InMemoryTrieCursor<'a, C> { self.cursor_next()?; } (Some((mem_key, Some(node))), _) - if self - .db_cursor_state - .entry() - .is_none_or(|(db_key, _)| &mem_key <= db_key) => + if db_entry.as_ref().is_none_or(|(db_key, _)| &mem_key <= db_key) => { // If overlay returns a node prior to the DB's node, or the DB is exhausted, // then we return the overlay's node. @@ -231,7 +233,7 @@ impl<'a, C: TrieCursor> InMemoryTrieCursor<'a, C> { // - mem_key > db_key // - overlay is exhausted // Return the db_entry. If DB is also exhausted then this returns None. - _ => return Ok(self.db_cursor_state.entry().cloned()), + _ => return Ok(db_entry), } } } @@ -249,8 +251,10 @@ impl TrieCursor for InMemoryTrieCursor<'_, C> { { self.seeked = true; - if self.db_cursor_state.entry().is_some_and(|(db_key, _)| db_key < &key) || - matches!(self.db_cursor_state, DbCursorState::NeedsPosition) + // An exact overlay hit can move the logical cursor ahead without touching the DB. If + // the DB cursor was still behind this key, force a re-seek before the next DB-backed + // operation so `next()` cannot return a stale earlier entry. + if matches!(&self.db_cursor_state, DbCursorState::Positioned((db_key, _)) if db_key < &key) { self.db_cursor_state = DbCursorState::NeedsPosition; } From d9699f0df3f379141b9909925620678dab8d5e08 Mon Sep 17 00:00:00 2001 From: Brian Picciano <933154+mediocregopher@users.noreply.github.com> Date: Thu, 16 Apr 2026 10:45:23 +0000 Subject: [PATCH 4/6] refactor(trie): make seeked debug-only Co-Authored-By: Brian Picciano <933154+mediocregopher@users.noreply.github.com> --- crates/trie/trie/src/trie_cursor/in_memory.rs | 46 +++++++++++++------ 1 file changed, 32 insertions(+), 14 deletions(-) diff --git a/crates/trie/trie/src/trie_cursor/in_memory.rs b/crates/trie/trie/src/trie_cursor/in_memory.rs index 95af0d100c3..0206ae8bbd5 100644 --- a/crates/trie/trie/src/trie_cursor/in_memory.rs +++ b/crates/trie/trie/src/trie_cursor/in_memory.rs @@ -62,6 +62,7 @@ pub struct InMemoryTrieCursor<'a, C> { in_memory_cursor: ForwardInMemoryCursor<'a, Nibbles, Option>, /// The key most recently returned from the Cursor. last_key: Option, + #[cfg(debug_assertions)] /// Whether an initial seek was called. seeked: bool, /// Reference to the full trie updates. @@ -109,6 +110,7 @@ impl<'a, C: TrieCursor> InMemoryTrieCursor<'a, C> { db_cursor_state: DbCursorState::NeedsPosition, in_memory_cursor, last_key: None, + #[cfg(debug_assertions)] seeked: false, trie_updates, } @@ -128,6 +130,7 @@ impl<'a, C: TrieCursor> InMemoryTrieCursor<'a, C> { db_cursor_state: DbCursorState::new(cursor_wiped), in_memory_cursor, last_key: None, + #[cfg(debug_assertions)] seeked: false, trie_updates, } @@ -184,8 +187,11 @@ impl<'a, C: TrieCursor> InMemoryTrieCursor<'a, C> { /// Advances the DB cursor state to the subsequent entry using the underlying cursor. fn cursor_next(&mut self) -> Result<(), DatabaseError> { - debug_assert!(self.seeked); - debug_assert!(!matches!(self.db_cursor_state, DbCursorState::NeedsPosition)); + #[cfg(debug_assertions)] + { + debug_assert!(self.seeked); + debug_assert!(!matches!(self.db_cursor_state, DbCursorState::NeedsPosition)); + } // Exhausted and wiped states are stable; only advance if the DB cursor currently points to // an entry. @@ -249,7 +255,10 @@ impl TrieCursor for InMemoryTrieCursor<'_, C> { if let Some((mem_key, entry_inner)) = mem_entry && *mem_key == key { - self.seeked = true; + #[cfg(debug_assertions)] + { + self.seeked = true; + } // An exact overlay hit can move the logical cursor ahead without touching the DB. If // the DB cursor was still behind this key, force a re-seek before the next DB-backed @@ -266,7 +275,10 @@ impl TrieCursor for InMemoryTrieCursor<'_, C> { self.cursor_seek(key)?; - self.seeked = true; + #[cfg(debug_assertions)] + { + self.seeked = true; + } let entry = match self.db_cursor_state.entry() { Some((db_key, node)) if db_key == &key => Some((key, node.clone())), @@ -284,7 +296,10 @@ impl TrieCursor for InMemoryTrieCursor<'_, C> { self.cursor_seek(key)?; self.in_memory_cursor.seek(&key); - self.seeked = true; + #[cfg(debug_assertions)] + { + self.seeked = true; + } let entry = self.choose_next_entry()?; self.set_last_key(&entry); @@ -292,7 +307,10 @@ impl TrieCursor for InMemoryTrieCursor<'_, C> { } fn next(&mut self) -> Result, DatabaseError> { - debug_assert!(self.seeked, "Cursor must be seek'd before next is called"); + #[cfg(debug_assertions)] + { + debug_assert!(self.seeked, "Cursor must be seek'd before next is called"); + } // A `last_key` of `None` indicates that the cursor is exhausted. let Some(last_key) = self.last_key else { @@ -330,15 +348,15 @@ impl TrieCursor for InMemoryTrieCursor<'_, C> { } fn reset(&mut self) { - let Self { cursor, db_cursor_state, in_memory_cursor, last_key, seeked, trie_updates: _ } = - self; - - cursor.reset(); - in_memory_cursor.reset(); + self.cursor.reset(); + self.in_memory_cursor.reset(); - *db_cursor_state = DbCursorState::NeedsPosition; - *last_key = None; - *seeked = false; + self.db_cursor_state = DbCursorState::NeedsPosition; + self.last_key = None; + #[cfg(debug_assertions)] + { + self.seeked = false; + } } } From 75f9932f03419cd482c1f88dbe77bf14dd24fd60 Mon Sep 17 00:00:00 2001 From: Brian Picciano <933154+mediocregopher@users.noreply.github.com> Date: Thu, 16 Apr 2026 11:43:55 +0000 Subject: [PATCH 5/6] test(trie): fix clippy redundant clone in cursor tests Co-Authored-By: Brian Picciano <933154+mediocregopher@users.noreply.github.com> --- crates/trie/trie/src/trie_cursor/in_memory.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/trie/trie/src/trie_cursor/in_memory.rs b/crates/trie/trie/src/trie_cursor/in_memory.rs index 0206ae8bbd5..5e38c74acb5 100644 --- a/crates/trie/trie/src/trie_cursor/in_memory.rs +++ b/crates/trie/trie/src/trie_cursor/in_memory.rs @@ -390,7 +390,7 @@ mod tests { test_case.db_nodes.into_iter().collect(); let db_nodes_arc = Arc::new(db_nodes_map); let visited_keys = Arc::new(Mutex::new(Vec::new())); - let mock_cursor = MockTrieCursor::new(db_nodes_arc, visited_keys.clone()); + let mock_cursor = MockTrieCursor::new(db_nodes_arc, visited_keys); let trie_updates = TrieUpdatesSorted::new(test_case.in_memory_nodes, Default::default()); let mut cursor = InMemoryTrieCursor::new_account(mock_cursor, &trie_updates); From 2f57b368482658fad1e2bcc0ab45fb1007155375 Mon Sep 17 00:00:00 2001 From: Brian Picciano <933154+mediocregopher@users.noreply.github.com> Date: Thu, 23 Apr 2026 13:58:35 +0000 Subject: [PATCH 6/6] perf(trie): borrow db cursor entry in choose_next_entry Co-authored-by: Brian Picciano <933154+mediocregopher@users.noreply.github.com> Amp-Thread-ID: https://ampcode.com/threads/T-019dba4e-0186-7501-9f17-bdf23d7d6ea6 Co-authored-by: Amp --- crates/trie/trie/src/trie_cursor/in_memory.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/crates/trie/trie/src/trie_cursor/in_memory.rs b/crates/trie/trie/src/trie_cursor/in_memory.rs index 5e38c74acb5..5fde874017e 100644 --- a/crates/trie/trie/src/trie_cursor/in_memory.rs +++ b/crates/trie/trie/src/trie_cursor/in_memory.rs @@ -211,11 +211,11 @@ impl<'a, C: TrieCursor> InMemoryTrieCursor<'a, C> { fn choose_next_entry(&mut self) -> Result, DatabaseError> { loop { let mem_entry = self.in_memory_cursor.current().cloned(); - let db_entry = self.db_cursor_state.entry().cloned(); + let db_entry = self.db_cursor_state.entry(); - match (mem_entry, db_entry.as_ref()) { + match (mem_entry, db_entry) { (Some((mem_key, None)), _) - if db_entry.as_ref().is_none_or(|(db_key, _)| &mem_key < db_key) => + if db_entry.is_none_or(|(db_key, _)| &mem_key < db_key) => { // If overlay has a removed node but DB cursor is exhausted or ahead of the // in-memory cursor then move ahead in-memory, as there might be further @@ -229,7 +229,7 @@ impl<'a, C: TrieCursor> InMemoryTrieCursor<'a, C> { self.cursor_next()?; } (Some((mem_key, Some(node))), _) - if db_entry.as_ref().is_none_or(|(db_key, _)| &mem_key <= db_key) => + if db_entry.is_none_or(|(db_key, _)| &mem_key <= db_key) => { // If overlay returns a node prior to the DB's node, or the DB is exhausted, // then we return the overlay's node. @@ -239,7 +239,7 @@ impl<'a, C: TrieCursor> InMemoryTrieCursor<'a, C> { // - mem_key > db_key // - overlay is exhausted // Return the db_entry. If DB is also exhausted then this returns None. - _ => return Ok(db_entry), + _ => return Ok(db_entry.cloned()), } } }