Skip to content

Commit 9999342

Browse files
author
MarcoFalke
committed
rpc: Only allow specific types to be P2(W)SH wrapped in decodescript
1 parent d20d6ac commit 9999342

File tree

2 files changed

+65
-53
lines changed

2 files changed

+65
-53
lines changed

src/rpc/rawtransaction.cpp

Lines changed: 57 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -552,8 +552,10 @@ static RPCHelpMan decodescript()
552552
{RPCResult::Type::STR, "asm", "Script public key"},
553553
{RPCResult::Type::STR, "type", "The output type (e.g. " + GetAllOutputTypes() + ")"},
554554
{RPCResult::Type::STR, "address", /* optional */ true, "The Bitcoin address (only if a well-defined address exists)"},
555-
{RPCResult::Type::STR, "p2sh", /* optional */ true, "address of P2SH script wrapping this redeem script (not returned if the script is already a P2SH)"},
556-
{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)",
555+
{RPCResult::Type::STR, "p2sh", /*optional=*/true,
556+
"address of P2SH script wrapping this redeem script (not returned for types that should not be wrapped)"},
557+
{RPCResult::Type::OBJ, "segwit", /*optional=*/true,
558+
"Result of a witness script public key wrapping this redeem script (not returned for types that should not be wrapped)",
557559
{
558560
{RPCResult::Type::STR, "asm", "String representation of the script public key"},
559561
{RPCResult::Type::STR_HEX, "hex", "Hex string of the script public key"},
@@ -584,22 +586,68 @@ static RPCHelpMan decodescript()
584586
std::vector<std::vector<unsigned char>> solutions_data;
585587
const TxoutType which_type{Solver(script, solutions_data)};
586588

587-
if (which_type != TxoutType::SCRIPTHASH) {
588-
// P2SH cannot be wrapped in a P2SH. If this script is already a P2SH,
589-
// don't return the address for a P2SH of the P2SH.
589+
const bool can_wrap{[&] {
590+
switch (which_type) {
591+
case TxoutType::MULTISIG:
592+
case TxoutType::NONSTANDARD:
593+
case TxoutType::PUBKEY:
594+
case TxoutType::PUBKEYHASH:
595+
case TxoutType::WITNESS_V0_KEYHASH:
596+
case TxoutType::WITNESS_V0_SCRIPTHASH:
597+
// Can be wrapped if the checks below pass
598+
break;
599+
case TxoutType::NULL_DATA:
600+
case TxoutType::SCRIPTHASH:
601+
case TxoutType::WITNESS_UNKNOWN:
602+
case TxoutType::WITNESS_V1_TAPROOT:
603+
// Should not be wrapped
604+
return false;
605+
} // no default case, so the compiler can warn about missing cases
606+
if (!script.HasValidOps() || script.IsUnspendable()) {
607+
return false;
608+
}
609+
for (CScript::const_iterator it{script.begin()}; it != script.end();) {
610+
opcodetype op;
611+
CHECK_NONFATAL(script.GetOp(it, op));
612+
if (op == OP_CHECKSIGADD || IsOpSuccess(op)) {
613+
return false;
614+
}
615+
}
616+
return true;
617+
}()};
618+
619+
if (can_wrap) {
590620
r.pushKV("p2sh", EncodeDestination(ScriptHash(script)));
591621
// P2SH and witness programs cannot be wrapped in P2WSH, if this script
592622
// is a witness program, don't return addresses for a segwit programs.
593-
if (which_type == TxoutType::PUBKEY || which_type == TxoutType::PUBKEYHASH || which_type == TxoutType::MULTISIG || which_type == TxoutType::NONSTANDARD) {
623+
const bool can_wrap_P2WSH{[&] {
624+
switch (which_type) {
625+
case TxoutType::MULTISIG:
626+
case TxoutType::PUBKEY:
594627
// Uncompressed pubkeys cannot be used with segwit checksigs.
595628
// If the script contains an uncompressed pubkey, skip encoding of a segwit program.
596-
if ((which_type == TxoutType::PUBKEY) || (which_type == TxoutType::MULTISIG)) {
597629
for (const auto& solution : solutions_data) {
598630
if ((solution.size() != 1) && !CPubKey(solution).IsCompressed()) {
599-
return r;
631+
return false;
600632
}
601633
}
602-
}
634+
return true;
635+
case TxoutType::NONSTANDARD:
636+
case TxoutType::PUBKEYHASH:
637+
// Can be P2WSH wrapped
638+
return true;
639+
case TxoutType::NULL_DATA:
640+
case TxoutType::SCRIPTHASH:
641+
case TxoutType::WITNESS_UNKNOWN:
642+
case TxoutType::WITNESS_V0_KEYHASH:
643+
case TxoutType::WITNESS_V0_SCRIPTHASH:
644+
case TxoutType::WITNESS_V1_TAPROOT:
645+
// Should not be wrapped
646+
return false;
647+
} // no default case, so the compiler can warn about missing cases
648+
CHECK_NONFATAL(false);
649+
}()};
650+
if (can_wrap_P2WSH) {
603651
UniValue sr(UniValue::VOBJ);
604652
CScript segwitScr;
605653
if (which_type == TxoutType::PUBKEY) {
@@ -608,7 +656,6 @@ static RPCHelpMan decodescript()
608656
segwitScr = GetScriptForDestination(WitnessV0KeyHash(uint160{solutions_data[0]}));
609657
} else {
610658
// Scripts that are not fit for P2WPKH are encoded as P2WSH.
611-
// Newer segwit program versions should be considered when then become available.
612659
segwitScr = GetScriptForDestination(WitnessV0ScriptHash(script));
613660
}
614661
ScriptPubKeyToUniv(segwitScr, sr, /* include_hex */ true);

test/functional/data/rpc_decodescript.json

Lines changed: 8 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,15 @@
44
{
55
"asm": "1 eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
66
"address": "bcrt1pamhwamhwamhwamhwamhwamhwamhwamhwamhwamhwamhwamhwamhqz6nvlh",
7-
"type": "witness_v1_taproot",
8-
"p2sh": "2Mt5gBng2UVL3xX4FUQinSBthq8gWQqs37g"
7+
"type": "witness_v1_taproot"
98
}
109
],
1110
[
1211
"5102eeee",
1312
{
1413
"asm": "1 -28398",
1514
"address": "bcrt1pamhqk96edn",
16-
"type": "witness_unknown",
17-
"p2sh": "2ND89Zqxi19tq7AjL5Y3un8fDWRwpwrk4tf"
15+
"type": "witness_unknown"
1816
}
1917
],
2018
[
@@ -38,38 +36,21 @@
3836
"6a00",
3937
{
4038
"asm": "OP_RETURN 0",
41-
"type": "nulldata",
42-
"p2sh": "2NG8CqGyR16jkZU5H7J9WM5xpCT6Fpw6bww"
39+
"type": "nulldata"
4340
}
4441
],
4542
[
4643
"6aee",
4744
{
4845
"asm": "OP_RETURN OP_UNKNOWN",
49-
"type": "nonstandard",
50-
"p2sh": "2NGU1bmCBhSooc3vkPYdea2ngDcwhNx8CeF",
51-
"segwit": {
52-
"asm": "0 44358a3abb4cc9f635f459edffb2a1210f849857aaf12106a1af645e034faa95",
53-
"hex": "002044358a3abb4cc9f635f459edffb2a1210f849857aaf12106a1af645e034faa95",
54-
"address": "bcrt1qgs6c5w4mfnylvd05t8kllv4pyy8cfxzh4tcjzp4p4aj9uq60422sw9mgmf",
55-
"type": "witness_v0_scripthash",
56-
"p2sh-segwit": "2N9xFeGJC4Z2BQcVEq7vyeNUZiVoANFbrX1"
57-
}
46+
"type": "nonstandard"
5847
}
5948
],
6049
[
6150
"6a02ee",
6251
{
6352
"asm": "OP_RETURN [error]",
64-
"type": "nonstandard",
65-
"p2sh": "2N9JFV56rrkTYVnrJTMFSpKNsq6j5NbAdQr",
66-
"segwit": {
67-
"asm": "0 6f3d493995bda1f72a8f4de96663be22b583623a05f5ae98f38c45b8e03ca5da",
68-
"hex": "00206f3d493995bda1f72a8f4de96663be22b583623a05f5ae98f38c45b8e03ca5da",
69-
"address": "bcrt1qdu75jwv4hkslw250fh5kvca7y26cxc36qh66ax8n33zm3cpu5hdqdtm4gp",
70-
"type": "witness_v0_scripthash",
71-
"p2sh-segwit": "2N3TqW8vuVr987Z695CmLNmLLXobBRMmqho"
72-
}
53+
"type": "nonstandard"
7354
}
7455
],
7556
[
@@ -91,30 +72,14 @@
9172
"ba",
9273
{
9374
"asm": "OP_CHECKSIGADD",
94-
"type": "nonstandard",
95-
"p2sh": "2MyX11u6v747zcKHTJMjXFgkj1vYZgHr4i1",
96-
"segwit": {
97-
"asm": "0 281c93990bac2c69cf372c9a3b66c406c86cca826d6407b68e644da22eef8186",
98-
"hex": "0020281c93990bac2c69cf372c9a3b66c406c86cca826d6407b68e644da22eef8186",
99-
"address": "bcrt1q9qwf8xgt4skxnneh9jdrkekyqmyxej5zd4jq0d5wv3x6yth0sxrqe2wl7r",
100-
"type": "witness_v0_scripthash",
101-
"p2sh-segwit": "2NBoeWVFMmZdEhLzP5kpvjnJ8c1GucsCbFK"
102-
}
75+
"type": "nonstandard"
10376
}
10477
],
10578
[
10679
"50",
10780
{
10881
"asm": "OP_RESERVED",
109-
"type": "nonstandard",
110-
"p2sh": "2NEqnmDnSWcfTRBG2t6M53ey6mjc8ncHesN",
111-
"segwit": {
112-
"asm": "0 5c62e091b8c0565f1bafad0dad5934276143ae2ccef7a5381e8ada5b1a8d26d2",
113-
"hex": "00205c62e091b8c0565f1bafad0dad5934276143ae2ccef7a5381e8ada5b1a8d26d2",
114-
"address": "bcrt1qt33wpydccpt97xa045x66kf5yas58t3vemm62wq73td9kx5dymfqknplwh",
115-
"type": "witness_v0_scripthash",
116-
"p2sh-segwit": "2NEtjT3ku2KjZo53bnwKX2v928Mzx5sjdUh"
117-
}
82+
"type": "nonstandard"
11883
}
11984
]
120-
]
85+
]

0 commit comments

Comments
 (0)