Refactor: split CKeyID/CScriptID/CTxDestination from CBitcoinAddress
This introduces internal types: * CKeyID: reference (hash160) of a key * CScriptID: reference (hash160) of a script * CTxDestination: a boost::variant of the former two CBitcoinAddress is retrofitted to be a Base58 encoding of a CTxDestination. This allows all internal code to only use the internal types, and only have RPC and GUI depend on the base58 code. Furthermore, the header dependencies are a lot saner now. base58.h is at the top (right below rpc and gui) instead of at the bottom. For the rest: wallet -> script -> keystore -> key. Only keystore still requires a forward declaration of CScript. Solving that would require splitting script into two layers.
This commit is contained in:
117
src/script.cpp
117
src/script.cpp
@@ -1312,7 +1312,7 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector<vector<unsi
|
||||
}
|
||||
|
||||
|
||||
bool Sign1(const CBitcoinAddress& address, const CKeyStore& keystore, uint256 hash, int nHashType, CScript& scriptSigRet)
|
||||
bool Sign1(const CKeyID& address, const CKeyStore& keystore, uint256 hash, int nHashType, CScript& scriptSigRet)
|
||||
{
|
||||
CKey key;
|
||||
if (!keystore.GetKey(address, key))
|
||||
@@ -1334,9 +1334,8 @@ bool SignN(const vector<valtype>& multisigdata, const CKeyStore& keystore, uint2
|
||||
for (vector<valtype>::const_iterator it = multisigdata.begin()+1; it != multisigdata.begin()+multisigdata.size()-1; it++)
|
||||
{
|
||||
const valtype& pubkey = *it;
|
||||
CBitcoinAddress address;
|
||||
address.SetPubKey(pubkey);
|
||||
if (Sign1(address, keystore, hash, nHashType, scriptSigRet))
|
||||
CKeyID keyID = CPubKey(pubkey).GetID();
|
||||
if (Sign1(keyID, keystore, hash, nHashType, scriptSigRet))
|
||||
{
|
||||
++nSigned;
|
||||
if (nSigned == nRequired) break;
|
||||
@@ -1360,22 +1359,22 @@ bool Solver(const CKeyStore& keystore, const CScript& scriptPubKey, uint256 hash
|
||||
if (!Solver(scriptPubKey, whichTypeRet, vSolutions))
|
||||
return false;
|
||||
|
||||
CBitcoinAddress address;
|
||||
CKeyID keyID;
|
||||
switch (whichTypeRet)
|
||||
{
|
||||
case TX_NONSTANDARD:
|
||||
return false;
|
||||
case TX_PUBKEY:
|
||||
address.SetPubKey(vSolutions[0]);
|
||||
return Sign1(address, keystore, hash, nHashType, scriptSigRet);
|
||||
keyID = CPubKey(vSolutions[0]).GetID();
|
||||
return Sign1(keyID, keystore, hash, nHashType, scriptSigRet);
|
||||
case TX_PUBKEYHASH:
|
||||
address.SetHash160(uint160(vSolutions[0]));
|
||||
if (!Sign1(address, keystore, hash, nHashType, scriptSigRet))
|
||||
keyID = CKeyID(uint160(vSolutions[0]));
|
||||
if (!Sign1(keyID, keystore, hash, nHashType, scriptSigRet))
|
||||
return false;
|
||||
else
|
||||
{
|
||||
CPubKey vch;
|
||||
keystore.GetPubKey(address, vch);
|
||||
keystore.GetPubKey(keyID, vch);
|
||||
scriptSigRet << vch;
|
||||
}
|
||||
return true;
|
||||
@@ -1436,14 +1435,30 @@ unsigned int HaveKeys(const vector<valtype>& pubkeys, const CKeyStore& keystore)
|
||||
unsigned int nResult = 0;
|
||||
BOOST_FOREACH(const valtype& pubkey, pubkeys)
|
||||
{
|
||||
CBitcoinAddress address;
|
||||
address.SetPubKey(pubkey);
|
||||
if (keystore.HaveKey(address))
|
||||
CKeyID keyID = CPubKey(pubkey).GetID();
|
||||
if (keystore.HaveKey(keyID))
|
||||
++nResult;
|
||||
}
|
||||
return nResult;
|
||||
}
|
||||
|
||||
|
||||
class CKeyStoreIsMineVisitor : public boost::static_visitor<bool>
|
||||
{
|
||||
private:
|
||||
const CKeyStore *keystore;
|
||||
public:
|
||||
CKeyStoreIsMineVisitor(const CKeyStore *keystoreIn) : keystore(keystoreIn) { }
|
||||
bool operator()(const CNoDestination &dest) const { return false; }
|
||||
bool operator()(const CKeyID &keyID) const { return keystore->HaveKey(keyID); }
|
||||
bool operator()(const CScriptID &scriptID) const { return keystore->HaveCScript(scriptID); }
|
||||
};
|
||||
|
||||
bool IsMine(const CKeyStore &keystore, const CTxDestination &dest)
|
||||
{
|
||||
return boost::apply_visitor(CKeyStoreIsMineVisitor(&keystore), dest);
|
||||
}
|
||||
|
||||
bool IsMine(const CKeyStore &keystore, const CScript& scriptPubKey)
|
||||
{
|
||||
vector<valtype> vSolutions;
|
||||
@@ -1451,21 +1466,21 @@ bool IsMine(const CKeyStore &keystore, const CScript& scriptPubKey)
|
||||
if (!Solver(scriptPubKey, whichType, vSolutions))
|
||||
return false;
|
||||
|
||||
CBitcoinAddress address;
|
||||
CKeyID keyID;
|
||||
switch (whichType)
|
||||
{
|
||||
case TX_NONSTANDARD:
|
||||
return false;
|
||||
case TX_PUBKEY:
|
||||
address.SetPubKey(vSolutions[0]);
|
||||
return keystore.HaveKey(address);
|
||||
keyID = CPubKey(vSolutions[0]).GetID();
|
||||
return keystore.HaveKey(keyID);
|
||||
case TX_PUBKEYHASH:
|
||||
address.SetHash160(uint160(vSolutions[0]));
|
||||
return keystore.HaveKey(address);
|
||||
keyID = CKeyID(uint160(vSolutions[0]));
|
||||
return keystore.HaveKey(keyID);
|
||||
case TX_SCRIPTHASH:
|
||||
{
|
||||
CScript subscript;
|
||||
if (!keystore.GetCScript(uint160(vSolutions[0]), subscript))
|
||||
if (!keystore.GetCScript(CScriptID(uint160(vSolutions[0])), subscript))
|
||||
return false;
|
||||
return IsMine(keystore, subscript);
|
||||
}
|
||||
@@ -1483,7 +1498,7 @@ bool IsMine(const CKeyStore &keystore, const CScript& scriptPubKey)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ExtractAddress(const CScript& scriptPubKey, CBitcoinAddress& addressRet)
|
||||
bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet)
|
||||
{
|
||||
vector<valtype> vSolutions;
|
||||
txnouttype whichType;
|
||||
@@ -1492,24 +1507,24 @@ bool ExtractAddress(const CScript& scriptPubKey, CBitcoinAddress& addressRet)
|
||||
|
||||
if (whichType == TX_PUBKEY)
|
||||
{
|
||||
addressRet.SetPubKey(vSolutions[0]);
|
||||
addressRet = CPubKey(vSolutions[0]).GetID();
|
||||
return true;
|
||||
}
|
||||
else if (whichType == TX_PUBKEYHASH)
|
||||
{
|
||||
addressRet.SetHash160(uint160(vSolutions[0]));
|
||||
addressRet = CKeyID(uint160(vSolutions[0]));
|
||||
return true;
|
||||
}
|
||||
else if (whichType == TX_SCRIPTHASH)
|
||||
{
|
||||
addressRet.SetScriptHash160(uint160(vSolutions[0]));
|
||||
addressRet = CScriptID(uint160(vSolutions[0]));
|
||||
return true;
|
||||
}
|
||||
// Multisig txns have more than one address...
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ExtractAddresses(const CScript& scriptPubKey, txnouttype& typeRet, vector<CBitcoinAddress>& addressRet, int& nRequiredRet)
|
||||
bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, vector<CTxDestination>& addressRet, int& nRequiredRet)
|
||||
{
|
||||
addressRet.clear();
|
||||
typeRet = TX_NONSTANDARD;
|
||||
@@ -1522,21 +1537,16 @@ bool ExtractAddresses(const CScript& scriptPubKey, txnouttype& typeRet, vector<C
|
||||
nRequiredRet = vSolutions.front()[0];
|
||||
for (unsigned int i = 1; i < vSolutions.size()-1; i++)
|
||||
{
|
||||
CBitcoinAddress address;
|
||||
address.SetPubKey(vSolutions[i]);
|
||||
CTxDestination address = CPubKey(vSolutions[i]).GetID();
|
||||
addressRet.push_back(address);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
nRequiredRet = 1;
|
||||
CBitcoinAddress address;
|
||||
if (typeRet == TX_PUBKEYHASH)
|
||||
address.SetHash160(uint160(vSolutions.front()));
|
||||
else if (typeRet == TX_SCRIPTHASH)
|
||||
address.SetScriptHash160(uint160(vSolutions.front()));
|
||||
else if (typeRet == TX_PUBKEY)
|
||||
address.SetPubKey(vSolutions.front());
|
||||
CTxDestination address;
|
||||
if (!ExtractDestination(scriptPubKey, address))
|
||||
return false;
|
||||
addressRet.push_back(address);
|
||||
}
|
||||
|
||||
@@ -1694,13 +1704,34 @@ bool CScript::IsPayToScriptHash() const
|
||||
this->at(22) == OP_EQUAL);
|
||||
}
|
||||
|
||||
void CScript::SetBitcoinAddress(const CBitcoinAddress& address)
|
||||
class CScriptVisitor : public boost::static_visitor<bool>
|
||||
{
|
||||
this->clear();
|
||||
if (address.IsScript())
|
||||
*this << OP_HASH160 << address.GetHash160() << OP_EQUAL;
|
||||
else
|
||||
*this << OP_DUP << OP_HASH160 << address.GetHash160() << OP_EQUALVERIFY << OP_CHECKSIG;
|
||||
private:
|
||||
CScript *script;
|
||||
public:
|
||||
CScriptVisitor(CScript *scriptin) { script = scriptin; }
|
||||
|
||||
bool operator()(const CNoDestination &dest) const {
|
||||
script->clear();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool operator()(const CKeyID &keyID) const {
|
||||
script->clear();
|
||||
*script << OP_DUP << OP_HASH160 << keyID << OP_EQUALVERIFY << OP_CHECKSIG;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool operator()(const CScriptID &scriptID) const {
|
||||
script->clear();
|
||||
*script << OP_HASH160 << scriptID << OP_EQUAL;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
void CScript::SetDestination(const CTxDestination& dest)
|
||||
{
|
||||
boost::apply_visitor(CScriptVisitor(this), dest);
|
||||
}
|
||||
|
||||
void CScript::SetMultisig(int nRequired, const std::vector<CKey>& keys)
|
||||
@@ -1712,11 +1743,3 @@ void CScript::SetMultisig(int nRequired, const std::vector<CKey>& keys)
|
||||
*this << key.GetPubKey();
|
||||
*this << EncodeOP_N(keys.size()) << OP_CHECKMULTISIG;
|
||||
}
|
||||
|
||||
void CScript::SetPayToScriptHash(const CScript& subscript)
|
||||
{
|
||||
assert(!subscript.empty());
|
||||
uint160 subscriptHash = Hash160(subscript);
|
||||
this->clear();
|
||||
*this << OP_HASH160 << subscriptHash << OP_EQUAL;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user