Add support for watch-only addresses

Changes:
* Add Add/Have WatchOnly methods to CKeyStore, and implementations
  in CBasicKeyStore.
* Add similar methods to CWallet, and support entries for it in
  CWalletDB.
* Make IsMine in script/wallet return a new enum 'isminetype',
  rather than a boolean. This allows distinguishing between
  spendable and unspendable coins.
* Add a field fSpendable to COutput (GetAvailableCoins' return type).
* Mark watchonly coins in listunspent as 'watchonly': true.
* Add 'watchonly' to validateaddress, suppressing script/pubkey/...
  in this case.

Based on a patch by Eric Lombrozo.

Conflicts:
	src/qt/walletmodel.cpp
	src/rpcserver.cpp
	src/wallet.cpp
This commit is contained in:
Pieter Wuille
2013-07-26 01:06:01 +02:00
committed by JaSK
parent dd49e92fb0
commit c8988460a2
16 changed files with 223 additions and 52 deletions

View File

@@ -1456,36 +1456,57 @@ public:
bool operator()(const CScriptID &scriptID) const { return keystore->HaveCScript(scriptID); }
};
bool IsMine(const CKeyStore &keystore, const CTxDestination &dest)
isminetype IsMine(const CKeyStore &keystore, const CTxDestination &dest)
{
return boost::apply_visitor(CKeyStoreIsMineVisitor(&keystore), dest);
if (boost::apply_visitor(CKeyStoreIsMineVisitor(&keystore), dest))
return MINE_SPENDABLE;
if (keystore.HaveWatchOnly(dest))
return MINE_WATCH_ONLY;
return MINE_NO;
}
bool IsMine(const CKeyStore &keystore, const CScript& scriptPubKey)
isminetype IsMine(const CKeyStore &keystore, const CScript& scriptPubKey)
{
vector<valtype> vSolutions;
txnouttype whichType;
if (!Solver(scriptPubKey, whichType, vSolutions))
return false;
if (!Solver(scriptPubKey, whichType, vSolutions)) {
if (keystore.HaveWatchOnly(scriptPubKey.GetID()))
return MINE_WATCH_ONLY;
return MINE_NO;
}
CKeyID keyID;
switch (whichType)
{
case TX_NONSTANDARD:
case TX_NULL_DATA:
return false;
break;
case TX_PUBKEY:
keyID = CPubKey(vSolutions[0]).GetID();
return keystore.HaveKey(keyID);
if (keystore.HaveKey(keyID))
return MINE_SPENDABLE;
if (keystore.HaveWatchOnly(keyID))
return MINE_WATCH_ONLY;
break;
case TX_PUBKEYHASH:
keyID = CKeyID(uint160(vSolutions[0]));
return keystore.HaveKey(keyID);
if (keystore.HaveKey(keyID))
return MINE_SPENDABLE;
if (keystore.HaveWatchOnly(keyID))
return MINE_WATCH_ONLY;
break;
case TX_SCRIPTHASH:
{
CScriptID scriptID = CScriptID(uint160(vSolutions[0]));
CScript subscript;
if (!keystore.GetCScript(CScriptID(uint160(vSolutions[0])), subscript))
return false;
return IsMine(keystore, subscript);
if (keystore.GetCScript(scriptID, subscript)) {
isminetype ret = IsMine(keystore, subscript);
if (ret)
return ret;
}
if (keystore.HaveWatchOnly(scriptID))
return MINE_WATCH_ONLY;
break;
}
case TX_MULTISIG:
{
@@ -1495,10 +1516,15 @@ bool IsMine(const CKeyStore &keystore, const CScript& scriptPubKey)
// them) enable spend-out-from-under-you attacks, especially
// in shared-wallet situations.
vector<valtype> keys(vSolutions.begin()+1, vSolutions.begin()+vSolutions.size()-1);
return HaveKeys(keys, keystore) == keys.size();
if (HaveKeys(keys, keystore) == keys.size())
return MINE_SPENDABLE;
break;
}
}
return false;
if (keystore.HaveWatchOnly(scriptPubKey.GetID()))
return MINE_WATCH_ONLY;
return MINE_NO;
}
bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet)