Skip to content

Commit bd331bd

Browse files
committed
Merge #17938: Disallow automatic conversion between disparate hash types
4d73691 Disallow automatic conversion between hash types (Ben Woosley) fa9ef2c Remove an apparently unnecessary conversion (Ben Woosley) 966a22d Explicitly support conversion between equivalent hash types (Ben Woosley) f32c1e0 Use explicit conversion from WitnessV0KeyHash -> CKeyID (Ben Woosley) 2c54217 Use explicit conversion from PKHash -> CKeyID (Ben Woosley) a9e451f Convert CPubKey to WitnessV0KeyHash directly (Ben Woosley) 3fcc468 Prefer explicit CScriptID construction (Ben Woosley) 0a5ea32 Prefer explicit uint160 conversion (Ben Woosley) Pull request description: This bases the script/standard hash types, TxDestination-related and CScriptID on a base template which does not silently convert the underlying `uintN` type. Inspired by and built on #17924. Commits are small and focused to ease review. Note some of these changes may be relative to existing bugs of the same sort as #17924. See particularly "Convert CPubKey to WitnessV0KeyHash directly" and "Remove an apparently unnecessary conversion". ACKs for top commit: achow101: ACK 4d73691 meshcollider: re-utACK 4d73691 Tree-SHA512: f1b3284ddc6fb6c6e726f2c22668b6d732d45eb5418262ed2b9c728f60be7be43dfb414b6ddd9915025c8dcd7f360dc3b46e997a945a2feb95b0e5c4f05d6b54
2 parents 879acc6 + 4d73691 commit bd331bd

File tree

11 files changed

+122
-42
lines changed

11 files changed

+122
-42
lines changed

