Skip to content

Commit c9964af

Browse files
author
+Sharon
committed
Add DecodeScriptSegwit struct and support in DecodeScript conversion
- Add `DecodeScriptSegwit` struct to model the `segwit` field returned by the `decodescript` RPC. - Update `DecodeScript` to include an optional `segwit` field.
1 parent c633a03 commit c9964af

File tree

11 files changed

+194
-12
lines changed

11 files changed

+194
-12
lines changed

types/src/model/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ pub use self::{
4141
raw_transactions::{
4242
AnalyzePsbt, AnalyzePsbtInput, AnalyzePsbtInputMissing, CombinePsbt, CombineRawTransaction,
4343
ConvertToPsbt, CreatePsbt, CreateRawTransaction, DecodePsbt, DecodeRawTransaction,
44-
DecodeScript, DescriptorProcessPsbt, FinalizePsbt, FundRawTransaction, GetRawTransaction,
44+
DecodeScript,DecodeScriptSegwit, DescriptorProcessPsbt, FinalizePsbt, FundRawTransaction, GetRawTransaction,
4545
GetRawTransactionVerbose, JoinPsbts, MempoolAcceptance, SendRawTransaction, SignFail,
4646
SignRawTransaction, SubmitPackage, SubmitPackageTxResult, SubmitPackageTxResultFees,
4747
TestMempoolAccept, UtxoUpdatePsbt,

types/src/model/raw_transactions.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,8 +116,30 @@ pub struct DecodeScript {
116116
pub addresses: Vec<Address<NetworkUnchecked>>,
117117
/// Address of P2SH script wrapping this redeem script (not returned if the script is already a P2SH).
118118
pub p2sh: Option<Address<NetworkUnchecked>>,
119+
/// Segwit data (see `DecodeScriptSegwit` for explanation).
120+
pub segwit: Option<DecodeScriptSegwit>,
119121
/// Address of the P2SH script wrapping this witness redeem script
120122
pub p2sh_segwit: Option<String>,
123+
124+
}
125+
/// Models the `segwit` field returned by the `decodescript` RPC.
126+
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
127+
#[serde(deny_unknown_fields)]
128+
pub struct DecodeScriptSegwit {
129+
/// The witness program.
130+
pub asm: String,
131+
/// Hex-encoded script.
132+
pub hex: String,
133+
/// The output type.
134+
pub type_: String,
135+
/// Bitcoin address (only if a well-defined address exists).
136+
pub address: Option<Address<NetworkUnchecked>>,
137+
/// The required signatures.
138+
pub required_signatures: Option<u64>,
139+
/// List of bitcoin addresses.
140+
pub addresses: Vec<Address<NetworkUnchecked>>,
141+
/// Address of the P2SH script wrapping this witness redeem script.
142+
pub p2sh_segwit: Option<String>,
121143
}
122144

123145
/// Models the result of JSON-RPC method `descriptorprocesspsbt`.

types/src/v17/raw_transactions/into.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,7 @@ impl DecodeScript {
310310
addresses,
311311
p2sh,
312312
p2sh_segwit: self.p2sh_segwit,
313+
segwit: None,
313314
})
314315
}
315316
}

