Skip to content

Commit

Permalink
Replace CScriptID and CKeyID in CTxDestination with dedicated type
Browse files Browse the repository at this point in the history
  • Loading branch information
instagibbs authored and stevenroose committed Mar 20, 2019
1 parent 3e7cff1 commit aa375e6
Show file tree
Hide file tree
Showing 28 changed files with 201 additions and 179 deletions.
4 changes: 2 additions & 2 deletions src/bench/ccoins_caching.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,9 @@ SetupDummyInputs(CBasicKeyStore& keystoreRet, CCoinsViewCache& coinsRet)

dummyTransactions[1].vout.resize(2);
dummyTransactions[1].vout[0].nValue = 21 * CENT;
dummyTransactions[1].vout[0].scriptPubKey = GetScriptForDestination(key[2].GetPubKey().GetID());
dummyTransactions[1].vout[0].scriptPubKey = GetScriptForDestination(PKHash(key[2].GetPubKey()));
dummyTransactions[1].vout[1].nValue = 22 * CENT;
dummyTransactions[1].vout[1].scriptPubKey = GetScriptForDestination(key[3].GetPubKey().GetID());
dummyTransactions[1].vout[1].scriptPubKey = GetScriptForDestination(PKHash(key[3].GetPubKey()));
AddCoins(coinsRet, dummyTransactions[1], 0);

return dummyTransactions;
Expand Down
6 changes: 3 additions & 3 deletions src/bitcoin-tx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,7 @@ static void MutateTxAddOutPubKey(CMutableTransaction& tx, const std::string& str
}
if (bScriptHash) {
// Get the ID for the script, and then construct a P2SH destination for it.
scriptPubKey = GetScriptForDestination(CScriptID(scriptPubKey));
scriptPubKey = GetScriptForDestination(ScriptHash(scriptPubKey));
}

// construct TxOut, append to transaction output list
Expand Down Expand Up @@ -399,7 +399,7 @@ static void MutateTxAddOutMultiSig(CMutableTransaction& tx, const std::string& s
"redeemScript exceeds size limit: %d > %d", scriptPubKey.size(), MAX_SCRIPT_ELEMENT_SIZE));
}
// Get the ID for the script, and then construct a P2SH destination for it.
scriptPubKey = GetScriptForDestination(CScriptID(scriptPubKey));
scriptPubKey = GetScriptForDestination(ScriptHash(scriptPubKey));
}

// construct TxOut, append to transaction output list
Expand Down Expand Up @@ -471,7 +471,7 @@ static void MutateTxAddOutScript(CMutableTransaction& tx, const std::string& str
throw std::runtime_error(strprintf(
"redeemScript exceeds size limit: %d > %d", scriptPubKey.size(), MAX_SCRIPT_ELEMENT_SIZE));
}
scriptPubKey = GetScriptForDestination(CScriptID(scriptPubKey));
scriptPubKey = GetScriptForDestination(ScriptHash(scriptPubKey));
}

// construct TxOut, append to transaction output list
Expand Down
8 changes: 4 additions & 4 deletions src/key_io.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,15 @@ class DestinationEncoder : public boost::static_visitor<std::string>
public:
explicit DestinationEncoder(const CChainParams& params, const bool for_parent) : m_params(params), for_parent(for_parent) {}

std::string operator()(const CKeyID& id) const
std::string operator()(const PKHash& id) const
{
CChainParams::Base58Type type = for_parent ? CChainParams::PARENT_PUBKEY_ADDRESS : CChainParams::PUBKEY_ADDRESS;
std::vector<unsigned char> data = m_params.Base58Prefix(type);
data.insert(data.end(), id.begin(), id.end());
return EncodeBase58Check(data);
}