src/outputtype.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ CTxDestination GetDestinationForKey(const CPubKey& key, OutputType type)
5353
case OutputType::P2SH_SEGWIT:
5454
case OutputType::BECH32: {
5555
if (!key.IsCompressed()) return PKHash(key);
56-
CTxDestination witdest = WitnessV0KeyHash(PKHash(key));
56+
CTxDestination witdest = WitnessV0KeyHash(key);
5757
CScript witprog = GetScriptForDestination(witdest);
5858
if (type == OutputType::P2SH_SEGWIT) {
5959
return ScriptHash(witprog);

src/qt/coincontroldialog.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -456,7 +456,7 @@ void CoinControlDialog::updateLabels(CCoinControl& m_coin_control, WalletModel *
456456
{
457457
CPubKey pubkey;
458458
PKHash *pkhash = boost::get<PKHash>(&address);
459-
if (pkhash && model->wallet().getPubKey(out.txout.scriptPubKey, CKeyID(*pkhash), pubkey))
459+
if (pkhash && model->wallet().getPubKey(out.txout.scriptPubKey, ToKeyID(*pkhash), pubkey))
460460
{
461461
nBytesInputs += (pubkey.IsCompressed() ? 148 : 180);
462462
}

src/rpc/rawtransaction.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -595,7 +595,7 @@ static UniValue decodescript(const JSONRPCRequest& request)
595595
if (which_type == TX_PUBKEY) {
596596
segwitScr = GetScriptForDestination(WitnessV0KeyHash(Hash160(solutions_data[0].begin(), solutions_data[0].end())));
597597
} else if (which_type == TX_PUBKEYHASH) {
598-
segwitScr = GetScriptForDestination(WitnessV0KeyHash(solutions_data[0]));
598+
segwitScr = GetScriptForDestination(WitnessV0KeyHash(uint160{solutions_data[0]}));
599599
} else {
600600
// Scripts that are not fit for P2WPKH are encoded as P2WSH.
601601
// Newer segwit program versions should be considered when then become available.

src/script/sign.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ static bool SignStep(const SigningProvider& provider, const BaseSignatureCreator
131131
}
132132
case TX_SCRIPTHASH:
133133
h160 = uint160(vSolutions[0]);
134-
if (GetCScript(provider, sigdata, h160, scriptRet)) {
134+
if (GetCScript(provider, sigdata, CScriptID{h160}, scriptRet)) {
135135
ret.push_back(std::vector<unsigned char>(scriptRet.begin(), scriptRet.end()));
136136
return true;
137137
}
@@ -165,7 +165,7 @@ static bool SignStep(const SigningProvider& provider, const BaseSignatureCreator
165165

166166
case TX_WITNESS_V0_SCRIPTHASH:
167167
CRIPEMD160().Write(&vSolutions[0][0], vSolutions[0].size()).Finalize(h160.begin());
168-
if (GetCScript(provider, sigdata, h160, scriptRet)) {
168+
if (GetCScript(provider, sigdata, CScriptID{h160}, scriptRet)) {
169169
ret.push_back(std::vector<unsigned char>(scriptRet.begin(), scriptRet.end()));
170170
return true;
171171
}
@@ -458,7 +458,7 @@ bool IsSegWitOutput(const SigningProvider& provider, const CScript& script)
458458
if (whichtype == TX_SCRIPTHASH) {
459459
auto h160 = uint160(solutions[0]);
460460
CScript subscript;
461-
if (provider.GetCScript(h160, subscript)) {
461+
if (provider.GetCScript(CScriptID{h160}, subscript)) {
462462
whichtype = Solver(subscript, solutions);
463463
if (whichtype == TX_WITNESS_V0_SCRIPTHASH || whichtype == TX_WITNESS_V0_KEYHASH || whichtype == TX_WITNESS_UNKNOWN) return true;
464464
}

src/script/signingprovider.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -180,18 +180,18 @@ CKeyID GetKeyForDestination(const SigningProvider& store, const CTxDestination&
180180
// Only supports destinations which map to single public keys, i.e. P2PKH,
181181
// P2WPKH, and P2SH-P2WPKH.
182182
if (auto id = boost::get<PKHash>(&dest)) {
183-
return CKeyID(*id);
183+
return ToKeyID(*id);
184184
}
185185
if (auto witness_id = boost::get<WitnessV0KeyHash>(&dest)) {
186-
return CKeyID(*witness_id);
186+
return ToKeyID(*witness_id);
187187
}
188188
if (auto script_hash = boost::get<ScriptHash>(&dest)) {
189189
CScript script;
190190
CScriptID script_id(*script_hash);
191191
CTxDestination inner_dest;
192192
if (store.GetCScript(script_id, script) && ExtractDestination(script, inner_dest)) {
193193
if (auto inner_witness_id = boost::get<WitnessV0KeyHash>(&inner_dest)) {
194-
return CKeyID(*inner_witness_id);
194+
return ToKeyID(*inner_witness_id);
195195
}
196196
}
197197
}

src/script/standard.cpp

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,27 @@ typedef std::vector<unsigned char> valtype;
1616
bool fAcceptDatacarrier = DEFAULT_ACCEPT_DATACARRIER;
1717
unsigned nMaxDatacarrierBytes = MAX_OP_RETURN_RELAY;
1818

19-
CScriptID::CScriptID(const CScript& in) : uint160(Hash160(in.begin(), in.end())) {}
19+
CScriptID::CScriptID(const CScript& in) : BaseHash(Hash160(in.begin(), in.end())) {}
20+
CScriptID::CScriptID(const ScriptHash& in) : BaseHash(static_cast<uint160>(in)) {}
2021

21-
ScriptHash::ScriptHash(const CScript& in) : uint160(Hash160(in.begin(), in.end())) {}
22+
ScriptHash::ScriptHash(const CScript& in) : BaseHash(Hash160(in.begin(), in.end())) {}
23+
ScriptHash::ScriptHash(const CScriptID& in) : BaseHash(static_cast<uint160>(in)) {}
2224

23-
PKHash::PKHash(const CPubKey& pubkey) : uint160(pubkey.GetID()) {}
25+
PKHash::PKHash(const CPubKey& pubkey) : BaseHash(pubkey.GetID()) {}
26+
PKHash::PKHash(const CKeyID& pubkey_id) : BaseHash(pubkey_id) {}
27+
28+
WitnessV0KeyHash::WitnessV0KeyHash(const CPubKey& pubkey) : BaseHash(pubkey.GetID()) {}
29+
WitnessV0KeyHash::WitnessV0KeyHash(const PKHash& pubkey_hash) : BaseHash(static_cast<uint160>(pubkey_hash)) {}
30+
31+
CKeyID ToKeyID(const PKHash& key_hash)
32+
{
33+
return CKeyID{static_cast<uint160>(key_hash)};
34+
}
35+
36+
CKeyID ToKeyID(const WitnessV0KeyHash& key_hash)
37+
{
38+
return CKeyID{static_cast<uint160>(key_hash)};
39+
}
2440

2541
WitnessV0ScriptHash::WitnessV0ScriptHash(const CScript& in)
2642
{
@@ -307,7 +323,7 @@ CScript GetScriptForWitness(const CScript& redeemscript)
307323
if (typ == TX_PUBKEY) {
308324
return GetScriptForDestination(WitnessV0KeyHash(Hash160(vSolutions[0].begin(), vSolutions[0].end())));
309325
} else if (typ == TX_PUBKEYHASH) {
310-
return GetScriptForDestination(WitnessV0KeyHash(vSolutions[0]));
326+
return GetScriptForDestination(WitnessV0KeyHash(uint160{vSolutions[0]}));
311327
}
312328
return GetScriptForDestination(WitnessV0ScriptHash(redeemscript));
313329
}

src/script/standard.h

Lines changed: 85 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,77 @@ static const bool DEFAULT_ACCEPT_DATACARRIER = true;
1818

1919
class CKeyID;
2020
class CScript;
21+
struct ScriptHash;
22+
23+
template<typename HashType>
24+
class BaseHash
25+
{
26+
protected:
27+
HashType m_hash;
28+
29+
public:
30+
BaseHash() : m_hash() {}
31+
BaseHash(const HashType& in) : m_hash(in) {}
32+
33+
unsigned char* begin()
34+
{
35+
return m_hash.begin();
36+
}
37+
38+
const unsigned char* begin() const
39+
{
40+
return m_hash.begin();
41+
}
42+
43+
unsigned char* end()
44+
{
45+
return m_hash.end();
46+
}
47+
48+
const unsigned char* end() const
49+
{
50+
return m_hash.end();
51+
}
52+
53+
operator std::vector<unsigned char>() const
54+
{
55+
return std::vector<unsigned char>{m_hash.begin(), m_hash.end()};
56+
}
57+
58+
std::string ToString() const
59+
{
60+
return m_hash.ToString();
61+
}
62+
63+
bool operator==(const BaseHash<HashType>& other) const noexcept
64+
{
65+
return m_hash == other.m_hash;
66+
}
67+
68+
bool operator!=(const BaseHash<HashType>& other) const noexcept
69+
{
70+
return !(m_hash == other.m_hash);
71+
}
72+
73+
bool operator<(const BaseHash<HashType>& other) const noexcept
74+
{
75+
return m_hash < other.m_hash;
76+
}
77+
78+
size_t size() const
79+
{
80+
return m_hash.size();
81+
}
82+
};
2183

2284
/** A reference to a CScript: the Hash160 of its serialization (see script.h) */
23-
class CScriptID : public uint160
85+
class CScriptID : public BaseHash<uint160>
2486
{
2587
public:
26-
CScriptID() : uint160() {}
88+
CScriptID() : BaseHash() {}
2789
explicit CScriptID(const CScript& in);
28-
CScriptID(const uint160& in) : uint160(in) {}
90+
explicit CScriptID(const uint160& in) : BaseHash(in) {}
91+
explicit CScriptID(const ScriptHash& in);
2992
};
3093

3194
/**
@@ -73,41 +136,44 @@ class CNoDestination {
73136
friend bool operator<(const CNoDestination &a, const CNoDestination &b) { return true; }
74137
};
75138

76-
struct PKHash : public uint160
139+
struct PKHash : public BaseHash<uint160>
77140
{
78-
PKHash() : uint160() {}
79-
explicit PKHash(const uint160& hash) : uint160(hash) {}
141+
PKHash() : BaseHash() {}
142+
explicit PKHash(const uint160& hash) : BaseHash(hash) {}
80143
explicit PKHash(const CPubKey& pubkey);
81-
using uint160::uint160;
144+
explicit PKHash(const CKeyID& pubkey_id);
82145
};
146+
CKeyID ToKeyID(const PKHash& key_hash);
83147

84148
struct WitnessV0KeyHash;
85-
struct ScriptHash : public uint160
149+
struct ScriptHash : public BaseHash<uint160>
86150
{
87-
ScriptHash() : uint160() {}
151+
ScriptHash() : BaseHash() {}
88152
// These don't do what you'd expect.
89153
// Use ScriptHash(GetScriptForDestination(...)) instead.
90154
explicit ScriptHash(const WitnessV0KeyHash& hash) = delete;
91155
explicit ScriptHash(const PKHash& hash) = delete;
92-
explicit ScriptHash(const uint160& hash) : uint160(hash) {}
156+
157+
explicit ScriptHash(const uint160& hash) : BaseHash(hash) {}
93158
explicit ScriptHash(const CScript& script);
94-
using uint160::uint160;
159+
explicit ScriptHash(const CScriptID& script);
95160
};
96161

97-
struct WitnessV0ScriptHash : public uint256
162+
struct WitnessV0ScriptHash : public BaseHash<uint256>
98163
{
99-
WitnessV0ScriptHash() : uint256() {}
100-
explicit WitnessV0ScriptHash(const uint256& hash) : uint256(hash) {}
164+
WitnessV0ScriptHash() : BaseHash() {}
165+
explicit WitnessV0ScriptHash(const uint256& hash) : BaseHash(hash) {}
101166
explicit WitnessV0ScriptHash(const CScript& script);
102-
using uint256::uint256;
103167
};
104168

105-
struct WitnessV0KeyHash : public uint160
169+
struct WitnessV0KeyHash : public BaseHash<uint160>
106170
{
107-
WitnessV0KeyHash() : uint160() {}
108-
explicit WitnessV0KeyHash(const uint160& hash) : uint160(hash) {}
109-
using uint160::uint160;
171+
WitnessV0KeyHash() : BaseHash() {}
172+
explicit WitnessV0KeyHash(const uint160& hash) : BaseHash(hash) {}
173+
explicit WitnessV0KeyHash(const CPubKey& pubkey);
174+
explicit WitnessV0KeyHash(const PKHash& pubkey_hash);
110175
};
176+
CKeyID ToKeyID(const WitnessV0KeyHash& key_hash);
111177

112178
//! CTxDestination subtype to encode any future Witness version
113179
struct WitnessUnknown

src/wallet/rpcdump.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,7 @@ UniValue importaddress(const JSONRPCRequest& request)
297297
pwallet->ImportScripts(scripts, 0 /* timestamp */);
298298

299299
if (fP2SH) {
300-
scripts.insert(GetScriptForDestination(ScriptHash(CScriptID(redeem_script))));
300+
scripts.insert(GetScriptForDestination(ScriptHash(redeem_script)));
301301
}
302302

303303
pwallet->ImportScriptPubKeys(strLabel, scripts, false /* have_solving_data */, true /* apply_label */, 1 /* timestamp */);

src/wallet/rpcwallet.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3517,7 +3517,7 @@ class DescribeWalletAddressVisitor : public boost::static_visitor<UniValue>
35173517

35183518
UniValue operator()(const PKHash& pkhash) const
35193519
{
3520-
CKeyID keyID(pkhash);
3520+
CKeyID keyID{ToKeyID(pkhash)};
35213521
UniValue obj(UniValue::VOBJ);
35223522
CPubKey vchPubKey;
35233523
if (provider && provider->GetPubKey(keyID, vchPubKey)) {
@@ -3542,7 +3542,7 @@ class DescribeWalletAddressVisitor : public boost::static_visitor<UniValue>
35423542
{
35433543
UniValue obj(UniValue::VOBJ);
35443544
CPubKey pubkey;
3545-
if (provider && provider->GetPubKey(CKeyID(id), pubkey)) {
3545+
if (provider && provider->GetPubKey(ToKeyID(id), pubkey)) {
35463546
obj.pushKV("pubkey", HexStr(pubkey));
35473547
}
35483548
return obj;

src/wallet/scriptpubkeyman.cpp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -573,9 +573,8 @@ bool LegacyScriptPubKeyMan::SignTransaction(CMutableTransaction& tx, const std::
573573

574574
SigningResult LegacyScriptPubKeyMan::SignMessage(const std::string& message, const PKHash& pkhash, std::string& str_sig) const
575575
{
576-
CKeyID key_id(pkhash);
577576
CKey key;
578-
if (!GetKey(key_id, key)) {
577+
if (!GetKey(ToKeyID(pkhash), key)) {
579578
return SigningResult::PRIVATE_KEY_NOT_AVAILABLE;
580579
}
581580

@@ -2052,9 +2051,8 @@ SigningResult DescriptorScriptPubKeyMan::SignMessage(const std::string& message,
20522051
return SigningResult::PRIVATE_KEY_NOT_AVAILABLE;
20532052
}
20542053

2055-
CKeyID key_id(pkhash);
20562054
CKey key;
2057-
if (!keys->GetKey(key_id, key)) {
2055+
if (!keys->GetKey(ToKeyID(pkhash), key)) {
20582056
return SigningResult::PRIVATE_KEY_NOT_AVAILABLE;
20592057
}
20602058

0 commit comments

Comments
 (0)