types/src/v22/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,7 @@ pub use self::{
253253
blockchain::GetMempoolInfo,
254254
control::Logging,
255255
network::{Banned, GetPeerInfo, ListBanned},
256-
raw_transactions::{DecodeScript, DecodeScriptError},
256+
raw_transactions::{DecodeScript, DecodeScriptError,DecodeScriptSegwit,DecodeScriptSegwitError},
257257
};
258258
#[doc(inline)]
259259
pub use crate::{

types/src/v22/raw_transactions/error.rs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,11 @@ pub enum DecodeScriptError {
1515
Address(address::ParseError),
1616
/// Conversion of the transaction `addresses` field failed.
1717
Addresses(address::ParseError),
18+
/// Conversion of the transaction `segwit` field failed.
19+
Segwit(DecodeScriptSegwitError),
1820
/// Conversion of the transaction `p2sh` field failed.
1921
P2sh(address::ParseError),
22+
2023
}
2124

2225
impl fmt::Display for DecodeScriptError {
@@ -27,6 +30,7 @@ impl fmt::Display for DecodeScriptError {
2730
E::Hex(ref e) => write_err!(f, "conversion of the `hex` field failed"; e),
2831
E::Address(ref e) => write_err!(f, "conversion of the `address` field failed"; e),
2932
E::Addresses(ref e) => write_err!(f, "conversion of the `addresses` field failed"; e),
33+
E::Segwit(ref e) => write_err!(f, "conversion of the `segwit` field failed"; e),
3034
E::P2sh(ref e) => write_err!(f, "conversion of the `p2sh` field failed"; e),
3135
}
3236
}
@@ -41,7 +45,49 @@ impl std::error::Error for DecodeScriptError {
4145
E::Hex(ref e) => Some(e),
4246
E::Address(ref e) => Some(e),
4347
E::Addresses(ref e) => Some(e),
48+
E::Segwit(ref e) => Some(e),
4449
E::P2sh(ref e) => Some(e),
4550
}
4651
}
4752
}
53+
54+
/// Error when converting a `DecodeScriptSegwit` type into the model type.
55+
#[derive(Debug)]
56+
pub enum DecodeScriptSegwitError {
57+
/// An invalid or missing field in the `DecodeScriptSegwit` data.
58+
InvalidField(&'static str),
59+
/// Conversion of the transaction `address` field failed.
60+
Address(address::ParseError),
61+
/// Conversion of the transaction `addresses` field failed.
62+
Addresses(address::ParseError),
63+
}
64+
65+
impl fmt::Display for DecodeScriptSegwitError {
66+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
67+
use DecodeScriptSegwitError as E;
68+
69+
match *self {
70+
E::InvalidField(name) =>
71+
write!(f, "conversion of the `segwit` field failed: invalid or missing field `{}`", name),
72+
E::Address(ref e) =>
73+
write_err!(f, "conversion of the `address` field in `segwit` failed"; e),
74+
E::Addresses(ref e) =>
75+
write_err!(f, "conversion of the `addresses` field in `segwit` failed"; e),
76+
}
77+
}
78+
}
79+
80+
#[cfg(feature = "std")]
81+
impl std::error::Error for DecodeScriptSegwitError {
82+
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
83+
use DecodeScriptSegwitError as E;
84+
85+
match *self {
86+
E::InvalidField(_) => None,
87+
E::Address(ref e) => Some(e),
88+
E::Addresses(ref e) => Some(e),
89+
}
90+
}
91+
}
92+
93+

types/src/v22/raw_transactions/into.rs

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22

33
use bitcoin::Address;
44

5-
use super::{DecodeScript, DecodeScriptError};
5+
use super::{DecodeScript, DecodeScriptError, DecodeScriptSegwit, DecodeScriptSegwitError};
6+
67
use crate::model;
78

89
impl DecodeScript {
@@ -23,7 +24,7 @@ impl DecodeScript {
2324
None => vec![],
2425
};
2526
let p2sh = self.p2sh.map(|s| s.parse::<Address<_>>()).transpose().map_err(E::P2sh)?;
26-
27+
2728
Ok(model::DecodeScript {
2829
script_pubkey: None,
2930
type_: self.type_,
@@ -32,7 +33,44 @@ impl DecodeScript {
3233
required_signatures: self.required_signatures,
3334
addresses,
3435
p2sh,
36+
segwit: self.segwit.map(|s| s.into_model()).transpose().map_err(E::Segwit)?,
3537
p2sh_segwit: self.p2sh_segwit,
38+
39+
})
40+
}
41+
}
42+
43+
impl DecodeScriptSegwit {
44+
/// Converts version specific type to a version nonspecific, more strongly typed type.
45+
pub fn into_model(self) -> Result<model::DecodeScriptSegwit, DecodeScriptSegwitError> {
46+
use DecodeScriptSegwitError as E;
47+
48+
let address = match self.address {
49+
Some(addr) => Some(addr.parse::<Address<_>>().map_err(E::Address)?),
50+
None => None,
51+
};
52+
// Convert `Option<Vec<String>>` to `Vec<Address<NetworkUnchecked>>`
53+
let addresses = match self.addresses {
54+
Some(addrs) => addrs
55+
.into_iter()
56+
.map(|s| s.parse::<Address<_>>())
57+
.collect::<Result<_, _>>()
58+
.map_err(E::Addresses)?,
59+
None => vec![],
60+
};
61+
62+
let required_signatures = self.required_signatures;
63+
let p2sh_segwit = self.p2sh_segwit;
64+
65+
Ok(model::DecodeScriptSegwit {
66+
asm: self.asm,
67+
hex: self.hex,
68+
type_: self.type_,
69+
address,
70+
required_signatures,
71+
addresses,
72+
p2sh_segwit,
3673
})
74+
3775
}
3876
}

