Skip to content

Commit 270cc61

Browse files
miniscript: Policy field accessors
1 parent a2d9f17 commit 270cc61

File tree

2 files changed

+33
-8
lines changed

2 files changed

+33
-8
lines changed

src/runtime/value.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -518,6 +518,7 @@ impl FieldAccess for Value {
518518
Value::Array(x) => x.get_field(field),
519519
Value::Psbt(x) => x.get_field(field),
520520
Value::Transaction(x) => x.get_field(field),
521+
Value::Policy(x) => x.get_field(field),
521522
Value::Descriptor(x) => x.get_field(field),
522523
Value::TapInfo(x) => x.get_field(field),
523524
Value::Address(x) => x.get_field(field),

src/stdlib/miniscript.rs

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
use std::convert::{TryFrom, TryInto};
22
use std::{fmt, sync::Arc};
33

4+
use bitcoin::ScriptBuf;
45
use miniscript::descriptor::{DescriptorType, ShInner, WshInner};
56
use miniscript::{ScriptContext, Threshold};
67

78
use crate::runtime::scope::{Mutable, ScopeRef};
89
use crate::runtime::{Array, Error, Evaluate, ExprRepr, FieldAccess, Result, Value};
910
use crate::stdlib::{btc::WshScript, taproot::tap_scripts_to_val};
10-
use crate::util::{DescriptorExt, DescriptorSecretKeyExt, MiniscriptExt};
11+
use crate::util::{DeriveExt, DescriptorExt, DescriptorSecretKeyExt, MiniscriptExt};
1112
use crate::{ast, DescriptorDpk as Descriptor, MiniscriptDpk as Miniscript, PolicyDpk as Policy};
1213

1314
pub use crate::runtime::AndOr;
@@ -245,7 +246,8 @@ pub mod fns {
245246
}
246247
}
247248

248-
// Descriptor fields accessors
249+
// Field accessors
250+
249251
impl FieldAccess for Descriptor {
250252
fn get_field(self, field: &Value) -> Option<Value> {
251253
Some(match field.as_str()? {
@@ -258,8 +260,9 @@ impl FieldAccess for Descriptor {
258260
"is_definite" => (!self.has_wildcard() && !self.is_multipath()).into(),
259261

260262
// Only available for definite descriptors (non-multi-path and no underived wildcards)
261-
"script_pubkey" | "scriptPubKey" => self.to_script_pubkey().ok()?.into(),
262-
"explicit_script" | "explicitScript" => self.to_explicit_script().ok()?.into(),
263+
"script_pubkey" => self.to_script_pubkey().ok()?.into(),
264+
// Only available for definite non-taproot descriptors
265+
"explicit_script" => self.to_explicit_script().ok()?.into(),
263266
// Only available for definite segwit descriptors
264267
"witness_program" => self.witness_program().ok()??.into(),
265268

@@ -278,6 +281,30 @@ impl FieldAccess for Descriptor {
278281
}
279282
}
280283

284+
impl FieldAccess for Policy {
285+
fn get_field(self, field: &Value) -> Option<Value> {
286+
fn compile<Ctx: miniscript::ScriptContext>(policy: &Policy) -> Result<ScriptBuf> {
287+
Ok(policy.compile::<Ctx>()?.derive_keys()?.encode())
288+
}
289+
Some(match field.as_str()? {
290+
"keys" => self.keys().into_iter().cloned().collect(),
291+
"is_valid" => self.is_valid().is_ok().into(),
292+
"is_safe" => self.is_safe_nonmalleable().0.into(),
293+
"is_nonmalleable" => self.is_safe_nonmalleable().1.into(),
294+
"is_wildcard" => self.has_wildcards().into(),
295+
"is_definite" => (!self.has_wildcards()).into(),
296+
297+
// Script compilation fields are only available for Policies that are `$p->is_valid && $p->is_safe && $p->is_nonmalleable && $p->is_definite`
298+
// You can use the tapscript()/segwitv0() functions to get a more useful exception instead of a 'field not found'
299+
"tapscript" => compile::<miniscript::Tap>(&self).ok()?.into(),
300+
"segwitv0" => compile::<miniscript::Segwitv0>(&self).ok()?.into(),
301+
_ => {
302+
return None;
303+
}
304+
})
305+
}
306+
}
307+
281308
fn into_policies(values: Vec<Value>) -> Result<Vec<Arc<Policy>>> {
282309
values
283310
.into_iter()
@@ -314,10 +341,7 @@ impl TryFrom<Value> for Policy {
314341
// PubKeys are coerced into a pk() policy
315342
Value::PubKey(pubkey) => Ok(Policy::Key(pubkey)),
316343
// SecKeys are coerced into a PubKey, then to a pk()
317-
Value::SecKey(seckey) => {
318-
let pubkey = seckey.to_public_()?;
319-
Ok(Policy::Key(pubkey))
320-
}
344+
Value::SecKey(seckey) => Ok(Policy::Key(seckey.to_public_()?)),
321345
v => Err(Error::NotPolicyLike(v.into())),
322346
}
323347
}

0 commit comments

Comments
 (0)