-
Notifications
You must be signed in to change notification settings - Fork 36.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Miniscript support in Output Descriptors #24148
Miniscript support in Output Descriptors #24148
Conversation
f2f7d89
to
6d3de87
Compare
290fe4e
to
c016f3c
Compare
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers. ConflictsReviewers, this pull request conflicts with the following ones:
If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first. |
6b1d90c
to
478e78c
Compare
Rebased. |
478e78c
to
a404f37
Compare
a404f37
to
be0ce4b
Compare
Rebased. |
be0ce4b
to
957452d
Compare
2da94a4 fuzz: add a fuzz target for Miniscript decoding from Script (Antoine Poinsot) f836999 Miniscript: ops limit and stack size computation (Pieter Wuille) 2e55e88 Miniscript: conversion from script (Pieter Wuille) 1ddaa66 Miniscript: type system, script creation, text notation, tests (Pieter Wuille) 4fe2936 script: expose getter for CScriptNum, add a BuildScript helper (Antoine Poinsot) f4e289f script: move CheckMinimalPush from interpreter to script.h (Antoine Poinsot) 31ec6ae script: make IsPushdataOp non-static (Antoine Poinsot) Pull request description: Miniscript is a language for writing (a subset of) Bitcoin Scripts in a structured way. Miniscript permits: - To safely extend the Output Descriptor language to many more scripting features thanks to the typing system (composition). - Statical analysis of spending conditions, maximum spending cost of each branch, security properties, third-party malleability. - General satisfaction of any correctly typed ("valid" [0]) Miniscript. The satisfaction itself is also analyzable. - To extend the possibilities of external signers, because of all of the above and since it carries enough metadata. Miniscript guarantees: - That for any statically-analyzed as "safe" [0] Script, a witness can be constructed in the bounds of the consensus and standardness rules (standardness complete). - That unless the conditions of the Miniscript are met, no witness can be created for the Script (consensus sound). - Third-party malleability protection for the satisfaction of a sane Miniscript, which is too complex to summarize here. For more details around Miniscript (including the specifications), please refer to the [website](https://bitcoin.sipa.be/miniscript/). Miniscript was designed by Pieter Wuille, Andrew Poelstra and Sanket Kanjalkar. This PR is an updated and rebased version of #16800. See [the commit history of the Miniscript repository](https://github.com/sipa/miniscript/commits/master) for details about the changes made since September 2019 (TL;DR: bugfixes, introduction of timelock conflicts in the type system, `pk()` and `pkh()` aliases, `thresh_m` renamed to `multi`, all recursive algorithms were made non-recursive). This PR is also the first in a series of 3: - The first one (here) integrates the backbone of Miniscript. - The second one (#24148) introduces support for Miniscript in Output Descriptors, allowing for watch-only support of Miniscript Descriptors in the wallet. - The third one (#24149) implements signing for these Miniscript Descriptors, using Miniscript's satisfaction algorithm. Note to reviewers: - Miniscript is currently defined only for P2WSH. No Taproot yet. - Miniscript is different from the policy language (a high-level logical representation of a spending policy). A policy->Miniscript compiler is not included here. - The fuzz target included here is more interestingly extended in the 3rd PR to check a script's satisfaction against `VerifyScript`. I think it could be further improved by having custom mutators as we now have for multisig (see #23105). A minified corpus of Miniscript Scripts is available at bitcoin-core/qa-assets#85. [0] We call "valid" any correctly-typed Miniscript. And "safe" any sane Miniscript, ie one whose satisfaction isn't malleable, which requires a key for any spending path, etc.. ACKs for top commit: jb55: ACK 2da94a4 laanwj: Light code review ACK 2da94a4 (mostly reviewed the changes to the existing code and build system) Tree-SHA512: d3ef558436cfcc699a50ad13caf1e776f7d0addddb433ee28ef38f66ea5c3e581382d8c748ccac9b51768e4b95712ed7a6112b0e3281a6551e0f325331de9167
I (slightly) messed up the last rebase here, but there was some updates in the meantime so i'll push a fix along with those soon. |
A nit, but was helpful when writing unit tests for Miniscript parsing
49ac002
to
d30202c
Compare
Miniscript descriptors are defined under P2WSH context (either `wsh()` or `sh(wsh())`). Only sane Miniscripts are accepted, as insane ones (although valid by type) can have surprising behaviour with regard to malleability guarantees and resources limitations. As Miniscript descriptors are longer and more complex than "legacy" descriptors, care was taken in error reporting to help a user determine for what reason a provided Miniscript is insane. Co-authored-by: Pieter Wuille <pieter.wuille@gmail.com>
d30202c
to
ffc79b8
Compare
Thanks @w0xlt, good catch: it's the unit test for
i was missing an diff --git a/src/test/miniscript_tests.cpp b/src/test/miniscript_tests.cpp
index f5bea00e1e..bc5c49ef63 100644
--- a/src/test/miniscript_tests.cpp
+++ b/src/test/miniscript_tests.cpp
@@ -299,10 +299,10 @@ BOOST_AUTO_TEST_CASE(fixed_tests)
// 2. It contains timelock mixes
// We'll report the timelock mix error, as it's "deeper" (closer to be a leaf node) than the "no 's' property"
// error is.
- const auto ms_ins = miniscript::FromString("or_i(and_b(after(1),after(10000000)),pk(03cdabb7f2dce7bfbd8a0b9570c6fd1e712e5d64045e9d6b517b3d5072251dc204))", CONVERTER);
- BOOST_CHECK(ms_ins && !ms_ins->IsSane());
+ const auto ms_ins = miniscript::FromString("or_i(and_b(after(1),a:after(1000000000)),pk(03cdabb7f2dce7bfbd8a0b9570c6fd1e712e5d64045e9d6b517b3d5072251dc204))", CONVERTER);
+ BOOST_CHECK(ms_ins && ms_ins->IsValid() && !ms_ins->IsSane());
const auto insane_sub = ms_ins->FindInsaneSub();
- BOOST_CHECK(insane_sub && *insane_sub->ToString(CONVERTER) == "and_b(after(1),after(10000000))");
+ BOOST_CHECK(insane_sub && *insane_sub->ToString(CONVERTER) == "and_b(after(1),a:after(1000000000))");
// Timelock tests
Test("after(100)", "?", TESTMODE_VALID | TESTMODE_NONMAL); // only heightlock I also took the opportunity to fix the two nits @Sjors had previously. |
It's still a bit weird that a |
re-utACK ffc79b8 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
reACK ffc79b8
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
only reviewed the tests and interface, non blocking nits only
) | ||
|
||
self.log.info("Testing we detect funds sent to one of them") | ||
addr = self.ms_wo_wallet.getnewaddress() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
imo makes more sense to do the rest of the test against an address we explicitly checked was derived correctly(instead of the 3rd one)
) | ||
self.ms_wo_wallet = self.nodes[0].get_wallet_rpc("ms_wo") | ||
|
||
# Sanity check we wouldn't let an insane Miniscript descriptor in |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sure, what I mean is "assuming this is merged, as a reader of the test, what is this?" i.e. should include link or self contained definition
ACK ffc79b8 |
d751beb Release notes for Miniscript support in P2WSH descriptors (Antoine Poinsot) Pull request description: Changelog for #24148. ACKs for top commit: Sjors: ACK d751beb achow101: ACK d751beb w0xlt: ACK d751beb Tree-SHA512: 5ecdc8501fdacca35b33f7425dbc192860e3e061bc9287b682c55d6da210cc5c0ff7154629e453a9a8d528bad518c35c49de31d114acab77bf27449940e9ca04
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
post-merge ACK. Did not review the tests. I like the error reporting by looking for inner insane sub.
ffc79b8 qa: functional test Miniscript watchonly support (Antoine Poinsot) bfb0367 Miniscript support in output descriptors (Antoine Poinsot) 4a08288 qa: better error reporting on descriptor parsing error (Antoine Poinsot) d25d58b miniscript: add a helper to find the first insane sub with no child (Antoine Poinsot) c38c7c5 miniscript: don't check for top level validity at parsing time (Antoine Poinsot) Pull request description: This adds Miniscript support for Output Descriptors without any signing logic (yet). See the OP of bitcoin#24147 for a description of Miniscript and a rationale of having it in Bitcoin Core. On its own, this PR adds "watchonly" support for Miniscript descriptors in the descriptor wallet. A follow-up adds signing support. A minified corpus of Miniscript Descriptors for the `descriptor_parse` fuzz target is available at bitcoin-core/qa-assets#92. The Miniscript descriptors used in the unit tests here and in bitcoin#24149 were cross-tested against the Rust implementation at https://github.com/rust-bitcoin/rust-miniscript. This PR contains code and insights from Pieter Wuille. ACKs for top commit: Sjors: re-utACK ffc79b8 achow101: ACK ffc79b8 w0xlt: reACK bitcoin@ffc79b8 Tree-SHA512: 02d919d38bb626d3c557eca3680ce71117739fa161b7a92cfdb6c9c432ed88870b1ed127ba24248574c40c7428217d7e9bdd986fd8cd7c51fae8c776e1271fb9
…scriptors d751beb Release notes for Miniscript support in P2WSH descriptors (Antoine Poinsot) Pull request description: Changelog for bitcoin#24148. ACKs for top commit: Sjors: ACK d751beb achow101: ACK d751beb w0xlt: ACK bitcoin@d751beb Tree-SHA512: 5ecdc8501fdacca35b33f7425dbc192860e3e061bc9287b682c55d6da210cc5c0ff7154629e453a9a8d528bad518c35c49de31d114acab77bf27449940e9ca04
Opening a miniscript-descriptor wallet in an older version of Bitcoin Core causes a crash. (How) did we handle backward compatibility for |
assert(m_out); | ||
Key key = m_keys.size(); | ||
auto pk = ParsePubkey(key, {&*begin, &*end}, ParseScriptContext::P2WSH, *m_out, m_key_parsing_error); | ||
if (!pk) return {}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I get two compiler warnings on master from this, gcc (Ubuntu 9.4.0-1ubuntu1~20.04.1) 9.4.0
:
script/descriptor.cpp: In function ‘miniscript::NodeRef<Key> miniscript::internal::DecodeScript(I&, I, const Ctx&) [with Key = unsigned int; Ctx = {anonymous}::KeyParser; I = __gnu_cxx::__normal_iterator<std::pair<opcodetype, std::vector<unsigned char> >*, std::vector<std::pair<opcodetype, std::vector<unsigned char> > > >]’:
script/descriptor.cpp:1243:17: warning: ‘<anonymous>’ may be used uninitialized in this function [-Wmaybe-uninitialized]
1243 | return {};
| ^
script/descriptor.cpp: In function ‘miniscript::NodeRef<Key> miniscript::internal::Parse(Span<const char>, const Ctx&) [with Key = unsigned int; Ctx = {anonymous}::KeyParser]’:
script/descriptor.cpp:1208:26: warning: ‘<anonymous>’ may be used uninitialized in this function [-Wmaybe-uninitialized]
1208 | if (!pk) return {};
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe that's a known false positive in certain GCC versions.
Not sure how it was done with |
930e2f2 Update the Miniscript fuzz tests from Bitcoin Core master (Antoine Poinsot) f62abcf Update the Miniscript unit tests from Bitcoin master (Antoine Poinsot) fd9bed0 miniscript: update the source from Bitcoin Core master branch (Antoine Poinsot) Pull request description: The PRs introducing Miniscript to Bitcoin Core contained the most up to date version of the code (bitcoin/bitcoin#24148 and bitcoin/bitcoin#24149). Now they are both merged, update the code here to reflect the updates made in these PRs. ACKs for top commit: sipa: ACK 930e2f2. Matches the Bitcoin Core master branch code, and compiles. Tree-SHA512: 0ef587d005dc472cada86b99e62f37aa6bbfa09a8d1db95726a0103c0e827880d557ebce39c87eeb281c952b77fcf462c9a779008eed5b2d0f2d63478f4fab4c
This adds Miniscript support for Output Descriptors without any signing logic (yet). See the OP of #24147 for a description of Miniscript and a rationale of having it in Bitcoin Core.
On its own, this PR adds "watchonly" support for Miniscript descriptors in the descriptor wallet. A follow-up adds signing support.
A minified corpus of Miniscript Descriptors for the
descriptor_parse
fuzz target is available at bitcoin-core/qa-assets#92.The Miniscript descriptors used in the unit tests here and in #24149 were cross-tested against the Rust implementation at https://github.com/rust-bitcoin/rust-miniscript.
This PR contains code and insights from Pieter Wuille.