Skip to content

Commit b7b5886

Browse files
committed
implement Encode/Decode for TxInWitness
1 parent d72094a commit b7b5886

4 files changed

Lines changed: 185 additions & 6 deletions

File tree

src/lib.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -99,9 +99,10 @@ pub use crate::transaction::{
9999
EcdsaSighashType, OutPoint, PeginData, PeginDataDecoder, PeginDataEncoder, PeginWitness,
100100
PeginWitnessDecoder, PeginWitnessDecoderError, PeginWitnessEncoder, PegoutData, Sequence,
101101
SequenceDecoder, SequenceDecoderError, SequenceEncoder, Transaction, TxIn, TxInDecoder,
102-
TxInDecoderError, TxInEncoder, TxInWitness, TxOut, TxOutDecoder, TxOutDecoderError,
103-
TxOutEncoder, TxOutWitness, TxOutWitnessDecoder, TxOutWitnessDecoderError, TxOutWitnessEncoder,
104-
Witness, WitnessDecoder, WitnessDecoderError, WitnessEncoder,
102+
TxInDecoderError, TxInEncoder, TxInWitness, TxInWitnessDecoder, TxInWitnessDecoderError,
103+
TxInWitnessEncoder, TxOut, TxOutDecoder, TxOutDecoderError, TxOutEncoder, TxOutWitness,
104+
TxOutWitnessDecoder, TxOutWitnessDecoderError, TxOutWitnessEncoder, Witness, WitnessDecoder,
105+
WitnessDecoderError, WitnessEncoder,
105106
};
106107

107108
// Encode a compact size to a slice without allocating

src/transaction/decoders.rs

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,12 @@ use core::fmt;
1010
use super::{
1111
AssetIssuance, OutPoint, Script, Sequence, TxIn, TxInWitness, TxOut, TxOutWitness, Txid,
1212
};
13+
use crate::confidential::{RangeProofDecoder, RangeProofDecoderError};
1314
use crate::encoding::{
1415
ArrayDecoder, Decode, Decoder, Decoder2, Decoder2Error, Decoder3, Decoder4, Decoder4Error,
1516
DecoderStatus, UnexpectedEofError,
1617
};
18+
use crate::{PeginWitnessDecoder, PeginWitnessDecoderError, WitnessDecoder, WitnessDecoderError};
1719

1820
/// Decoder for the [`OutPoint`] type.
1921
///
@@ -223,6 +225,113 @@ impl std::error::Error for TxInDecoderError {
223225
}
224226
}
225227

