Changeset View
Changeset View
Standalone View
Standalone View
src/script/ismine.cpp
// Copyright (c) 2009-2010 Satoshi Nakamoto | // Copyright (c) 2009-2010 Satoshi Nakamoto | ||||
// Copyright (c) 2009-2016 The Bitcoin Core developers | // Copyright (c) 2009-2016 The Bitcoin Core developers | ||||
// Distributed under the MIT software license, see the accompanying | // Distributed under the MIT software license, see the accompanying | ||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php. | // file COPYING or http://www.opensource.org/licenses/mit-license.php. | ||||
#include <script/ismine.h> | #include <script/ismine.h> | ||||
#include <key.h> | #include <key.h> | ||||
#include <keystore.h> | #include <keystore.h> | ||||
#include <script/script.h> | #include <script/script.h> | ||||
#include <script/sign.h> | #include <script/sign.h> | ||||
#include <script/standard.h> | #include <script/standard.h> | ||||
typedef std::vector<uint8_t> valtype; | typedef std::vector<uint8_t> valtype; | ||||
static bool HaveKeys(const std::vector<valtype> &pubkeys, | namespace { | ||||
const CKeyStore &keystore) { | |||||
/** | |||||
* This is an enum that tracks the execution context of a script, similar to | |||||
* SigVersion in script/interpreter. It is separate however because we want to | |||||
* distinguish between top-level scriptPubKey execution and P2SH redeemScript | |||||
* execution (a distinction that has no impact on consensus rules). | |||||
*/ | |||||
enum class IsMineSigVersion { | |||||
TOP = 0, //! scriptPubKey execution | |||||
P2SH = 1, //! P2SH redeemScript | |||||
}; | |||||
bool HaveKeys(const std::vector<valtype> &pubkeys, const CKeyStore &keystore) { | |||||
for (const valtype &pubkey : pubkeys) { | for (const valtype &pubkey : pubkeys) { | ||||
CKeyID keyID = CPubKey(pubkey).GetID(); | CKeyID keyID = CPubKey(pubkey).GetID(); | ||||
if (!keystore.HaveKey(keyID)) { | if (!keystore.HaveKey(keyID)) { | ||||
return false; | return false; | ||||
} | } | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
isminetype IsMine(const CKeyStore &keystore, const CScript &scriptPubKey) { | isminetype IsMineInner(const CKeyStore &keystore, const CScript &scriptPubKey, | ||||
bool isInvalid = false; | bool &isInvalid, IsMineSigVersion sigversion) { | ||||
return IsMine(keystore, scriptPubKey, isInvalid); | |||||
} | |||||
isminetype IsMine(const CKeyStore &keystore, const CTxDestination &dest) { | |||||
bool isInvalid = false; | |||||
return IsMine(keystore, dest, isInvalid); | |||||
} | |||||
isminetype IsMine(const CKeyStore &keystore, const CTxDestination &dest, | |||||
bool &isInvalid) { | |||||
CScript script = GetScriptForDestination(dest); | |||||
return IsMine(keystore, script, isInvalid); | |||||
} | |||||
isminetype IsMine(const CKeyStore &keystore, const CScript &scriptPubKey, | |||||
bool &isInvalid) { | |||||
isInvalid = false; | isInvalid = false; | ||||
std::vector<valtype> vSolutions; | std::vector<valtype> vSolutions; | ||||
txnouttype whichType; | txnouttype whichType; | ||||
if (!Solver(scriptPubKey, whichType, vSolutions)) { | if (!Solver(scriptPubKey, whichType, vSolutions)) { | ||||
if (keystore.HaveWatchOnly(scriptPubKey)) | if (keystore.HaveWatchOnly(scriptPubKey)) | ||||
return ISMINE_WATCH_UNSOLVABLE; | return ISMINE_WATCH_UNSOLVABLE; | ||||
return ISMINE_NO; | return ISMINE_NO; | ||||
Show All 11 Lines | switch (whichType) { | ||||
case TX_PUBKEYHASH: | case TX_PUBKEYHASH: | ||||
keyID = CKeyID(uint160(vSolutions[0])); | keyID = CKeyID(uint160(vSolutions[0])); | ||||
if (keystore.HaveKey(keyID)) return ISMINE_SPENDABLE; | if (keystore.HaveKey(keyID)) return ISMINE_SPENDABLE; | ||||
break; | break; | ||||
case TX_SCRIPTHASH: { | case TX_SCRIPTHASH: { | ||||
CScriptID scriptID = CScriptID(uint160(vSolutions[0])); | CScriptID scriptID = CScriptID(uint160(vSolutions[0])); | ||||
CScript subscript; | CScript subscript; | ||||
if (keystore.GetCScript(scriptID, subscript)) { | if (keystore.GetCScript(scriptID, subscript)) { | ||||
isminetype ret = IsMine(keystore, subscript, isInvalid); | isminetype ret = IsMineInner(keystore, subscript, isInvalid, | ||||
IsMineSigVersion::P2SH); | |||||
if (ret == ISMINE_SPENDABLE || ret == ISMINE_WATCH_SOLVABLE || | if (ret == ISMINE_SPENDABLE || ret == ISMINE_WATCH_SOLVABLE || | ||||
(ret == ISMINE_NO && isInvalid)) | (ret == ISMINE_NO && isInvalid)) | ||||
return ret; | return ret; | ||||
} | } | ||||
break; | break; | ||||
} | } | ||||
case TX_MULTISIG: { | case TX_MULTISIG: { | ||||
// Never treat bare multisig outputs as ours (they can still be made | |||||
// watchonly-though) | |||||
if (sigversion == IsMineSigVersion::TOP) { | |||||
break; | |||||
} | |||||
// Only consider transactions "mine" if we own ALL the keys | // Only consider transactions "mine" if we own ALL the keys | ||||
// involved. Multi-signature transactions that are partially owned | // involved. Multi-signature transactions that are partially owned | ||||
// (somebody else has a key that can spend them) enable | // (somebody else has a key that can spend them) enable | ||||
// spend-out-from-under-you attacks, especially in shared-wallet | // spend-out-from-under-you attacks, especially in shared-wallet | ||||
// situations. | // situations. | ||||
std::vector<valtype> keys(vSolutions.begin() + 1, | std::vector<valtype> keys(vSolutions.begin() + 1, | ||||
vSolutions.begin() + vSolutions.size() - | vSolutions.begin() + vSolutions.size() - | ||||
1); | 1); | ||||
Show All 10 Lines | if (keystore.HaveWatchOnly(scriptPubKey)) { | ||||
SignatureData sigs; | SignatureData sigs; | ||||
return ProduceSignature(keystore, DUMMY_SIGNATURE_CREATOR, scriptPubKey, | return ProduceSignature(keystore, DUMMY_SIGNATURE_CREATOR, scriptPubKey, | ||||
sigs) | sigs) | ||||
? ISMINE_WATCH_SOLVABLE | ? ISMINE_WATCH_SOLVABLE | ||||
: ISMINE_WATCH_UNSOLVABLE; | : ISMINE_WATCH_UNSOLVABLE; | ||||
} | } | ||||
return ISMINE_NO; | return ISMINE_NO; | ||||
} | } | ||||
} // namespace | |||||
isminetype IsMine(const CKeyStore &keystore, const CScript &scriptPubKey, | |||||
bool &isInvalid) { | |||||
return IsMineInner(keystore, scriptPubKey, isInvalid, | |||||
IsMineSigVersion::TOP); | |||||
} | |||||
isminetype IsMine(const CKeyStore &keystore, const CScript &scriptPubKey) { | |||||
bool isInvalid = false; | |||||
return IsMine(keystore, scriptPubKey, isInvalid); | |||||
} | |||||
isminetype IsMine(const CKeyStore &keystore, const CTxDestination &dest) { | |||||
CScript script = GetScriptForDestination(dest); | |||||
return IsMine(keystore, script); | |||||
} |