Skip to content

Commit d72094a

Browse files
committed
implement Encode/Decode for TxIn
1 parent 02ab70d commit d72094a

4 files changed

Lines changed: 321 additions & 12 deletions

File tree

src/lib.rs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -95,11 +95,13 @@ pub use crate::schnorr::{SchnorrSig, SchnorrSigError};
9595
pub use crate::script::Script;
9696
pub use crate::sighash::SchnorrSighashType;
9797
pub use crate::transaction::{
98-
AssetIssuance, EcdsaSighashType, OutPoint, PeginData, PeginDataDecoder, PeginDataEncoder,
99-
PeginWitness, PeginWitnessDecoder, PeginWitnessDecoderError, PeginWitnessEncoder, PegoutData,
100-
Sequence, Transaction, TxIn, TxInWitness, TxOut, TxOutDecoder, TxOutDecoderError, TxOutEncoder,
101-
TxOutWitness, TxOutWitnessDecoder, TxOutWitnessDecoderError, TxOutWitnessEncoder, Witness,
102-
WitnessDecoder, WitnessDecoderError, WitnessEncoder,
98+
AssetIssuance, AssetIssuanceDecoder, AssetIssuanceDecoderError, AssetIssuanceEncoder,
99+
EcdsaSighashType, OutPoint, PeginData, PeginDataDecoder, PeginDataEncoder, PeginWitness,
100+
PeginWitnessDecoder, PeginWitnessDecoderError, PeginWitnessEncoder, PegoutData, Sequence,
101+
SequenceDecoder, SequenceDecoderError, SequenceEncoder, Transaction, TxIn, TxInDecoder,
102+
TxInDecoderError, TxInEncoder, TxInWitness, TxOut, TxOutDecoder, TxOutDecoderError,
103+
TxOutEncoder, TxOutWitness, TxOutWitnessDecoder, TxOutWitnessDecoderError, TxOutWitnessEncoder,
104+
Witness, WitnessDecoder, WitnessDecoderError, WitnessEncoder,
103105
};
104106

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

src/transaction/decoders.rs

Lines changed: 213 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,222 @@
77
88
use core::fmt;
99

10-
use super::{TxOut, TxOutWitness};
10+
use super::{
11+
AssetIssuance, OutPoint, Script, Sequence, TxIn, TxInWitness, TxOut, TxOutWitness, Txid,
12+
};
1113
use crate::encoding::{
12-
Decode, Decoder, Decoder2, Decoder2Error, Decoder4, Decoder4Error, DecoderStatus,
14+
ArrayDecoder, Decode, Decoder, Decoder2, Decoder2Error, Decoder3, Decoder4, Decoder4Error,
15+
DecoderStatus, UnexpectedEofError,
1316
};
1417

