Skip to content

Commit 0b8fa43

Browse files
committed
transaction: strongly type script_witness
Just copy witness.rs from rust-bitcoin aeadac41b45a170beddbdbea8ada3d1621f09e7c, remove the alloc/std gates, and remove the LowerHex/UpperHex impls for which we need the private `HexPrimitive` type from bitcoin-primitives. Also fix the witness encoder to be exact-sized; see rust-bitcoin/rust-bitcoin#6426
1 parent 9f82b4b commit 0b8fa43

11 files changed

Lines changed: 1798 additions & 24 deletions

File tree

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ match_bool = "allow" # Adds extra indentation and LOC.
7474
match_same_arms = "allow" # Collapses things that are conceptually unrelated to each other.
7575
must_use_candidate = "allow" # Useful for audit but many false positives.
7676
similar_names = "allow" # Too many (subjectively) false positives.
77+
struct_field_names = "allow" # Dumb
7778
# Exhaustive list of pedantic clippy lints
7879
assigning_clones = "warn"
7980
bool_to_int_with_if = "warn"
@@ -168,7 +169,6 @@ stable_sort_primitive = "warn"
168169
str_split_at_newline = "warn"
169170
string_add_assign = "warn"
170171
struct_excessive_bools = "warn"
171-
struct_field_names = "warn"
172172
too_many_lines = "allow" # FIXME 14 triggers for this lint; probably most should be fixed
173173
transmute_ptr_to_ptr = "warn"
174174
trivially_copy_pass_by_ref = "warn"

elementsd-tests/src/taproot.rs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,7 @@ fn taproot_spend_test(
223223
hash_ty: sighash_ty,
224224
};
225225

226-
tx.input[0].witness.script_witness = vec![schnorr_sig.to_vec()];
226+
tx.input[0].witness.script_witness.push(schnorr_sig.to_vec());
227227
} else {
228228
// script spend
229229
// try spending using leaf1
@@ -250,11 +250,9 @@ fn taproot_spend_test(
250250
hash_ty: sighash_ty,
251251
};
252252

253-
tx.input[0].witness.script_witness = vec![
254-
schnorr_sig.to_vec(), // witness
255-
script_ver.0.into_bytes(), // leaf script
256-
ctrl_block.serialize(), // control block
257-
];
253+
tx.input[0].witness.script_witness.push(schnorr_sig.to_vec()); // witness
254+
tx.input[0].witness.script_witness.push(script_ver.0.into_bytes()); // leaf script
255+
tx.input[0].witness.script_witness.push(ctrl_block.serialize()); // control block
258256
}
259257

260258
let tx_hex = serialize_hex(&tx);

