From 739864985035817235728e410502b3b3c45cd108 Mon Sep 17 00:00:00 2001 From: stringhandler Date: Tue, 26 May 2026 17:10:38 +0200 Subject: [PATCH 1/4] test: add witness pruning test verifying serialized output size --- src/lib.rs | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 9170b17a..f03fb7ae 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -981,6 +981,65 @@ pub(crate) mod tests { .assert_run_success(); } + #[test] + fn prune_removes_unused_witness_from_serialized_output() { + use crate::value::ValueConstructible; + // Program has three u8 witnesses: X, Y (true branch), Z (false branch). + // With X=1 the true branch is taken, so Z is in the pruned (non-executed) branch. + // + // Without pruning: all three witnesses are serialized → 3 bytes. + // With pruning: Z's node is gone from the DAG → 2 bytes. + let compiled = CompiledProgram::new( + std::borrow::Cow::Borrowed( + r#"fn main() { + let x: u8 = witness::X; + match jet::eq_8(x, 1) { + true => { let y: u8 = witness::Y; assert!(jet::eq_8(y, 2)); }, + false => { let z: u8 = witness::Z; assert!(jet::eq_8(z, 3)); }, + } +}"#, + ), + Arguments::default(), + false, + ) + .expect("program compiles"); + + let mut witnesses = std::collections::HashMap::new(); + witnesses.insert(crate::str::WitnessName::from_str_unchecked("X"), Value::u8(1)); + witnesses.insert(crate::str::WitnessName::from_str_unchecked("Y"), Value::u8(2)); + witnesses.insert(crate::str::WitnessName::from_str_unchecked("Z"), Value::u8(0)); + let witness_values = WitnessValues::from(witnesses); + + // Without pruning: all three witnesses (X, Y, Z) are serialized. + let unpruned = compiled + .satisfy(witness_values.shallow_clone()) + .expect("satisfy succeeds"); + let (_, unpruned_witness_bytes) = unpruned.redeem().to_vec_with_witness(); + assert_eq!( + unpruned_witness_bytes.len(), + 3, + "unpruned: expected 3 witness bytes (X + Z + Y), got {}", + unpruned_witness_bytes.len() + ); + + // With pruning: Z's node is removed from the DAG, leaving only X and Y. + let env = dummy_env::dummy_with( + elements::LockTime::ZERO, + elements::Sequence::MAX, + false, + ); + let pruned = compiled + .satisfy_with_env(witness_values, Some(&env)) + .expect("satisfy_with_env succeeds"); + let (_, pruned_witness_bytes) = pruned.redeem().to_vec_with_witness(); + assert_eq!( + pruned_witness_bytes.len(), + 2, + "pruned: expected 2 witness bytes (X + Y only), got {}", + pruned_witness_bytes.len() + ); + } + #[test] #[cfg(feature = "serde")] fn p2ms() { From b9174da556d485a96a4e0c8c0f6637dccdc10159 Mon Sep 17 00:00:00 2001 From: stringhandler Date: Mon, 8 Jun 2026 16:15:08 +0200 Subject: [PATCH 2/4] fix compile --- src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib.rs b/src/lib.rs index f03fb7ae..5430e30f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1001,6 +1001,7 @@ pub(crate) mod tests { ), Arguments::default(), false, + Box::new(ElementsJetHinter::new()), ) .expect("program compiles"); From 00c9bd376a04e1821e67ef276b016e197b5b3edf Mon Sep 17 00:00:00 2001 From: Andrew Cann Date: Mon, 3 Aug 2026 20:12:05 +0800 Subject: [PATCH 3/4] test: add another witness pruning test Add test prune_removes_unused_byte_of_u16_witness_from_serialized_output Also rename: prune_removes_unused_witness_from_serialized_output to: prune_removes_witness_in_unexecuted_match_branch_from_serialized_output --- src/lib.rs | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 5430e30f..e25face1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -982,7 +982,7 @@ pub(crate) mod tests { } #[test] - fn prune_removes_unused_witness_from_serialized_output() { + fn prune_removes_witness_in_unexecuted_match_branch_from_serialized_output() { use crate::value::ValueConstructible; // Program has three u8 witnesses: X, Y (true branch), Z (false branch). // With X=1 the true branch is taken, so Z is in the pruned (non-executed) branch. @@ -1041,6 +1041,60 @@ pub(crate) mod tests { ); } + #[test] + fn prune_removes_unused_byte_of_u16_witness_from_serialized_output() { + use crate::value::ValueConstructible; + // Program has a single u16 witness which is destructured into two u8s. Only the most + // significant byte is read so pruning should remove the least-significant byte. + let compiled = CompiledProgram::new( + std::borrow::Cow::Borrowed( + r#"fn main() { + let x: u16 = witness::X; + let (x1, x0) : (u8, u8) = ::into(x); + assert!(jet::eq_8(x1, 0x12)); +}"#, + ), + Arguments::default(), + false, + Box::new(ElementsJetHinter::new()), + ) + .expect("program compiles"); + + let mut witnesses = std::collections::HashMap::new(); + witnesses.insert(crate::str::WitnessName::from_str_unchecked("X"), Value::u16(0x1234)); + let witness_values = WitnessValues::from(witnesses); + + // Without pruning: both bytes of X are serialized. + let unpruned = compiled + .satisfy(witness_values.shallow_clone()) + .expect("satisfy succeeds"); + let (_, unpruned_witness_bytes) = unpruned.redeem().to_vec_with_witness(); + assert_eq!( + unpruned_witness_bytes.len(), + 2, + "unpruned: expected 2 witness bytes, got {}", + unpruned_witness_bytes.len() + ); + + // With pruning: the least significant byte of X is removed from the DAG leaving only a + // most significant byte. + let env = dummy_env::dummy_with( + elements::LockTime::ZERO, + elements::Sequence::MAX, + false, + ); + let pruned = compiled + .satisfy_with_env(witness_values, Some(&env)) + .expect("satisfy_with_env succeeds"); + let (_, pruned_witness_bytes) = pruned.redeem().to_vec_with_witness(); + assert_eq!( + pruned_witness_bytes.len(), + 1, + "pruned: expected 1 witness byte, got {}", + pruned_witness_bytes.len() + ); + } + #[test] #[cfg(feature = "serde")] fn p2ms() { From e41b5bab232f4835b7aaaf297a4f9f46490521a9 Mon Sep 17 00:00:00 2001 From: Andrew Cann Date: Mon, 3 Aug 2026 20:14:50 +0800 Subject: [PATCH 4/4] run cargo-fmt --- src/lib.rs | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index e25face1..e3739251 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1006,9 +1006,18 @@ pub(crate) mod tests { .expect("program compiles"); let mut witnesses = std::collections::HashMap::new(); - witnesses.insert(crate::str::WitnessName::from_str_unchecked("X"), Value::u8(1)); - witnesses.insert(crate::str::WitnessName::from_str_unchecked("Y"), Value::u8(2)); - witnesses.insert(crate::str::WitnessName::from_str_unchecked("Z"), Value::u8(0)); + witnesses.insert( + crate::str::WitnessName::from_str_unchecked("X"), + Value::u8(1), + ); + witnesses.insert( + crate::str::WitnessName::from_str_unchecked("Y"), + Value::u8(2), + ); + witnesses.insert( + crate::str::WitnessName::from_str_unchecked("Z"), + Value::u8(0), + ); let witness_values = WitnessValues::from(witnesses); // Without pruning: all three witnesses (X, Y, Z) are serialized. @@ -1024,11 +1033,7 @@ pub(crate) mod tests { ); // With pruning: Z's node is removed from the DAG, leaving only X and Y. - let env = dummy_env::dummy_with( - elements::LockTime::ZERO, - elements::Sequence::MAX, - false, - ); + let env = dummy_env::dummy_with(elements::LockTime::ZERO, elements::Sequence::MAX, false); let pruned = compiled .satisfy_with_env(witness_values, Some(&env)) .expect("satisfy_with_env succeeds"); @@ -1061,7 +1066,10 @@ pub(crate) mod tests { .expect("program compiles"); let mut witnesses = std::collections::HashMap::new(); - witnesses.insert(crate::str::WitnessName::from_str_unchecked("X"), Value::u16(0x1234)); + witnesses.insert( + crate::str::WitnessName::from_str_unchecked("X"), + Value::u16(0x1234), + ); let witness_values = WitnessValues::from(witnesses); // Without pruning: both bytes of X are serialized. @@ -1078,11 +1086,7 @@ pub(crate) mod tests { // With pruning: the least significant byte of X is removed from the DAG leaving only a // most significant byte. - let env = dummy_env::dummy_with( - elements::LockTime::ZERO, - elements::Sequence::MAX, - false, - ); + let env = dummy_env::dummy_with(elements::LockTime::ZERO, elements::Sequence::MAX, false); let pruned = compiled .satisfy_with_env(witness_values, Some(&env)) .expect("satisfy_with_env succeeds");