types/src/v22/raw_transactions/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ mod into;
99

1010
use serde::{Deserialize, Serialize};
1111

12-
pub use self::error::DecodeScriptError;
12+
pub use self::error::{DecodeScriptError,DecodeScriptSegwitError};
1313

1414
/// Result of JSON-RPC method `decodescript`.
1515
///
@@ -64,5 +64,5 @@ pub struct DecodeScriptSegwit {
6464
pub addresses: Option<Vec<String>>,
6565
/// Address of P2SH script wrapping this redeem script (not returned if the script is already a P2SH).
6666
#[serde(rename = "p2sh-segwit")]
67-
pub p2sh_segtwit: Option<String>,
67+
pub p2sh_segwit: Option<String>,
6868
}

types/src/v23/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,7 @@ pub use self::{
250250
network::GetPeerInfo,
251251
raw_transactions::{
252252
DecodePsbt, DecodePsbtError, DecodeScript, DecodeScriptError, GlobalXpub, Proprietary,
253-
PsbtInput, PsbtOutput,
253+
PsbtInput, PsbtOutput,DecodeScriptSegwit,DecodeScriptSegwitError
254254
},
255255
util::CreateMultisig,
256256
wallet::{GetTransaction, GetTransactionError},
@@ -306,5 +306,5 @@ pub use crate::{
306306
},
307307
v20::{GenerateToDescriptor, GetTransactionDetail},
308308
v21::{GetNetworkInfo, UnloadWallet},
309-
v22::{Banned, GetMempoolInfo, ListBanned, ScriptPubkey},
309+
v22::{Banned, GetMempoolInfo, ListBanned, ScriptPubkey,},
310310
};

types/src/v23/raw_transactions/error.rs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,8 @@ pub enum DecodeScriptError {
265265
Address(address::ParseError),
266266
/// Conversion of the transaction `addresses` field failed.
267267
Addresses(address::ParseError),
268+
/// Conversion of the transaction `segwit` field failed.
269+
Segwit(DecodeScriptSegwitError),
268270
/// Conversion of the transaction `p2sh` field failed.
269271
P2sh(address::ParseError),
270272
}
@@ -277,6 +279,7 @@ impl fmt::Display for DecodeScriptError {
277279
E::Hex(ref e) => write_err!(f, "conversion of the `hex` field failed"; e),
278280
E::Address(ref e) => write_err!(f, "conversion of the `address` field failed"; e),
279281
E::Addresses(ref e) => write_err!(f, "conversion of the `addresses` field failed"; e),
282+
E::Segwit(ref e) => write_err!(f, "conversion of the `segwit` field failed"; e),
280283
E::P2sh(ref e) => write_err!(f, "conversion of the `p2sh` field failed"; e),
281284
}
282285
}
@@ -291,7 +294,42 @@ impl std::error::Error for DecodeScriptError {
291294
E::Hex(ref e) => Some(e),
292295
E::Address(ref e) => Some(e),
293296
E::Addresses(ref e) => Some(e),
297+
E::Segwit(ref e) => Some(e),
294298
E::P2sh(ref e) => Some(e),
295299
}
296300
}
297301
}
302+
303+
/// Error when converting a `DecodeScriptSegwit` type into the model type.
304+
#[derive(Debug)]
305+
pub enum DecodeScriptSegwitError {
306+
/// Conversion of the transaction `address` field failed.
307+
Address(address::ParseError),
308+
/// Conversion of the transaction `addresses` field failed.
309+
Addresses(address::ParseError),
310+
}
311+
312+
impl fmt::Display for DecodeScriptSegwitError {
313+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
314+
use DecodeScriptSegwitError as E;
315+
316+
match *self {
317+
E::Address(ref e) =>
318+
write_err!(f, "conversion of the `address` field in `segwit` failed"; e),
319+
E::Addresses(ref e) =>
320+
write_err!(f, "conversion of the `addresses` field in `segwit` failed"; e),
321+
}
322+
}
323+
}
324+
325+
#[cfg(feature = "std")]
326+
impl std::error::Error for DecodeScriptSegwitError {
327+
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
328+
use DecodeScriptSegwitError as E;
329+
330+
match *self {
331+
E::Address(ref e) => Some(e),
332+
E::Addresses(ref e) => Some(e),
333+
}
334+
}
335+
}