examples/raw_blind.rs

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -305,15 +305,13 @@ fn main() {
305305

306306
// Finalize(TODO in miniscript)
307307
pset.inputs_mut()[0].partial_sigs.clear();
308-
pset.inputs_mut()[0].final_script_witness = Some(vec![
309-
inp0_sig,
310-
inp0_pk.to_bytes(),
311-
]);
308+
let wit = pset.inputs_mut()[0].final_script_witness.insert(elements::Witness::new());
309+
wit.push(inp0_sig);
310+
wit.push(inp0_pk.to_bytes());
312311
pset.inputs_mut()[1].partial_sigs.clear();
313-
pset.inputs_mut()[1].final_script_witness = Some(vec![
314-
inp1_sig,
315-
inp1_pk.to_bytes(),
316-
]);
312+
let wit = pset.inputs_mut()[1].final_script_witness.insert(elements::Witness::new());
313+
wit.push(inp1_sig);
314+
wit.push(inp1_pk.to_bytes());
317315
assert_eq!(pset, deser_pset(&tests["finalized"]));
318316

319317
// Extracted tx

src/encode.rs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,27 @@ pub use bitcoin::{self, consensus::encode::MAX_VEC_SIZE};
2929

3030
use crate::taproot::TapLeafHash;
3131

32+
struct ByteCounter<W> {
33+
inner: W,
34+
count: usize,
35+
}
36+
37+
impl<W> io::Write for ByteCounter<W>
38+
where W: io::Write
39+
{
40+
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
41+
let res = self.inner.write(buf);
42+
if let Ok(size) = res {
43+
self.count += size;
44+
}
45+
res
46+
}
47+
48+
fn flush(&mut self) -> io::Result<()> {
49+
self.inner.flush()
50+
}
51+
}
52+
3253
/// Encoding error
3354
#[derive(Debug)]
3455
pub enum Error {
@@ -63,6 +84,8 @@ pub enum Error {
6384
BadLockTime(crate::LockTime),
6485
/// `VarInt` was encoded in a non-minimal way.
6586
NonMinimalVarInt,
87+
/// Error decoding a transaction witness.
88+
Witness(crate::WitnessDecoderError),
6689
}
6790

6891
impl fmt::Display for Error {
@@ -90,6 +113,7 @@ impl fmt::Display for Error {
90113
Error::HexVariableError(ref e) => write!(f, "Hex variable error: {}", e),
91114
Error::BadLockTime(ref lt) => write!(f, "Invalid locktime {}", lt),
92115
Error::NonMinimalVarInt => write!(f, "non-minimal varint"),
116+
Self::Witness(..) => f.write_str("error decoding witness"),
93117
}
94118
}
95119
}
@@ -98,6 +122,7 @@ impl error::Error for Error {
98122
fn cause(&self) -> Option<&dyn error::Error> {
99123
match *self {
100124
Error::Secp256k1zkp(ref e) => Some(e),
125+
Self::Witness(ref e) => Some(e),
101126
_ => None,
102127
}
103128
}
@@ -240,6 +265,24 @@ impl Decodable for crate::locktime::Time {
240265
}
241266
}
242267

