aboutsummaryrefslogtreecommitdiff
path: root/src/rpc
diff options
context:
space:
mode:
authorMarcoFalke <falke.marco@gmail.com>2021-11-12 14:11:02 +0100
committerMarcoFalke <falke.marco@gmail.com>2021-12-06 10:33:12 +0100
commit99993425afc2c352b26e678b7ffbc74362ac3527 (patch)
treea9ae4ccedb0f323f23df80409abdbb90b0b3bf0d /src/rpc
parentd20d6ac545159fb98bd9ac828678ddf20f5d016d (diff)
rpc: Only allow specific types to be P2(W)SH wrapped in decodescript
Diffstat (limited to 'src/rpc')
-rw-r--r--src/rpc/rawtransaction.cpp67
1 files changed, 57 insertions, 10 deletions
diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp
index b369cce014..bd56e584e1 100644
--- a/src/rpc/rawtransaction.cpp
+++ b/src/rpc/rawtransaction.cpp
@@ -552,8 +552,10 @@ static RPCHelpMan decodescript()
{RPCResult::Type::STR, "asm", "Script public key"},
{RPCResult::Type::STR, "type", "The output type (e.g. " + GetAllOutputTypes() + ")"},
{RPCResult::Type::STR, "address", /* optional */ true, "The Bitcoin address (only if a well-defined address exists)"},
- {RPCResult::Type::STR, "p2sh", /* optional */ true, "address of P2SH script wrapping this redeem script (not returned if the script is already a P2SH)"},
- {RPCResult::Type::OBJ, "segwit", /* optional */ true, "Result of a witness script public key wrapping this redeem script (not returned if the script is a P2SH or witness)",
+ {RPCResult::Type::STR, "p2sh", /*optional=*/true,
+ "address of P2SH script wrapping this redeem script (not returned for types that should not be wrapped)"},
+ {RPCResult::Type::OBJ, "segwit", /*optional=*/true,
+ "Result of a witness script public key wrapping this redeem script (not returned for types that should not be wrapped)",
{
{RPCResult::Type::STR, "asm", "String representation of the script public key"},
{RPCResult::Type::STR_HEX, "hex", "Hex string of the script public key"},
@@ -584,22 +586,68 @@ static RPCHelpMan decodescript()
std::vector<std::vector<unsigned char>> solutions_data;
const TxoutType which_type{Solver(script, solutions_data)};
- if (which_type != TxoutType::SCRIPTHASH) {
- // P2SH cannot be wrapped in a P2SH. If this script is already a P2SH,
- // don't return the address for a P2SH of the P2SH.
+ const bool can_wrap{[&] {
+ switch (which_type) {
+ case TxoutType::MULTISIG:
+ case TxoutType::NONSTANDARD:
+ case TxoutType::PUBKEY:
+ case TxoutType::PUBKEYHASH:
+ case TxoutType::WITNESS_V0_KEYHASH:
+ case TxoutType::WITNESS_V0_SCRIPTHASH:
+ // Can be wrapped if the checks below pass
+ break;
+ case TxoutType::NULL_DATA:
+ case TxoutType::SCRIPTHASH:
+ case TxoutType::WITNESS_UNKNOWN:
+ case TxoutType::WITNESS_V1_TAPROOT:
+ // Should not be wrapped
+ return false;
+ } // no default case, so the compiler can warn about missing cases
+ if (!script.HasValidOps() || script.IsUnspendable()) {
+ return false;
+ }
+ for (CScript::const_iterator it{script.begin()}; it != script.end();) {
+ opcodetype op;
+ CHECK_NONFATAL(script.GetOp(it, op));
+ if (op == OP_CHECKSIGADD || IsOpSuccess(op)) {
+ return false;
+ }
+ }
+ return true;
+ }()};
+
+ if (can_wrap) {
r.pushKV("p2sh", EncodeDestination(ScriptHash(script)));
// P2SH and witness programs cannot be wrapped in P2WSH, if this script
// is a witness program, don't return addresses for a segwit programs.
- if (which_type == TxoutType::PUBKEY || which_type == TxoutType::PUBKEYHASH || which_type == TxoutType::MULTISIG || which_type == TxoutType::NONSTANDARD) {
+ const bool can_wrap_P2WSH{[&] {
+ switch (which_type) {
+ case TxoutType::MULTISIG:
+ case TxoutType::PUBKEY:
// Uncompressed pubkeys cannot be used with segwit checksigs.
// If the script contains an uncompressed pubkey, skip encoding of a segwit program.
- if ((which_type == TxoutType::PUBKEY) || (which_type == TxoutType::MULTISIG)) {
for (const auto& solution : solutions_data) {
if ((solution.size() != 1) && !CPubKey(solution).IsCompressed()) {
- return r;
+ return false;
}
}
- }
+ return true;
+ case TxoutType::NONSTANDARD:
+ case TxoutType::PUBKEYHASH:
+ // Can be P2WSH wrapped
+ return true;
+ case TxoutType::NULL_DATA:
+ case TxoutType::SCRIPTHASH:
+ case TxoutType::WITNESS_UNKNOWN:
+ case TxoutType::WITNESS_V0_KEYHASH:
+ case TxoutType::WITNESS_V0_SCRIPTHASH:
+ case TxoutType::WITNESS_V1_TAPROOT:
+ // Should not be wrapped
+ return false;
+ } // no default case, so the compiler can warn about missing cases
+ CHECK_NONFATAL(false);
+ }()};
+ if (can_wrap_P2WSH) {
UniValue sr(UniValue::VOBJ);
CScript segwitScr;
if (which_type == TxoutType::PUBKEY) {
@@ -608,7 +656,6 @@ static RPCHelpMan decodescript()
segwitScr = GetScriptForDestination(WitnessV0KeyHash(uint160{solutions_data[0]}));
} else {
// Scripts that are not fit for P2WPKH are encoded as P2WSH.
- // Newer segwit program versions should be considered when then become available.
segwitScr = GetScriptForDestination(WitnessV0ScriptHash(script));
}
ScriptPubKeyToUniv(segwitScr, sr, /* include_hex */ true);