types/src/v23/raw_transactions/into.rs

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,10 @@ use bitcoin::{Address, Amount};
1010

1111
use super::{
1212
DecodePsbt, DecodePsbtError, DecodeScript, DecodeScriptError, GlobalXpub, GlobalXpubError,
13-
Proprietary, PsbtInput, PsbtInputError, PsbtOutput, PsbtOutputError,
13+
Proprietary, PsbtInput, PsbtInputError, PsbtOutput, PsbtOutputError,DecodeScriptSegwit,
14+
DecodeScriptSegwitError,
1415
};
16+
1517
use crate::model;
1618

1719
impl DecodePsbt {
@@ -324,8 +326,10 @@ impl DecodeScript {
324326
.map_err(E::Addresses)?,
325327
None => vec![],
326328
};
327-
let p2sh = self.p2sh.map(|s| s.parse::<Address<_>>()).transpose().map_err(E::P2sh)?;
328329

330+
331+
let p2sh = self.p2sh.map(|s| s.parse::<Address<_>>()).transpose().map_err(E::P2sh)?;
332+
329333
Ok(model::DecodeScript {
330334
script_pubkey: None,
331335
type_: self.type_,
@@ -334,7 +338,40 @@ impl DecodeScript {
334338
required_signatures: self.required_signatures,
335339
addresses,
336340
p2sh,
341+
segwit: self.segwit.map(|s| s.into_model()).transpose().map_err(E::Segwit)?,
342+
p2sh_segwit: self.p2sh_segwit,
343+
344+
})
345+
}
346+
}
347+
impl DecodeScriptSegwit {
348+
/// Converts version specific type to a version nonspecific, more strongly typed type.
349+
pub fn into_model(self) -> Result<model::DecodeScriptSegwit, DecodeScriptSegwitError> {
350+
use DecodeScriptSegwitError as E;
351+
352+
let address = match self.address {
353+
Some(addr) => Some(addr.parse::<Address<_>>().map_err(E::Address)?),
354+
None => None,
355+
};
356+
357+
let addresses = match self.addresses {
358+
Some(addrs) => addrs
359+
.into_iter()
360+
.map(|s| s.parse::<Address<_>>())
361+
.collect::<Result<_, _>>()
362+
.map_err(E::Addresses)?,
363+
None => vec![],
364+
};
365+
366+
Ok(model::DecodeScriptSegwit {
367+
asm: self.asm,
368+
hex: self.hex,
369+
type_: self.type_,
370+
address,
371+
required_signatures: self.required_signatures,
372+
addresses,
337373
p2sh_segwit: self.p2sh_segwit,
338374
})
339375
}
340376
}
377+

0 commit comments

Comments
 (0)