268+
impl Encodable for crate::Witness {
269+
fn consensus_encode<W: io::Write>(&self, e: W) -> Result<usize, Error> {
270+
let mut counter = ByteCounter { inner: e, count: 0 };
271+
crate::encoding::encode_to_writer(self, &mut counter)?;
272+
Ok(counter.count)
273+
}
274+
}
275+
276+
impl Decodable for crate::Witness {
277+
fn consensus_decode<D: io::Read>(d: D) -> Result<Self, Error> {
278+
match crate::encoding::decode_from_read_unbuffered(d) {
279+
Ok(wit) => Ok(wit),
280+
Err(crate::encoding::ReadError::Io(e)) => Err(Error::Io(e)),
281+
Err(crate::encoding::ReadError::Decode(e)) => Err(Error::Witness(e)),
282+
}
283+
}
284+
}
285+
243286
/// A variable sized integer.
244287
pub struct VarInt(pub u64);
245288
impl Encodable for VarInt {

src/lib.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,8 @@ mod endian;
7777
pub mod genesis;
7878

7979
// export everything at the top level so it can be used as `elements::Transaction` etc.
80+
use internals::array_vec::ArrayVec;
81+
8082
pub use crate::address::{Address, AddressError, AddressParams};
8183
pub use crate::blind::{
8284
BlindError, ConfidentialTxOutError, CtLocation, CtLocationType, RangeProofMessage,
@@ -94,5 +96,13 @@ pub use crate::script::Script;
9496
pub use crate::sighash::SchnorrSighashType;
9597
pub use crate::transaction::{
9698
AssetIssuance, EcdsaSighashType, OutPoint, PeginData, PegoutData, Sequence, Transaction, TxIn,
97-
TxInWitness, TxOut, TxOutWitness,
99+
TxInWitness, TxOut, TxOutWitness, Witness, WitnessDecoder, WitnessDecoderError, WitnessEncoder,
98100
};
101+
102+
// Encode a compact size to a slice without allocating
103+
pub(crate) fn compact_size_encode(value: usize) -> ArrayVec<u8, 9> {
104+
use crate::encoding::Encoder as _;
105+
106+
let encoder = encoding::CompactSizeEncoder::new(value);
107+
ArrayVec::from_slice(encoder.current_chunk())
108+
}

src/pset/map/input.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@ pub struct Input {
199199
pub final_script_sig: Option<Script>,
200200
/// The finalized, fully-constructed scriptWitness with signatures and any
201201
/// other scripts necessary for this input to pass validation.
202-
pub final_script_witness: Option<Vec<Vec<u8>>>,
202+
pub final_script_witness: Option<crate::Witness>,
203203
/// TODO: Proof of reserves commitment
204204
/// RIPEMD160 hash to preimage map
205205
pub ripemd160_preimages: BTreeMap<ripemd160::Hash, Vec<u8>>,
@@ -627,7 +627,7 @@ impl Map for Input {
627627
}
628628
PSET_IN_FINAL_SCRIPTWITNESS => {
629629
impl_pset_insert_pair! {
630-
self.final_script_witness <= <raw_key: _>|<raw_value: Vec<Vec<u8>>>
630+
self.final_script_witness <= <raw_key: _>|<raw_value: crate::Witness>
631631
}
632632
}
633633
PSET_IN_RIPEMD160 => {

src/pset/mod.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -306,8 +306,7 @@ impl PartiallySignedTransaction {
306306
.unwrap_or(RangeProof::EMPTY),
307307
script_witness: psetin
308308
.final_script_witness
309-
.as_ref()
310-
.map(Vec::to_owned)
309+
.clone()
311310
.unwrap_or_default(),
312311
pegin_witness: psetin
313312
.pegin_witness

src/pset/serialize.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,8 @@ impl_pset_de_serialize!(crate::Sequence);
6868
impl_pset_de_serialize!(crate::locktime::Height);
6969
impl_pset_de_serialize!(crate::locktime::Time);
7070
impl_pset_de_serialize!([u8; 32]);
71-
impl_pset_de_serialize!(Vec<Vec<u8>>); // scriptWitness
71+
impl_pset_de_serialize!(Vec<Vec<u8>>); // peginWitness
72+
impl_pset_de_serialize!(crate::Witness); // scriptWitness
7273
impl_pset_hash_de_serialize!(Txid);
7374
impl_pset_hash_de_serialize!(ripemd160::Hash);
7475
impl_pset_hash_de_serialize!(sha256::Hash);

src/sighash.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -831,7 +831,7 @@ impl<R: DerefMut<Target = Transaction>> SighashCache<R> {
831831
/// sig_hasher.witness_mut(inp).unwrap().push(Vec::new());
832832
/// }
833833
/// ```
834-
pub fn witness_mut(&mut self, input_index: usize) -> Option<&mut Vec<Vec<u8>>> {
834+
pub fn witness_mut(&mut self, input_index: usize) -> Option<&mut crate::Witness> {
835835
self.tx.input.get_mut(input_index).map(|i| &mut i.witness.script_witness)
836836
}
837837
}

src/transaction/mod.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
//! # Transactions
1616
//!
1717
18+
mod witness;
19+
1820
use std::{io, fmt, str, cmp};
1921
use std::collections::HashMap;
2022
use std::convert::TryFrom;
@@ -35,6 +37,8 @@ use secp256k1_zkp::{
3537
Tweak, ZERO_TWEAK,
3638
};
3739

40+
pub use self::witness::{Witness, WitnessDecoder, WitnessDecoderError, WitnessEncoder};
41+
3842
/// Description of an asset issuance in a transaction input
3943
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
4044
pub struct AssetIssuance {
@@ -365,7 +369,7 @@ pub struct TxInWitness {
365369
/// Rangeproof for inflation keys
366370
pub inflation_keys_rangeproof: RangeProof,
367371
/// Traditional script witness
368-
pub script_witness: Vec<Vec<u8>>,
372+
pub script_witness: Witness,
369373
/// Pegin witness, basically the same thing
370374
pub pegin_witness: Vec<Vec<u8>>,
371375
}
@@ -377,7 +381,7 @@ impl TxInWitness {
377381
TxInWitness {
378382
amount_rangeproof: RangeProof::EMPTY,
379383
inflation_keys_rangeproof: RangeProof::EMPTY,
380-
script_witness: Vec::new(),
384+
script_witness: Witness::new(),
381385
pegin_witness: Vec::new(),
382386
}
383387
}

0 commit comments

Comments
 (0)