-
Notifications
You must be signed in to change notification settings - Fork 35.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support for watch-only addresses #2861
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1454,36 +1454,57 @@ class CKeyStoreIsMineVisitor : public boost::static_visitor<bool> | |
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; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This seems inconsistent with the way DescribeAddressVisitor is written: it allows for the case where the wallet has a redeemScript in it that can't be spent, yet the visitor will only show information on the redeemScript if it can be spent. I think it'd make more sense for it to be possible to have a redeemScript in your wallet that you can't spend, and for DescribeAddressVisitor to still show all the information known about the address in that case. |
||
} | ||
if (keystore.HaveWatchOnly(scriptID)) | ||
return MINE_WATCH_ONLY; | ||
break; | ||
} | ||
case TX_MULTISIG: | ||
{ | ||
|
@@ -1493,10 +1514,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) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm in favor of keeping importaddress as it is, but if we do allow the wallet to contain redeemScripts that you don't have the keys to spend it'd make sense to also add my "addredeemscript" patch, but more importantly make sure addmultisigaddress automatically creates a watch-only address if you add a multi-sig address to your wallet for which you don't have all the private keys.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The reason for not automatically causing ownership when a multisig address is created, is because the software still deals very badly with double spending, so you don't want multiple instances to be able to spend the same coins simultaneously. With watch-only, that concern doesn't exist, and I think the best solution is consider anything related to the imported address 'mine'.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, you're saying that when adding a multisig script for which you don't have all keys, it should automatically become watch-only. That seems reasonable, but maybe the semantics will be too confusing in that case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, scrap that idea then.
I see how it could cause confusion, especially for someone debugging a RPC-using thing who is assuming they can spend every addr.