Merge rust-bitcoin/rust-bitcoin#4279: `Witness` api improvements and test cleanups
84bee2f7b0
Simplify `Witness` construction in tests (Martin Habovstiak)3551ec2c69
Don't access internalls of `Witness` in tests (Martin Habovstiak)c8078360d2
Impl `PartialEq` between `Witness` and containers (Martin Habovstiak)587a66da47
Add a bunch of missing conversions for `Witness` (Martin Habovstiak) Pull request description: This is supposed to go in front of #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: ACK84bee2f7b0
apoelstra: ACK 84bee2f7b06a7bd1f435aaad18fa76a15188326e; successfully ran local tests Tree-SHA512: 7973f2a56b070babba7b4c632f45858154ccd00f8e77956ad2d28cb66e1fd18ff60d92c031ba3b76d0958e4acd34adfca10607fa26ec569dfd52ba1c1e2c79eb
This commit is contained in:
commit
143531de7c
|
@ -387,14 +387,8 @@ mod test {
|
|||
// annex starting with 0x50 causes the branching logic.
|
||||
let annex = hex!("50");
|
||||
|
||||
let witness_vec = vec![tapscript.clone(), control_block.clone()];
|
||||
let witness_vec_annex = vec![tapscript.clone(), control_block, annex];
|
||||
|
||||
let witness_serialized: Vec<u8> = serialize(&witness_vec);
|
||||
let witness_serialized_annex: Vec<u8> = serialize(&witness_vec_annex);
|
||||
|
||||
let witness = deserialize::<Witness>(&witness_serialized[..]).unwrap();
|
||||
let witness_annex = deserialize::<Witness>(&witness_serialized_annex[..]).unwrap();
|
||||
let witness = Witness::from([&*tapscript, &control_block]);
|
||||
let witness_annex = Witness::from([&*tapscript, &control_block, &annex]);
|
||||
|
||||
// With or without annex, the tapscript should be returned.
|
||||
assert_eq!(witness.tapscript(), Some(Script::from_bytes(&tapscript[..])));
|
||||
|
@ -409,14 +403,8 @@ mod test {
|
|||
// annex starting with 0x50 causes the branching logic.
|
||||
let annex = hex!("50");
|
||||
|
||||
let witness_vec = vec![tapscript.clone(), control_block.clone()];
|
||||
let witness_vec_annex = vec![tapscript.clone(), control_block, annex];
|
||||
|
||||
let witness_serialized: Vec<u8> = serialize(&witness_vec);
|
||||
let witness_serialized_annex: Vec<u8> = serialize(&witness_vec_annex);
|
||||
|
||||
let witness = deserialize::<Witness>(&witness_serialized[..]).unwrap();
|
||||
let witness_annex = deserialize::<Witness>(&witness_serialized_annex[..]).unwrap();
|
||||
let witness = Witness::from([&*tapscript, &control_block]);
|
||||
let witness_annex = Witness::from([&*tapscript, &control_block, &annex]);
|
||||
|
||||
let expected_leaf_script =
|
||||
LeafScript { version: LeafVersion::TapScript, script: Script::from_bytes(&tapscript) };
|
||||
|
@ -432,14 +420,8 @@ mod test {
|
|||
// annex starting with 0x50 causes the branching logic.
|
||||
let annex = hex!("50");
|
||||
|
||||
let witness_vec = vec![signature.clone()];
|
||||
let witness_vec_annex = vec![signature.clone(), annex];
|
||||
|
||||
let witness_serialized: Vec<u8> = serialize(&witness_vec);
|
||||
let witness_serialized_annex: Vec<u8> = serialize(&witness_vec_annex);
|
||||
|
||||
let witness = deserialize::<Witness>(&witness_serialized[..]).unwrap();
|
||||
let witness_annex = deserialize::<Witness>(&witness_serialized_annex[..]).unwrap();
|
||||
let witness = Witness::from([&*signature]);
|
||||
let witness_annex = Witness::from([&*signature, &annex]);
|
||||
|
||||
// With or without annex, no tapscript should be returned.
|
||||
assert_eq!(witness.tapscript(), None);
|
||||
|
@ -454,18 +436,9 @@ mod test {
|
|||
let annex = hex!("50");
|
||||
let signature = vec![0xff; 64];
|
||||
|
||||
let witness_vec = vec![tapscript.clone(), control_block.clone()];
|
||||
let witness_vec_annex = vec![tapscript.clone(), control_block.clone(), annex.clone()];
|
||||
let witness_vec_key_spend_annex = vec![signature, annex];
|
||||
|
||||
let witness_serialized: Vec<u8> = serialize(&witness_vec);
|
||||
let witness_serialized_annex: Vec<u8> = serialize(&witness_vec_annex);
|
||||
let witness_serialized_key_spend_annex: Vec<u8> = serialize(&witness_vec_key_spend_annex);
|
||||
|
||||
let witness = deserialize::<Witness>(&witness_serialized[..]).unwrap();
|
||||
let witness_annex = deserialize::<Witness>(&witness_serialized_annex[..]).unwrap();
|
||||
let witness_key_spend_annex =
|
||||
deserialize::<Witness>(&witness_serialized_key_spend_annex[..]).unwrap();
|
||||
let witness = Witness::from([&*tapscript, &control_block]);
|
||||
let witness_annex = Witness::from([&*tapscript, &control_block, &annex]);
|
||||
let witness_key_spend_annex = Witness::from([&*signature, &annex]);
|
||||
|
||||
// With or without annex, the tapscript should be returned.
|
||||
assert_eq!(witness.taproot_control_block(), Some(&control_block[..]));
|
||||
|
@ -480,14 +453,8 @@ mod test {
|
|||
// annex starting with 0x50 causes the branching logic.
|
||||
let annex = hex!("50");
|
||||
|
||||
let witness_vec = vec![tapscript.clone(), control_block.clone()];
|
||||
let witness_vec_annex = vec![tapscript.clone(), control_block.clone(), annex.clone()];
|
||||
|
||||
let witness_serialized: Vec<u8> = serialize(&witness_vec);
|
||||
let witness_serialized_annex: Vec<u8> = serialize(&witness_vec_annex);
|
||||
|
||||
let witness = deserialize::<Witness>(&witness_serialized[..]).unwrap();
|
||||
let witness_annex = deserialize::<Witness>(&witness_serialized_annex[..]).unwrap();
|
||||
let witness = Witness::from([&*tapscript, &control_block]);
|
||||
let witness_annex = Witness::from([&*tapscript, &control_block, &annex]);
|
||||
|
||||
// With or without annex, the tapscript should be returned.
|
||||
assert_eq!(witness.taproot_annex(), None);
|
||||
|
@ -498,14 +465,8 @@ mod test {
|
|||
// annex starting with 0x50 causes the branching logic.
|
||||
let annex = hex!("50");
|
||||
|
||||
let witness_vec = vec![signature.clone()];
|
||||
let witness_vec_annex = vec![signature.clone(), annex.clone()];
|
||||
|
||||
let witness_serialized: Vec<u8> = serialize(&witness_vec);
|
||||
let witness_serialized_annex: Vec<u8> = serialize(&witness_vec_annex);
|
||||
|
||||
let witness = deserialize::<Witness>(&witness_serialized[..]).unwrap();
|
||||
let witness_annex = deserialize::<Witness>(&witness_serialized_annex[..]).unwrap();
|
||||
let witness = Witness::from([&*signature]);
|
||||
let witness_annex = Witness::from([&*signature, &annex]);
|
||||
|
||||
// With or without annex, the tapscript should be returned.
|
||||
assert_eq!(witness.taproot_annex(), None);
|
||||
|
|
|
@ -14,7 +14,7 @@ use internals::compact_size;
|
|||
use internals::wrap_debug::WrapDebug;
|
||||
use internals::slice::SliceExt;
|
||||
|
||||
use crate::prelude::Vec;
|
||||
use crate::prelude::{Box, Vec};
|
||||
|
||||
/// The Witness is the data used to unlock bitcoin since the [SegWit upgrade].
|
||||
///
|
||||
|
@ -238,6 +238,109 @@ fn decode_cursor(bytes: &[u8], start_of_indices: usize, index: usize) -> Option<
|
|||
bytes.get_array::<4>(start).map(|index_bytes| u32::from_ne_bytes(*index_bytes) as usize)
|
||||
}
|
||||
|
||||
// Note: we use `Borrow` in the following `PartialEq` impls specifically because of its additional
|
||||
// constraints on equality semantics.
|
||||
impl<T: core::borrow::Borrow<[u8]>> PartialEq<[T]> for Witness {
|
||||
fn eq(&self, rhs: &[T]) -> bool {
|
||||
if self.len() != rhs.len() {
|
||||
return false;
|
||||
}
|
||||
self.iter().zip(rhs).all(|(left, right)| left == right.borrow())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: core::borrow::Borrow<[u8]>> PartialEq<&[T]> for Witness {
|
||||
fn eq(&self, rhs: &&[T]) -> bool {
|
||||
*self == **rhs
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: core::borrow::Borrow<[u8]>> PartialEq<Witness> for [T] {
|
||||
fn eq(&self, rhs: &Witness) -> bool {
|
||||
*rhs == *self
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: core::borrow::Borrow<[u8]>> PartialEq<Witness> for &[T] {
|
||||
fn eq(&self, rhs: &Witness) -> bool {
|
||||
*rhs == **self
|
||||
}
|
||||
}
|
||||
|
||||
impl<const N: usize, T: core::borrow::Borrow<[u8]>> PartialEq<[T; N]> for Witness {
|
||||
fn eq(&self, rhs: &[T; N]) -> bool {
|
||||
*self == *rhs.as_slice()
|
||||
}
|
||||
}
|
||||
|
||||
impl<const N: usize, T: core::borrow::Borrow<[u8]>> PartialEq<&[T; N]> for Witness {
|
||||
fn eq(&self, rhs: &&[T; N]) -> bool {
|
||||
*self == *rhs.as_slice()
|
||||
}
|
||||
}
|
||||
|
||||
impl<const N: usize, T: core::borrow::Borrow<[u8]>> PartialEq<Witness> for [T; N] {
|
||||
fn eq(&self, rhs: &Witness) -> bool {
|
||||
*rhs == *self
|
||||
}
|
||||
}
|
||||
|
||||
impl<const N: usize, T: core::borrow::Borrow<[u8]>> PartialEq<Witness> for &[T; N] {
|
||||
fn eq(&self, rhs: &Witness) -> bool {
|
||||
*rhs == **self
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: core::borrow::Borrow<[u8]>> PartialEq<Vec<T>> for Witness {
|
||||
fn eq(&self, rhs: &Vec<T>) -> bool {
|
||||
*self == **rhs
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: core::borrow::Borrow<[u8]>> PartialEq<Witness> for Vec<T> {
|
||||
fn eq(&self, rhs: &Witness) -> bool {
|
||||
*rhs == *self
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: core::borrow::Borrow<[u8]>> PartialEq<Box<[T]>> for Witness {
|
||||
fn eq(&self, rhs: &Box<[T]>) -> bool {
|
||||
*self == **rhs
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: core::borrow::Borrow<[u8]>> PartialEq<Witness> for Box<[T]> {
|
||||
fn eq(&self, rhs: &Witness) -> bool {
|
||||
*rhs == *self
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: core::borrow::Borrow<[u8]>> PartialEq<alloc::rc::Rc<[T]>> for Witness {
|
||||
fn eq(&self, rhs: &alloc::rc::Rc<[T]>) -> bool {
|
||||
*self == **rhs
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: core::borrow::Borrow<[u8]>> PartialEq<Witness> for alloc::rc::Rc<[T]> {
|
||||
fn eq(&self, rhs: &Witness) -> bool {
|
||||
*rhs == *self
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_has_atomic = "ptr")]
|
||||
impl<T: core::borrow::Borrow<[u8]>> PartialEq<alloc::sync::Arc<[T]>> for Witness {
|
||||
fn eq(&self, rhs: &alloc::sync::Arc<[T]>) -> bool {
|
||||
*self == **rhs
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_has_atomic = "ptr")]
|
||||
impl<T: core::borrow::Borrow<[u8]>> PartialEq<Witness> for alloc::sync::Arc<[T]> {
|
||||
fn eq(&self, rhs: &Witness) -> bool {
|
||||
*rhs == *self
|
||||
}
|
||||
}
|
||||
|
||||
/// Debug implementation that displays the witness as a structured output containing:
|
||||
/// - Number of witness elements
|
||||
/// - Total bytes across all elements
|
||||
|
@ -410,6 +513,46 @@ impl From<Vec<&[u8]>> for Witness {
|
|||
fn from(vec: Vec<&[u8]>) -> Self { Witness::from_slice(&vec) }
|
||||
}
|
||||
|
||||
impl<const N: usize> From<[&[u8]; N]> for Witness {
|
||||
#[inline]
|
||||
fn from(arr: [&[u8]; N]) -> Self { Witness::from_slice(&arr) }
|
||||
}
|
||||
|
||||
impl<const N: usize> From<&[&[u8]; N]> for Witness {
|
||||
#[inline]
|
||||
fn from(arr: &[&[u8]; N]) -> Self { Witness::from_slice(arr) }
|
||||
}
|
||||
|
||||
impl<const N: usize> From<&[[u8; N]]> for Witness {
|
||||
#[inline]
|
||||
fn from(slice: &[[u8; N]]) -> Self { Witness::from_slice(slice) }
|
||||
}
|
||||
|
||||
impl<const N: usize> From<&[&[u8; N]]> for Witness {
|
||||
#[inline]
|
||||
fn from(slice: &[&[u8; N]]) -> Self { Witness::from_slice(slice) }
|
||||
}
|
||||
|
||||
impl<const N: usize, const M: usize> From<[[u8; M]; N]> for Witness {
|
||||
#[inline]
|
||||
fn from(slice: [[u8; M]; N]) -> Self { Witness::from_slice(&slice) }
|
||||
}
|
||||
|
||||
impl<const N: usize, const M: usize> From<&[[u8; M]; N]> for Witness {
|
||||
#[inline]
|
||||
fn from(slice: &[[u8; M]; N]) -> Self { Witness::from_slice(slice) }
|
||||
}
|
||||
|
||||
impl<const N: usize, const M: usize> From<[&[u8; M]; N]> for Witness {
|
||||
#[inline]
|
||||
fn from(slice: [&[u8; M]; N]) -> Self { Witness::from_slice(&slice) }
|
||||
}
|
||||
|
||||
impl<const N: usize, const M: usize> From<&[&[u8; M]; N]> for Witness {
|
||||
#[inline]
|
||||
fn from(slice: &[&[u8; M]; N]) -> Self { Witness::from_slice(slice) }
|
||||
}
|
||||
|
||||
impl Default for Witness {
|
||||
#[inline]
|
||||
fn default() -> Self { Self::new() }
|
||||
|
@ -438,11 +581,7 @@ mod test {
|
|||
|
||||
// A witness with a single element that is empty (zero length).
|
||||
fn single_empty_element() -> Witness {
|
||||
// The first is 0 serialized as a compact size integer.
|
||||
// The last four bytes represent start at index 0.
|
||||
let content = [0_u8; 5];
|
||||
|
||||
Witness { witness_elements: 1, content: content.to_vec(), indices_start: 1 }
|
||||
Witness::from([[0u8; 0]])
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -477,13 +616,7 @@ mod test {
|
|||
witness.push(push);
|
||||
assert!(!witness.is_empty());
|
||||
|
||||
let elements = [1u8, 11];
|
||||
let expected = Witness {
|
||||
witness_elements: 1,
|
||||
content: append_u32_vec(&elements, &[0]), // Start at index 0.
|
||||
indices_start: elements.len(),
|
||||
};
|
||||
assert_eq!(witness, expected);
|
||||
assert_eq!(witness, [[11_u8]]);
|
||||
|
||||
let element_0 = push.as_slice();
|
||||
assert_eq!(element_0, &witness[0]);
|
||||
|
@ -500,13 +633,7 @@ mod test {
|
|||
let push = [21u8, 22u8];
|
||||
witness.push(push);
|
||||
|
||||
let elements = [1u8, 11, 2, 21, 22];
|
||||
let expected = Witness {
|
||||
witness_elements: 2,
|
||||
content: append_u32_vec(&elements, &[0, 2]),
|
||||
indices_start: elements.len(),
|
||||
};
|
||||
assert_eq!(witness, expected);
|
||||
assert_eq!(witness, [&[11_u8] as &[_], &[21, 22]]);
|
||||
|
||||
let element_1 = push.as_slice();
|
||||
assert_eq!(element_1, &witness[1]);
|
||||
|
@ -523,13 +650,7 @@ mod test {
|
|||
let push = [31u8, 32u8];
|
||||
witness.push(push);
|
||||
|
||||
let elements = [1u8, 11, 2, 21, 22, 2, 31, 32];
|
||||
let expected = Witness {
|
||||
witness_elements: 3,
|
||||
content: append_u32_vec(&elements, &[0, 2, 5]),
|
||||
indices_start: elements.len(),
|
||||
};
|
||||
assert_eq!(witness, expected);
|
||||
assert_eq!(witness, [&[11_u8] as &[_], &[21, 22], &[31, 32]]);
|
||||
|
||||
let element_2 = push.as_slice();
|
||||
assert_eq!(element_2, &witness[2]);
|
||||
|
@ -603,6 +724,27 @@ mod test {
|
|||
assert!(expected.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn partial_eq() {
|
||||
const EMPTY_BYTES: &[u8] = &[];
|
||||
assert_eq!(Vec::<&[u8]>::new(), Witness::new());
|
||||
macro_rules! ck {
|
||||
($container:expr) => {
|
||||
{
|
||||
let container = $container;
|
||||
let witness = Witness::from(Clone::clone(&container));
|
||||
assert_eq!(witness, container, stringify!($container));
|
||||
}
|
||||
}
|
||||
}
|
||||
ck!([EMPTY_BYTES]);
|
||||
ck!([EMPTY_BYTES, EMPTY_BYTES]);
|
||||
ck!([[42]]);
|
||||
ck!([[42, 21]]);
|
||||
ck!([&[42], EMPTY_BYTES]);
|
||||
ck!([[42u8], [21]]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "serde")]
|
||||
fn serde_bincode_backward_compatibility() {
|
||||
|
|
Loading…
Reference in New Issue