Skip to content

Commit 0b188b7

Browse files
committed
Clean up context dependent checks in descriptor parsing
This changes all context dependent checks in the parser to be disjunctions of equality checks, rather than also including inequalities. This makes sure that adding a new context enum in the future won't change semantics for existing checks. The error messages are also made a bit more consistent.
1 parent 33275a9 commit 0b188b7

File tree

2 files changed

+22
-16
lines changed

2 files changed

+22
-16
lines changed

src/script/descriptor.cpp

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -973,8 +973,8 @@ std::unique_ptr<DescriptorImpl> ParseScript(uint32_t& key_exp_index, Span<const
973973
if (!pubkey) return nullptr;
974974
++key_exp_index;
975975
return std::make_unique<ComboDescriptor>(std::move(pubkey));
976-
} else if (ctx != ParseScriptContext::TOP && Func("combo", expr)) {
977-
error = "Cannot have combo in non-top level";
976+
} else if (Func("combo", expr)) {
977+
error = "Can only have combo() at top level";
978978
return nullptr;
979979
}
980980
if ((sorted_multi = Func("sortedmulti", expr)) || Func("multi", expr)) {
@@ -1022,29 +1022,29 @@ std::unique_ptr<DescriptorImpl> ParseScript(uint32_t& key_exp_index, Span<const
10221022
}
10231023
return std::make_unique<MultisigDescriptor>(thres, std::move(providers), sorted_multi);
10241024
}
1025-
if (ctx != ParseScriptContext::P2WSH && Func("wpkh", expr)) {
1025+
if ((ctx == ParseScriptContext::TOP || ctx == ParseScriptContext::P2SH) && Func("wpkh", expr)) {
10261026
auto pubkey = ParsePubkey(key_exp_index, expr, ParseScriptContext::P2WPKH, out, error);
10271027
if (!pubkey) return nullptr;
10281028
key_exp_index++;
10291029
return std::make_unique<WPKHDescriptor>(std::move(pubkey));
1030-
} else if (ctx == ParseScriptContext::P2WSH && Func("wpkh", expr)) {
1031-
error = "Cannot have wpkh within wsh";
1030+
} else if (Func("wpkh", expr)) {
1031+
error = "Can only have wpkh() at top level or inside sh()";
10321032
return nullptr;
10331033
}
10341034
if (ctx == ParseScriptContext::TOP && Func("sh", expr)) {
10351035
auto desc = ParseScript(key_exp_index, expr, ParseScriptContext::P2SH, out, error);
10361036
if (!desc || expr.size()) return nullptr;
10371037
return std::make_unique<SHDescriptor>(std::move(desc));
1038-
} else if (ctx != ParseScriptContext::TOP && Func("sh", expr)) {
1039-
error = "Cannot have sh in non-top level";
1038+
} else if (Func("sh", expr)) {
1039+
error = "Can only have sh() at top level";
10401040
return nullptr;
10411041
}
1042-
if (ctx != ParseScriptContext::P2WSH && Func("wsh", expr)) {
1042+
if ((ctx == ParseScriptContext::TOP || ctx == ParseScriptContext::P2SH) && Func("wsh", expr)) {
10431043
auto desc = ParseScript(key_exp_index, expr, ParseScriptContext::P2WSH, out, error);
10441044
if (!desc || expr.size()) return nullptr;
10451045
return std::make_unique<WSHDescriptor>(std::move(desc));
1046-
} else if (ctx == ParseScriptContext::P2WSH && Func("wsh", expr)) {
1047-
error = "Cannot have wsh within wsh";
1046+
} else if (Func("wsh", expr)) {
1047+
error = "Can only have wsh() at top level or inside sh()";
10481048
return nullptr;
10491049
}
10501050
if (ctx == ParseScriptContext::TOP && Func("addr", expr)) {
@@ -1054,6 +1054,9 @@ std::unique_ptr<DescriptorImpl> ParseScript(uint32_t& key_exp_index, Span<const
10541054
return nullptr;
10551055
}
10561056
return std::make_unique<AddressDescriptor>(std::move(dest));
1057+
} else if (Func("addr", expr)) {
1058+
error = "Can only have addr() at top level";
1059+
return nullptr;
10571060
}
10581061
if (ctx == ParseScriptContext::TOP && Func("raw", expr)) {
10591062
std::string str(expr.begin(), expr.end());
@@ -1063,6 +1066,9 @@ std::unique_ptr<DescriptorImpl> ParseScript(uint32_t& key_exp_index, Span<const
10631066
}
10641067
auto bytes = ParseHex(str);
10651068
return std::make_unique<RawDescriptor>(CScript(bytes.begin(), bytes.end()));
1069+
} else if (Func("raw", expr)) {
1070+
error = "Can only have raw() at top level";
1071+
return nullptr;
10661072
}
10671073
if (ctx == ParseScriptContext::P2SH) {
10681074
error = "A function is needed within P2SH";

src/test/descriptor_tests.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ void CheckUnparsable(const std::string& prv, const std::string& pub, const std::
2424
auto parse_pub = Parse(pub, keys_pub, error);
2525
BOOST_CHECK_MESSAGE(!parse_priv, prv);
2626
BOOST_CHECK_MESSAGE(!parse_pub, pub);
27-
BOOST_CHECK(error == expected_error);
27+
BOOST_CHECK_EQUAL(error, expected_error);
2828
}
2929

3030
constexpr int DEFAULT = 0;
@@ -355,12 +355,12 @@ BOOST_AUTO_TEST_CASE(descriptor_test)
355355

356356
// Check for invalid nesting of structures
357357
CheckUnparsable("sh(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)", "sh(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", "A function is needed within P2SH"); // P2SH needs a script, not a key
358-
CheckUnparsable("sh(combo(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1))", "sh(combo(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd))", "Cannot have combo in non-top level"); // Old must be top level
358+
CheckUnparsable("sh(combo(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1))", "sh(combo(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd))", "Can only have combo() at top level"); // Old must be top level
359359
CheckUnparsable("wsh(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)", "wsh(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", "A function is needed within P2WSH"); // P2WSH needs a script, not a key
360-
CheckUnparsable("wsh(wpkh(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1))", "wsh(wpkh(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd))", "Cannot have wpkh within wsh"); // Cannot embed witness inside witness
361-
CheckUnparsable("wsh(sh(pk(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)))", "wsh(sh(pk(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)))", "Cannot have sh in non-top level"); // Cannot embed P2SH inside P2WSH
362-
CheckUnparsable("sh(sh(pk(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)))", "sh(sh(pk(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)))", "Cannot have sh in non-top level"); // Cannot embed P2SH inside P2SH
363-
CheckUnparsable("wsh(wsh(pk(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)))", "wsh(wsh(pk(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)))", "Cannot have wsh within wsh"); // Cannot embed P2WSH inside P2WSH
360+
CheckUnparsable("wsh(wpkh(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1))", "wsh(wpkh(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd))", "Can only have wpkh() at top level or inside sh()"); // Cannot embed witness inside witness
361+
CheckUnparsable("wsh(sh(pk(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)))", "wsh(sh(pk(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)))", "Can only have sh() at top level"); // Cannot embed P2SH inside P2WSH
362+
CheckUnparsable("sh(sh(pk(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)))", "sh(sh(pk(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)))", "Can only have sh() at top level"); // Cannot embed P2SH inside P2SH
363+
CheckUnparsable("wsh(wsh(pk(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)))", "wsh(wsh(pk(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)))", "Can only have wsh() at top level or inside sh()"); // Cannot embed P2WSH inside P2WSH
364364

365365
// Checksums
366366
Check("sh(multi(2,[00000000/111'/222]xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc,xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0))#ggrsrxfy", "sh(multi(2,[00000000/111'/222]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0))#tjg09x5t", "sh(multi(2,[00000000/111'/222]xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc,xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0))#ggrsrxfy", "sh(multi(2,[00000000/111'/222]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0))#tjg09x5t", DEFAULT, {{"a91445a9a622a8b0a1269944be477640eedc447bbd8487"}}, OutputType::LEGACY, {{0x8000006FUL,222},{0}});

0 commit comments

Comments
 (0)