Skip to content

Commit 5fb98e1

Browse files
committed
Add compile_tr() policy compiler for Taptree-native descriptors
1 parent c577536 commit 5fb98e1

File tree

6 files changed

+1052
-0
lines changed

6 files changed

+1052
-0
lines changed

src/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,7 @@ add_library(bitcoin_common STATIC EXCLUDE_FROM_ALL
181181
script/descriptor.cpp
182182
script/miniscript.cpp
183183
script/parsing.cpp
184+
script/policy.cpp
184185
script/sign.cpp
185186
script/signingprovider.cpp
186187
script/solver.cpp

src/script/descriptor.cpp

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include <pubkey.h>
1010
#include <script/miniscript.h>
1111
#include <script/parsing.h>
12+
#include <script/policy.h>
1213
#include <script/script.h>
1314
#include <script/signingprovider.h>
1415
#include <script/solver.h>
@@ -1941,6 +1942,55 @@ std::vector<std::unique_ptr<DescriptorImpl>> ParseScript(uint32_t& key_exp_index
19411942
error = "Can only have addr() at top level";
19421943
return {};
19431944
}
1945+
if (ctx == ParseScriptContext::TOP && Func("compile_tr", expr)) {
1946+
auto arg = Expr(expr);
1947+
auto internal_keys = ParsePubkey(key_exp_index, arg, ParseScriptContext::P2TR, out, error);
1948+
if (internal_keys.empty()) {
1949+
error = strprintf("compile_tr(): %s", error);
1950+
return {};
1951+
}
1952+
++key_exp_index;
1953+
if (!Const(",", expr)) {
1954+
error = "compile_tr(): expected ',' after internal key";
1955+
return {};
1956+
}
1957+
1958+
KeyParser parser(/*out = */&out, /* in = */nullptr, /* ctx = */miniscript::MiniscriptContext::TAPSCRIPT, key_exp_index);
1959+
auto pol = policy::ParsePolicy<uint32_t>(expr, parser);
1960+
if (!pol) {
1961+
error = "compile_tr(): invalid policy expression";
1962+
if (!parser.m_key_parsing_error.empty()) error = strprintf("compile_tr(): %s", parser.m_key_parsing_error);
1963+
return {};
1964+
}
1965+
1966+
auto result = policy::CompileTrNative<uint32_t>(*pol);
1967+
if (!result) {
1968+
error = "compile_tr(): policy compilation failed (too many leaves or unsupported policy)";
1969+
return {};
1970+
}
1971+
1972+
auto& [scripts, depths] = *result;
1973+
1974+
// Each compiled leaf's Node<uint32_t> uses key indices from parser.m_keys.
1975+
// Give each MiniscriptDescriptor a clone of all keys so indices resolve correctly.
1976+
std::vector<std::unique_ptr<DescriptorImpl>> descs;
1977+
for (size_t i = 0; i < scripts.size(); ++i) {
1978+
std::vector<std::unique_ptr<PubkeyProvider>> leaf_keys;
1979+
for (const auto& key_vec : parser.m_keys) {
1980+
leaf_keys.push_back(key_vec.at(0)->Clone());
1981+
}
1982+
descs.push_back(std::make_unique<MiniscriptDescriptor>(
1983+
std::move(leaf_keys), std::move(scripts[i])));
1984+
}
1985+
1986+
key_exp_index += parser.m_keys.size();
1987+
ret.emplace_back(std::make_unique<TRDescriptor>(std::move(internal_keys.at(0)), std::move(descs), depths));
1988+
return ret;
1989+
1990+
} else if (Func("compile_tr", expr)) {
1991+
error = "Can only have compile_tr at top level";
1992+
return {};
1993+
}
19441994
if (ctx == ParseScriptContext::TOP && Func("tr", expr)) {
19451995
auto arg = Expr(expr);
19461996
auto internal_keys = ParsePubkey(key_exp_index, arg, ParseScriptContext::P2TR, out, error);

src/script/policy.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// Copyright (c) 2026 The Bitcoin Knots developers
2+
// Distributed under the MIT software license, see the accompanying
3+
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4+
5+
#include <script/policy.h>

0 commit comments

Comments
 (0)