Skip to content

Commit e3fd3d6

Browse files
taproot: TaprootSpendInfo field accessors
1 parent b7101cc commit e3fd3d6

File tree

2 files changed

+42
-64
lines changed

2 files changed

+42
-64
lines changed

src/runtime/mod.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -249,9 +249,10 @@ pub trait FieldAccess {
249249
impl FieldAccess for Value {
250250
fn get_field(self, field: &Value) -> Option<Value> {
251251
match self {
252-
Value::Array(array) => array.get_field(field),
253-
Value::Psbt(psbt) => psbt.get_field(field),
254-
Value::Transaction(tx) => tx.get_field(field),
252+
Value::Array(x) => x.get_field(field),
253+
Value::Psbt(x) => x.get_field(field),
254+
Value::Transaction(x) => x.get_field(field),
255+
Value::TapInfo(x) => x.get_field(field),
255256
_ => None,
256257
}
257258
}

src/stdlib/taproot.rs

Lines changed: 38 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,10 @@ use miniscript::descriptor::{self, DescriptorPublicKey};
1111

1212
use super::miniscript::{multi_andor, AndOr};
1313
use crate::runtime::scope::{Mutable, Scope, ScopeRef};
14-
use crate::runtime::{Array, Error, Result, Value};
15-
use crate::util::{self, fmt_list, DescriptorExt, DescriptorPubKeyExt, PrettyDisplay, EC};
14+
use crate::runtime::{Array, Error, FieldAccess, Result, Value};
15+
use crate::util::{
16+
self, fmt_list, DescriptorExt, DescriptorPubKeyExt, PrettyDisplay, TapInfoExt, EC,
17+
};
1618
use crate::{DescriptorDpk as Descriptor, ExprRepr, PolicyDpk as Policy};
1719

1820
pub fn attach_stdlib(scope: &ScopeRef<Mutable>) {
@@ -21,11 +23,7 @@ pub fn attach_stdlib(scope: &ScopeRef<Mutable>) {
2123
// Taproot Descriptor/TaprootSpendInfo construction
2224
scope.set_fn("tr", fns::tr).unwrap();
2325

24-
// Functions for extracting information out of Descriptors/TaprootSpendInfo
25-
scope.set_fn("tr::internalKey", fns::internalKey).unwrap();
26-
scope.set_fn("tr::outputKey", fns::outputKey).unwrap();
27-
scope.set_fn("tr::merkleRoot", fns::merkleRoot).unwrap();
28-
scope.set_fn("tr::scripts", fns::scripts).unwrap();
26+
// Construct the witness control block
2927
scope.set_fn("tr::ctrl", fns::ctrl).unwrap();
3028

3129
// Convert a tr() descriptor into a TaprootSpendInfo
@@ -55,57 +53,9 @@ pub mod fns {
5553
super::tr(a, b, &scope.borrow())
5654
}
5755

58-
/// tr::internalKey(TapInfo|Descriptor) -> PubKey
59-
///
60-
/// Get the internal x-only key of the given TapInfo/Descriptor
61-
pub fn internalKey(args: Array, _: &ScopeRef) -> Result<Value> {
62-
Ok(match args.arg_into()? {
63-
Value::TapInfo(tapinfo) => tapinfo.internal_key().into(),
64-
Value::Descriptor(Descriptor::Tr(tr)) => tr.internal_key().clone().into(),
65-
_ => bail!(Error::InvalidArguments),
66-
})
67-
}
68-
69-
/// tr::outputKey(TapInfo) -> PubKey | (PubKey, Number)
70-
///
71-
/// Get the output key of the given TapInfo, optionally with the parity as a tuple of (key, parity)
72-
pub fn outputKey(args: Array, _: &ScopeRef) -> Result<Value> {
73-
let (tapinfo, with_parity): (TaprootSpendInfo, Option<bool>) = args.args_into()?;
74-
let key = tapinfo.output_key();
75-
76-
Ok(if with_parity.unwrap_or(false) {
77-
(key, tapinfo.output_key_parity()).into()
78-
} else {
79-
key.into()
80-
})
81-
}
82-
83-
/// tr::merkleRoot(TapInfo) -> Hash
84-
///
85-
/// Get the merkle root hash of the given TapInfo
86-
pub fn merkleRoot(args: Array, _: &ScopeRef) -> Result<Value> {
87-
let tapinfo: TaprootSpendInfo = args.arg_into()?;
88-
89-
Ok(match tapinfo.merkle_root() {
90-
None => Vec::<u8>::new().into(), // empty byte vector signifies an empty script tree
91-
Some(root) => root.into(),
92-
})
93-
}
94-
95-
/// tr::scripts(TapInfo|Descriptor) -> Array<Script>
96-
///
97-
/// Get an array of all scripts in the tree
98-
pub fn scripts(args: Array, _: &ScopeRef) -> Result<Value> {
99-
let tapinfo: TaprootSpendInfo = args.arg_into()?;
100-
let scripts = tapinfo.script_map().keys();
101-
Ok(Value::array(
102-
scripts.map(|(script, _)| script.clone().into()).collect(),
103-
))
104-
}
105-
10656
/// tr::ctrl(TapInfo|Descriptor, Script|Policy, Byte version=TapScript) -> Array<Script>
10757
///
108-
/// Get the control block for the given script/policy
58+
/// Construct the witness control block for the given Script/Policy
10959
pub fn ctrl(args: Array, _: &ScopeRef) -> Result<Value> {
11060
let (tapinfo, script_or_policy, leaf_ver): (TaprootSpendInfo, Value, Option<LeafVersion>) =
11161
args.args_into()?;
@@ -123,7 +73,7 @@ pub mod fns {
12373

12474
/// tr::tapinfo(Descriptor|TapInfo) -> TapInfo
12575
///
126-
/// Convert the Tr Descriptor into a TapInfo (or return TapInfo as-is)
76+
/// Convert Tr Descriptor into a TapInfo (or return TapInfo as-is)
12777
pub fn tapinfo(args: Array, _: &ScopeRef) -> Result<Value> {
12878
Ok(Value::TapInfo(args.arg_into()?))
12979
}
@@ -148,15 +98,42 @@ pub mod fns {
14898
}
14999
}
150100

101+
// TaprootSpendInfo field accessors
102+
impl FieldAccess for TaprootSpendInfo {
103+
fn get_field(self, field: &Value) -> Option<Value> {
104+
// Similar fields are available on tr() Descriptors
105+
Some(match field.as_str()? {
106+
"script_pubkey" => self.script_pubkey().into(),
107+
"witness_program" => self.witness_program().into(),
108+
"address_type" => bitcoin::AddressType::P2tr.into(),
109+
110+
"internal_key" => self.internal_key().into(),
111+
"merkle_root" => self.merkle_root()?.into(),
112+
"output_key" => self.output_key().into(),
113+
"output_key_parity" => self.output_key_parity().into(),
114+
"scripts" => tap_scripts_to_val(&self),
115+
_ => {
116+
return None;
117+
}
118+
})
119+
}
120+
}
121+
122+
/// As a flat Array of Script, with no leaf versions
123+
pub fn tap_scripts_to_val(tapinfo: &TaprootSpendInfo) -> Value {
124+
let scripts_vers = tapinfo.script_map().keys();
125+
scripts_vers.map(|(script, _)| script.clone()).collect()
126+
}
127+
151128
impl TryFrom<Value> for TaprootSpendInfo {
152129
type Error = Error;
153130
fn try_from(value: Value) -> Result<Self> {
154131
Ok(match value {
155132
Value::TapInfo(tapinfo) => tapinfo,
156-
Value::Descriptor(desc) => match desc.definite()? {
157-
miniscript::Descriptor::Tr(tr_desc) => (*tr_desc.spend_info()).clone(),
158-
_ => bail!(Error::NotTapInfoLike(Value::Descriptor(desc).into())),
159-
},
133+
Value::Descriptor(desc) => (*desc
134+
.tap_info()?
135+
.ok_or_else(|| Error::NotTapInfoLike(Value::Descriptor(desc).into()))?)
136+
.clone(),
160137
v => bail!(Error::NotTapInfoLike(v.into())),
161138
})
162139
}

0 commit comments

Comments
 (0)