forked from bitcoin/bitcoin
-
Notifications
You must be signed in to change notification settings - Fork 154
Add compile_tr() for Taptree-native policy compilation #270
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
Open
kwsantiago
wants to merge
6
commits into
bitcoinknots:29.x-knots
Choose a base branch
from
privkeyio:compile-tr-native
base: 29.x-knots
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
23b7327
miniscript: add HasBranchingOpcodes() to Node
kwsantiago 43f190a
Add policy type and parser for spending policies
kwsantiago 5dca352
Add Taptree-native policy compiler
kwsantiago c142144
Add compile_tr() descriptor function
kwsantiago 3805e3e
policy: add pre-validation before compilation
kwsantiago 3f21771
test: add policy validation and timelock mix tests
kwsantiago File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -9,6 +9,7 @@ | |
| #include <pubkey.h> | ||
| #include <script/miniscript.h> | ||
| #include <script/parsing.h> | ||
| #include <script/policy.h> | ||
| #include <script/script.h> | ||
| #include <script/signingprovider.h> | ||
| #include <script/solver.h> | ||
|
|
@@ -1941,6 +1942,85 @@ std::vector<std::unique_ptr<DescriptorImpl>> ParseScript(uint32_t& key_exp_index | |
| error = "Can only have addr() at top level"; | ||
| return {}; | ||
| } | ||
| if (ctx == ParseScriptContext::TOP && Func("compile_tr", expr)) { | ||
| auto arg = Expr(expr); | ||
| auto internal_keys = ParsePubkey(key_exp_index, arg, ParseScriptContext::P2TR, out, error); | ||
| if (internal_keys.empty()) { | ||
| error = strprintf("compile_tr(): %s", error); | ||
| return {}; | ||
| } | ||
| ++key_exp_index; | ||
| if (!Const(",", expr)) { | ||
| error = "compile_tr(): expected ',' after internal key"; | ||
| return {}; | ||
| } | ||
|
|
||
| KeyParser parser(/*out=*/&out, /*in=*/nullptr, /*ctx=*/miniscript::MiniscriptContext::TAPSCRIPT, key_exp_index); | ||
| auto pol = policy::ParsePolicy<uint32_t>(expr, parser); | ||
| if (!pol || !expr.empty()) { | ||
| error = "compile_tr(): invalid policy expression"; | ||
| if (!parser.m_key_parsing_error.empty()) error = strprintf("compile_tr(): %s", parser.m_key_parsing_error); | ||
| return {}; | ||
| } | ||
|
|
||
| auto result = policy::CompileTrNative<uint32_t>(*pol); | ||
| if (!result) { | ||
| error = "compile_tr(): policy compilation failed (too many leaves or unsupported policy)"; | ||
| return {}; | ||
| } | ||
|
|
||
| auto& [scripts, depths] = *result; | ||
|
|
||
| size_t max_providers_len = internal_keys.size(); | ||
| if (!parser.m_keys.empty()) { | ||
| max_providers_len = std::max(max_providers_len, std::max_element(parser.m_keys.begin(), parser.m_keys.end(), | ||
| [](const std::vector<std::unique_ptr<PubkeyProvider>>& a, const std::vector<std::unique_ptr<PubkeyProvider>>& b) { | ||
| return a.size() < b.size(); | ||
| })->size()); | ||
| } | ||
|
|
||
| for (auto& vec : parser.m_keys) { | ||
| if (vec.size() == 1) { | ||
| for (size_t j = 1; j < max_providers_len; ++j) { | ||
| vec.emplace_back(vec.at(0)->Clone()); | ||
| } | ||
| } else if (vec.size() != max_providers_len) { | ||
| error = "compile_tr(): multipath derivation paths have mismatched lengths"; | ||
| return {}; | ||
| } | ||
| } | ||
|
|
||
| if (internal_keys.size() > 1 && internal_keys.size() != max_providers_len) { | ||
| error = "compile_tr(): multipath internal key mismatches multipath subscripts lengths"; | ||
| return {}; | ||
| } | ||
| while (internal_keys.size() < max_providers_len) { | ||
| internal_keys.emplace_back(internal_keys.at(0)->Clone()); | ||
| } | ||
|
|
||
| key_exp_index += parser.m_keys.size(); | ||
| assert(TaprootBuilder::ValidDepths(depths)); | ||
|
|
||
| for (size_t mp = 0; mp < max_providers_len; ++mp) { | ||
| std::vector<std::unique_ptr<DescriptorImpl>> descs; | ||
| descs.reserve(scripts.size()); | ||
| for (size_t i = 0; i < scripts.size(); ++i) { | ||
| std::vector<std::unique_ptr<PubkeyProvider>> leaf_keys; | ||
| leaf_keys.reserve(parser.m_keys.size()); | ||
| for (auto& key_vec : parser.m_keys) { | ||
| leaf_keys.push_back(key_vec.at(mp)->Clone()); | ||
| } | ||
| descs.push_back(std::make_unique<MiniscriptDescriptor>( | ||
| std::move(leaf_keys), (mp == max_providers_len - 1) ? std::move(scripts[i]) : scripts[i]->Clone())); | ||
| } | ||
| ret.emplace_back(std::make_unique<TRDescriptor>(std::move(internal_keys.at(mp)), std::move(descs), depths)); | ||
| } | ||
| return ret; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Where can I find design material on this? |
||
|
|
||
| } else if (Func("compile_tr", expr)) { | ||
| error = "Can only have compile_tr at top level"; | ||
| return {}; | ||
| } | ||
| if (ctx == ParseScriptContext::TOP && Func("tr", expr)) { | ||
| auto arg = Expr(expr); | ||
| auto internal_keys = ParsePubkey(key_exp_index, arg, ParseScriptContext::P2TR, out, error); | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| // Copyright (c) 2026 The Bitcoin Knots developers | ||
| // Distributed under the MIT software license, see the accompanying | ||
| // file COPYING or http://www.opensource.org/licenses/mit-license.php. | ||
|
|
||
| #include <script/policy.h> |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
Where is
key_exp_indexused? (I've searched throughout the parser and I don't see it ever used.)