Merge rust-bitcoin/rust-bitcoin#1380: `Witness` API improvements

d78a996bf6 Add `Witness::from_slice()` and depreciate `Witness:from_vec()` (Noah Lanson)
d5bdf5d225 Add non-generic `Witness::push_slice()` method (Noah Lanson)

Pull request description:

  Cleanup PR to improve the `Witness` API by:
  - Adding `Witness::from_slice()` and depreciating `Witness::from_vec()` methods (#1371).
  - Making `Witness::push()` not generic and take in `&[u8]` instead of `AsRef<[u8]>` (#1372).

  Note: `Witness::from_vec()` has been marked for depreciation from `0.30.0`. Let me know if this should be different.

ACKs for top commit:
  tcharding:
    ACK d78a996bf6
  apoelstra:
    ACK d78a996bf6

Tree-SHA512: 3a0b11b1ea77966a773cf7c9e9853822192897eac495fc0a23068bad3b0c46714fc839b20ceeb6e076aa10ea8ff0c023dfc418feff2f892cf11e8c057e5b0c7d
This commit is contained in:
Andrew Poelstra 2022-11-14 20:09:29 +00:00
commit 60f3a19acd
No known key found for this signature in database
GPG Key ID: C588D63CE41B97C1
3 changed files with 41 additions and 31 deletions

View File

@ -1396,7 +1396,7 @@ mod tests {
// test that we get a failure if we corrupt a signature
let mut witness: Vec<_> = spending.input[1].witness.to_vec();
witness[0][10] = 42;
spending.input[1].witness = Witness::from_vec(witness);
spending.input[1].witness = Witness::from_slice(&witness);
match spending.verify(|point: &OutPoint| {
if let Some(tx) = spent3.remove(&point.txid) {
return tx.output.get(point.vout as usize).cloned();

View File

@ -20,15 +20,16 @@ use crate::util::taproot::TAPROOT_ANNEX_PREFIX;
/// The Witness is the data used to unlock bitcoins since the [segwit upgrade](https://github.com/bitcoin/bips/blob/master/bip-0143.mediawiki)
///
/// Can be logically seen as an array of byte-arrays `Vec<Vec<u8>>` and indeed you can convert from
/// it [`Witness::from_vec`] and convert into it [`Witness::to_vec`].
/// Can be logically seen as an array of bytestrings, i.e. `Vec<Vec<u8>>`, and it is serialized on the wire
/// in that format. You can convert between this type and `Vec<Vec<u8>>` by using [`Witness::from_slice`]
/// and [`Witness::to_vec`].
///
/// For serialization and deserialization performance it is stored internally as a single `Vec`,
/// saving some allocations.
///
#[derive(Clone, Default, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
pub struct Witness {
/// contains the witness Vec<Vec<u8>> serialization without the initial varint indicating the
/// Contains the witness Vec<Vec<u8>> serialization without the initial varint indicating the
/// number of elements (which is stored in `witness_elements`)
content: Vec<u8>,
@ -167,26 +168,31 @@ impl Witness {
}
/// Creates [`Witness`] object from an array of byte-arrays
#[deprecated(since="0.30.0", note="use `Witness::from_slice()` instead")]
pub fn from_vec(vec: Vec<Vec<u8>>) -> Self {
let witness_elements = vec.len();
let index_size = witness_elements * 4;
Witness::from_slice(&vec)
}
let content_size: usize = vec
/// Creates a [`Witness`] object from a slice of bytes slices where each slice is a witness item.
pub fn from_slice<T: AsRef<[u8]>>(slice: &[T]) -> Self {
let witness_elements = slice.len();
let index_size = witness_elements * 4;
let content_size = slice
.iter()
.map(|el| el.len() + VarInt(el.len() as u64).len())
.map(|elem| elem.as_ref().len() + VarInt(elem.as_ref().len() as u64).len())
.sum();
let mut content = vec![0u8; content_size + index_size];
let mut cursor = 0usize;
for (i, el) in vec.into_iter().enumerate() {
for (i, elem) in slice.iter().enumerate() {
encode_cursor(&mut content, content_size, i, cursor);
let el_len_varint = VarInt(el.len() as u64);
el_len_varint
.consensus_encode(&mut &mut content[cursor..cursor + el_len_varint.len()])
let elem_len_varint = VarInt(elem.as_ref().len() as u64);
elem_len_varint
.consensus_encode(&mut &mut content[cursor..cursor + elem_len_varint.len()])
.expect("writers on vec don't errors, space granted by content_size");
cursor += el_len_varint.len();
content[cursor..cursor + el.len()].copy_from_slice(&el);
cursor += el.len();
cursor += elem_len_varint.len();
content[cursor..cursor + elem.as_ref().len()].copy_from_slice(elem.as_ref());
cursor += elem.as_ref().len();
}
Witness {
@ -237,7 +243,11 @@ impl Witness {
/// Push a new element on the witness, requires an allocation
pub fn push<T: AsRef<[u8]>>(&mut self, new_element: T) {
let new_element = new_element.as_ref();
self.push_slice(new_element.as_ref());
}
/// Push a new element slice onto the witness stack.
fn push_slice(&mut self, new_element: &[u8]) {
self.witness_elements += 1;
let previous_content_end = self.indices_start;
let element_len_varint = VarInt(new_element.len() as u64);
@ -434,7 +444,7 @@ impl<'de> serde::Deserialize<'de> for Witness {
})?;
ret.push(vec);
}
Ok(Witness::from_vec(ret))
Ok(Witness::from_slice(&ret))
}
}
@ -442,7 +452,7 @@ impl<'de> serde::Deserialize<'de> for Witness {
deserializer.deserialize_seq(Visitor)
} else {
let vec: Vec<Vec<u8>> = serde::Deserialize::deserialize(deserializer)?;
Ok(Witness::from_vec(vec))
Ok(Witness::from_slice(&vec))
}
}
}
@ -572,7 +582,7 @@ mod test {
assert_eq!(&witness[0], &w0[..]);
assert_eq!(&witness[1], &w1[..]);
let w_into = Witness::from_vec(witness_vec);
let w_into = Witness::from_slice(&witness_vec);
assert_eq!(w_into, witness);
assert_eq!(witness_serialized, serialize(&witness));
@ -646,7 +656,7 @@ mod test {
use bincode;
let old_witness_format = vec![vec![0u8], vec![2]];
let new_witness_format = Witness::from_vec(old_witness_format.clone());
let new_witness_format = Witness::from_slice(&old_witness_format);
let old = bincode::serialize(&old_witness_format).unwrap();
let new = bincode::serialize(&new_witness_format).unwrap();
@ -662,7 +672,7 @@ mod test {
fn test_serde_human() {
use serde_json;
let witness = Witness::from_vec(vec![vec![0u8, 123, 75], vec![2u8, 6, 3, 7, 8]]);
let witness = Witness::from_slice(&[vec![0u8, 123, 75], vec![2u8, 6, 3, 7, 8]]);
let json = serde_json::to_string(&witness).unwrap();
@ -681,8 +691,8 @@ mod benches {
#[bench]
pub fn bench_big_witness_to_vec(bh: &mut Bencher) {
let raw_witness = vec![vec![1u8]; 5];
let witness = Witness::from_vec(raw_witness);
let raw_witness = [[1u8]; 5];
let witness = Witness::from_slice(&raw_witness);
bh.iter(|| {
black_box(witness.to_vec());
@ -692,7 +702,7 @@ mod benches {
#[bench]
pub fn bench_witness_to_vec(bh: &mut Bencher) {
let raw_witness = vec![vec![1u8]; 3];
let witness = Witness::from_vec(raw_witness);
let witness = Witness::from_slice(&raw_witness);
bh.iter(|| {
black_box(witness.to_vec());

View File

@ -1058,7 +1058,7 @@ mod tests {
},
script_sig: hex_script!("160014be18d152a9b012039daf3da7de4f53349eecb985"),
sequence: Sequence::MAX,
witness: Witness::from_vec(vec![Vec::from_hex("03d2e15674941bad4a996372cb87e1856d3652606d98562fe39c5e9e7e413f2105").unwrap()]),
witness: Witness::from_slice(&[Vec::from_hex("03d2e15674941bad4a996372cb87e1856d3652606d98562fe39c5e9e7e413f2105").unwrap()]),
}],
output: vec![
TxOut {
@ -1117,7 +1117,7 @@ mod tests {
"304402204f67e2afb76142d44fae58a2495d33a3419daa26cd0db8d04f3452b63289ac0f022010762a9fb67e94cc5cad9026f6dc99ff7f070f4278d30fbc7d0c869dd38c7fe701".parse().unwrap(),
)].into_iter().collect(),
bip32_derivation: keypaths.clone(),
final_script_witness: Some(Witness::from_vec(vec![vec![1, 3], vec![5]])),
final_script_witness: Some(Witness::from_slice(&[vec![1, 3], vec![5]])),
ripemd160_preimages: vec![(ripemd160::Hash::hash(&[]), vec![1, 2])].into_iter().collect(),
sha256_preimages: vec![(sha256::Hash::hash(&[]), vec![1, 2])].into_iter().collect(),
hash160_preimages: vec![(hash160::Hash::hash(&[]), vec![1, 2])].into_iter().collect(),
@ -1279,7 +1279,7 @@ mod tests {
},
script_sig: hex_script!("160014be18d152a9b012039daf3da7de4f53349eecb985"),
sequence: Sequence::MAX,
witness: Witness::from_vec(vec![
witness: Witness::from_slice(&[
Vec::from_hex("304402202712be22e0270f394f568311dc7ca9a68970b8025fdd3b240229f07f8a5f3a240220018b38d7dcd314e734c9276bd6fb40f673325bc4baa144c800d2f2f02db2765c01").unwrap(),
Vec::from_hex("03d2e15674941bad4a996372cb87e1856d3652606d98562fe39c5e9e7e413f2105").unwrap(),
]),
@ -1293,7 +1293,7 @@ mod tests {
},
script_sig: hex_script!("160014fe3e9ef1a745e974d902c4355943abcb34bd5353"),
sequence: Sequence::MAX,
witness: Witness::from_vec(vec![
witness: Witness::from_slice(&[
Vec::from_hex("3045022100d12b852d85dcd961d2f5f4ab660654df6eedcc794c0c33ce5cc309ffb5fce58d022067338a8e0e1725c197fb1a88af59f51e44e4255b20167c8684031c05d1f2592a01").unwrap(),
Vec::from_hex("0223b72beef0965d10be0778efecd61fcac6f79a4ea169393380734464f84f2ab3").unwrap(),
]),
@ -1591,7 +1591,7 @@ mod tests {
},
script_sig: hex_script!("160014be18d152a9b012039daf3da7de4f53349eecb985"),
sequence: Sequence::MAX,
witness: Witness::from_vec(vec![
witness: Witness::from_slice(&[
Vec::from_hex("304402202712be22e0270f394f568311dc7ca9a68970b8025fdd3b240229f07f8a5f3a240220018b38d7dcd314e734c9276bd6fb40f673325bc4baa144c800d2f2f02db2765c01").unwrap(),
Vec::from_hex("03d2e15674941bad4a996372cb87e1856d3652606d98562fe39c5e9e7e413f2105").unwrap(),
]),
@ -1605,7 +1605,7 @@ mod tests {
},
script_sig: hex_script!("160014fe3e9ef1a745e974d902c4355943abcb34bd5353"),
sequence: Sequence::MAX,
witness: Witness::from_vec(vec![
witness: Witness::from_slice(&[
Vec::from_hex("3045022100d12b852d85dcd961d2f5f4ab660654df6eedcc794c0c33ce5cc309ffb5fce58d022067338a8e0e1725c197fb1a88af59f51e44e4255b20167c8684031c05d1f2592a01").unwrap(),
Vec::from_hex("0223b72beef0965d10be0778efecd61fcac6f79a4ea169393380734464f84f2ab3").unwrap(),
]),