psbt: Change m_tap_tree to store just the tuples

Instead of having an entire TaprootBuilder which may or may not be
complete, and could potentially have future changes that interact oddly
with taproot tree tuples, have m_tap_tree be just the tuples.

When needed in other a TaprootBuilder for actual use, the tuples will be
added to a a TaprootBuilder that, in the future, can take in whatever
other data is needed as well.

Github-Pull: #25858
Rebased-From: 0577d423ad
This commit is contained in:
Andrew Chow 2022-08-16 21:17:43 -04:00 committed by fanquake
parent a9419eff0c
commit d810fde8ea
No known key found for this signature in database
GPG key ID: 2EEB9F5CC09526C1
3 changed files with 19 additions and 25 deletions

View file

@ -218,8 +218,14 @@ void PSBTOutput::FillSignatureData(SignatureData& sigdata) const
for (const auto& key_pair : hd_keypaths) {
sigdata.misc_pubkeys.emplace(key_pair.first.GetID(), key_pair);
}
if (m_tap_tree.has_value() && m_tap_internal_key.IsFullyValid()) {
TaprootSpendData spenddata = m_tap_tree->GetSpendData();
if (!m_tap_tree.empty() && m_tap_internal_key.IsFullyValid()) {
TaprootBuilder builder;
for (const auto& [depth, leaf_ver, script] : m_tap_tree) {
builder.Add((int)depth, script, (int)leaf_ver, /*track=*/true);
}
assert(builder.IsComplete());
builder.Finalize(m_tap_internal_key);
TaprootSpendData spenddata = builder.GetSpendData();
sigdata.tr_spenddata.internal_key = m_tap_internal_key;
sigdata.tr_spenddata.Merge(spenddata);
@ -244,7 +250,7 @@ void PSBTOutput::FromSignatureData(const SignatureData& sigdata)
m_tap_internal_key = sigdata.tr_spenddata.internal_key;
}
if (sigdata.tr_builder.has_value()) {
m_tap_tree = sigdata.tr_builder;
m_tap_tree = sigdata.tr_builder->GetTreeTuples();
}
for (const auto& [pubkey, leaf_origin] : sigdata.taproot_misc_pubkeys) {
m_tap_bip32_paths.emplace(pubkey, leaf_origin);
@ -265,7 +271,7 @@ void PSBTOutput::Merge(const PSBTOutput& output)
if (redeem_script.empty() && !output.redeem_script.empty()) redeem_script = output.redeem_script;
if (witness_script.empty() && !output.witness_script.empty()) witness_script = output.witness_script;
if (m_tap_internal_key.IsNull() && !output.m_tap_internal_key.IsNull()) m_tap_internal_key = output.m_tap_internal_key;
if (!m_tap_tree.has_value() && output.m_tap_tree.has_value()) m_tap_tree = output.m_tap_tree;
if (m_tap_tree.empty() && !output.m_tap_tree.empty()) m_tap_tree = output.m_tap_tree;
}
bool PSBTInputSigned(const PSBTInput& input)
{

View file

@ -713,7 +713,7 @@ struct PSBTOutput
CScript witness_script;
std::map<CPubKey, KeyOriginInfo> hd_keypaths;
XOnlyPubKey m_tap_internal_key;
std::optional<TaprootBuilder> m_tap_tree;
std::vector<std::tuple<uint8_t, uint8_t, CScript>> m_tap_tree;
std::map<XOnlyPubKey, std::pair<std::set<uint256>, KeyOriginInfo>> m_tap_bip32_paths;
std::map<std::vector<unsigned char>, std::vector<unsigned char>> unknown;
std::set<PSBTProprietary> m_proprietary;
@ -754,15 +754,11 @@ struct PSBTOutput
}
// Write taproot tree
if (m_tap_tree.has_value()) {
if (!m_tap_tree.empty()) {
SerializeToVector(s, PSBT_OUT_TAP_TREE);
std::vector<unsigned char> value;
CVectorWriter s_value(s.GetType(), s.GetVersion(), value, 0);
const auto& tuples = m_tap_tree->GetTreeTuples();
for (const auto& tuple : tuples) {
uint8_t depth = std::get<0>(tuple);
uint8_t leaf_ver = std::get<1>(tuple);
CScript script = std::get<2>(tuple);
for (const auto& [depth, leaf_ver, script] : m_tap_tree) {
s_value << depth;
s_value << leaf_ver;
s_value << script;
@ -858,13 +854,13 @@ struct PSBTOutput
} else if (key.size() != 1) {
throw std::ios_base::failure("Output Taproot tree key is more than one byte type");
}
m_tap_tree.emplace();
std::vector<unsigned char> tree_v;
s >> tree_v;
SpanReader s_tree(s.GetType(), s.GetVersion(), tree_v);
if (s_tree.empty()) {
throw std::ios_base::failure("Output Taproot tree must not be empty");
}
TaprootBuilder builder;
while (!s_tree.empty()) {
uint8_t depth;
uint8_t leaf_ver;
@ -878,9 +874,10 @@ struct PSBTOutput
if ((leaf_ver & ~TAPROOT_LEAF_MASK) != 0) {
throw std::ios_base::failure("Output Taproot tree has a leaf with an invalid leaf version");
}
m_tap_tree->Add((int)depth, script, (int)leaf_ver, true /* track */);
m_tap_tree.push_back(std::make_tuple(depth, leaf_ver, script));
builder.Add((int)depth, script, (int)leaf_ver, true /* track */);
}
if (!m_tap_tree->IsComplete()) {
if (!builder.IsComplete()) {
throw std::ios_base::failure("Output Taproot tree is malformed");
}
break;
@ -934,11 +931,6 @@ struct PSBTOutput
}
}
// Finalize m_tap_tree so that all of the computed things are computed
if (m_tap_tree.has_value() && m_tap_tree->IsComplete() && m_tap_internal_key.IsFullyValid()) {
m_tap_tree->Finalize(m_tap_internal_key);
}
if (!found_sep) {
throw std::ios_base::failure("Separator is missing at the end of an output map");
}

View file

@ -1241,13 +1241,9 @@ static RPCHelpMan decodepsbt()
}
// Taproot tree
if (output.m_tap_tree.has_value()) {
if (!output.m_tap_tree.empty()) {
UniValue tree(UniValue::VARR);
const auto& tuples = output.m_tap_tree->GetTreeTuples();
for (const auto& tuple : tuples) {
uint8_t depth = std::get<0>(tuple);
uint8_t leaf_ver = std::get<1>(tuple);
CScript script = std::get<2>(tuple);
for (const auto& [depth, leaf_ver, script] : output.m_tap_tree) {
UniValue elem(UniValue::VOBJ);
elem.pushKV("depth", (int)depth);
elem.pushKV("leaf_ver", (int)leaf_ver);