18+
/// Decoder for the [`OutPoint`] type.
19+
///
20+
/// This is a non-public struct and we do not implement [`Decode`] for [`OutPoint`]
21+
/// because we can't actually encode/decode outpoints independently of the rest of
22+
/// a [`TxIn`]. This is because we mask bits into the vout of the outpoint.
23+
#[derive(Default)]
24+
struct OutPointDecoder {
25+
inner: Decoder2<ArrayDecoder<32>, ArrayDecoder<4>>,
26+
}
27+
28+
/// Decoder error for the [`OutPoint`] type.
29+
#[derive(Clone, PartialEq, Eq, Debug)]
30+
struct OutPointDecoderError(Decoder2Error<UnexpectedEofError, UnexpectedEofError>);
31+
32+
impl fmt::Display for OutPointDecoderError {
33+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
34+
f.write_str("error decoding outpoint")
35+
}
36+
}
37+
38+
impl std::error::Error for OutPointDecoderError {
39+
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { Some(&self.0) }
40+
}
41+
42+
impl Decoder for OutPointDecoder {
43+
type Output = OutPoint;
44+
type Error = OutPointDecoderError;
45+
46+
fn push_bytes(&mut self, bytes: &mut &[u8]) -> Result<DecoderStatus, Self::Error> {
47+
self.inner.push_bytes(bytes).map_err(OutPointDecoderError)
48+
}
49+
50+
fn end(self) -> Result<Self::Output, Self::Error> {
51+
let (txid, vout) = self.inner.end().map_err(OutPointDecoderError)?;
52+
Ok(OutPoint { txid: Txid::from_byte_array(txid), vout: u32::from_le_bytes(vout) })
53+
}
54+
55+
fn read_limit(&self) -> usize { self.inner.read_limit() }
56+
}
57+
58+
decoder_newtype! {
59+
/// Decoder for the [`Sequence`] type.
60+
#[derive(Default)]
61+
pub struct SequenceDecoder(ArrayDecoder<4>);
62+
63+
/// Decoder error for the [`Sequence`] type.
64+
#[derive(Clone, PartialEq, Eq, Debug)]
65+
pub struct SequenceDecoderError(UnexpectedEofError);
66+
const ERROR_DISPLAY = "error decoding sequence";
67+
68+
impl Decode for Sequence {
69+
fn convert_inner(bytes) -> Result<_, UnexpectedEofError> {
70+
Ok(Sequence::from_consensus(u32::from_le_bytes(bytes)))
71+
}
72+
}
73+
}
74+
75+
decoder_newtype! {
76+
/// Decoder for the [`AssetIssuance`] type.
77+
#[derive(Default)]
78+
pub struct AssetIssuanceDecoder(Decoder4<
79+
ArrayDecoder<32>,
80+
ArrayDecoder<32>,
81+
crate::confidential::ValueDecoder,
82+
crate::confidential::ValueDecoder,
83+
>);
84+
/// Decoder error for the [`AssetIssuance`] type.
85+
#[derive(Clone, PartialEq, Eq, Debug)]
86+
pub struct AssetIssuanceDecoderError(enum AssetIssuanceDecoderErrorInner {
87+
Decode(Decoder4Error<
88+
UnexpectedEofError,
89+
UnexpectedEofError,
90+
crate::confidential::ValueDecoderError,
91+
crate::confidential::ValueDecoderError,
92+
>),
93+
InvalidTweak(secp256k1_zkp::Error),
94+
});
95+
96+
impl Decode for AssetIssuance {
97+
fn convert_inner(output) -> Result<_, AssetIssuanceDecoderError> {
98+
let (asset_blinding_nonce, asset_entropy, amount, inflation_keys) = output;
99+
Ok(AssetIssuance {
100+
asset_blinding_nonce: secp256k1_zkp::Tweak::from_inner(asset_blinding_nonce)
101+
.map_err(AssetIssuanceDecoderErrorInner::InvalidTweak)
102+
.map_err(AssetIssuanceDecoderError)?,
103+
asset_entropy,
104+
amount,
105+
inflation_keys,
106+
})
107+
}
108+
}
109+
}
110+
111+
impl fmt::Display for AssetIssuanceDecoderError {
112+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
113+
use AssetIssuanceDecoderErrorInner as Inner;
114+
match self.0 {
115+
Inner::Decode(_) => f.write_str("error decoding asset issuance"),
116+
Inner::InvalidTweak(_) => f.write_str("asset issuance had out-of-range blinding nonce"),
117+
}
118+
}
119+
}
120+
121+
impl std::error::Error for AssetIssuanceDecoderError {
122+
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
123+
use AssetIssuanceDecoderErrorInner as Inner;
124+
match self.0 {
125+
Inner::Decode(ref e) => Some(e),
126+
Inner::InvalidTweak(ref e) => Some(e),
127+
}
128+
}
129+
}
130+
131+
fn vout_is_pegin(vout: u32) -> bool { vout != 0xffff_ffff && vout & (1 << 30) != 0 }
132+
fn vout_has_issuance(vout: u32) -> bool { vout != 0xffff_ffff && vout & (1 << 31) != 0 }
133+
134+
decoder_state_machine! {
135+
/// Decoder for the [`TxIn`] type.
136+
pub struct TxInDecoder(enum TxInDecoderInner {
137+
Done(TxIn),
138+
Errored,
139+
Initial {
140+
decoder: Decoder3<
141+
OutPointDecoder,
142+
crate::script::ScriptDecoder,
143+
SequenceDecoder,
144+
>,
145+
=> transition_initial(output, ...) -> Result {
146+
let (mut outpoint, script_sig, sequence) = output;
147+
if vout_has_issuance(outpoint.vout) {
148+
Ok(TxInDecoderInner::AssetIssuance {
149+
decoder: AssetIssuanceDecoder::default(),
150+
outpoint, script_sig, sequence,
151+
})
152+
} else {
153+
let orig_vout = outpoint.vout;
154+
outpoint.vout &= !((1 << 30) | (1 << 31));
155+
Ok(TxInDecoderInner::Done(TxIn {
156+
previous_output: outpoint,
157+
is_pegin: vout_is_pegin(orig_vout),
158+
script_sig,
159+
sequence,
160+
asset_issuance: AssetIssuance::null(),
161+
witness: TxInWitness::default(),
162+
}))
163+
}
164+
}
165+
},
166+
AssetIssuance {
167+
decoder: AssetIssuanceDecoder,
168+
outpoint: OutPoint,
169+
script_sig: Script,
170+
sequence: Sequence
171+
=> transition_asset_issuance(asset_issuance, ...) -> Result {
172+
if asset_issuance.is_null() {
173+
return Err(TxInDecoderErrorInner::SuperfluousIssuance);
174+
}
175+
176+
let orig_vout = outpoint.vout;
177+
let mut outpoint = outpoint;
178+
outpoint.vout &= !((1 << 30) | (1 << 31));
179+
Ok(TxInDecoderInner::Done(TxIn {
180+
previous_output: outpoint,
181+
is_pegin: vout_is_pegin(orig_vout),
182+
script_sig,
183+
sequence,
184+
asset_issuance,
185+
witness: TxInWitness::default(),
186+
}))
187+
}
188+
},
189+
});
190+
191+
/// Decoder error for the [`TxIn`] type.
192+
#[derive(Clone, PartialEq, Eq, Debug)]
193+
pub struct TxInDecoderError(enum TxInDecoderErrorInner {
194+
[macro-inserted decoder variants]
195+
SuperfluousIssuance,
196+
});
197+
}
198+
199+
impl Default for TxInDecoder {
200+
fn default() -> Self { Self(TxInDecoderInner::Initial { decoder: Decoder3::default() }) }
201+
}
202+
203+
impl fmt::Display for TxInDecoderError {
204+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
205+
use TxInDecoderErrorInner as Inner;
206+
match self.0 {
207+
Inner::Initial(..) => f.write_str("error decoding outpoint, scriptsig or sequence"),
208+
Inner::AssetIssuance(..) => f.write_str("error decoding asset issuance"),
209+
Inner::SuperfluousIssuance =>
210+
f.write_str("input had issuance flag set, but null issuance"),
211+
}
212+
}
213+
}
214+
215+
impl std::error::Error for TxInDecoderError {
216+
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
217+
use TxInDecoderErrorInner as Inner;
218+
match self.0 {
219+
Inner::Initial(ref e) => Some(e),
220+
Inner::AssetIssuance(ref e) => Some(e),
221+
Inner::SuperfluousIssuance => None,
222+
}
223+
}
224+
}
225+
15226
decoder_newtype! {
16227
/// Decoder for the [`TxOutWitness`] type.
17228
#[derive(Default)]

src/transaction/encoders.rs

Lines changed: 99 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,105 @@
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::{TxOut, TxOutWitness};
9-
use crate::encoding::{encoder_newtype_exact, Encode, Encoder, Encoder2, Encoder4, EncoderStatus};
8+
use super::{AssetIssuance, Sequence, TxIn, TxOut, TxOutWitness};
9+
use crate::encoding::{
10+
encoder_newtype_exact, ArrayEncoder, ArrayRefEncoder, Encode, Encoder, Encoder2, Encoder4,
11+
EncoderStatus,
12+
};
13+
14+
// While we define an [`OutPointEncoder`] struct, we don't actually implement `Encode` or `Decode`
15+
// for [`OutPoint`], since the outpoint encoding depends on pegin/issuance data from the rest of
16+
// the txin. We just use it as a private building block.
17+
18+
encoder_newtype_exact! {
19+
/// Encoder for the [`OutPoint`] type.
20+
#[derive(Clone, Debug)]
21+
struct OutPointEncoder<'e>(Encoder2<
22+
ArrayRefEncoder<'e, 32>,
23+
ArrayEncoder<4>,
24+
>);
25+
}
26+
27+
impl<'e> OutPointEncoder<'e> {
28+
fn from_txin(txin: &'e TxIn) -> Self {
29+
let mut vout = txin.previous_output.vout;
30+
if txin.is_pegin {
31+
vout |= 1 << 30;
32+
}
33+
if txin.has_issuance() {
34+
vout |= 1 << 31;
35+
}
36+
37+
Self::new(Encoder2::new(
38+
ArrayRefEncoder::without_length_prefix(txin.previous_output.txid.as_byte_array()),
39+
ArrayEncoder::without_length_prefix(vout.to_le_bytes()),
40+
))
41+
}
42+
}
43+
44+
encoder_newtype_exact! {
45+
/// Encoder for the [`Sequence`] type.
46+
#[derive(Clone, Debug)]
47+
pub struct SequenceEncoder<'e>(ArrayEncoder<4>);
48+
}
49+
50+
impl Encode for Sequence {
51+
type Encoder<'e> = SequenceEncoder<'e>;
52+
53+
fn encoder(&self) -> Self::Encoder<'_> {
54+
SequenceEncoder::new(ArrayEncoder::without_length_prefix(
55+
self.to_consensus_u32().to_le_bytes(),
56+
))
57+
}
58+
}
59+
60+
encoder_newtype_exact! {
61+
/// Encoder for the [`AssetIssuance`] type.
62+
#[derive(Clone, Debug)]
63+
pub struct AssetIssuanceEncoder<'e>(Encoder4<
64+
ArrayRefEncoder<'e, 32>,
65+
ArrayRefEncoder<'e, 32>,
66+
crate::confidential::ValueEncoder<'e>,
67+
crate::confidential::ValueEncoder<'e>,
68+
>);
69+
}
70+
71+
impl Encode for AssetIssuance {
72+
type Encoder<'e> = AssetIssuanceEncoder<'e>;
73+
74+
fn encoder(&self) -> Self::Encoder<'_> {
75+
AssetIssuanceEncoder::new(Encoder4::new(
76+
ArrayRefEncoder::without_length_prefix(self.asset_blinding_nonce.as_ref()),
77+
ArrayRefEncoder::without_length_prefix(&self.asset_entropy),
78+
self.amount.encoder(),
79+
self.inflation_keys.encoder(),
80+
))
81+
}
82+
}
83+
84+
encoder_newtype_exact! {
85+
/// Encoder for the [`TxIn`] type.
86+
#[derive(Clone, Debug)]
87+
pub struct TxInEncoder<'e>(Encoder4<
88+
OutPointEncoder<'e>,
89+
crate::script::ScriptEncoder<'e>,
90+
SequenceEncoder<'e>,
91+
Option<AssetIssuanceEncoder<'e>>,
92+
>);
93+
}
94+
95+
impl Encode for TxIn {
96+
type Encoder<'e> = TxInEncoder<'e>;
97+
98+
fn encoder(&self) -> Self::Encoder<'_> {
99+
TxInEncoder::new(Encoder4::new(
100+
OutPointEncoder::from_txin(self),
101+
self.script_sig.encoder(),
102+
self.sequence.encoder(),
103+
self.has_issuance().then(|| self.asset_issuance.encoder()),
104+
))
105+
}
106+
}
10107

11108
encoder_newtype_exact! {
12109
/// Encoder for the [`TxOutWitness`] type.

src/transaction/mod.rs

Lines changed: 2 additions & 3 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::{TxOutDecoder, TxOutDecoderError, TxOutWitnessDecoder, TxOutWitnessDecoderError};
43-
pub use self::encoders::{TxOutEncoder, TxOutWitnessEncoder};
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};
4444
pub use self::pegin_witness::{
4545
PeginData, PeginDataDecoder, PeginDataEncoder,
4646
PeginWitness, PeginWitnessDecoder, PeginWitnessDecoderError, PeginWitnessEncoder};
@@ -367,7 +367,6 @@ impl std::error::Error for RelativeLockTimeError {
367367
}
368368
}
369369

370-
371370
/// Transaction input witness
372371
#[derive(Clone, PartialEq, Eq, Debug, Hash, PartialOrd, Ord)]
373372
pub struct TxInWitness {

0 commit comments

Comments
 (0)