228+
/// Decoder for the [`TxInWitness`] type.
229+
#[derive(Default)]
230+
pub struct TxInWitnessDecoder {
231+
inner: Decoder4<RangeProofDecoder, RangeProofDecoder, WitnessDecoder, PeginWitnessDecoder>,
232+
}
233+
234+
/// Decoder error for the [`TxInWitness`] type.
235+
#[derive(Clone, PartialEq, Eq, Debug)]
236+
pub struct TxInWitnessDecoderError(
237+
Decoder4Error<
238+
RangeProofDecoderError,
239+
RangeProofDecoderError,
240+
WitnessDecoderError,
241+
PeginWitnessDecoderError,
242+
>,
243+
);
244+
245+
impl fmt::Display for TxInWitnessDecoderError {
246+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
247+
f.write_str("error decoding transaction input witness")
248+
}
249+
}
250+
251+
impl std::error::Error for TxInWitnessDecoderError {
252+
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { Some(&self.0) }
253+
}
254+
255+
impl Decoder for TxInWitnessDecoder {
256+
type Output = TxInWitness;
257+
type Error = TxInWitnessDecoderError;
258+
259+
fn push_bytes(&mut self, bytes: &mut &[u8]) -> Result<DecoderStatus, Self::Error> {
260+
self.inner.push_bytes(bytes).map_err(TxInWitnessDecoderError)
261+
}
262+
263+
fn end(self) -> Result<Self::Output, Self::Error> {
264+
let (amount_rangeproof, inflation_keys_rangeproof, script_witness, pegin_witness) =
265+
self.inner.end().map_err(TxInWitnessDecoderError)?;
266+
267+
Ok(TxInWitness {
268+
amount_rangeproof,
269+
inflation_keys_rangeproof,
270+
script_witness,
271+
pegin_witness,
272+
})
273+
}
274+
275+
fn read_limit(&self) -> usize { self.inner.read_limit() }
276+
}
277+
278+
impl Decode for TxInWitness {
279+
type Decoder = TxInWitnessDecoder;
280+
}
281+
282+
/// An decoder for the witnesses in a sequence of [`TxIn`]s.
283+
///
284+
/// Comsumes a vec of [`TxIn`]s on construction and then yields that
285+
/// same vector, with the witness fields overwritten.
286+
#[derive(Default)]
287+
struct TxInWitnessesDecoder {
288+
txins: Vec<TxIn>,
289+
index: usize,
290+
// Invariant: if this is Some then
291+
decoder: Option<TxInWitnessDecoder>,
292+
}
293+
294+
impl TxInWitnessesDecoder {
295+
#[allow(dead_code)] // will be used in the Transaction Encode/Decode commit
296+
fn new(txins: Vec<TxIn>) -> Self { Self { txins, index: 0, decoder: None } }
297+
}
298+
299+
impl Decoder for TxInWitnessesDecoder {
300+
type Output = Vec<TxIn>;
301+
type Error = TxInWitnessDecoderError;
302+
303+
fn push_bytes(&mut self, bytes: &mut &[u8]) -> Result<DecoderStatus, Self::Error> {
304+
loop {
305+
let Some(next_txin) = self.txins.get_mut(self.index) else {
306+
return Ok(DecoderStatus::Ready);
307+
};
308+
309+
let mut decoder = self.decoder.take().unwrap_or_else(TxInWitness::decoder);
310+
if decoder.push_bytes(bytes)?.needs_more() {
311+
self.decoder = Some(decoder);
312+
return Ok(DecoderStatus::NeedsMore);
313+
}
314+
next_txin.witness = decoder.end()?;
315+
self.index += 1;
316+
}
317+
}
318+
319+
fn end(mut self) -> Result<Self::Output, Self::Error> {
320+
loop {
321+
let Some(last_txin) = self.txins.get_mut(self.index) else {
322+
return Ok(self.txins);
323+
};
324+
325+
last_txin.witness = self.decoder.take().unwrap_or_else(TxInWitness::decoder).end()?;
326+
self.index += 1;
327+
}
328+
}
329+
330+
fn read_limit(&self) -> usize {
331+
self.decoder.as_ref().map_or(0, TxInWitnessDecoder::read_limit)
332+
}
333+
}
334+
226335
decoder_newtype! {
227336
/// Decoder for the [`TxOutWitness`] type.
228337
#[derive(Default)]

src/transaction/encoders.rs

Lines changed: 70 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,13 @@
55
//! These are encapsulated because there are many of them, but in the end we
66
//! only expose the top-level ones outside of this module.
77
8-
use super::{AssetIssuance, Sequence, TxIn, TxOut, TxOutWitness};
8+
use super::{AssetIssuance, Sequence, TxIn, TxInWitness, TxOut, TxOutWitness};
9+
use crate::confidential::RangeProofEncoder;
910
use crate::encoding::{
1011
encoder_newtype_exact, ArrayEncoder, ArrayRefEncoder, Encode, Encoder, Encoder2, Encoder4,
1112
EncoderStatus,
1213
};
14+
use crate::{PeginWitnessEncoder, WitnessEncoder};
1315

1416
// While we define an [`OutPointEncoder`] struct, we don't actually implement `Encode` or `Decode`
1517
// for [`OutPoint`], since the outpoint encoding depends on pegin/issuance data from the rest of
@@ -81,6 +83,73 @@ impl Encode for AssetIssuance {
8183
}
8284
}
8385

