script_standard_tests.cpp
1 // Copyright (c) 2017-2022 The Bitcoin Core 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 <test/data/bip341_wallet_vectors.json.h> 6 7 #include <key.h> 8 #include <key_io.h> 9 #include <script/script.h> 10 #include <script/signingprovider.h> 11 #include <script/solver.h> 12 #include <test/util/setup_common.h> 13 #include <util/strencodings.h> 14 15 #include <boost/test/unit_test.hpp> 16 17 #include <univalue.h> 18 19 20 BOOST_FIXTURE_TEST_SUITE(script_standard_tests, BasicTestingSetup) 21 22 BOOST_AUTO_TEST_CASE(dest_default_is_no_dest) 23 { 24 CTxDestination dest; 25 BOOST_CHECK(!IsValidDestination(dest)); 26 } 27 28 BOOST_AUTO_TEST_CASE(script_standard_Solver_success) 29 { 30 CKey keys[3]; 31 CPubKey pubkeys[3]; 32 for (int i = 0; i < 3; i++) { 33 keys[i].MakeNewKey(true); 34 pubkeys[i] = keys[i].GetPubKey(); 35 } 36 37 CScript s; 38 std::vector<std::vector<unsigned char> > solutions; 39 40 // TxoutType::PUBKEY 41 s.clear(); 42 s << ToByteVector(pubkeys[0]) << OP_CHECKSIG; 43 BOOST_CHECK_EQUAL(Solver(s, solutions), TxoutType::PUBKEY); 44 BOOST_CHECK_EQUAL(solutions.size(), 1U); 45 BOOST_CHECK(solutions[0] == ToByteVector(pubkeys[0])); 46 47 // TxoutType::PUBKEYHASH 48 s.clear(); 49 s << OP_DUP << OP_HASH160 << ToByteVector(pubkeys[0].GetID()) << OP_EQUALVERIFY << OP_CHECKSIG; 50 BOOST_CHECK_EQUAL(Solver(s, solutions), TxoutType::PUBKEYHASH); 51 BOOST_CHECK_EQUAL(solutions.size(), 1U); 52 BOOST_CHECK(solutions[0] == ToByteVector(pubkeys[0].GetID())); 53 54 // TxoutType::SCRIPTHASH 55 CScript redeemScript(s); // initialize with leftover P2PKH script 56 s.clear(); 57 s << OP_HASH160 << ToByteVector(CScriptID(redeemScript)) << OP_EQUAL; 58 BOOST_CHECK_EQUAL(Solver(s, solutions), TxoutType::SCRIPTHASH); 59 BOOST_CHECK_EQUAL(solutions.size(), 1U); 60 BOOST_CHECK(solutions[0] == ToByteVector(CScriptID(redeemScript))); 61 62 // TxoutType::MULTISIG 63 s.clear(); 64 s << OP_1 << 65 ToByteVector(pubkeys[0]) << 66 ToByteVector(pubkeys[1]) << 67 OP_2 << OP_CHECKMULTISIG; 68 BOOST_CHECK_EQUAL(Solver(s, solutions), TxoutType::MULTISIG); 69 BOOST_CHECK_EQUAL(solutions.size(), 4U); 70 BOOST_CHECK(solutions[0] == std::vector<unsigned char>({1})); 71 BOOST_CHECK(solutions[1] == ToByteVector(pubkeys[0])); 72 BOOST_CHECK(solutions[2] == ToByteVector(pubkeys[1])); 73 BOOST_CHECK(solutions[3] == std::vector<unsigned char>({2})); 74 75 s.clear(); 76 s << OP_2 << 77 ToByteVector(pubkeys[0]) << 78 ToByteVector(pubkeys[1]) << 79 ToByteVector(pubkeys[2]) << 80 OP_3 << OP_CHECKMULTISIG; 81 BOOST_CHECK_EQUAL(Solver(s, solutions), TxoutType::MULTISIG); 82 BOOST_CHECK_EQUAL(solutions.size(), 5U); 83 BOOST_CHECK(solutions[0] == std::vector<unsigned char>({2})); 84 BOOST_CHECK(solutions[1] == ToByteVector(pubkeys[0])); 85 BOOST_CHECK(solutions[2] == ToByteVector(pubkeys[1])); 86 BOOST_CHECK(solutions[3] == ToByteVector(pubkeys[2])); 87 BOOST_CHECK(solutions[4] == std::vector<unsigned char>({3})); 88 89 // TxoutType::NULL_DATA 90 s.clear(); 91 s << OP_RETURN << 92 std::vector<unsigned char>({0}) << 93 std::vector<unsigned char>({75}) << 94 std::vector<unsigned char>({255}); 95 BOOST_CHECK_EQUAL(Solver(s, solutions), TxoutType::NULL_DATA); 96 BOOST_CHECK_EQUAL(solutions.size(), 0U); 97 98 // TxoutType::WITNESS_V0_KEYHASH 99 s.clear(); 100 s << OP_0 << ToByteVector(pubkeys[0].GetID()); 101 BOOST_CHECK_EQUAL(Solver(s, solutions), TxoutType::WITNESS_V0_KEYHASH); 102 BOOST_CHECK_EQUAL(solutions.size(), 1U); 103 BOOST_CHECK(solutions[0] == ToByteVector(pubkeys[0].GetID())); 104 105 // TxoutType::WITNESS_V0_SCRIPTHASH 106 uint256 scriptHash; 107 CSHA256().Write(redeemScript.data(), redeemScript.size()) 108 .Finalize(scriptHash.begin()); 109 110 s.clear(); 111 s << OP_0 << ToByteVector(scriptHash); 112 BOOST_CHECK_EQUAL(Solver(s, solutions), TxoutType::WITNESS_V0_SCRIPTHASH); 113 BOOST_CHECK_EQUAL(solutions.size(), 1U); 114 BOOST_CHECK(solutions[0] == ToByteVector(scriptHash)); 115 116 // TxoutType::WITNESS_V1_TAPROOT 117 s.clear(); 118 s << OP_1 << ToByteVector(uint256::ZERO); 119 BOOST_CHECK_EQUAL(Solver(s, solutions), TxoutType::WITNESS_V1_TAPROOT); 120 BOOST_CHECK_EQUAL(solutions.size(), 1U); 121 BOOST_CHECK(solutions[0] == ToByteVector(uint256::ZERO)); 122 123 // TxoutType::WITNESS_UNKNOWN 124 s.clear(); 125 s << OP_16 << ToByteVector(uint256::ONE); 126 BOOST_CHECK_EQUAL(Solver(s, solutions), TxoutType::WITNESS_UNKNOWN); 127 BOOST_CHECK_EQUAL(solutions.size(), 2U); 128 BOOST_CHECK(solutions[0] == std::vector<unsigned char>{16}); 129 BOOST_CHECK(solutions[1] == ToByteVector(uint256::ONE)); 130 131 // TxoutType::NONSTANDARD 132 s.clear(); 133 s << OP_9 << OP_ADD << OP_11 << OP_EQUAL; 134 BOOST_CHECK_EQUAL(Solver(s, solutions), TxoutType::NONSTANDARD); 135 } 136 137 BOOST_AUTO_TEST_CASE(script_standard_Solver_failure) 138 { 139 CKey key = GenerateRandomKey(); 140 CPubKey pubkey = key.GetPubKey(); 141 142 CScript s; 143 std::vector<std::vector<unsigned char> > solutions; 144 145 // TxoutType::PUBKEY with incorrectly sized pubkey 146 s.clear(); 147 s << std::vector<unsigned char>(30, 0x01) << OP_CHECKSIG; 148 BOOST_CHECK_EQUAL(Solver(s, solutions), TxoutType::NONSTANDARD); 149 150 // TxoutType::PUBKEYHASH with incorrectly sized key hash 151 s.clear(); 152 s << OP_DUP << OP_HASH160 << ToByteVector(pubkey) << OP_EQUALVERIFY << OP_CHECKSIG; 153 BOOST_CHECK_EQUAL(Solver(s, solutions), TxoutType::NONSTANDARD); 154 155 // TxoutType::SCRIPTHASH with incorrectly sized script hash 156 s.clear(); 157 s << OP_HASH160 << std::vector<unsigned char>(21, 0x01) << OP_EQUAL; 158 BOOST_CHECK_EQUAL(Solver(s, solutions), TxoutType::NONSTANDARD); 159 160 // TxoutType::MULTISIG 0/2 161 s.clear(); 162 s << OP_0 << ToByteVector(pubkey) << OP_1 << OP_CHECKMULTISIG; 163 BOOST_CHECK_EQUAL(Solver(s, solutions), TxoutType::NONSTANDARD); 164 165 // TxoutType::MULTISIG 2/1 166 s.clear(); 167 s << OP_2 << ToByteVector(pubkey) << OP_1 << OP_CHECKMULTISIG; 168 BOOST_CHECK_EQUAL(Solver(s, solutions), TxoutType::NONSTANDARD); 169 170 // TxoutType::MULTISIG n = 2 with 1 pubkey 171 s.clear(); 172 s << OP_1 << ToByteVector(pubkey) << OP_2 << OP_CHECKMULTISIG; 173 BOOST_CHECK_EQUAL(Solver(s, solutions), TxoutType::NONSTANDARD); 174 175 // TxoutType::MULTISIG n = 1 with 0 pubkeys 176 s.clear(); 177 s << OP_1 << OP_1 << OP_CHECKMULTISIG; 178 BOOST_CHECK_EQUAL(Solver(s, solutions), TxoutType::NONSTANDARD); 179 180 // TxoutType::NULL_DATA with other opcodes 181 s.clear(); 182 s << OP_RETURN << std::vector<unsigned char>({75}) << OP_ADD; 183 BOOST_CHECK_EQUAL(Solver(s, solutions), TxoutType::NONSTANDARD); 184 185 // TxoutType::WITNESS_UNKNOWN with incorrect program size 186 s.clear(); 187 s << OP_0 << std::vector<unsigned char>(19, 0x01); 188 BOOST_CHECK_EQUAL(Solver(s, solutions), TxoutType::NONSTANDARD); 189 } 190 191 BOOST_AUTO_TEST_CASE(script_standard_ExtractDestination) 192 { 193 CKey key = GenerateRandomKey(); 194 CPubKey pubkey = key.GetPubKey(); 195 196 CScript s; 197 CTxDestination address; 198 199 // TxoutType::PUBKEY 200 s.clear(); 201 s << ToByteVector(pubkey) << OP_CHECKSIG; 202 BOOST_CHECK(!ExtractDestination(s, address)); 203 BOOST_CHECK(std::get<PubKeyDestination>(address) == PubKeyDestination(pubkey)); 204 205 // TxoutType::PUBKEYHASH 206 s.clear(); 207 s << OP_DUP << OP_HASH160 << ToByteVector(pubkey.GetID()) << OP_EQUALVERIFY << OP_CHECKSIG; 208 BOOST_CHECK(ExtractDestination(s, address)); 209 BOOST_CHECK(std::get<PKHash>(address) == PKHash(pubkey)); 210 211 // TxoutType::SCRIPTHASH 212 CScript redeemScript(s); // initialize with leftover P2PKH script 213 s.clear(); 214 s << OP_HASH160 << ToByteVector(CScriptID(redeemScript)) << OP_EQUAL; 215 BOOST_CHECK(ExtractDestination(s, address)); 216 BOOST_CHECK(std::get<ScriptHash>(address) == ScriptHash(redeemScript)); 217 218 // TxoutType::MULTISIG 219 s.clear(); 220 s << OP_1 << ToByteVector(pubkey) << OP_1 << OP_CHECKMULTISIG; 221 BOOST_CHECK(!ExtractDestination(s, address)); 222 223 // TxoutType::NULL_DATA 224 s.clear(); 225 s << OP_RETURN << std::vector<unsigned char>({75}); 226 BOOST_CHECK(!ExtractDestination(s, address)); 227 228 // TxoutType::WITNESS_V0_KEYHASH 229 s.clear(); 230 s << OP_0 << ToByteVector(pubkey.GetID()); 231 BOOST_CHECK(ExtractDestination(s, address)); 232 WitnessV0KeyHash keyhash; 233 CHash160().Write(pubkey).Finalize(keyhash); 234 BOOST_CHECK(std::get<WitnessV0KeyHash>(address) == keyhash); 235 236 // TxoutType::WITNESS_V0_SCRIPTHASH 237 s.clear(); 238 WitnessV0ScriptHash scripthash; 239 CSHA256().Write(redeemScript.data(), redeemScript.size()).Finalize(scripthash.begin()); 240 s << OP_0 << ToByteVector(scripthash); 241 BOOST_CHECK(ExtractDestination(s, address)); 242 BOOST_CHECK(std::get<WitnessV0ScriptHash>(address) == scripthash); 243 244 // TxoutType::WITNESS_UNKNOWN with unknown version 245 s.clear(); 246 s << OP_1 << ToByteVector(pubkey); 247 BOOST_CHECK(ExtractDestination(s, address)); 248 WitnessUnknown unk{1, ToByteVector(pubkey)}; 249 BOOST_CHECK(std::get<WitnessUnknown>(address) == unk); 250 } 251 252 BOOST_AUTO_TEST_CASE(script_standard_GetScriptFor_) 253 { 254 CKey keys[3]; 255 CPubKey pubkeys[3]; 256 for (int i = 0; i < 3; i++) { 257 keys[i].MakeNewKey(true); 258 pubkeys[i] = keys[i].GetPubKey(); 259 } 260 261 CScript expected, result; 262 263 // PKHash 264 expected.clear(); 265 expected << OP_DUP << OP_HASH160 << ToByteVector(pubkeys[0].GetID()) << OP_EQUALVERIFY << OP_CHECKSIG; 266 result = GetScriptForDestination(PKHash(pubkeys[0])); 267 BOOST_CHECK(result == expected); 268 269 // CScriptID 270 CScript redeemScript(result); 271 expected.clear(); 272 expected << OP_HASH160 << ToByteVector(CScriptID(redeemScript)) << OP_EQUAL; 273 result = GetScriptForDestination(ScriptHash(redeemScript)); 274 BOOST_CHECK(result == expected); 275 276 // CNoDestination 277 expected.clear(); 278 result = GetScriptForDestination(CNoDestination()); 279 BOOST_CHECK(result == expected); 280 281 // GetScriptForRawPubKey 282 expected.clear(); 283 expected << ToByteVector(pubkeys[0]) << OP_CHECKSIG; 284 result = GetScriptForRawPubKey(pubkeys[0]); 285 BOOST_CHECK(result == expected); 286 287 // GetScriptForMultisig 288 expected.clear(); 289 expected << OP_2 << 290 ToByteVector(pubkeys[0]) << 291 ToByteVector(pubkeys[1]) << 292 ToByteVector(pubkeys[2]) << 293 OP_3 << OP_CHECKMULTISIG; 294 result = GetScriptForMultisig(2, std::vector<CPubKey>(pubkeys, pubkeys + 3)); 295 BOOST_CHECK(result == expected); 296 297 // WitnessV0KeyHash 298 expected.clear(); 299 expected << OP_0 << ToByteVector(pubkeys[0].GetID()); 300 result = GetScriptForDestination(WitnessV0KeyHash(Hash160(ToByteVector(pubkeys[0])))); 301 BOOST_CHECK(result == expected); 302 result = GetScriptForDestination(WitnessV0KeyHash(pubkeys[0].GetID())); 303 BOOST_CHECK(result == expected); 304 305 // WitnessV0ScriptHash (multisig) 306 CScript witnessScript; 307 witnessScript << OP_1 << ToByteVector(pubkeys[0]) << OP_1 << OP_CHECKMULTISIG; 308 309 uint256 scriptHash; 310 CSHA256().Write(witnessScript.data(), witnessScript.size()) 311 .Finalize(scriptHash.begin()); 312 313 expected.clear(); 314 expected << OP_0 << ToByteVector(scriptHash); 315 result = GetScriptForDestination(WitnessV0ScriptHash(witnessScript)); 316 BOOST_CHECK(result == expected); 317 } 318 319 BOOST_AUTO_TEST_CASE(script_standard_taproot_builder) 320 { 321 BOOST_CHECK_EQUAL(TaprootBuilder::ValidDepths({}), true); 322 BOOST_CHECK_EQUAL(TaprootBuilder::ValidDepths({0}), true); 323 BOOST_CHECK_EQUAL(TaprootBuilder::ValidDepths({1}), false); 324 BOOST_CHECK_EQUAL(TaprootBuilder::ValidDepths({2}), false); 325 BOOST_CHECK_EQUAL(TaprootBuilder::ValidDepths({0,0}), false); 326 BOOST_CHECK_EQUAL(TaprootBuilder::ValidDepths({0,1}), false); 327 BOOST_CHECK_EQUAL(TaprootBuilder::ValidDepths({0,2}), false); 328 BOOST_CHECK_EQUAL(TaprootBuilder::ValidDepths({1,0}), false); 329 BOOST_CHECK_EQUAL(TaprootBuilder::ValidDepths({1,1}), true); 330 BOOST_CHECK_EQUAL(TaprootBuilder::ValidDepths({1,2}), false); 331 BOOST_CHECK_EQUAL(TaprootBuilder::ValidDepths({2,0}), false); 332 BOOST_CHECK_EQUAL(TaprootBuilder::ValidDepths({2,1}), false); 333 BOOST_CHECK_EQUAL(TaprootBuilder::ValidDepths({2,2}), false); 334 BOOST_CHECK_EQUAL(TaprootBuilder::ValidDepths({0,0,0}), false); 335 BOOST_CHECK_EQUAL(TaprootBuilder::ValidDepths({0,0,1}), false); 336 BOOST_CHECK_EQUAL(TaprootBuilder::ValidDepths({0,0,2}), false); 337 BOOST_CHECK_EQUAL(TaprootBuilder::ValidDepths({0,1,0}), false); 338 BOOST_CHECK_EQUAL(TaprootBuilder::ValidDepths({0,1,1}), false); 339 BOOST_CHECK_EQUAL(TaprootBuilder::ValidDepths({0,1,2}), false); 340 BOOST_CHECK_EQUAL(TaprootBuilder::ValidDepths({0,2,0}), false); 341 BOOST_CHECK_EQUAL(TaprootBuilder::ValidDepths({0,2,1}), false); 342 BOOST_CHECK_EQUAL(TaprootBuilder::ValidDepths({0,2,2}), false); 343 BOOST_CHECK_EQUAL(TaprootBuilder::ValidDepths({1,0,0}), false); 344 BOOST_CHECK_EQUAL(TaprootBuilder::ValidDepths({1,0,1}), false); 345 BOOST_CHECK_EQUAL(TaprootBuilder::ValidDepths({1,0,2}), false); 346 BOOST_CHECK_EQUAL(TaprootBuilder::ValidDepths({1,1,0}), false); 347 BOOST_CHECK_EQUAL(TaprootBuilder::ValidDepths({1,1,1}), false); 348 BOOST_CHECK_EQUAL(TaprootBuilder::ValidDepths({1,1,2}), false); 349 BOOST_CHECK_EQUAL(TaprootBuilder::ValidDepths({1,2,0}), false); 350 BOOST_CHECK_EQUAL(TaprootBuilder::ValidDepths({1,2,1}), false); 351 BOOST_CHECK_EQUAL(TaprootBuilder::ValidDepths({1,2,2}), true); 352 BOOST_CHECK_EQUAL(TaprootBuilder::ValidDepths({2,0,0}), false); 353 BOOST_CHECK_EQUAL(TaprootBuilder::ValidDepths({2,0,1}), false); 354 BOOST_CHECK_EQUAL(TaprootBuilder::ValidDepths({2,0,2}), false); 355 BOOST_CHECK_EQUAL(TaprootBuilder::ValidDepths({2,1,0}), false); 356 BOOST_CHECK_EQUAL(TaprootBuilder::ValidDepths({2,1,1}), false); 357 BOOST_CHECK_EQUAL(TaprootBuilder::ValidDepths({2,1,2}), false); 358 BOOST_CHECK_EQUAL(TaprootBuilder::ValidDepths({2,2,0}), false); 359 BOOST_CHECK_EQUAL(TaprootBuilder::ValidDepths({2,2,1}), true); 360 BOOST_CHECK_EQUAL(TaprootBuilder::ValidDepths({2,2,2}), false); 361 BOOST_CHECK_EQUAL(TaprootBuilder::ValidDepths({2,2,2,3,4,5,6,7,8,9,10,11,12,14,14,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,31,31,31,31,31,31,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,128}), true); 362 BOOST_CHECK_EQUAL(TaprootBuilder::ValidDepths({128,128,127,126,125,124,123,122,121,120,119,118,117,116,115,114,113,112,111,110,109,108,107,106,105,104,103,102,101,100,99,98,97,96,95,94,93,92,91,90,89,88,87,86,85,84,83,82,81,80,79,78,77,76,75,74,73,72,71,70,69,68,67,66,65,64,63,62,61,60,59,58,57,56,55,54,53,52,51,50,49,48,47,46,45,44,43,42,41,40,39,38,37,36,35,34,33,32,31,30,29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1}), true); 363 BOOST_CHECK_EQUAL(TaprootBuilder::ValidDepths({129,129,128,127,126,125,124,123,122,121,120,119,118,117,116,115,114,113,112,111,110,109,108,107,106,105,104,103,102,101,100,99,98,97,96,95,94,93,92,91,90,89,88,87,86,85,84,83,82,81,80,79,78,77,76,75,74,73,72,71,70,69,68,67,66,65,64,63,62,61,60,59,58,57,56,55,54,53,52,51,50,49,48,47,46,45,44,43,42,41,40,39,38,37,36,35,34,33,32,31,30,29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1}), false); 364 365 XOnlyPubKey key_inner{ParseHex("79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798")}; 366 XOnlyPubKey key_1{ParseHex("c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5")}; 367 XOnlyPubKey key_2{ParseHex("f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9")}; 368 CScript script_1 = CScript() << ToByteVector(key_1) << OP_CHECKSIG; 369 CScript script_2 = CScript() << ToByteVector(key_2) << OP_CHECKSIG; 370 uint256 hash_3 = uint256S("31fe7061656bea2a36aa60a2f7ef940578049273746935d296426dc0afd86b68"); 371 372 TaprootBuilder builder; 373 BOOST_CHECK(builder.IsValid() && builder.IsComplete()); 374 builder.Add(2, script_2, 0xc0); 375 BOOST_CHECK(builder.IsValid() && !builder.IsComplete()); 376 builder.AddOmitted(2, hash_3); 377 BOOST_CHECK(builder.IsValid() && !builder.IsComplete()); 378 builder.Add(1, script_1, 0xc0); 379 BOOST_CHECK(builder.IsValid() && builder.IsComplete()); 380 builder.Finalize(key_inner); 381 BOOST_CHECK(builder.IsValid() && builder.IsComplete()); 382 BOOST_CHECK_EQUAL(EncodeDestination(builder.GetOutput()), "bc1pj6gaw944fy0xpmzzu45ugqde4rz7mqj5kj0tg8kmr5f0pjq8vnaqgynnge"); 383 } 384 385 BOOST_AUTO_TEST_CASE(bip341_spk_test_vectors) 386 { 387 using control_set = decltype(TaprootSpendData::scripts)::mapped_type; 388 389 UniValue tests; 390 tests.read(json_tests::bip341_wallet_vectors); 391 392 const auto& vectors = tests["scriptPubKey"]; 393 394 for (const auto& vec : vectors.getValues()) { 395 TaprootBuilder spktest; 396 std::map<std::pair<std::vector<unsigned char>, int>, int> scriptposes; 397 std::function<void (const UniValue&, int)> parse_tree = [&](const UniValue& node, int depth) { 398 if (node.isNull()) return; 399 if (node.isObject()) { 400 auto script = ParseHex(node["script"].get_str()); 401 int idx = node["id"].getInt<int>(); 402 int leaf_version = node["leafVersion"].getInt<int>(); 403 scriptposes[{script, leaf_version}] = idx; 404 spktest.Add(depth, script, leaf_version); 405 } else { 406 parse_tree(node[0], depth + 1); 407 parse_tree(node[1], depth + 1); 408 } 409 }; 410 parse_tree(vec["given"]["scriptTree"], 0); 411 spktest.Finalize(XOnlyPubKey(ParseHex(vec["given"]["internalPubkey"].get_str()))); 412 BOOST_CHECK_EQUAL(HexStr(GetScriptForDestination(spktest.GetOutput())), vec["expected"]["scriptPubKey"].get_str()); 413 BOOST_CHECK_EQUAL(EncodeDestination(spktest.GetOutput()), vec["expected"]["bip350Address"].get_str()); 414 auto spend_data = spktest.GetSpendData(); 415 BOOST_CHECK_EQUAL(vec["intermediary"]["merkleRoot"].isNull(), spend_data.merkle_root.IsNull()); 416 if (!spend_data.merkle_root.IsNull()) { 417 BOOST_CHECK_EQUAL(vec["intermediary"]["merkleRoot"].get_str(), HexStr(spend_data.merkle_root)); 418 } 419 BOOST_CHECK_EQUAL(spend_data.scripts.size(), scriptposes.size()); 420 for (const auto& scriptpos : scriptposes) { 421 BOOST_CHECK(spend_data.scripts[scriptpos.first] == control_set{ParseHex(vec["expected"]["scriptPathControlBlocks"][scriptpos.second].get_str())}); 422 } 423 } 424 } 425 426 BOOST_AUTO_TEST_SUITE_END()