Skip to content

Commit 143531d

Browse files
committed
Merge rust-bitcoin#4279: Witness api improvements and test cleanups
84bee2f Simplify `Witness` construction in tests (Martin Habovstiak) 3551ec2 Don't access internalls of `Witness` in tests (Martin Habovstiak) c807836 Impl `PartialEq` between `Witness` and containers (Martin Habovstiak) 587a66d Add a bunch of missing conversions for `Witness` (Martin Habovstiak) Pull request description: This is supposed to go in front of rust-bitcoin#4250 `Witness` lacked a bunch of APIs that were making it harder to use and test, so this also adds them in addition to cleaning up tests. (I only realized they are missing when I tried to clean up tests and got a bunch of errors.) ACKs for top commit: tcharding: ACK 84bee2f apoelstra: ACK 84bee2f; successfully ran local tests Tree-SHA512: 7973f2a56b070babba7b4c632f45858154ccd00f8e77956ad2d28cb66e1fd18ff60d92c031ba3b76d0958e4acd34adfca10607fa26ec569dfd52ba1c1e2c79eb
2 parents ecffb40 + 84bee2f commit 143531d

File tree

2 files changed

+182
-79
lines changed

2 files changed

+182
-79
lines changed

bitcoin/src/blockdata/witness.rs

