From 0a5ea32ce605984094c5552877cb99bc81654f2c Mon Sep 17 00:00:00 2001 From: Ben Woosley Date: Tue, 14 Jan 2020 22:37:16 -0800 Subject: [PATCH 1/8] Prefer explicit uint160 conversion --- src/rpc/rawtransaction.cpp | 2 +- src/script/standard.cpp | 2 +- src/script/standard.h | 4 ---- 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index e14217c30..814f8bddf 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -595,7 +595,7 @@ static UniValue decodescript(const JSONRPCRequest& request) if (which_type == TX_PUBKEY) { segwitScr = GetScriptForDestination(WitnessV0KeyHash(Hash160(solutions_data[0].begin(), solutions_data[0].end()))); } else if (which_type == TX_PUBKEYHASH) { - segwitScr = GetScriptForDestination(WitnessV0KeyHash(solutions_data[0])); + 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. diff --git a/src/script/standard.cpp b/src/script/standard.cpp index d199a84ce..b6ee6117d 100644 --- a/src/script/standard.cpp +++ b/src/script/standard.cpp @@ -307,7 +307,7 @@ CScript GetScriptForWitness(const CScript& redeemscript) if (typ == TX_PUBKEY) { return GetScriptForDestination(WitnessV0KeyHash(Hash160(vSolutions[0].begin(), vSolutions[0].end()))); } else if (typ == TX_PUBKEYHASH) { - return GetScriptForDestination(WitnessV0KeyHash(vSolutions[0])); + return GetScriptForDestination(WitnessV0KeyHash(uint160{vSolutions[0]})); } return GetScriptForDestination(WitnessV0ScriptHash(redeemscript)); } diff --git a/src/script/standard.h b/src/script/standard.h index 292942567..c1a9fc90b 100644 --- a/src/script/standard.h +++ b/src/script/standard.h @@ -78,7 +78,6 @@ struct PKHash : public uint160 PKHash() : uint160() {} explicit PKHash(const uint160& hash) : uint160(hash) {} explicit PKHash(const CPubKey& pubkey); - using uint160::uint160; }; struct WitnessV0KeyHash; @@ -91,7 +90,6 @@ struct ScriptHash : public uint160 explicit ScriptHash(const PKHash& hash) = delete; explicit ScriptHash(const uint160& hash) : uint160(hash) {} explicit ScriptHash(const CScript& script); - using uint160::uint160; }; struct WitnessV0ScriptHash : public uint256 @@ -99,14 +97,12 @@ struct WitnessV0ScriptHash : public uint256 WitnessV0ScriptHash() : uint256() {} explicit WitnessV0ScriptHash(const uint256& hash) : uint256(hash) {} explicit WitnessV0ScriptHash(const CScript& script); - using uint256::uint256; }; struct WitnessV0KeyHash : public uint160 { WitnessV0KeyHash() : uint160() {} explicit WitnessV0KeyHash(const uint160& hash) : uint160(hash) {} - using uint160::uint160; }; //! CTxDestination subtype to encode any future Witness version From 3fcc46812334074d2c77a6233e8a961cd0785872 Mon Sep 17 00:00:00 2001 From: Ben Woosley Date: Tue, 14 Jan 2020 22:48:34 -0800 Subject: [PATCH 2/8] Prefer explicit CScriptID construction --- src/script/sign.cpp | 6 +++--- src/script/standard.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/script/sign.cpp b/src/script/sign.cpp index 1e00afcf8..43988c4fd 100644 --- a/src/script/sign.cpp +++ b/src/script/sign.cpp @@ -131,7 +131,7 @@ static bool SignStep(const SigningProvider& provider, const BaseSignatureCreator } case TX_SCRIPTHASH: h160 = uint160(vSolutions[0]); - if (GetCScript(provider, sigdata, h160, scriptRet)) { + if (GetCScript(provider, sigdata, CScriptID{h160}, scriptRet)) { ret.push_back(std::vector(scriptRet.begin(), scriptRet.end())); return true; } @@ -165,7 +165,7 @@ static bool SignStep(const SigningProvider& provider, const BaseSignatureCreator case TX_WITNESS_V0_SCRIPTHASH: CRIPEMD160().Write(&vSolutions[0][0], vSolutions[0].size()).Finalize(h160.begin()); - if (GetCScript(provider, sigdata, h160, scriptRet)) { + if (GetCScript(provider, sigdata, CScriptID{h160}, scriptRet)) { ret.push_back(std::vector(scriptRet.begin(), scriptRet.end())); return true; } @@ -458,7 +458,7 @@ bool IsSegWitOutput(const SigningProvider& provider, const CScript& script) if (whichtype == TX_SCRIPTHASH) { auto h160 = uint160(solutions[0]); CScript subscript; - if (provider.GetCScript(h160, subscript)) { + if (provider.GetCScript(CScriptID{h160}, subscript)) { whichtype = Solver(subscript, solutions); if (whichtype == TX_WITNESS_V0_SCRIPTHASH || whichtype == TX_WITNESS_V0_KEYHASH || whichtype == TX_WITNESS_UNKNOWN) return true; } diff --git a/src/script/standard.h b/src/script/standard.h index c1a9fc90b..7c74d05be 100644 --- a/src/script/standard.h +++ b/src/script/standard.h @@ -25,7 +25,7 @@ class CScriptID : public uint160 public: CScriptID() : uint160() {} explicit CScriptID(const CScript& in); - CScriptID(const uint160& in) : uint160(in) {} + explicit CScriptID(const uint160& in) : uint160(in) {} }; /** From a9e451f144480d7b170e49087df162989d31cd20 Mon Sep 17 00:00:00 2001 From: Ben Woosley Date: Tue, 14 Jan 2020 23:46:14 -0800 Subject: [PATCH 3/8] Convert CPubKey to WitnessV0KeyHash directly The round-tripping through PKHash has no effect, and is potentially misleading as such. --- src/outputtype.cpp | 2 +- src/script/standard.cpp | 1 + src/script/standard.h | 1 + src/wallet/test/ismine_tests.cpp | 6 +++--- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/outputtype.cpp b/src/outputtype.cpp index ea7a86d6d..871474d56 100644 --- a/src/outputtype.cpp +++ b/src/outputtype.cpp @@ -53,7 +53,7 @@ CTxDestination GetDestinationForKey(const CPubKey& key, OutputType type) case OutputType::P2SH_SEGWIT: case OutputType::BECH32: { if (!key.IsCompressed()) return PKHash(key); - CTxDestination witdest = WitnessV0KeyHash(PKHash(key)); + CTxDestination witdest = WitnessV0KeyHash(key); CScript witprog = GetScriptForDestination(witdest); if (type == OutputType::P2SH_SEGWIT) { return ScriptHash(witprog); diff --git a/src/script/standard.cpp b/src/script/standard.cpp index b6ee6117d..3e0a9e230 100644 --- a/src/script/standard.cpp +++ b/src/script/standard.cpp @@ -21,6 +21,7 @@ CScriptID::CScriptID(const CScript& in) : uint160(Hash160(in.begin(), in.end())) ScriptHash::ScriptHash(const CScript& in) : uint160(Hash160(in.begin(), in.end())) {} PKHash::PKHash(const CPubKey& pubkey) : uint160(pubkey.GetID()) {} +WitnessV0KeyHash::WitnessV0KeyHash(const CPubKey& pubkey) : uint160(pubkey.GetID()) {} WitnessV0ScriptHash::WitnessV0ScriptHash(const CScript& in) { diff --git a/src/script/standard.h b/src/script/standard.h index 7c74d05be..382d8d002 100644 --- a/src/script/standard.h +++ b/src/script/standard.h @@ -103,6 +103,7 @@ struct WitnessV0KeyHash : public uint160 { WitnessV0KeyHash() : uint160() {} explicit WitnessV0KeyHash(const uint160& hash) : uint160(hash) {} + explicit WitnessV0KeyHash(const CPubKey& pubkey); }; //! CTxDestination subtype to encode any future Witness version diff --git a/src/wallet/test/ismine_tests.cpp b/src/wallet/test/ismine_tests.cpp index cdb052292..e416f1604 100644 --- a/src/wallet/test/ismine_tests.cpp +++ b/src/wallet/test/ismine_tests.cpp @@ -167,7 +167,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard) keystore.SetupLegacyScriptPubKeyMan(); LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore); - CScript witnessscript = GetScriptForDestination(WitnessV0KeyHash(PKHash(pubkeys[0]))); + CScript witnessscript = GetScriptForDestination(WitnessV0KeyHash(pubkeys[0])); scriptPubKey = GetScriptForDestination(WitnessV0ScriptHash(witnessscript)); BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(witnessscript)); @@ -202,7 +202,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard) LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore); BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0])); - scriptPubKey = GetScriptForDestination(WitnessV0KeyHash(PKHash(pubkeys[0]))); + scriptPubKey = GetScriptForDestination(WitnessV0KeyHash(pubkeys[0])); // Keystore implicitly has key and P2SH redeemScript BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(scriptPubKey)); @@ -217,7 +217,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard) LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore); BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(uncompressedKey)); - scriptPubKey = GetScriptForDestination(WitnessV0KeyHash(PKHash(uncompressedPubkey))); + scriptPubKey = GetScriptForDestination(WitnessV0KeyHash(uncompressedPubkey)); // Keystore has key, but no P2SH redeemScript result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey); From 2c54217f913967703b404747133be67cf2f4feac Mon Sep 17 00:00:00 2001 From: Ben Woosley Date: Wed, 15 Jan 2020 13:40:14 -0800 Subject: [PATCH 4/8] Use explicit conversion from PKHash -> CKeyID These types are equivalent, in data etc, so they need only their data cast across. Note a function is used rather than a casting operator as CKeyID is defined at a lower level than script/standard --- src/qt/coincontroldialog.cpp | 2 +- src/script/signingprovider.cpp | 2 +- src/script/standard.cpp | 5 +++++ src/script/standard.h | 1 + src/wallet/rpcwallet.cpp | 2 +- src/wallet/scriptpubkeyman.cpp | 6 ++---- 6 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp index f44a9f285..7c7285850 100644 --- a/src/qt/coincontroldialog.cpp +++ b/src/qt/coincontroldialog.cpp @@ -456,7 +456,7 @@ void CoinControlDialog::updateLabels(CCoinControl& m_coin_control, WalletModel * { CPubKey pubkey; PKHash *pkhash = boost::get(&address); - if (pkhash && model->wallet().getPubKey(out.txout.scriptPubKey, CKeyID(*pkhash), pubkey)) + if (pkhash && model->wallet().getPubKey(out.txout.scriptPubKey, ToKeyID(*pkhash), pubkey)) { nBytesInputs += (pubkey.IsCompressed() ? 148 : 180); } diff --git a/src/script/signingprovider.cpp b/src/script/signingprovider.cpp index 01757e2f6..a4eb0a839 100644 --- a/src/script/signingprovider.cpp +++ b/src/script/signingprovider.cpp @@ -180,7 +180,7 @@ CKeyID GetKeyForDestination(const SigningProvider& store, const CTxDestination& // Only supports destinations which map to single public keys, i.e. P2PKH, // P2WPKH, and P2SH-P2WPKH. if (auto id = boost::get(&dest)) { - return CKeyID(*id); + return ToKeyID(*id); } if (auto witness_id = boost::get(&dest)) { return CKeyID(*witness_id); diff --git a/src/script/standard.cpp b/src/script/standard.cpp index 3e0a9e230..4b408d82e 100644 --- a/src/script/standard.cpp +++ b/src/script/standard.cpp @@ -23,6 +23,11 @@ ScriptHash::ScriptHash(const CScript& in) : uint160(Hash160(in.begin(), in.end() PKHash::PKHash(const CPubKey& pubkey) : uint160(pubkey.GetID()) {} WitnessV0KeyHash::WitnessV0KeyHash(const CPubKey& pubkey) : uint160(pubkey.GetID()) {} +CKeyID ToKeyID(const PKHash& key_hash) +{ + return CKeyID{static_cast(key_hash)}; +} + WitnessV0ScriptHash::WitnessV0ScriptHash(const CScript& in) { CSHA256().Write(in.data(), in.size()).Finalize(begin()); diff --git a/src/script/standard.h b/src/script/standard.h index 382d8d002..1c630744b 100644 --- a/src/script/standard.h +++ b/src/script/standard.h @@ -79,6 +79,7 @@ struct PKHash : public uint160 explicit PKHash(const uint160& hash) : uint160(hash) {} explicit PKHash(const CPubKey& pubkey); }; +CKeyID ToKeyID(const PKHash& key_hash); struct WitnessV0KeyHash; struct ScriptHash : public uint160 diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index c3a64cf46..43c1aa1a7 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -3517,7 +3517,7 @@ public: UniValue operator()(const PKHash& pkhash) const { - CKeyID keyID(pkhash); + CKeyID keyID{ToKeyID(pkhash)}; UniValue obj(UniValue::VOBJ); CPubKey vchPubKey; if (provider && provider->GetPubKey(keyID, vchPubKey)) { diff --git a/src/wallet/scriptpubkeyman.cpp b/src/wallet/scriptpubkeyman.cpp index 8a2a79864..6ec34951e 100644 --- a/src/wallet/scriptpubkeyman.cpp +++ b/src/wallet/scriptpubkeyman.cpp @@ -573,9 +573,8 @@ bool LegacyScriptPubKeyMan::SignTransaction(CMutableTransaction& tx, const std:: SigningResult LegacyScriptPubKeyMan::SignMessage(const std::string& message, const PKHash& pkhash, std::string& str_sig) const { - CKeyID key_id(pkhash); CKey key; - if (!GetKey(key_id, key)) { + if (!GetKey(ToKeyID(pkhash), key)) { return SigningResult::PRIVATE_KEY_NOT_AVAILABLE; } @@ -2052,9 +2051,8 @@ SigningResult DescriptorScriptPubKeyMan::SignMessage(const std::string& message, return SigningResult::PRIVATE_KEY_NOT_AVAILABLE; } - CKeyID key_id(pkhash); CKey key; - if (!keys->GetKey(key_id, key)) { + if (!keys->GetKey(ToKeyID(pkhash), key)) { return SigningResult::PRIVATE_KEY_NOT_AVAILABLE; } From f32c1e07fd6c174ff3f6406a619550d2f6c19360 Mon Sep 17 00:00:00 2001 From: Ben Woosley Date: Wed, 15 Jan 2020 13:41:25 -0800 Subject: [PATCH 5/8] Use explicit conversion from WitnessV0KeyHash -> CKeyID These types are equivalent, in data etc, so they need only their data cast across. --- src/script/signingprovider.cpp | 4 ++-- src/script/standard.cpp | 5 +++++ src/script/standard.h | 1 + src/wallet/rpcwallet.cpp | 2 +- 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/script/signingprovider.cpp b/src/script/signingprovider.cpp index a4eb0a839..2d8dc7d47 100644 --- a/src/script/signingprovider.cpp +++ b/src/script/signingprovider.cpp @@ -183,7 +183,7 @@ CKeyID GetKeyForDestination(const SigningProvider& store, const CTxDestination& return ToKeyID(*id); } if (auto witness_id = boost::get(&dest)) { - return CKeyID(*witness_id); + return ToKeyID(*witness_id); } if (auto script_hash = boost::get(&dest)) { CScript script; @@ -191,7 +191,7 @@ CKeyID GetKeyForDestination(const SigningProvider& store, const CTxDestination& CTxDestination inner_dest; if (store.GetCScript(script_id, script) && ExtractDestination(script, inner_dest)) { if (auto inner_witness_id = boost::get(&inner_dest)) { - return CKeyID(*inner_witness_id); + return ToKeyID(*inner_witness_id); } } } diff --git a/src/script/standard.cpp b/src/script/standard.cpp index 4b408d82e..a47ccef84 100644 --- a/src/script/standard.cpp +++ b/src/script/standard.cpp @@ -28,6 +28,11 @@ CKeyID ToKeyID(const PKHash& key_hash) return CKeyID{static_cast(key_hash)}; } +CKeyID ToKeyID(const WitnessV0KeyHash& key_hash) +{ + return CKeyID{static_cast(key_hash)}; +} + WitnessV0ScriptHash::WitnessV0ScriptHash(const CScript& in) { CSHA256().Write(in.data(), in.size()).Finalize(begin()); diff --git a/src/script/standard.h b/src/script/standard.h index 1c630744b..6c882e92a 100644 --- a/src/script/standard.h +++ b/src/script/standard.h @@ -106,6 +106,7 @@ struct WitnessV0KeyHash : public uint160 explicit WitnessV0KeyHash(const uint160& hash) : uint160(hash) {} explicit WitnessV0KeyHash(const CPubKey& pubkey); }; +CKeyID ToKeyID(const WitnessV0KeyHash& key_hash); //! CTxDestination subtype to encode any future Witness version struct WitnessUnknown diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 43c1aa1a7..fb79e0653 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -3542,7 +3542,7 @@ public: { UniValue obj(UniValue::VOBJ); CPubKey pubkey; - if (provider && provider->GetPubKey(CKeyID(id), pubkey)) { + if (provider && provider->GetPubKey(ToKeyID(id), pubkey)) { obj.pushKV("pubkey", HexStr(pubkey)); } return obj; From 966a22d859db37b1775e2180e5be032fc4fdf483 Mon Sep 17 00:00:00 2001 From: Ben Woosley Date: Wed, 15 Jan 2020 21:48:59 +0000 Subject: [PATCH 6/8] Explicitly support conversion between equivalent hash types ScriptHash <-> CScriptID CKeyID -> PKHash PKHash -> WitnessV0KeyHash --- src/script/standard.cpp | 5 +++++ src/script/standard.h | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/src/script/standard.cpp b/src/script/standard.cpp index a47ccef84..f8bfc3b69 100644 --- a/src/script/standard.cpp +++ b/src/script/standard.cpp @@ -17,11 +17,16 @@ bool fAcceptDatacarrier = DEFAULT_ACCEPT_DATACARRIER; unsigned nMaxDatacarrierBytes = MAX_OP_RETURN_RELAY; CScriptID::CScriptID(const CScript& in) : uint160(Hash160(in.begin(), in.end())) {} +CScriptID::CScriptID(const ScriptHash& in) : uint160(static_cast(in)) {} ScriptHash::ScriptHash(const CScript& in) : uint160(Hash160(in.begin(), in.end())) {} +ScriptHash::ScriptHash(const CScriptID& in) : uint160(static_cast(in)) {} PKHash::PKHash(const CPubKey& pubkey) : uint160(pubkey.GetID()) {} +PKHash::PKHash(const CKeyID& pubkey_id) : uint160(pubkey_id) {} + WitnessV0KeyHash::WitnessV0KeyHash(const CPubKey& pubkey) : uint160(pubkey.GetID()) {} +WitnessV0KeyHash::WitnessV0KeyHash(const PKHash& pubkey_hash) : uint160(static_cast(pubkey_hash)) {} CKeyID ToKeyID(const PKHash& key_hash) { diff --git a/src/script/standard.h b/src/script/standard.h index 6c882e92a..d235e6e17 100644 --- a/src/script/standard.h +++ b/src/script/standard.h @@ -18,6 +18,7 @@ static const bool DEFAULT_ACCEPT_DATACARRIER = true; class CKeyID; class CScript; +struct ScriptHash; /** A reference to a CScript: the Hash160 of its serialization (see script.h) */ class CScriptID : public uint160 @@ -26,6 +27,7 @@ public: CScriptID() : uint160() {} explicit CScriptID(const CScript& in); explicit CScriptID(const uint160& in) : uint160(in) {} + explicit CScriptID(const ScriptHash& in); }; /** @@ -78,6 +80,7 @@ struct PKHash : public uint160 PKHash() : uint160() {} explicit PKHash(const uint160& hash) : uint160(hash) {} explicit PKHash(const CPubKey& pubkey); + explicit PKHash(const CKeyID& pubkey_id); }; CKeyID ToKeyID(const PKHash& key_hash); @@ -91,6 +94,7 @@ struct ScriptHash : public uint160 explicit ScriptHash(const PKHash& hash) = delete; explicit ScriptHash(const uint160& hash) : uint160(hash) {} explicit ScriptHash(const CScript& script); + explicit ScriptHash(const CScriptID& script); }; struct WitnessV0ScriptHash : public uint256 @@ -105,6 +109,7 @@ struct WitnessV0KeyHash : public uint160 WitnessV0KeyHash() : uint160() {} explicit WitnessV0KeyHash(const uint160& hash) : uint160(hash) {} explicit WitnessV0KeyHash(const CPubKey& pubkey); + explicit WitnessV0KeyHash(const PKHash& pubkey_hash); }; CKeyID ToKeyID(const WitnessV0KeyHash& key_hash); From fa9ef2cdbed32438bdb32623af6e06f13ecd35e4 Mon Sep 17 00:00:00 2001 From: Ben Woosley Date: Wed, 15 Jan 2020 14:02:31 -0800 Subject: [PATCH 7/8] Remove an apparently unnecessary conversion CScript -> CScriptID -> ScriptHash is unnecessary because ScriptHash and CScriptID do the same thing. --- src/wallet/rpcdump.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp index d9fe741a6..541675bce 100644 --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -297,7 +297,7 @@ UniValue importaddress(const JSONRPCRequest& request) pwallet->ImportScripts(scripts, 0 /* timestamp */); if (fP2SH) { - scripts.insert(GetScriptForDestination(ScriptHash(CScriptID(redeem_script)))); + scripts.insert(GetScriptForDestination(ScriptHash(redeem_script))); } pwallet->ImportScriptPubKeys(strLabel, scripts, false /* have_solving_data */, true /* apply_label */, 1 /* timestamp */); From 4d7369125a82214ea42b808a32b71b315a5c3c72 Mon Sep 17 00:00:00 2001 From: Ben Woosley Date: Wed, 15 Jan 2020 14:03:57 -0800 Subject: [PATCH 8/8] Disallow automatic conversion between hash types A templated BaseHash does not allow for automatic conversion, thus conversions much be explicitly allowed / whitelisted, which will reduce the risk of unintended conversions. --- src/script/standard.cpp | 16 +++---- src/script/standard.h | 92 ++++++++++++++++++++++++++++++++++------- 2 files changed, 85 insertions(+), 23 deletions(-) diff --git a/src/script/standard.cpp b/src/script/standard.cpp index f8bfc3b69..2adf6ce56 100644 --- a/src/script/standard.cpp +++ b/src/script/standard.cpp @@ -16,17 +16,17 @@ typedef std::vector valtype; bool fAcceptDatacarrier = DEFAULT_ACCEPT_DATACARRIER; unsigned nMaxDatacarrierBytes = MAX_OP_RETURN_RELAY; -CScriptID::CScriptID(const CScript& in) : uint160(Hash160(in.begin(), in.end())) {} -CScriptID::CScriptID(const ScriptHash& in) : uint160(static_cast(in)) {} +CScriptID::CScriptID(const CScript& in) : BaseHash(Hash160(in.begin(), in.end())) {} +CScriptID::CScriptID(const ScriptHash& in) : BaseHash(static_cast(in)) {} -ScriptHash::ScriptHash(const CScript& in) : uint160(Hash160(in.begin(), in.end())) {} -ScriptHash::ScriptHash(const CScriptID& in) : uint160(static_cast(in)) {} +ScriptHash::ScriptHash(const CScript& in) : BaseHash(Hash160(in.begin(), in.end())) {} +ScriptHash::ScriptHash(const CScriptID& in) : BaseHash(static_cast(in)) {} -PKHash::PKHash(const CPubKey& pubkey) : uint160(pubkey.GetID()) {} -PKHash::PKHash(const CKeyID& pubkey_id) : uint160(pubkey_id) {} +PKHash::PKHash(const CPubKey& pubkey) : BaseHash(pubkey.GetID()) {} +PKHash::PKHash(const CKeyID& pubkey_id) : BaseHash(pubkey_id) {} -WitnessV0KeyHash::WitnessV0KeyHash(const CPubKey& pubkey) : uint160(pubkey.GetID()) {} -WitnessV0KeyHash::WitnessV0KeyHash(const PKHash& pubkey_hash) : uint160(static_cast(pubkey_hash)) {} +WitnessV0KeyHash::WitnessV0KeyHash(const CPubKey& pubkey) : BaseHash(pubkey.GetID()) {} +WitnessV0KeyHash::WitnessV0KeyHash(const PKHash& pubkey_hash) : BaseHash(static_cast(pubkey_hash)) {} CKeyID ToKeyID(const PKHash& key_hash) { diff --git a/src/script/standard.h b/src/script/standard.h index d235e6e17..4baed6da6 100644 --- a/src/script/standard.h +++ b/src/script/standard.h @@ -20,13 +20,74 @@ class CKeyID; class CScript; struct ScriptHash; +template +class BaseHash +{ +protected: + HashType m_hash; + +public: + BaseHash() : m_hash() {} + BaseHash(const HashType& in) : m_hash(in) {} + + unsigned char* begin() + { + return m_hash.begin(); + } + + const unsigned char* begin() const + { + return m_hash.begin(); + } + + unsigned char* end() + { + return m_hash.end(); + } + + const unsigned char* end() const + { + return m_hash.end(); + } + + operator std::vector() const + { + return std::vector{m_hash.begin(), m_hash.end()}; + } + + std::string ToString() const + { + return m_hash.ToString(); + } + + bool operator==(const BaseHash& other) const noexcept + { + return m_hash == other.m_hash; + } + + bool operator!=(const BaseHash& other) const noexcept + { + return !(m_hash == other.m_hash); + } + + bool operator<(const BaseHash& other) const noexcept + { + return m_hash < other.m_hash; + } + + size_t size() const + { + return m_hash.size(); + } +}; + /** A reference to a CScript: the Hash160 of its serialization (see script.h) */ -class CScriptID : public uint160 +class CScriptID : public BaseHash { public: - CScriptID() : uint160() {} + CScriptID() : BaseHash() {} explicit CScriptID(const CScript& in); - explicit CScriptID(const uint160& in) : uint160(in) {} + explicit CScriptID(const uint160& in) : BaseHash(in) {} explicit CScriptID(const ScriptHash& in); }; @@ -75,39 +136,40 @@ public: friend bool operator<(const CNoDestination &a, const CNoDestination &b) { return true; } }; -struct PKHash : public uint160 +struct PKHash : public BaseHash { - PKHash() : uint160() {} - explicit PKHash(const uint160& hash) : uint160(hash) {} + PKHash() : BaseHash() {} + explicit PKHash(const uint160& hash) : BaseHash(hash) {} explicit PKHash(const CPubKey& pubkey); explicit PKHash(const CKeyID& pubkey_id); }; CKeyID ToKeyID(const PKHash& key_hash); struct WitnessV0KeyHash; -struct ScriptHash : public uint160 +struct ScriptHash : public BaseHash { - ScriptHash() : uint160() {} + ScriptHash() : BaseHash() {} // These don't do what you'd expect. // Use ScriptHash(GetScriptForDestination(...)) instead. explicit ScriptHash(const WitnessV0KeyHash& hash) = delete; explicit ScriptHash(const PKHash& hash) = delete; - explicit ScriptHash(const uint160& hash) : uint160(hash) {} + + explicit ScriptHash(const uint160& hash) : BaseHash(hash) {} explicit ScriptHash(const CScript& script); explicit ScriptHash(const CScriptID& script); }; -struct WitnessV0ScriptHash : public uint256 +struct WitnessV0ScriptHash : public BaseHash { - WitnessV0ScriptHash() : uint256() {} - explicit WitnessV0ScriptHash(const uint256& hash) : uint256(hash) {} + WitnessV0ScriptHash() : BaseHash() {} + explicit WitnessV0ScriptHash(const uint256& hash) : BaseHash(hash) {} explicit WitnessV0ScriptHash(const CScript& script); }; -struct WitnessV0KeyHash : public uint160 +struct WitnessV0KeyHash : public BaseHash { - WitnessV0KeyHash() : uint160() {} - explicit WitnessV0KeyHash(const uint160& hash) : uint160(hash) {} + WitnessV0KeyHash() : BaseHash() {} + explicit WitnessV0KeyHash(const uint160& hash) : BaseHash(hash) {} explicit WitnessV0KeyHash(const CPubKey& pubkey); explicit WitnessV0KeyHash(const PKHash& pubkey_hash); };