From: valued mammal Date: Tue, 19 Nov 2024 15:43:15 +0000 (-0500) Subject: test(core): test `Drop` implementation of `CPInner` X-Git-Tag: v1.0.0-beta.6~16^2 X-Git-Url: http://internal-gitweb-vhost/script/%22https:/struct.EncoderStringWriter.html?a=commitdiff_plain;h=2df5861c5e1bf308f1b215b19e00d882aee07e87;p=bdk test(core): test `Drop` implementation of `CPInner` Check that dropping `CheckPoint` does not cause nasty behavior by creating a large linked list in memory and then destroying it. --- diff --git a/crates/core/src/checkpoint.rs b/crates/core/src/checkpoint.rs index 9b5b0bbd..9bfdf2ee 100644 --- a/crates/core/src/checkpoint.rs +++ b/crates/core/src/checkpoint.rs @@ -38,7 +38,7 @@ impl Drop for CPInner { // that no recursive drop calls can happen even with multiple threads. match Arc::try_unwrap(arc_node).ok() { Some(mut node) => { - // Keep goign backwards + // Keep going backwards current = node.prev.take(); // Don't call `drop` on `CPInner` since that risks it becoming recursive. core::mem::forget(node); diff --git a/crates/core/tests/test_checkpoint.rs b/crates/core/tests/test_checkpoint.rs index 2ec96c15..a5194e5b 100644 --- a/crates/core/tests/test_checkpoint.rs +++ b/crates/core/tests/test_checkpoint.rs @@ -1,5 +1,5 @@ -use bdk_core::CheckPoint; -use bdk_testenv::block_id; +use bdk_core::{BlockId, CheckPoint}; +use bdk_testenv::{block_id, hash}; /// Inserting a block that already exists in the checkpoint chain must always succeed. #[test] @@ -32,3 +32,22 @@ fn checkpoint_insert_existing() { } } } + +#[test] +fn checkpoint_destruction_is_sound() { + // Prior to the fix in https://github.com/bitcoindevkit/bdk/pull/1731 + // this could have caused a stack overflow due to drop recursion in Arc. + // We test that a long linked list can clean itself up without blowing + // out the stack. + let mut cp = CheckPoint::new(BlockId { + height: 0, + hash: hash!("g"), + }); + let end = 10_000; + for height in 1u32..end { + let hash = bitcoin::hashes::Hash::hash(height.to_be_bytes().as_slice()); + let block = BlockId { height, hash }; + cp = cp.push(block).unwrap(); + } + assert_eq!(cp.iter().count() as u32, end); +}