Lines changed: 13 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -387,14 +387,8 @@ mod test {
387387
// annex starting with 0x50 causes the branching logic.
388388
let annex = hex!("50");
389389

390-
let witness_vec = vec![tapscript.clone(), control_block.clone()];
391-
let witness_vec_annex = vec![tapscript.clone(), control_block, annex];
392-
393-
let witness_serialized: Vec<u8> = serialize(&witness_vec);
394-
let witness_serialized_annex: Vec<u8> = serialize(&witness_vec_annex);
395-
396-
let witness = deserialize::<Witness>(&witness_serialized[..]).unwrap();
397-
let witness_annex = deserialize::<Witness>(&witness_serialized_annex[..]).unwrap();
390+
let witness = Witness::from([&*tapscript, &control_block]);
391+
let witness_annex = Witness::from([&*tapscript, &control_block, &annex]);
398392

399393
// With or without annex, the tapscript should be returned.
400394
assert_eq!(witness.tapscript(), Some(Script::from_bytes(&tapscript[..])));
@@ -409,14 +403,8 @@ mod test {
409403
// annex starting with 0x50 causes the branching logic.
410404
let annex = hex!("50");
411405

412-
let witness_vec = vec![tapscript.clone(), control_block.clone()];
413-
let witness_vec_annex = vec![tapscript.clone(), control_block, annex];
414-
415-
let witness_serialized: Vec<u8> = serialize(&witness_vec);
416-
let witness_serialized_annex: Vec<u8> = serialize(&witness_vec_annex);
417-
418-
let witness = deserialize::<Witness>(&witness_serialized[..]).unwrap();
419-
let witness_annex = deserialize::<Witness>(&witness_serialized_annex[..]).unwrap();
406+
let witness = Witness::from([&*tapscript, &control_block]);
407+
let witness_annex = Witness::from([&*tapscript, &control_block, &annex]);
420408

421409
let expected_leaf_script =
422410
LeafScript { version: LeafVersion::TapScript, script: Script::from_bytes(&tapscript) };
@@ -432,14 +420,8 @@ mod test {
432420
// annex starting with 0x50 causes the branching logic.
433421
let annex = hex!("50");
434422

435-
let witness_vec = vec![signature.clone()];
436-
let witness_vec_annex = vec![signature.clone(), annex];
437-
438-
let witness_serialized: Vec<u8> = serialize(&witness_vec);
439-
let witness_serialized_annex: Vec<u8> = serialize(&witness_vec_annex);
440-
441-
let witness = deserialize::<Witness>(&witness_serialized[..]).unwrap();
442-
let witness_annex = deserialize::<Witness>(&witness_serialized_annex[..]).unwrap();
423+
let witness = Witness::from([&*signature]);
424+
let witness_annex = Witness::from([&*signature, &annex]);
443425

444426
// With or without annex, no tapscript should be returned.
445427
assert_eq!(witness.tapscript(), None);
@@ -454,18 +436,9 @@ mod test {
454436
let annex = hex!("50");
455437
let signature = vec![0xff; 64];
456438

457-
let witness_vec = vec![tapscript.clone(), control_block.clone()];
458-
let witness_vec_annex = vec![tapscript.clone(), control_block.clone(), annex.clone()];
459-
let witness_vec_key_spend_annex = vec![signature, annex];
460-
461-
let witness_serialized: Vec<u8> = serialize(&witness_vec);
462-
let witness_serialized_annex: Vec<u8> = serialize(&witness_vec_annex);
463-
let witness_serialized_key_spend_annex: Vec<u8> = serialize(&witness_vec_key_spend_annex);
464-
465-
let witness = deserialize::<Witness>(&witness_serialized[..]).unwrap();
466-
let witness_annex = deserialize::<Witness>(&witness_serialized_annex[..]).unwrap();
467-
let witness_key_spend_annex =
468-
deserialize::<Witness>(&witness_serialized_key_spend_annex[..]).unwrap();
439+
let witness = Witness::from([&*tapscript, &control_block]);
440+
let witness_annex = Witness::from([&*tapscript, &control_block, &annex]);
441+
let witness_key_spend_annex = Witness::from([&*signature, &annex]);
469442

470443
// With or without annex, the tapscript should be returned.
471444
assert_eq!(witness.taproot_control_block(), Some(&control_block[..]));
@@ -480,14 +453,8 @@ mod test {
480453
// annex starting with 0x50 causes the branching logic.
481454
let annex = hex!("50");
482455

483-
let witness_vec = vec![tapscript.clone(), control_block.clone()];
484-
let witness_vec_annex = vec![tapscript.clone(), control_block.clone(), annex.clone()];
485-
486-
let witness_serialized: Vec<u8> = serialize(&witness_vec);
487-
let witness_serialized_annex: Vec<u8> = serialize(&witness_vec_annex);
488-
489-
let witness = deserialize::<Witness>(&witness_serialized[..]).unwrap();
490-
let witness_annex = deserialize::<Witness>(&witness_serialized_annex[..]).unwrap();
456+
let witness = Witness::from([&*tapscript, &control_block]);
457+
let witness_annex = Witness::from([&*tapscript, &control_block, &annex]);
491458

492459
// With or without annex, the tapscript should be returned.
493460
assert_eq!(witness.taproot_annex(), None);
@@ -498,14 +465,8 @@ mod test {
498465
// annex starting with 0x50 causes the branching logic.
499466
let annex = hex!("50");
500467

501-
let witness_vec = vec![signature.clone()];
502-
let witness_vec_annex = vec![signature.clone(), annex.clone()];
503-
504-
let witness_serialized: Vec<u8> = serialize(&witness_vec);
505-
let witness_serialized_annex: Vec<u8> = serialize(&witness_vec_annex);
506-
507-
let witness = deserialize::<Witness>(&witness_serialized[..]).unwrap();
508-
let witness_annex = deserialize::<Witness>(&witness_serialized_annex[..]).unwrap();
468+
let witness = Witness::from([&*signature]);
469+
let witness_annex = Witness::from([&*signature, &annex]);
509470

510471
// With or without annex, the tapscript should be returned.
511472
assert_eq!(witness.taproot_annex(), None);

primitives/src/witness.rs

Lines changed: 169 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use internals::compact_size;
1414
use internals::wrap_debug::WrapDebug;
1515
use internals::slice::SliceExt;
1616

17-
use crate::prelude::Vec;
17+
use crate::prelude::{Box, Vec};
1818

1919
/// The Witness is the data used to unlock bitcoin since the [SegWit upgrade].
2020
///
@@ -238,6 +238,109 @@ fn decode_cursor(bytes: &[u8], start_of_indices: usize, index: usize) -> Option<
238238
bytes.get_array::<4>(start).map(|index_bytes| u32::from_ne_bytes(*index_bytes) as usize)
239239
}
240240

241+
// Note: we use `Borrow` in the following `PartialEq` impls specifically because of its additional
242+
// constraints on equality semantics.
243+
impl<T: core::borrow::Borrow<[u8]>> PartialEq<[T]> for Witness {
244+
fn eq(&self, rhs: &[T]) -> bool {
245+
if self.len() != rhs.len() {
246+
return false;
247+
}
248+
self.iter().zip(rhs).all(|(left, right)| left == right.borrow())
249+
}
250+
}
251+
252+
impl<T: core::borrow::Borrow<[u8]>> PartialEq<&[T]> for Witness {
253+
fn eq(&self, rhs: &&[T]) -> bool {
254+
*self == **rhs
255+
}
256+
}
257+
258+
impl<T: core::borrow::Borrow<[u8]>> PartialEq<Witness> for [T] {
259+
fn eq(&self, rhs: &Witness) -> bool {
260+
*rhs == *self
261+
}
262+
}
263+
264+
impl<T: core::borrow::Borrow<[u8]>> PartialEq<Witness> for &[T] {
265+
fn eq(&self, rhs: &Witness) -> bool {
266+
*rhs == **self
267+
}
268+
}
269+
270+
impl<const N: usize, T: core::borrow::Borrow<[u8]>> PartialEq<[T; N]> for Witness {
271+
fn eq(&self, rhs: &[T; N]) -> bool {
272+
*self == *rhs.as_slice()
273+
}
274+
}
275+
276+
impl<const N: usize, T: core::borrow::Borrow<[u8]>> PartialEq<&[T; N]> for Witness {
277+
fn eq(&self, rhs: &&[T; N]) -> bool {
278+
*self == *rhs.as_slice()
279+
}
280+
}
281+
282+
impl<const N: usize, T: core::borrow::Borrow<[u8]>> PartialEq<Witness> for [T; N] {
283+
fn eq(&self, rhs: &Witness) -> bool {
284+
*rhs == *self
285+
}
286+
}
287+
288+
impl<const N: usize, T: core::borrow::Borrow<[u8]>> PartialEq<Witness> for &[T; N] {
289+
fn eq(&self, rhs: &Witness) -> bool {
290+
*rhs == **self
291+
}
292+
}
293+
294+
impl<T: core::borrow::Borrow<[u8]>> PartialEq<Vec<T>> for Witness {
295+
fn eq(&self, rhs: &Vec<T>) -> bool {
296+
*self == **rhs
297+
}
298+
}
299+
300+
impl<T: core::borrow::Borrow<[u8]>> PartialEq<Witness> for Vec<T> {
301+
fn eq(&self, rhs: &Witness) -> bool {
302+
*rhs == *self
303+
}
304+
}
305+
306+
impl<T: core::borrow::Borrow<[u8]>> PartialEq<Box<[T]>> for Witness {
307+
fn eq(&self, rhs: &Box<[T]>) -> bool {
308+
*self == **rhs
309+
}
310+
}
311+
312+
impl<T: core::borrow::Borrow<[u8]>> PartialEq<Witness> for Box<[T]> {
313+
fn eq(&self, rhs: &Witness) -> bool {
314+
*rhs == *self
315+
}
316+
}
317+
318+
impl<T: core::borrow::Borrow<[u8]>> PartialEq<alloc::rc::Rc<[T]>> for Witness {
319+
fn eq(&self, rhs: &alloc::rc::Rc<[T]>) -> bool {
320+
*self == **rhs
321+
}
322+
}
323+
324+
impl<T: core::borrow::Borrow<[u8]>> PartialEq<Witness> for alloc::rc::Rc<[T]> {
325+
fn eq(&self, rhs: &Witness) -> bool {
326+
*rhs == *self
327+
}
328+
}
329+
330+
#[cfg(target_has_atomic = "ptr")]
331+
impl<T: core::borrow::Borrow<[u8]>> PartialEq<alloc::sync::Arc<[T]>> for Witness {
332+
fn eq(&self, rhs: &alloc::sync::Arc<[T]>) -> bool {
333+
*self == **rhs
334+
}
335+
}
336+
337+
#[cfg(target_has_atomic = "ptr")]
338+
impl<T: core::borrow::Borrow<[u8]>> PartialEq<Witness> for alloc::sync::Arc<[T]> {
339+
fn eq(&self, rhs: &Witness) -> bool {
340+
*rhs == *self
341+
}
342+
}
343+
241344
/// Debug implementation that displays the witness as a structured output containing:
242345
/// - Number of witness elements
243346
/// - Total bytes across all elements
@@ -410,6 +513,46 @@ impl From<Vec<&[u8]>> for Witness {
410513
fn from(vec: Vec<&[u8]>) -> Self { Witness::from_slice(&vec) }
411514
}
412515

516+
impl<const N: usize> From<[&[u8]; N]> for Witness {
517+
#[inline]
518+
fn from(arr: [&[u8]; N]) -> Self { Witness::from_slice(&arr) }
519+
}
520+
521+
impl<const N: usize> From<&[&[u8]; N]> for Witness {
522+
#[inline]
523+
fn from(arr: &[&[u8]; N]) -> Self { Witness::from_slice(arr) }
524+
}
525+
526+
impl<const N: usize> From<&[[u8; N]]> for Witness {
527+
#[inline]
528+
fn from(slice: &[[u8; N]]) -> Self { Witness::from_slice(slice) }
529+
}
530+
531+
impl<const N: usize> From<&[&[u8; N]]> for Witness {
532+
#[inline]
533+
fn from(slice: &[&[u8; N]]) -> Self { Witness::from_slice(slice) }
534+
}
535+
536+
impl<const N: usize, const M: usize> From<[[u8; M]; N]> for Witness {
537+
#[inline]
538+
fn from(slice: [[u8; M]; N]) -> Self { Witness::from_slice(&slice) }
539+
}
540+
541+
impl<const N: usize, const M: usize> From<&[[u8; M]; N]> for Witness {
542+
#[inline]
543+
fn from(slice: &[[u8; M]; N]) -> Self { Witness::from_slice(slice) }
544+
}
545+
546+
impl<const N: usize, const M: usize> From<[&[u8; M]; N]> for Witness {
547+
#[inline]
548+
fn from(slice: [&[u8; M]; N]) -> Self { Witness::from_slice(&slice) }
549+
}
550+
551+
impl<const N: usize, const M: usize> From<&[&[u8; M]; N]> for Witness {
552+
#[inline]
553+
fn from(slice: &[&[u8; M]; N]) -> Self { Witness::from_slice(slice) }
554+
}
555+
413556
impl Default for Witness {
414557
#[inline]
415558
fn default() -> Self { Self::new() }
@@ -438,11 +581,7 @@ mod test {
438581

439582
// A witness with a single element that is empty (zero length).
440583
fn single_empty_element() -> Witness {
441-
// The first is 0 serialized as a compact size integer.
442-
// The last four bytes represent start at index 0.
443-
let content = [0_u8; 5];
444-
445-
Witness { witness_elements: 1, content: content.to_vec(), indices_start: 1 }
584+
Witness::from([[0u8; 0]])
446585
}
447586

448587
#[test]
@@ -477,13 +616,7 @@ mod test {
477616
witness.push(push);
478617
assert!(!witness.is_empty());
479618

480-
let elements = [1u8, 11];
481-
let expected = Witness {
482-
witness_elements: 1,
483-
content: append_u32_vec(&elements, &[0]), // Start at index 0.
484-
indices_start: elements.len(),
485-
};
486-
assert_eq!(witness, expected);
619+
assert_eq!(witness, [[11_u8]]);
487620

488621
let element_0 = push.as_slice();
489622
assert_eq!(element_0, &witness[0]);
@@ -500,13 +633,7 @@ mod test {
500633
let push = [21u8, 22u8];
501634
witness.push(push);
502635

503-
let elements = [1u8, 11, 2, 21, 22];
504-
let expected = Witness {
505-
witness_elements: 2,
506-
content: append_u32_vec(&elements, &[0, 2]),
507-
indices_start: elements.len(),
508-
};
509-
assert_eq!(witness, expected);
636+
assert_eq!(witness, [&[11_u8] as &[_], &[21, 22]]);
510637

511638
let element_1 = push.as_slice();
512639
assert_eq!(element_1, &witness[1]);
@@ -523,13 +650,7 @@ mod test {
523650
let push = [31u8, 32u8];
524651
witness.push(push);
525652

526-
let elements = [1u8, 11, 2, 21, 22, 2, 31, 32];
527-
let expected = Witness {
528-
witness_elements: 3,
529-
content: append_u32_vec(&elements, &[0, 2, 5]),
530-
indices_start: elements.len(),
531-
};
532-
assert_eq!(witness, expected);
653+
assert_eq!(witness, [&[11_u8] as &[_], &[21, 22], &[31, 32]]);
533654

534655
let element_2 = push.as_slice();
535656
assert_eq!(element_2, &witness[2]);
@@ -603,6 +724,27 @@ mod test {
603724
assert!(expected.is_empty());
604725
}
605726

727+
#[test]
728+
fn partial_eq() {
729+
const EMPTY_BYTES: &[u8] = &[];
730+
assert_eq!(Vec::<&[u8]>::new(), Witness::new());
731+
macro_rules! ck {
732+
($container:expr) => {
733+
{
734+
let container = $container;
735+
let witness = Witness::from(Clone::clone(&container));
736+
assert_eq!(witness, container, stringify!($container));
737+
}
738+
}
739+
}
740+
ck!([EMPTY_BYTES]);
741+
ck!([EMPTY_BYTES, EMPTY_BYTES]);
742+
ck!([[42]]);
743+
ck!([[42, 21]]);
744+
ck!([&[42], EMPTY_BYTES]);
745+
ck!([[42u8], [21]]);
746+
}
747+
606748
#[test]
607749
#[cfg(feature = "serde")]
608750
fn serde_bincode_backward_compatibility() {

0 commit comments

Comments
 (0)