diff --git a/src/miniscript/decode.rs b/src/miniscript/decode.rs index 63dbe2047..8cd08d51c 100644 --- a/src/miniscript/decode.rs +++ b/src/miniscript/decode.rs @@ -224,10 +224,20 @@ pub fn parse(tokens: &mut TokenIter) -> Result, E // pubkeyhash and [T] VERIFY and [T] 0NOTEQUAL Tk::Verify => match_token!( tokens, - Tk::Equal, Tk::Hash20(hash), Tk::Hash160, Tk::Dup - => term.reduce0(Terminal::PkH( - hash160::Hash::from_inner(hash) - ))?, + Tk::Equal => match_token!( + tokens, + Tk::Hash20(hash), Tk::Hash160, Tk::Dup => { + term.reduce0(Terminal::PkH( + hash160::Hash::from_inner(hash) + ))? + }, + Tk::Hash32(hash), Tk::Sha256, Tk::Verify, Tk::Equal, Tk::Num(32), Tk::Size => { + non_term.push(NonTerm::Verify); + term.reduce0(Terminal::Sha256( + sha256::Hash::from_inner(hash) + ))? + }, + ), x => { tokens.un_next(x); non_term.push(NonTerm::Verify); @@ -343,16 +353,9 @@ pub fn parse(tokens: &mut TokenIter) -> Result, E } Some(NonTerm::MaybeAndV) => { // Handle `and_v` prefixing - match tokens.peek() { - None - | Some(&Tk::If) - | Some(&Tk::NotIf) - | Some(&Tk::Else) - | Some(&Tk::ToAltStack) => {} - _ => { - non_term.push(NonTerm::AndV); - non_term.push(NonTerm::Expression); - } + if is_and_v(tokens) { + non_term.push(NonTerm::AndV); + non_term.push(NonTerm::Expression); } } Some(NonTerm::MaybeSwap) => { @@ -377,7 +380,14 @@ pub fn parse(tokens: &mut TokenIter) -> Result, E Some(NonTerm::Verify) => term.reduce1(Terminal::Verify)?, Some(NonTerm::NonZero) => term.reduce1(Terminal::NonZero)?, Some(NonTerm::ZeroNotEqual) => term.reduce1(Terminal::ZeroNotEqual)?, - Some(NonTerm::AndV) => term.reduce2(Terminal::AndV)?, + Some(NonTerm::AndV) => { + if is_and_v(tokens) { + non_term.push(NonTerm::AndV); + non_term.push(NonTerm::MaybeAndV); + } else { + term.reduce2(Terminal::AndV)? + } + } Some(NonTerm::AndB) => term.reduce2(Terminal::AndB)?, Some(NonTerm::OrB) => term.reduce2(Terminal::OrB)?, Some(NonTerm::OrC) => term.reduce2(Terminal::OrC)?, @@ -472,3 +482,10 @@ pub fn parse(tokens: &mut TokenIter) -> Result, E assert_eq!(term.0.len(), 1); Ok(term.pop().unwrap()) } + +fn is_and_v(tokens: &mut TokenIter) -> bool { + match tokens.peek() { + None | Some(&Tk::If) | Some(&Tk::NotIf) | Some(&Tk::Else) | Some(&Tk::ToAltStack) => false, + _ => true, + } +} diff --git a/src/miniscript/mod.rs b/src/miniscript/mod.rs index 41efa1450..8d16091e3 100644 --- a/src/miniscript/mod.rs +++ b/src/miniscript/mod.rs @@ -686,6 +686,49 @@ mod tests { OP_PUSHBYTES_33 0289637f97580a796e050791ad5a2f27af1803645d95df021a3c2d82eb8c2ca7ff \ OP_PUSHNUM_5 OP_CHECKMULTISIG)", ); + + roundtrip( + &ms_str!( + "t:and_v(\ + vu:hash256(131772552c01444cd81360818376a040b7c3b2b7b0a53550ee3edde216cec61b),\ + v:sha256(ec4916dd28fc4c10d78e287ca5d9cc51ee1ae73cbfde08c6b37324cbfaac8bc5)\ + )"), + "Script(OP_IF OP_SIZE OP_PUSHBYTES_1 20 OP_EQUALVERIFY OP_HASH256 OP_PUSHBYTES_32 131772552c01444cd81360818376a040b7c3b2b7b0a53550ee3edde216cec61b OP_EQUAL OP_ELSE OP_0 OP_ENDIF OP_VERIFY OP_SIZE OP_PUSHBYTES_1 20 OP_EQUALVERIFY OP_SHA256 OP_PUSHBYTES_32 ec4916dd28fc4c10d78e287ca5d9cc51ee1ae73cbfde08c6b37324cbfaac8bc5 OP_EQUALVERIFY OP_PUSHNUM_1)" + ); + roundtrip( + &ms_str!("and_n(pk(03daed4f2be3a8bf278e70132fb0beb7522f570e144bf615c07e996d443dee8729),and_b(l:older(4252898),a:older(16)))"), + "Script(OP_PUSHBYTES_33 03daed4f2be3a8bf278e70132fb0beb7522f570e144bf615c07e996d443dee8729 OP_CHECKSIG OP_NOTIF OP_0 OP_ELSE OP_IF OP_0 OP_ELSE OP_PUSHBYTES_3 e2e440 OP_CSV OP_ENDIF OP_TOALTSTACK OP_PUSHNUM_16 OP_CSV OP_FROMALTSTACK OP_BOOLAND OP_ENDIF)" + ); + roundtrip( + &ms_str!( + "t:andor(multi(\ + 3,\ + 02d7924d4f7d43ea965a465ae3095ff41131e5946f3c85f79e44adbcf8e27e080e,\ + 03fff97bd5755eeea420453a14355235d382f6472f8568a18b2f057a1460297556,\ + 02e493dbf1c10d80f3581e4904930b1404cc6c13900ee0758474fa94abe8c4cd13\ + ),\ + v:older(4194305),\ + v:sha256(9267d3dbed802941483f1afa2a6bc68de5f653128aca9bf1461c5d0a3ad36ed2)\ + )"), + "Script(OP_PUSHNUM_3 OP_PUSHBYTES_33 02d7924d4f7d43ea965a465ae3095ff41131e5946f3c85f79e44adbcf8e27e080e \ + OP_PUSHBYTES_33 03fff97bd5755eeea420453a14355235d382f6472f8568a18b2f057a1460297556 \ + OP_PUSHBYTES_33 02e493dbf1c10d80f3581e4904930b1404cc6c13900ee0758474fa94abe8c4cd13 \ + OP_PUSHNUM_3 OP_CHECKMULTISIG OP_NOTIF OP_SIZE OP_PUSHBYTES_1 20 OP_EQUALVERIFY OP_SHA256 \ + OP_PUSHBYTES_32 9267d3dbed802941483f1afa2a6bc68de5f653128aca9bf1461c5d0a3ad36ed2 OP_EQUALVERIFY \ + OP_ELSE OP_PUSHBYTES_3 010040 OP_CSV OP_VERIFY OP_ENDIF OP_PUSHNUM_1)" + ); + roundtrip( + &ms_str!( + "t:and_v(\ + vu:hash256(131772552c01444cd81360818376a040b7c3b2b7b0a53550ee3edde216cec61b),\ + v:sha256(ec4916dd28fc4c10d78e287ca5d9cc51ee1ae73cbfde08c6b37324cbfaac8bc5)\ + )"), + "Script(\ + OP_IF OP_SIZE OP_PUSHBYTES_1 20 OP_EQUALVERIFY OP_HASH256 OP_PUSHBYTES_32 131772552c01444cd81360818376a040b7c3b2b7b0a53550ee3edde216cec61b OP_EQUAL \ + OP_ELSE OP_0 OP_ENDIF OP_VERIFY OP_SIZE OP_PUSHBYTES_1 20 OP_EQUALVERIFY OP_SHA256 OP_PUSHBYTES_32 ec4916dd28fc4c10d78e287ca5d9cc51ee1ae73cbfde08c6b37324cbfaac8bc5 OP_EQUALVERIFY \ + OP_PUSHNUM_1\ + )" + ); } #[test]