I don’t really find this fn to be a UniValue
helper, pretty much all the logic is sighash specific. While thinking for a better place to sit, I ended up thinking the better solution may be to keep it where it is but just remove the (imo unnecessary) dependency on UV? Offloading the default value and type check to a helper function like ParseSighashString
is opaque, and even though my approach here is slightly more verbose in the callsite, I find the clarity of what’s happening to be worth it (different callsites may require different behaviour in case of wrong types or sighash_str
).
What do you think?
(I think returning a std::optional
instead of throwing is probably even better, but orthogonal to this pull)
0diff --git a/src/core_io.h b/src/core_io.h
1index 997f3bfd5b..ea07042b82 100644
2--- a/src/core_io.h
3+++ b/src/core_io.h
4@@ -46,7 +46,7 @@ bool DecodeHexBlockHeader(CBlockHeader&, const std::string& hex_header);
5 */
6 bool ParseHashStr(const std::string& strHex, uint256& result);
7 std::vector<unsigned char> ParseHexUV(const UniValue& v, const std::string& strName);
8-int ParseSighashString(const UniValue& sighash);
9+int ParseSighashString(const std::string& sighash);
10
11 // core_write.cpp
12 UniValue ValueFromAmount(const CAmount amount);
13diff --git a/src/core_read.cpp b/src/core_read.cpp
14index 84cd559b7f..31f121206c 100644
15--- a/src/core_read.cpp
16+++ b/src/core_read.cpp
17@@ -252,26 +252,20 @@ std::vector<unsigned char> ParseHexUV(const UniValue& v, const std::string& strN
18 return ParseHex(strHex);
19 }
20
21-int ParseSighashString(const UniValue& sighash)
22+int ParseSighashString(const std::string& sighash_str)
23 {
24- int hash_type = SIGHASH_DEFAULT;
25- if (!sighash.isNull()) {
26- static std::map<std::string, int> map_sighash_values = {
27- {std::string("DEFAULT"), int(SIGHASH_DEFAULT)},
28- {std::string("ALL"), int(SIGHASH_ALL)},
29- {std::string("ALL|ANYONECANPAY"), int(SIGHASH_ALL|SIGHASH_ANYONECANPAY)},
30- {std::string("NONE"), int(SIGHASH_NONE)},
31- {std::string("NONE|ANYONECANPAY"), int(SIGHASH_NONE|SIGHASH_ANYONECANPAY)},
32- {std::string("SINGLE"), int(SIGHASH_SINGLE)},
33- {std::string("SINGLE|ANYONECANPAY"), int(SIGHASH_SINGLE|SIGHASH_ANYONECANPAY)},
34- };
35- const std::string& strHashType = sighash.get_str();
36- const auto& it = map_sighash_values.find(strHashType);
37- if (it != map_sighash_values.end()) {
38- hash_type = it->second;
39- } else {
40- throw std::runtime_error(strHashType + " is not a valid sighash parameter.");
41- }
42+ static std::map<std::string, int> map_sighash_values = {
43+ {std::string("DEFAULT"), int(SIGHASH_DEFAULT)},
44+ {std::string("ALL"), int(SIGHASH_ALL)},
45+ {std::string("ALL|ANYONECANPAY"), int(SIGHASH_ALL|SIGHASH_ANYONECANPAY)},
46+ {std::string("NONE"), int(SIGHASH_NONE)},
47+ {std::string("NONE|ANYONECANPAY"), int(SIGHASH_NONE|SIGHASH_ANYONECANPAY)},
48+ {std::string("SINGLE"), int(SIGHASH_SINGLE)},
49+ {std::string("SINGLE|ANYONECANPAY"), int(SIGHASH_SINGLE|SIGHASH_ANYONECANPAY)},
50+ };
51+ const auto& it{map_sighash_values.find(sighash_str)};
52+ if (it != map_sighash_values.end()) {
53+ return it->second;
54 }
55- return hash_type;
56+ throw std::runtime_error(sighash_str + " is not a valid sighash parameter.");
57 }
58diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp
59index eb0200ccf5..e0e30b2d9e 100644
60--- a/src/rpc/rawtransaction.cpp
61+++ b/src/rpc/rawtransaction.cpp
62@@ -1964,7 +1964,7 @@ RPCHelpMan descriptorprocesspsbt()
63 EvalDescriptorStringOrObject(descs[i], provider, /*expand_priv=*/true);
64 }
65
66- int sighash_type = ParseSighashString(request.params[2]);
67+ int sighash_type{request.params[2].isNull() ? SIGHASH_DEFAULT: ParseSighashString(request.params[2].get_str())};
68 bool bip32derivs = request.params[3].isNull() ? true : request.params[3].get_bool();
69 bool finalize = request.params[4].isNull() ? true : request.params[4].get_bool();
70
71diff --git a/src/rpc/rawtransaction_util.cpp b/src/rpc/rawtransaction_util.cpp
72index 3a6fa39e4d..7272cca1c5 100644
73--- a/src/rpc/rawtransaction_util.cpp
74+++ b/src/rpc/rawtransaction_util.cpp
75@@ -289,7 +289,7 @@ void ParsePrevouts(const UniValue& prevTxsUnival, FillableSigningProvider* keyst
76
77 void SignTransaction(CMutableTransaction& mtx, const SigningProvider* keystore, const std::map<COutPoint, Coin>& coins, const UniValue& hashType, UniValue& result)
78 {
79- int nHashType = ParseSighashString(hashType);
80+ int nHashType{hashType.isNull() ? SIGHASH_DEFAULT : ParseSighashString(hashType.get_str())};
81
82 // Script verification errors
83 std::map<int, bilingual_str> input_errors;
84diff --git a/src/test/fuzz/parse_univalue.cpp b/src/test/fuzz/parse_univalue.cpp
85index bfa856211d..5cb2c64f26 100644
86--- a/src/test/fuzz/parse_univalue.cpp
87+++ b/src/test/fuzz/parse_univalue.cpp
88@@ -73,10 +73,6 @@ FUZZ_TARGET(parse_univalue, .init = initialize_parse_univalue)
89 } catch (const UniValue&) {
90 } catch (const std::runtime_error&) {
91 }
92- try {
93- (void)ParseSighashString(univalue);
94- } catch (const std::runtime_error&) {
95- }
96 try {
97 (void)AmountFromValue(univalue);
98 } catch (const UniValue&) {
99diff --git a/src/wallet/rpc/spend.cpp b/src/wallet/rpc/spend.cpp
100index b695d4bed3..3d74b12ef7 100644
101--- a/src/wallet/rpc/spend.cpp
102+++ b/src/wallet/rpc/spend.cpp
103@@ -943,7 +943,7 @@ RPCHelpMan signrawtransactionwithwallet()
104 // Parse the prevtxs array
105 ParsePrevouts(request.params[1], nullptr, coins);
106
107- int nHashType = ParseSighashString(request.params[2]);
108+ int nHashType{request.params[2].isNull() ? SIGHASH_DEFAULT: ParseSighashString(request.params[2].get_str())};
109
110 // Script verification errors
111 std::map<int, bilingual_str> input_errors;
112@@ -1587,7 +1587,7 @@ RPCHelpMan walletprocesspsbt()
113 }
114
115 // Get the sighash type
116- int nHashType = ParseSighashString(request.params[2]);
117+ int nHashType{request.params[2].isNull() ? SIGHASH_DEFAULT: ParseSighashString(request.params[2].get_str())};
118
119 // Fill transaction with our data and also sign
120 bool sign = request.params[1].isNull() ? true : request.params[1].get_bool();