86+
encoder_newtype_exact! {
87+
/// Encoder for the [`TxInWitness`] type.
88+
#[derive(Clone, Debug)]
89+
pub struct TxInWitnessEncoder<'e>(Encoder4<
90+
RangeProofEncoder<'e>,
91+
RangeProofEncoder<'e>,
92+
WitnessEncoder<'e>,
93+
PeginWitnessEncoder<'e>,
94+
>);
95+
}
96+
97+
impl Encode for TxInWitness {
98+
type Encoder<'e> = TxInWitnessEncoder<'e>;
99+
100+
fn encoder(&self) -> Self::Encoder<'_> {
101+
TxInWitnessEncoder::new(Encoder4::new(
102+
self.amount_rangeproof.encoder(),
103+
self.inflation_keys_rangeproof.encoder(),
104+
self.script_witness.encoder(),
105+
self.pegin_witness.encoder(),
106+
))
107+
}
108+
}
109+
110+
/// An encoder for the witnesses in a sequence of [`TxIn`]s.
111+
#[derive(Clone, Debug)]
112+
struct TxInWitnessesEncoder<'e> {
113+
txins: &'e [TxIn],
114+
cur_enc: Option<TxInWitnessEncoder<'e>>,
115+
}
116+
117+
impl<'e> TxInWitnessesEncoder<'e> {
118+
#[allow(dead_code)] // will be used in the Transaction Encode/Decode commit
119+
fn new(txins: &'e [TxIn]) -> Self {
120+
Self { txins, cur_enc: txins.first().map(|txin| txin.witness.encoder()) }
121+
}
122+
}
123+
124+
impl Encoder for TxInWitnessesEncoder<'_> {
125+
fn current_chunk(&self) -> &[u8] {
126+
self.cur_enc.as_ref().map(Encoder::current_chunk).unwrap_or_default()
127+
}
128+
129+
fn advance(&mut self) -> EncoderStatus {
130+
let Some(cur) = self.cur_enc.as_mut() else {
131+
return EncoderStatus::Finished;
132+
};
133+
134+
loop {
135+
if cur.advance().has_more() {
136+
return EncoderStatus::HasMore;
137+
}
138+
// self.inputs guaranteed to be non-empty if cur_enc is non-None.
139+
self.txins = &self.txins[1..];
140+
if let Some(txin) = self.txins.first() {
141+
*cur = txin.witness.encoder();
142+
if !cur.current_chunk().is_empty() {
143+
return EncoderStatus::HasMore;
144+
}
145+
} else {
146+
self.cur_enc = None;
147+
return EncoderStatus::Finished;
148+
}
149+
}
150+
}
151+
}
152+
84153
encoder_newtype_exact! {
85154
/// Encoder for the [`TxIn`] type.
86155
#[derive(Clone, Debug)]

src/transaction/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,8 @@ use secp256k1_zkp::{
3939
Tweak, ZERO_TWEAK,
4040
};
4141

42-
pub use self::decoders::{AssetIssuanceDecoder, AssetIssuanceDecoderError, SequenceDecoder, SequenceDecoderError, TxInDecoder, TxInDecoderError, TxOutDecoder, TxOutDecoderError, TxOutWitnessDecoder, TxOutWitnessDecoderError};
43-
pub use self::encoders::{AssetIssuanceEncoder, SequenceEncoder, TxInEncoder, TxOutEncoder, TxOutWitnessEncoder};
42+
pub use self::decoders::{AssetIssuanceDecoder, AssetIssuanceDecoderError, SequenceDecoder, SequenceDecoderError, TxInDecoder, TxInDecoderError, TxInWitnessDecoder, TxInWitnessDecoderError, TxOutDecoder, TxOutDecoderError, TxOutWitnessDecoder, TxOutWitnessDecoderError};
43+
pub use self::encoders::{AssetIssuanceEncoder, SequenceEncoder, TxInEncoder, TxInWitnessEncoder, TxOutEncoder, TxOutWitnessEncoder};
4444
pub use self::pegin_witness::{
4545
PeginData, PeginDataDecoder, PeginDataEncoder,
4646
PeginWitness, PeginWitnessDecoder, PeginWitnessDecoderError, PeginWitnessEncoder};

0 commit comments

Comments
 (0)