Skip to content

Commit c6dfc12

Browse files
committed
This fix has a bunch of bug fixes.
Sorry for clubbing them all together into a single commit. First, the upstream serialization fmt::Display does not work as expected for the purposes for elements-miniscript. It serializes the explicit asset and explicit values as 32 bytes and u64 respectively. Second is a bug that is specific to elements-miniscript, we were not checking that the correct possition and parent are being used while creating a new miniscript. This allowed to create fragments that allowed to use confidential::Value in asset_eq fragments. Third, this removes the from_str implementations from AssetExpr, ValueExpr and SpkExpr. These expressions cannot be independent as they are parent context dependent. Add a from_arg_str implementation instead
1 parent 2a5455a commit c6dfc12

File tree

2 files changed

+55
-31
lines changed

2 files changed

+55
-31
lines changed

src/extensions/introspect_ops.rs

Lines changed: 51 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -168,24 +168,22 @@ impl<T: ExtParam> fmt::Debug for AssetExpr<T> {
168168
}
169169
}
170170

171-
impl<T: ExtParam> FromStr for AssetExpr<T> {
172-
type Err = Error;
173-
174-
fn from_str(s: &str) -> Result<Self, Self::Err> {
171+
impl<T: ExtParam> ArgFromStr for AssetExpr<T> {
172+
fn arg_from_str(s: &str, parent: &str, pos: usize) -> Result<Self, Error> {
175173
let top = expression::Tree::from_str(s)?;
176-
Self::from_tree(&top)
174+
Self::from_tree_parent(&top, parent, pos)
177175
}
178176
}
179177

180-
impl<T: ExtParam> FromTree for AssetExpr<T> {
181-
fn from_tree(top: &Tree<'_>) -> Result<Self, Error> {
178+
impl<T: ExtParam> AssetExpr<T> {
179+
fn from_tree_parent(top: &Tree<'_>, parent: &str, pos: usize) -> Result<Self, Error> {
182180
match (top.name, top.args.len()) {
183181
("curr_inp_asset", 0) => Ok(AssetExpr::CurrInputAsset),
184182
("inp_asset", 1) => expression::terminal(&top.args[0], expression::parse_num::<usize>)
185183
.map(AssetExpr::Input),
186184
("out_asset", 1) => expression::terminal(&top.args[0], expression::parse_num::<usize>)
187185
.map(AssetExpr::Output),
188-
(asset, 0) => Ok(AssetExpr::Const(T::arg_from_str(asset, "", 0)?)),
186+
(asset, 0) => Ok(AssetExpr::Const(T::arg_from_str(asset, parent, pos)?)),
189187
_ => Err(Error::Unexpected(format!(
190188
"{}({} args) while parsing Extension",
191189
top.name,
@@ -244,24 +242,22 @@ impl<T: ExtParam> fmt::Debug for ValueExpr<T> {
244242
}
245243
}
246244

247-
impl<T: ExtParam> FromStr for ValueExpr<T> {
248-
type Err = Error;
249-
250-
fn from_str(s: &str) -> Result<Self, Self::Err> {
245+
impl<T: ExtParam> ArgFromStr for ValueExpr<T> {
246+
fn arg_from_str(s: &str, parent: &str, pos: usize) -> Result<Self, Error> {
251247
let top = expression::Tree::from_str(s)?;
252-
Self::from_tree(&top)
248+
Self::from_tree_parent(&top, parent, pos)
253249
}
254250
}
255251

256-
impl<T: ExtParam> FromTree for ValueExpr<T> {
257-
fn from_tree(top: &Tree<'_>) -> Result<Self, Error> {
252+
impl<T: ExtParam> ValueExpr<T> {
253+
fn from_tree_parent(top: &Tree<'_>, parent: &str, pos: usize) -> Result<Self, Error> {
258254
match (top.name, top.args.len()) {
259255
("curr_inp_value", 0) => Ok(ValueExpr::CurrInputValue),
260256
("inp_value", 1) => expression::terminal(&top.args[0], expression::parse_num::<usize>)
261257
.map(ValueExpr::Input),
262258
("out_value", 1) => expression::terminal(&top.args[0], expression::parse_num::<usize>)
263259
.map(ValueExpr::Output),
264-
(value, 0) => Ok(ValueExpr::Const(T::arg_from_str(value, "", 0)?)),
260+
(value, 0) => Ok(ValueExpr::Const(T::arg_from_str(value, parent, pos)?)),
265261
_ => Err(Error::Unexpected(format!(
266262
"{}({} args) while parsing Extension",
267263
top.name,
@@ -320,24 +316,22 @@ impl<T: ExtParam> fmt::Debug for SpkExpr<T> {
320316
}
321317
}
322318

323-
impl<T: ExtParam> FromStr for SpkExpr<T> {
324-
type Err = Error;
325-
326-
fn from_str(s: &str) -> Result<Self, Self::Err> {
319+
impl<T: ExtParam> ArgFromStr for SpkExpr<T> {
320+
fn arg_from_str(s: &str, parent: &str, pos: usize) -> Result<Self, Error> {
327321
let top = expression::Tree::from_str(s)?;
328-
Self::from_tree(&top)
322+
Self::from_tree_parent(&top, parent, pos)
329323
}
330324
}
331325

332-
impl<T: ExtParam> FromTree for SpkExpr<T> {
333-
fn from_tree(top: &Tree<'_>) -> Result<Self, Error> {
326+
impl<T: ExtParam> SpkExpr<T> {
327+
fn from_tree_parent(top: &Tree<'_>, parent: &str, pos: usize) -> Result<Self, Error> {
334328
match (top.name, top.args.len()) {
335329
("curr_inp_spk", 0) => Ok(SpkExpr::CurrInputSpk),
336330
("inp_spk", 1) => expression::terminal(&top.args[0], expression::parse_num::<usize>)
337331
.map(SpkExpr::Input),
338332
("out_spk", 1) => expression::terminal(&top.args[0], expression::parse_num::<usize>)
339333
.map(SpkExpr::Output),
340-
(asset, 0) => Ok(SpkExpr::Const(T::arg_from_str(asset, "", 0)?)),
334+
(asset, 0) => Ok(SpkExpr::Const(T::arg_from_str(asset, parent, pos)?)),
341335
_ => Err(Error::Unexpected(format!(
342336
"{}({} args) while parsing Extension",
343337
top.name,
@@ -385,11 +379,27 @@ impl<T: ExtParam> FromStr for CovOps<T> {
385379
impl<T: ExtParam> FromTree for CovOps<T> {
386380
fn from_tree(top: &Tree<'_>) -> Result<Self, Error> {
387381
match (top.name, top.args.len()) {
388-
("is_exp_asset", 1) => expression::unary(top, CovOps::IsExpAsset),
389-
("is_exp_value", 1) => expression::unary(top, CovOps::IsExpValue),
390-
("asset_eq", 2) => expression::binary(top, CovOps::AssetEq),
391-
("value_eq", 2) => expression::binary(top, CovOps::ValueEq),
392-
("spk_eq", 2) => expression::binary(top, CovOps::SpkEq),
382+
("is_exp_asset", 1) => {
383+
AssetExpr::from_tree_parent(&top.args[0], &top.name, 0).map(CovOps::IsExpAsset)
384+
}
385+
("is_exp_value", 1) => {
386+
ValueExpr::from_tree_parent(&top.args[0], &top.name, 0).map(CovOps::IsExpValue)
387+
}
388+
("asset_eq", 2) => {
389+
let l = AssetExpr::from_tree_parent(&top.args[0], &top.name, 0)?;
390+
let r = AssetExpr::from_tree_parent(&top.args[1], &top.name, 1)?;
391+
Ok(CovOps::AssetEq(l, r))
392+
}
393+
("value_eq", 2) => {
394+
let l = ValueExpr::from_tree_parent(&top.args[0], &top.name, 0)?;
395+
let r = ValueExpr::from_tree_parent(&top.args[1], &top.name, 1)?;
396+
Ok(CovOps::ValueEq(l, r))
397+
}
398+
("spk_eq", 2) => {
399+
let l = SpkExpr::from_tree_parent(&top.args[0], &top.name, 0)?;
400+
let r = SpkExpr::from_tree_parent(&top.args[1], &top.name, 1)?;
401+
Ok(CovOps::SpkEq(l, r))
402+
}
393403
("curr_idx_eq", 1) => {
394404
expression::terminal(&top.args[0], expression::parse_num::<usize>)
395405
.map(CovOps::CurrIndEq)
@@ -1148,6 +1158,16 @@ mod tests {
11481158
_test_parse("and_v(v:pk(K),and_v(v:value_eq(ConfVal,ConfVal),and_v(v:spk_eq(V1Spk,V1Spk),curr_idx_eq(1))))");
11491159
}
11501160

1161+
#[test]
1162+
fn options_fail_test() {
1163+
type MsExt = Miniscript<XOnlyPublicKey, Tap, CovOps<CovExtArgs>>;
1164+
1165+
// 33 bytes explicit asset succeeds
1166+
MsExt::from_str_insane("asset_eq(out_asset(0),0179d51a47e4ac8e32306486dd0926a88678c392f2ed5f213e3ff2ad461c7c25e1)").unwrap();
1167+
// 32 bytes explicit asset without prefix fails
1168+
MsExt::from_str_insane("asset_eq(out_asset(0),79d51a47e4ac8e32306486dd0926a88678c392f2ed5f213e3ff2ad461c7c25e1)").unwrap_err();
1169+
}
1170+
11511171
#[rustfmt::skip]
11521172
fn _test_parse(s: &str) {
11531173
type MsExtStr = Miniscript<String, Tap, CovOps<String>>;
@@ -1174,5 +1194,7 @@ mod tests {
11741194
let ms = ms.translate_ext(&mut ext_t).unwrap();
11751195
// script rtt
11761196
assert_eq!(ms.encode(), MsExt::parse_insane(&ms.encode()).unwrap().encode());
1197+
// String rtt of the translated script
1198+
assert_eq!(ms, MsExt::from_str_insane(&ms.to_string()).unwrap())
11771199
}
11781200
}

src/extensions/mod.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
55
use std::{fmt, hash};
66

7+
use bitcoin::hashes::hex::ToHex;
8+
use elements::encode::serialize;
79
use elements::script::Builder;
810
use elements::{confidential, Transaction, TxOut};
911

@@ -354,8 +356,8 @@ impl fmt::Display for CovExtArgs {
354356
match self {
355357
CovExtArgs::XOnlyKey(x) => write!(f, "{}", x),
356358
CovExtArgs::CsfsMsg(m) => write!(f, "{}", m),
357-
CovExtArgs::Asset(a) => write!(f, "{}", a),
358-
CovExtArgs::Value(v) => write!(f, "{}", v),
359+
CovExtArgs::Asset(a) => write!(f, "{}", serialize(a).to_hex()),
360+
CovExtArgs::Value(v) => write!(f, "{}", serialize(v).to_hex()),
359361
CovExtArgs::Script(s) => write!(f, "{}", s),
360362
}
361363
}

0 commit comments

Comments
 (0)