std::string operator()(const CScriptID& id) const
std::string operator()(const ScriptHash& id) const
{
CChainParams::Base58Type type = for_parent ? CChainParams::PARENT_SCRIPT_ADDRESS : CChainParams::SCRIPT_ADDRESS;
std::vector<unsigned char> data = m_params.Base58Prefix(type);
Expand Down Expand Up @@ -91,15 +91,15 @@ CTxDestination DecodeDestination(const std::string& str, const CChainParams& par
const std::vector<unsigned char>& pubkey_prefix = params.Base58Prefix(type_pkh);
if (data.size() == hash.size() + pubkey_prefix.size() && std::equal(pubkey_prefix.begin(), pubkey_prefix.end(), data.begin())) {
std::copy(data.begin() + pubkey_prefix.size(), data.end(), hash.begin());
return CKeyID(hash);
return PKHash(hash);
}
// Script-hash-addresses have version 5 (or 196 testnet).
// The data vector contains RIPEMD160(SHA256(cscript)), where cscript is the serialized redemption script.
CChainParams::Base58Type type_sh = for_parent ? CChainParams::PARENT_SCRIPT_ADDRESS : CChainParams::SCRIPT_ADDRESS;
const std::vector<unsigned char>& script_prefix = params.Base58Prefix(type_sh);
if (data.size() == hash.size() + script_prefix.size() && std::equal(script_prefix.begin(), script_prefix.end(), data.begin())) {
std::copy(data.begin() + script_prefix.size(), data.end(), hash.begin());
return CScriptID(hash);
return ScriptHash(hash);
}
}
data.clear();
Expand Down
9 changes: 5 additions & 4 deletions src/keystore.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -178,16 +178,17 @@ CKeyID GetKeyForDestination(const CKeyStore& store, const CTxDestination& dest)
{
// Only supports destinations which map to single public keys, i.e. P2PKH,
// P2WPKH, and P2SH-P2WPKH.
if (auto id = boost::get<CKeyID>(&dest)) {
return *id;
if (auto id = boost::get<PKHash>(&dest)) {
return CKeyID(*id);
}
if (auto witness_id = boost::get<WitnessV0KeyHash>(&dest)) {
return CKeyID(*witness_id);
}
if (auto script_id = boost::get<CScriptID>(&dest)) {
if (auto script_hash = boost::get<ScriptHash>(&dest)) {
CScript script;
CScriptID script_id(*script_hash);
CTxDestination inner_dest;
if (store.GetCScript(*script_id, script) && ExtractDestination(script, inner_dest)) {
if (store.GetCScript(script_id, script) && ExtractDestination(script, inner_dest)) {
if (auto inner_witness_id = boost::get<WitnessV0KeyHash>(&inner_dest)) {
return CKeyID(*inner_witness_id);
}
Expand Down
18 changes: 9 additions & 9 deletions src/outputtype.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,14 @@ const std::string& FormatOutputType(OutputType type)
CTxDestination GetDestinationForKey(const CPubKey& key, OutputType type)
{
switch (type) {
case OutputType::LEGACY: return key.GetID();
case OutputType::LEGACY: return PKHash(key);
case OutputType::P2SH_SEGWIT:
case OutputType::BECH32: {
if (!key.IsCompressed()) return key.GetID();
CTxDestination witdest = WitnessV0KeyHash(key.GetID());
if (!key.IsCompressed()) return PKHash(key);
CTxDestination witdest = WitnessV0KeyHash(PKHash(key));
CScript witprog = GetScriptForDestination(witdest);
if (type == OutputType::P2SH_SEGWIT) {
return CScriptID(witprog);
return ScriptHash(witprog);
} else {
return witdest;
}
Expand All @@ -63,10 +63,10 @@ CTxDestination GetDestinationForKey(const CPubKey& key, OutputType type)

std::vector<CTxDestination> GetAllDestinationsForKey(const CPubKey& key)
{
CKeyID keyid = key.GetID();
PKHash keyid(key);
if (key.IsCompressed()) {
CTxDestination segwit = WitnessV0KeyHash(keyid);
CTxDestination p2sh = CScriptID(GetScriptForDestination(segwit));
CTxDestination p2sh = ScriptHash(GetScriptForDestination(segwit));
return std::vector<CTxDestination>{std::move(keyid), std::move(p2sh), std::move(segwit)};
} else {
return std::vector<CTxDestination>{std::move(keyid)};
Expand All @@ -80,19 +80,19 @@ CTxDestination AddAndGetDestinationForScript(CKeyStore& keystore, const CScript&
// Note that scripts over 520 bytes are not yet supported.
switch (type) {
case OutputType::LEGACY:
return CScriptID(script);
return ScriptHash(script);
case OutputType::P2SH_SEGWIT:
case OutputType::BECH32: {
CTxDestination witdest = WitnessV0ScriptHash(script);
CScript witprog = GetScriptForDestination(witdest);
// Check if the resulting program is solvable (i.e. doesn't use an uncompressed key)
if (!IsSolvable(keystore, witprog)) return CScriptID(script);
if (!IsSolvable(keystore, witprog)) return ScriptHash(script);
// Add the redeemscript, so that P2WSH and P2SH-P2WSH outputs are recognized as ours.
keystore.AddCScript(witprog);
if (type == OutputType::BECH32) {
return witdest;
} else {
return CScriptID(witprog);
return ScriptHash(CScriptID(witprog));
}
}
default: assert(false);
Expand Down
2 changes: 1 addition & 1 deletion src/pegins.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ static bool CheckPeginTx(const std::vector<unsigned char>& tx_data, T& pegtx, co
// Check that the witness program matches the p2ch on the p2sh-p2wsh transaction output
CScript tweaked_fedpegscript = calculate_contract(Params().GetConsensus().fedpegScript, claim_script);
CScript witness_output(GetScriptForWitness(tweaked_fedpegscript));
CScript expected_script(CScript() << OP_HASH160 << ToByteVector(CScriptID(witness_output)) << OP_EQUAL);
CScript expected_script(CScript() << OP_HASH160 << ToByteVector(ScriptHash(CScriptID(witness_output))) << OP_EQUAL);
if (pegtx->vout[prevout.n].scriptPubKey != expected_script) {
return false;
}
Expand Down
8 changes: 4 additions & 4 deletions src/rpc/misc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -177,8 +177,8 @@ static UniValue verifymessage(const JSONRPCRequest& request)
throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address");
}

const CKeyID *keyID = boost::get<CKeyID>(&destination);
if (!keyID) {
const PKHash *pkhash = boost::get<PKHash>(&destination);
if (!pkhash) {
throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key");
}

Expand All @@ -196,7 +196,7 @@ static UniValue verifymessage(const JSONRPCRequest& request)
if (!pubkey.RecoverCompact(ss.GetHash(), vchSig))
return false;

return (pubkey.GetID() == *keyID);
return (pubkey.GetID() == *pkhash);
}

static UniValue signmessagewithprivkey(const JSONRPCRequest& request)
Expand Down Expand Up @@ -470,7 +470,7 @@ UniValue tweakfedpegscript(const JSONRPCRequest& request)
std::vector<unsigned char> scriptData = ParseHex(request.params[0].get_str());
CScript claim_script = CScript(scriptData.begin(), scriptData.end());
CScript tweaked_script = calculate_contract(Params().GetConsensus().fedpegScript, claim_script);
CTxDestination parent_addr(CScriptID(GetScriptForWitness(tweaked_script)));
CTxDestination parent_addr(ScriptHash(GetScriptForWitness(tweaked_script)));

UniValue ret(UniValue::VOBJ);
ret.pushKV("script", HexStr(tweaked_script));
Expand Down
4 changes: 2 additions & 2 deletions src/rpc/rawtransaction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -639,7 +639,7 @@ static UniValue decodescript(const JSONRPCRequest& request)
if (type.isStr() && type.get_str() != "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.
r.pushKV("p2sh", EncodeDestination(CScriptID(script)));
r.pushKV("p2sh", EncodeDestination(ScriptHash(CScriptID(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 (type.get_str() == "pubkey" || type.get_str() == "pubkeyhash" || type.get_str() == "multisig" || type.get_str() == "nonstandard") {
Expand All @@ -666,7 +666,7 @@ static UniValue decodescript(const JSONRPCRequest& request)
segwitScr = GetScriptForDestination(WitnessV0ScriptHash(script));
}
ScriptPubKeyToUniv(segwitScr, sr, true);
sr.pushKV("p2sh-segwit", EncodeDestination(CScriptID(segwitScr)));
sr.pushKV("p2sh-segwit", EncodeDestination(ScriptHash(CScriptID(segwitScr))));
r.pushKV("segwit", sr);
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/rpc/util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,15 +76,15 @@ class DescribeAddressVisitor : public boost::static_visitor<UniValue>
return UniValue(UniValue::VOBJ);
}

UniValue operator()(const CKeyID& keyID) const
UniValue operator()(const PKHash& keyID) const
{
UniValue obj(UniValue::VOBJ);
obj.pushKV("isscript", false);
obj.pushKV("iswitness", false);
return obj;
}

UniValue operator()(const CScriptID& scriptID) const
UniValue operator()(const ScriptHash& scriptID) const
{
UniValue obj(UniValue::VOBJ);
obj.pushKV("isscript", true);
Expand Down
8 changes: 4 additions & 4 deletions src/script/descriptor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ class SingleKeyDescriptor final : public Descriptor
}
};

CScript P2PKHGetScript(const CPubKey& pubkey) { return GetScriptForDestination(pubkey.GetID()); }
CScript P2PKHGetScript(const CPubKey& pubkey) { return GetScriptForDestination(PKHash(pubkey)); }
CScript P2PKGetScript(const CPubKey& pubkey) { return GetScriptForRawPubKey(pubkey); }
CScript P2WPKHGetScript(const CPubKey& pubkey) { return GetScriptForDestination(WitnessV0KeyHash(pubkey.GetID())); }

Expand Down Expand Up @@ -320,7 +320,7 @@ class ConvertorDescriptor : public Descriptor
}
};

CScript ConvertP2SH(const CScript& script) { return GetScriptForDestination(CScriptID(script)); }
CScript ConvertP2SH(const CScript& script) { return GetScriptForDestination(ScriptHash(script)); }
CScript ConvertP2WSH(const CScript& script) { return GetScriptForDestination(WitnessV0ScriptHash(script)); }

/** A parsed combo(P) descriptor. */
Expand All @@ -347,14 +347,14 @@ class ComboDescriptor final : public Descriptor
CKeyID keyid = key.GetID();
{
CScript p2pk = GetScriptForRawPubKey(key);
CScript p2pkh = GetScriptForDestination(keyid);
CScript p2pkh = GetScriptForDestination(PKHash(keyid));
output_scripts = std::vector<CScript>{std::move(p2pk), std::move(p2pkh)};
out.pubkeys.emplace(keyid, key);
}
if (key.IsCompressed()) {
CScript p2wpkh = GetScriptForDestination(WitnessV0KeyHash(keyid));
CScriptID p2wpkh_id(p2wpkh);
CScript p2sh_p2wpkh = GetScriptForDestination(p2wpkh_id);
CScript p2sh_p2wpkh = GetScriptForDestination(ScriptHash(p2wpkh_id));
out.scripts.emplace(p2wpkh_id, p2wpkh);
output_scripts.push_back(std::move(p2wpkh));
output_scripts.push_back(std::move(p2sh_p2wpkh));
Expand Down
2 changes: 1 addition & 1 deletion src/script/ismine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ IsMineResult IsMineInner(const CKeyStore& keystore, const CScript& scriptPubKey,
// This also applies to the P2WSH case.
break;
}
ret = std::max(ret, IsMineInner(keystore, GetScriptForDestination(CKeyID(uint160(vSolutions[0]))), IsMineSigVersion::WITNESS_V0));
ret = std::max(ret, IsMineInner(keystore, GetScriptForDestination(PKHash(uint160(vSolutions[0]))), IsMineSigVersion::WITNESS_V0));
break;
}
case TX_PUBKEYHASH:
Expand Down
16 changes: 10 additions & 6 deletions src/script/standard.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ unsigned nMaxDatacarrierBytes = MAX_OP_RETURN_RELAY;

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()) {}

WitnessV0ScriptHash::WitnessV0ScriptHash(const CScript& in)
{
CSHA256().Write(in.data(), in.size()).Finalize(begin());
Expand Down Expand Up @@ -174,17 +178,17 @@ bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet)
if (!pubKey.IsValid())
return false;

addressRet = pubKey.GetID();
addressRet = PKHash(pubKey);
return true;
}
else if (whichType == TX_PUBKEYHASH)
{
addressRet = CKeyID(uint160(vSolutions[0]));
addressRet = PKHash(uint160(vSolutions[0]));
return true;
}
else if (whichType == TX_SCRIPTHASH)
{
addressRet = CScriptID(uint160(vSolutions[0]));
addressRet = ScriptHash(uint160(vSolutions[0]));
return true;
} else if (whichType == TX_WITNESS_V0_KEYHASH) {
WitnessV0KeyHash hash;
Expand Down Expand Up @@ -229,7 +233,7 @@ bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, std::
if (!pubKey.IsValid())
continue;

CTxDestination address = pubKey.GetID();
CTxDestination address = PKHash(pubKey);
addressRet.push_back(address);
}

Expand Down Expand Up @@ -262,13 +266,13 @@ class CScriptVisitor : public boost::static_visitor<bool>
return false;
}

bool operator()(const CKeyID &keyID) const {
bool operator()(const PKHash &keyID) const {
script->clear();
*script << OP_DUP << OP_HASH160 << ToByteVector(keyID) << OP_EQUALVERIFY << OP_CHECKSIG;
return true;
}

bool operator()(const CScriptID &scriptID) const {
bool operator()(const ScriptHash &scriptID) const {
script->clear();
*script << OP_HASH160 << ToByteVector(scriptID) << OP_EQUAL;
return true;
Expand Down
22 changes: 19 additions & 3 deletions src/script/standard.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,22 @@ class CNoDestination {
friend bool operator<(const CNoDestination &a, const CNoDestination &b) { return true; }
};

struct PKHash : public uint160
{
PKHash() : uint160() {}
explicit PKHash(const uint160& hash) : uint160(hash) {}
explicit PKHash(const CPubKey& pubkey);
using uint160::uint160;
};

struct ScriptHash : public uint160
{
ScriptHash() : uint160() {}
explicit ScriptHash(const uint160& hash) : uint160(hash) {}
explicit ScriptHash(const CScript& script);
using uint160::uint160;
};

struct WitnessV0ScriptHash : public uint256
{
WitnessV0ScriptHash() : uint256() {}
Expand Down Expand Up @@ -129,15 +145,15 @@ class NullData
/**
* A txout script template with a specific destination. It is either:
* * CNoDestination: no destination set
* * CKeyID: TX_PUBKEYHASH destination (P2PKH)
* * CScriptID: TX_SCRIPTHASH destination (P2SH)
* * PKHash: TX_PUBKEYHASH destination (P2PKH)
* * ScriptHash: TX_SCRIPTHASH destination (P2SH)
* * WitnessV0ScriptHash: TX_WITNESS_V0_SCRIPTHASH destination (P2WSH)
* * WitnessV0KeyHash: TX_WITNESS_V0_KEYHASH destination (P2WPKH)
* * WitnessUnknown: TX_WITNESS_UNKNOWN destination (P2W???)
* * NullData: TX_NULL_DATA destination (OP_RETURN)
* A CTxDestination is the internal data type encoded in a bitcoin address
*/
typedef boost::variant<CNoDestination, CKeyID, CScriptID, WitnessV0ScriptHash, WitnessV0KeyHash, WitnessUnknown, NullData> CTxDestination;
typedef boost::variant<CNoDestination, PKHash, ScriptHash, WitnessV0ScriptHash, WitnessV0KeyHash, WitnessUnknown, NullData> CTxDestination;

/** Check whether a CTxDestination is a CNoDestination. */
bool IsValidDestination(const CTxDestination& dest);
Expand Down
8 changes: 4 additions & 4 deletions src/test/coins_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -481,17 +481,17 @@ BOOST_AUTO_TEST_CASE(ccoins_serialization)
ss1 >> cc1;
BOOST_CHECK_EQUAL(cc1.fCoinBase, false);
BOOST_CHECK_EQUAL(cc1.nHeight, 203998U);
BOOST_CHECK_EQUAL(cc1.out.nValue, CAmount{60000000000});
BOOST_CHECK_EQUAL(HexStr(cc1.out.scriptPubKey), HexStr(GetScriptForDestination(CKeyID(uint160(ParseHex("816115944e077fe7c803cfa57f29b36bf87c1d35"))))));
BOOST_CHECK_EQUAL(cc1.out.nValue.GetAmount(), 60000000000);
BOOST_CHECK_EQUAL(HexStr(cc1.out.scriptPubKey), HexStr(GetScriptForDestination(PKHash(uint160(ParseHex("816115944e077fe7c803cfa57f29b36bf87c1d35"))))));

// Good example
CDataStream ss2(ParseHex("8ddf77bbd123008c988f1a4a4de2161e0f50aac7f17e7f9555caa4"), SER_DISK, CLIENT_VERSION);
Coin cc2;
ss2 >> cc2;
BOOST_CHECK_EQUAL(cc2.fCoinBase, true);
BOOST_CHECK_EQUAL(cc2.nHeight, 120891U);
BOOST_CHECK_EQUAL(cc2.out.nValue, 110397);
BOOST_CHECK_EQUAL(HexStr(cc2.out.scriptPubKey), HexStr(GetScriptForDestination(CKeyID(uint160(ParseHex("8c988f1a4a4de2161e0f50aac7f17e7f9555caa4"))))));
BOOST_CHECK_EQUAL(cc2.out.nValue.GetAmount(), 110397);
BOOST_CHECK_EQUAL(HexStr(cc2.out.scriptPubKey), HexStr(GetScriptForDestination(PKHash(uint160(ParseHex("8c988f1a4a4de2161e0f50aac7f17e7f9555caa4"))))));

// Smallest possible example
CDataStream ss3(ParseHex("000006"), SER_DISK, CLIENT_VERSION);
Expand Down
Loading

0 comments on commit aa375e6

Please sign in to comment.