From c8b3c951b52f799d5e3b1802db0b479f0ba3f766 Mon Sep 17 00:00:00 2001 From: gabriele-0201 Date: Thu, 4 Dec 2025 14:14:31 +0100 Subject: [PATCH 1/2] fix: properly handle deletions within overlays --- nomt/src/merkle/seek.rs | 46 ++++++++++++++------- nomt/tests/overlay.rs | 92 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 123 insertions(+), 15 deletions(-) diff --git a/nomt/src/merkle/seek.rs b/nomt/src/merkle/seek.rs index 41760d180f..114d343e06 100644 --- a/nomt/src/merkle/seek.rs +++ b/nomt/src/merkle/seek.rs @@ -192,6 +192,7 @@ impl SeekRequest { fn continue_leaf_fetch(&mut self, leaf: Option) { let RequestState::FetchingLeaf { + ref mut overlay_deletions, ref mut beatree_iterator, .. } = self.state @@ -203,13 +204,24 @@ impl SeekRequest { beatree_iterator.provide_leaf(leaf); } - let (key, value_hash) = match beatree_iterator.next() { - None => panic!("leaf must exist position={}", self.position.path()), - Some(IterOutput::Blocked) => return, - Some(IterOutput::Item(key, value)) => { - (key, H::hash_value(&value)) // hash + let mut deletions_idx = 0; + let (key, value_hash) = loop { + match beatree_iterator.next() { + None => panic!("leaf must exist position={}", self.position.path()), + Some(IterOutput::Blocked) => { + overlay_deletions.drain(..deletions_idx); + return; + } + Some(IterOutput::Item(key, _value)) + if deletions_idx < overlay_deletions.len() + && overlay_deletions[deletions_idx] == key => + { + deletions_idx += 1; + continue; + } + Some(IterOutput::Item(key, value)) => break (key, H::hash_value(&value)), + Some(IterOutput::OverflowItem(key, value_hash, _)) => break (key, value_hash), } - Some(IterOutput::OverflowItem(key, value_hash, _)) => (key, value_hash), }; self.state = RequestState::Completed(Some(trie::LeafData { @@ -351,6 +363,7 @@ enum RequestState { Seeking, // Fetching one leaf FetchingLeaf { + overlay_deletions: Vec, beatree_iterator: BeatreeIterator, needed_leaves: NeededLeavesIter, }, @@ -373,16 +386,18 @@ impl RequestState { ) -> Self { let (start, end) = range_bounds(pos.raw_path(), pos.depth() as usize); - // First see if the item is present within the overlay. - let overlay_item = overlay - .value_iter(start, end) - .filter(|(_, v)| v.as_option().is_some()) - .next(); + let overlay_items = overlay.value_iter(start, end); + let mut overlay_deletions = vec![]; - if let Some((key_path, overlay_leaf)) = overlay_item { - let value_hash = match overlay_leaf { - // PANIC: we filtered out all deletions above. - ValueChange::Delete => panic!(), + for (key_path, overlay_change) in overlay_items { + let value_hash = match overlay_change { + ValueChange::Delete => { + // All deletes must be collected to filter out from the beatree iterator. + overlay_deletions.push(key_path); + continue; + } + // If an insertion is found within the overlay, it is expected to be + // the item associated with the leaf that is being fetched. ValueChange::Insert(value) => H::hash_value(value), ValueChange::InsertOverflow(_, value_hash) => value_hash.clone(), }; @@ -397,6 +412,7 @@ impl RequestState { let beatree_iterator = read_transaction.iterator(start, end); let needed_leaves = beatree_iterator.needed_leaves(); RequestState::FetchingLeaf { + overlay_deletions, beatree_iterator, needed_leaves, } diff --git a/nomt/tests/overlay.rs b/nomt/tests/overlay.rs index 3603e294f7..56d536f24e 100644 --- a/nomt/tests/overlay.rs +++ b/nomt/tests/overlay.rs @@ -160,3 +160,95 @@ fn overlay_uncommitted_not_on_disk() { assert_eq!(test.read([2; 32]), None); assert_eq!(test.read([3; 32]), None); } + +#[test] +fn overlay_deletions() { + let test_db = || -> Test { + let mut test = Test::new("overlay_deletions"); + // subtree at 0000000_0/1 + test.write([0; 32], Some(vec![1, 1])); + test.write([1; 32], Some(vec![2, 2])); + + // subtree at 001000_00/01/10 + test.write([32; 32], Some(vec![1, 1])); + test.write([33; 32], Some(vec![2, 2])); + test.write([34; 32], Some(vec![3, 3])); + + // subtree at 100000_00/01/10/11 + test.write([128; 32], Some(vec![4, 4])); + test.write([129; 32], Some(vec![5, 5])); + test.write([130; 32], Some(vec![6, 6])); + test.write([131; 32], Some(vec![7, 7])); + + test.commit(); + test + }; + + // Delete the first item for each subtree + let mut test = test_db(); + + test.write([0; 32], None); + test.write([32; 32], None); + test.write([128; 32], None); + let overlay_a = test.update().0; + + test.start_overlay_session([&overlay_a]); + assert_eq!(test.read([0; 32]), None); + assert_eq!(test.read([1; 32]), Some(vec![2, 2])); + + assert_eq!(test.read([32; 32]), None); + assert_eq!(test.read([33; 32]), Some(vec![2, 2])); + assert_eq!(test.read([34; 32]), Some(vec![3, 3])); + + assert_eq!(test.read([128; 32]), None); + assert_eq!(test.read([129; 32]), Some(vec![5, 5])); + assert_eq!(test.read([130; 32]), Some(vec![6, 6])); + assert_eq!(test.read([131; 32]), Some(vec![7, 7])); + + let _overlay_b = test.update().0; + + // Delete the second item for each subtree + let mut test = test_db(); + + test.write([1; 32], None); + test.write([33; 32], None); + test.write([129; 32], None); + let overlay_a = test.update().0; + + test.start_overlay_session([&overlay_a]); + assert_eq!(test.read([0; 32]), Some(vec![1, 1])); + assert_eq!(test.read([1; 32]), None); + + assert_eq!(test.read([32; 32]), Some(vec![1, 1])); + assert_eq!(test.read([33; 32]), None); + assert_eq!(test.read([34; 32]), Some(vec![3, 3])); + + assert_eq!(test.read([128; 32]), Some(vec![4, 4])); + assert_eq!(test.read([129; 32]), None); + assert_eq!(test.read([130; 32]), Some(vec![6, 6])); + assert_eq!(test.read([131; 32]), Some(vec![7, 7])); + + let _overlay_b = test.update().0; + + // Sequence of deletes + let mut test = test_db(); + + test.write([32; 32], None); + test.write([33; 32], None); + test.write([128; 32], None); + test.write([129; 32], None); + test.write([131; 32], None); + let overlay_a = test.update().0; + + test.start_overlay_session([&overlay_a]); + assert_eq!(test.read([32; 32]), None); + assert_eq!(test.read([33; 32]), None); + assert_eq!(test.read([34; 32]), Some(vec![3, 3])); + + assert_eq!(test.read([128; 32]), None); + assert_eq!(test.read([129; 32]), None); + assert_eq!(test.read([130; 32]), Some(vec![6, 6])); + assert_eq!(test.read([131; 32]), None); + + let _overlay_b = test.update().0; +} From 11d17641af0d3b39245651be4b603afa3938a8e9 Mon Sep 17 00:00:00 2001 From: gabriele-0201 Date: Thu, 4 Dec 2025 15:35:39 +0100 Subject: [PATCH 2/2] fix: add overlay base-root and state-root consistency check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When beginning a session, ensure that the oldest overlay’s previous root matches the current state root. This prevents the creation of invalid sessions that could reuse a chain of overlays that were previously committed or or a chain that is no longer valid because another overlay chain has been committed. --- benchtop/src/nomt.rs | 4 +- examples/commit_batch/src/lib.rs | 2 +- examples/read_value/src/main.rs | 2 +- fuzz/fuzz_targets/api_surface.rs | 6 +-- nomt/src/lib.rs | 9 ++-- nomt/src/overlay.rs | 18 +++++++- nomt/tests/common/mod.rs | 21 ++++++--- nomt/tests/overlay.rs | 74 ++++++++++++++++++++++++++++++++ nomt/tests/prev_root_check.rs | 12 +++--- nomt/tests/rollback.rs | 14 +++--- torture/src/agent.rs | 2 +- 11 files changed, 132 insertions(+), 32 deletions(-) diff --git a/benchtop/src/nomt.rs b/benchtop/src/nomt.rs index 83949b6fa9..a56101edb8 100644 --- a/benchtop/src/nomt.rs +++ b/benchtop/src/nomt.rs @@ -95,7 +95,7 @@ impl NomtDB { } else { session_params.overlay(overlay_window.iter()).unwrap() }; - let session = self.nomt.begin_session(session_params); + let session = self.nomt.begin_session(session_params).unwrap(); let mut transaction = Tx { session: &session, @@ -147,7 +147,7 @@ impl NomtDB { } else { session_params.overlay(overlay_window.iter()).unwrap() }; - let session = self.nomt.begin_session(session_params); + let session = self.nomt.begin_session(session_params).unwrap(); let mut results: Vec> = (0..workloads.len()).map(|_| None).collect(); let use_timer = timer.is_some(); diff --git a/examples/commit_batch/src/lib.rs b/examples/commit_batch/src/lib.rs index c31f7210d5..3a4662f3df 100644 --- a/examples/commit_batch/src/lib.rs +++ b/examples/commit_batch/src/lib.rs @@ -26,7 +26,7 @@ impl NomtDB { // Writes do not occur immediately, instead, // they are cached and applied all at once later on let session = - nomt.begin_session(SessionParams::default().witness_mode(WitnessMode::read_write())); + nomt.begin_session(SessionParams::default().witness_mode(WitnessMode::read_write()))?; // Here we will move the data saved under b"key1" to b"key2" and deletes it // diff --git a/examples/read_value/src/main.rs b/examples/read_value/src/main.rs index 3e3036f392..43dd7d96a4 100644 --- a/examples/read_value/src/main.rs +++ b/examples/read_value/src/main.rs @@ -16,7 +16,7 @@ fn main() -> Result<()> { // Instantiate a new Session object to handle read and write operations // and generate a Witness later on let session = - nomt.begin_session(SessionParams::default().witness_mode(WitnessMode::read_write())); + nomt.begin_session(SessionParams::default().witness_mode(WitnessMode::read_write()))?; // Reading a key from the database let key_path = sha2::Sha256::digest(b"key").into(); diff --git a/fuzz/fuzz_targets/api_surface.rs b/fuzz/fuzz_targets/api_surface.rs index dd62963d65..67b70aee99 100644 --- a/fuzz/fuzz_targets/api_surface.rs +++ b/fuzz/fuzz_targets/api_surface.rs @@ -16,9 +16,9 @@ fuzz_target!(|run: Run| { for call in run.calls.calls { match call { NomtCall::BeginSession { session_calls } => { - let session = db.begin_session( - SessionParams::default().witness_mode(WitnessMode::read_write()), - ); + let session = db + .begin_session(SessionParams::default().witness_mode(WitnessMode::read_write())) + .unwrap(); for session_call in session_calls { match session_call { SessionCall::TentativeRead { diff --git a/nomt/src/lib.rs b/nomt/src/lib.rs index e19a66e172..ac18caf3a9 100644 --- a/nomt/src/lib.rs +++ b/nomt/src/lib.rs @@ -303,8 +303,9 @@ impl Nomt { /// prevent writes to the database. Sessions are the main way of reading to the database, /// and permit a changeset to be committed either directly to the database or into an /// in-memory [`Overlay`]. - pub fn begin_session(&self, params: SessionParams) -> Session { + pub fn begin_session(&self, params: SessionParams) -> anyhow::Result> { let live_overlay = params.overlay; + live_overlay.ensure_base_root(self.root())?; // We must take the access guard before instantiating the rollback delta, // because it creates a read transaction and any commits or rollbacks will block @@ -326,7 +327,7 @@ impl Nomt { .parent_root() .unwrap_or_else(|| self.root().into_inner()); - Session { + Ok(Session { store, merkle_updater: self.merkle_update_pool.begin::( self.page_cache.clone(), @@ -342,7 +343,7 @@ impl Nomt { access_guard, prev_root: Root(prev_root), _marker: std::marker::PhantomData, - } + }) } /// Perform a rollback of the last `n` commits. @@ -373,7 +374,7 @@ impl Nomt { // We hold a write guard and don't need the session to take any other. session_params.take_global_guard = false; - let sess = self.begin_session(session_params); + let sess = self.begin_session(session_params)?; // Convert the traceback into a series of write commands. let mut actuals = Vec::new(); diff --git a/nomt/src/overlay.rs b/nomt/src/overlay.rs index b6b4a28873..c26803af3b 100644 --- a/nomt/src/overlay.rs +++ b/nomt/src/overlay.rs @@ -237,6 +237,7 @@ pub enum InvalidAncestors { #[derive(Clone)] pub(super) struct LiveOverlay { parent: Option>, + base_root: Option, ancestor_data: Vec>, min_seqn: u64, } @@ -250,12 +251,14 @@ impl LiveOverlay { let Some(parent) = live_ancestors.next().map(|p| p.inner.clone()) else { return Ok(LiveOverlay { parent: None, + base_root: None, ancestor_data: Vec::new(), min_seqn: 0, }); }; let mut ancestor_data = Vec::new(); + let mut base_root = Some(Root(parent.prev_root)); for (supposed_ancestor, actual_ancestor) in live_ancestors.zip(parent.ancestor_data.iter()) { let Some(actual_ancestor) = actual_ancestor.upgrade() else { @@ -266,7 +269,8 @@ impl LiveOverlay { return Err(InvalidAncestors::NotAncestor); } - ancestor_data.push(actual_ancestor); + base_root = Some(supposed_ancestor.prev_root()); + ancestor_data.push(actual_ancestor.clone()); } // verify that the chain is complete. The last ancestor's parent must either be `None` or @@ -286,6 +290,7 @@ impl LiveOverlay { Ok(LiveOverlay { parent: Some(parent), ancestor_data, + base_root, min_seqn, }) } @@ -418,6 +423,17 @@ impl LiveOverlay { pub(super) fn parent_root(&self) -> Option { self.parent.as_ref().map(|p| p.root) } + + /// Ensure that the oldest overlay's previous root matches + /// the specified current state root. + pub fn ensure_base_root(&self, state_root: Root) -> anyhow::Result<()> { + self.base_root + .map_or(true, |base_root| base_root == state_root) + .then(|| ()) + .ok_or(anyhow::anyhow!( + "State root and oldest overlay prev root do not match." + )) + } } #[cfg(test)] diff --git a/nomt/tests/common/mod.rs b/nomt/tests/common/mod.rs index 603209fd4a..461be6f202 100644 --- a/nomt/tests/common/mod.rs +++ b/nomt/tests/common/mod.rs @@ -76,8 +76,9 @@ impl Test { o.hashtable_buckets(hashtable_buckets); o.commit_concurrency(commit_concurrency); let nomt = Nomt::open(o).unwrap(); - let session = - nomt.begin_session(SessionParams::default().witness_mode(WitnessMode::read_write())); + let session = nomt + .begin_session(SessionParams::default().witness_mode(WitnessMode::read_write())) + .unwrap(); Self { nomt, session: Some(session), @@ -128,7 +129,8 @@ impl Test { finished.commit(&self.nomt).unwrap(); self.session = Some( self.nomt - .begin_session(SessionParams::default().witness_mode(WitnessMode::read_write())), + .begin_session(SessionParams::default().witness_mode(WitnessMode::read_write())) + .unwrap(), ); (root, witness) } @@ -142,7 +144,8 @@ impl Test { self.session = Some( self.nomt - .begin_session(SessionParams::default().witness_mode(WitnessMode::read_write())), + .begin_session(SessionParams::default().witness_mode(WitnessMode::read_write())) + .unwrap(), ); (finished.into_overlay(), witness) @@ -155,10 +158,16 @@ impl Test { overlay.commit(&self.nomt).unwrap(); self.session = Some( self.nomt - .begin_session(SessionParams::default().witness_mode(WitnessMode::read_write())), + .begin_session(SessionParams::default().witness_mode(WitnessMode::read_write())) + .unwrap(), ); } + pub fn try_begin_session(&mut self, params: SessionParams) -> anyhow::Result<()> { + self.session = Some(self.nomt.begin_session(params)?); + Ok(()) + } + pub fn start_overlay_session<'a>(&mut self, ancestors: impl IntoIterator) { // force drop of live session before creating a new one. self.access.clear(); @@ -167,7 +176,7 @@ impl Test { .witness_mode(WitnessMode::read_write()) .overlay(ancestors) .unwrap(); - self.session = Some(self.nomt.begin_session(params)); + self.session = Some(self.nomt.begin_session(params).unwrap()); } pub fn prove(&self, key: KeyPath) -> PathProof { diff --git a/nomt/tests/overlay.rs b/nomt/tests/overlay.rs index 56d536f24e..60a1ba176a 100644 --- a/nomt/tests/overlay.rs +++ b/nomt/tests/overlay.rs @@ -252,3 +252,77 @@ fn overlay_deletions() { let _overlay_b = test.update().0; } + +#[test] +fn overlay_detect_alredy_committed_chain() { + let mut test = Test::new("overlay_wrong_chains"); + + test.write([0; 32], Some(vec![1])); + let overlay_a = test.update().0; + + test.start_overlay_session([&overlay_a]); + test.write([0; 32], Some(vec![2])); + let overlay_b = test.update().0; + + test.start_overlay_session([&overlay_b, &overlay_a]); + test.write([0; 32], Some(vec![3])); + let overlay_c = test.update().0; + + let params = nomt::SessionParams::default() + .witness_mode(nomt::WitnessMode::read_write()) + .overlay([&overlay_c, &overlay_b, &overlay_a]) + .unwrap(); + + test.commit_overlay(overlay_a); + test.commit_overlay(overlay_b); + test.commit_overlay(overlay_c); + + assert!(test.try_begin_session(params).is_err()); +} + +#[test] +fn overlay_detect_parallel_non_committed_overlay_chain() { + let mut test = Test::new("overlay_detect_parallel_non_committed_overlay_chain"); + + test.write([0; 32], Some(vec![1])); + let overlay_a = test.update().0; + + test.start_overlay_session([&overlay_a]); + test.write([0; 32], Some(vec![2])); + let overlay_b = test.update().0; + + test.start_overlay_session([&overlay_b, &overlay_a]); + test.write([0; 32], Some(vec![3])); + let overlay_c = test.update().0; + + test.write([0; 32], Some(vec![4])); + let overlay_d = test.update().0; + + test.start_overlay_session([&overlay_d]); + test.write([0; 32], Some(vec![5])); + let overlay_e = test.update().0; + + test.start_overlay_session([&overlay_e, &overlay_d]); + test.write([0; 32], Some(vec![6])); + let overlay_f = test.update().0; + + test.start_overlay_session([&overlay_f, &overlay_e, &overlay_d]); + test.write([0; 32], Some(vec![7])); + let overlay_g = test.update().0; + + test.commit_overlay(overlay_d); + test.commit_overlay(overlay_e); + test.commit_overlay(overlay_f); + + let params = nomt::SessionParams::default() + .witness_mode(nomt::WitnessMode::read_write()) + .overlay([&overlay_c, &overlay_b, &overlay_a]) + .unwrap(); + assert!(test.try_begin_session(params).is_err()); + + let params = nomt::SessionParams::default() + .witness_mode(nomt::WitnessMode::read_write()) + .overlay([&overlay_g]) + .unwrap(); + assert!(test.try_begin_session(params).is_ok()); +} diff --git a/nomt/tests/prev_root_check.rs b/nomt/tests/prev_root_check.rs index 031abf4784..995aaf6b1e 100644 --- a/nomt/tests/prev_root_check.rs +++ b/nomt/tests/prev_root_check.rs @@ -22,12 +22,12 @@ fn setup_nomt(path: &str) -> Nomt { #[test] fn test_prev_root_commits() { let nomt = setup_nomt("prev_root_commits"); - let session1 = nomt.begin_session(SessionParams::default()); + let session1 = nomt.begin_session(SessionParams::default()).unwrap(); let finished1 = session1 .finish(vec![([1; 32], KeyReadWrite::Write(Some(vec![1, 2, 3])))]) .unwrap(); - let session2 = nomt.begin_session(SessionParams::default()); + let session2 = nomt.begin_session(SessionParams::default()).unwrap(); let finished2 = session2 .finish(vec![([1; 32], KeyReadWrite::Write(Some(vec![1, 2, 3])))]) .unwrap(); @@ -40,13 +40,13 @@ fn test_prev_root_commits() { #[test] fn test_prev_root_overlay_invalidated() { let nomt = setup_nomt("prev_root_overlay_invalidated"); - let session1 = nomt.begin_session(SessionParams::default()); + let session1 = nomt.begin_session(SessionParams::default()).unwrap(); let finished1 = session1 .finish(vec![([1; 32], KeyReadWrite::Write(Some(vec![1, 2, 3])))]) .unwrap(); let overlay1 = finished1.into_overlay(); - let session2 = nomt.begin_session(SessionParams::default()); + let session2 = nomt.begin_session(SessionParams::default()).unwrap(); let finished2 = session2 .finish(vec![([1; 32], KeyReadWrite::Write(Some(vec![1, 2, 3])))]) .unwrap(); @@ -59,13 +59,13 @@ fn test_prev_root_overlay_invalidated() { #[test] fn test_prev_root_overlay_invalidates_session() { let nomt = setup_nomt("prev_root_overlays"); - let session1 = nomt.begin_session(SessionParams::default()); + let session1 = nomt.begin_session(SessionParams::default()).unwrap(); let finished1 = session1 .finish(vec![([1; 32], KeyReadWrite::Write(Some(vec![1, 2, 3])))]) .unwrap(); let overlay1 = finished1.into_overlay(); - let session2 = nomt.begin_session(SessionParams::default()); + let session2 = nomt.begin_session(SessionParams::default()).unwrap(); let finished2 = session2 .finish(vec![([1; 32], KeyReadWrite::Write(Some(vec![1, 2, 3])))]) .unwrap(); diff --git a/nomt/tests/rollback.rs b/nomt/tests/rollback.rs index a3216ca530..684953ab33 100644 --- a/nomt/tests/rollback.rs +++ b/nomt/tests/rollback.rs @@ -41,7 +41,7 @@ fn test_rollback_disabled() { /* should_clean_up */ true, ); - let session = nomt.begin_session(SessionParams::default()); + let session = nomt.begin_session(SessionParams::default()).unwrap(); let finished = session .finish(vec![( hex!("0000000000000000000000000000000000000000000000000000000000000001"), @@ -64,7 +64,7 @@ fn test_rollback_to_initial() { /* should_clean_up */ true, ); - let session = nomt.begin_session(SessionParams::default()); + let session = nomt.begin_session(SessionParams::default()).unwrap(); let finished = session .finish(vec![( hex!("0000000000000000000000000000000000000000000000000000000000000001"), @@ -181,7 +181,7 @@ impl TestPlan { "removing keys: {}", display_keys(to_remove[commit_no].iter()) ); - let session = nomt.begin_session(SessionParams::default()); + let session = nomt.begin_session(SessionParams::default()).unwrap(); let mut operations = Vec::new(); for (key, value) in to_insert[commit_no].iter() { operations.push((key.clone(), KeyReadWrite::Write(Some(value.clone())))); @@ -207,7 +207,7 @@ impl TestPlan { fn apply_forward(&self, nomt: &mut Nomt) { for commit_no in 0..self.to_insert.len() { - let session = nomt.begin_session(SessionParams::default()); + let session = nomt.begin_session(SessionParams::default()).unwrap(); let mut operations = Vec::new(); for (key, value) in self.to_insert[commit_no].iter() { operations.push((key.clone(), KeyReadWrite::Write(Some(value.clone())))); @@ -429,7 +429,7 @@ fn test_rollback_change_history() { plan.verify_restored_state(&mut nomt, 7); // 3. Create new commits - let session = nomt.begin_session(SessionParams::default()); + let session = nomt.begin_session(SessionParams::default()).unwrap(); let new_key = KeyPath::from([0xAA; 32]); let new_value = vec![0xBB; 32]; let finished = session @@ -464,7 +464,7 @@ fn test_rollback_read_then_write() { ); // Create a new key and write a value to it - let session = nomt.begin_session(SessionParams::default()); + let session = nomt.begin_session(SessionParams::default()).unwrap(); let key = KeyPath::from([0xAA; 32]); let original_value = vec![0xBB; 32]; let finished = session @@ -479,7 +479,7 @@ fn test_rollback_read_then_write() { // // The expected behavior is that the value from the ReadThenWrite operation takes precedence // over the original value. - let session = nomt.begin_session(SessionParams::default()); + let session = nomt.begin_session(SessionParams::default()).unwrap(); assert_eq!(session.read(key).unwrap(), Some(original_value.clone())); let new_value = vec![0xCC; 32]; let finished = session diff --git a/torture/src/agent.rs b/torture/src/agent.rs index f20c03682c..bed309d10a 100644 --- a/torture/src/agent.rs +++ b/torture/src/agent.rs @@ -318,7 +318,7 @@ impl Agent { let nomt = self.nomt.as_ref().unwrap(); assert!(self.session.is_none()); self.session - .replace(nomt.begin_session(SessionParams::default())); + .replace(nomt.begin_session(SessionParams::default()).unwrap()); } /// Read the specified keys from an already opened session, it requires