mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-12-12 05:34:57 +01:00
Move ismine to wallet module
This commit is contained in:
@@ -1,193 +0,0 @@
|
||||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2018 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <script/ismine.h>
|
||||
|
||||
#include <key.h>
|
||||
#include <keystore.h>
|
||||
#include <script/script.h>
|
||||
#include <script/sign.h>
|
||||
|
||||
|
||||
typedef std::vector<unsigned char> valtype;
|
||||
|
||||
namespace {
|
||||
|
||||
/**
|
||||
* 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
|
||||
WITNESS_V0 = 2, //!< P2WSH witness script execution
|
||||
};
|
||||
|
||||
/**
|
||||
* This is an internal representation of isminetype + invalidity.
|
||||
* Its order is significant, as we return the max of all explored
|
||||
* possibilities.
|
||||
*/
|
||||
enum class IsMineResult
|
||||
{
|
||||
NO = 0, //!< Not ours
|
||||
WATCH_ONLY = 1, //!< Included in watch-only balance
|
||||
SPENDABLE = 2, //!< Included in all balances
|
||||
INVALID = 3, //!< Not spendable by anyone (uncompressed pubkey in segwit, P2SH inside P2SH or witness, witness inside witness)
|
||||
};
|
||||
|
||||
bool PermitsUncompressed(IsMineSigVersion sigversion)
|
||||
{
|
||||
return sigversion == IsMineSigVersion::TOP || sigversion == IsMineSigVersion::P2SH;
|
||||
}
|
||||
|
||||
bool HaveKeys(const std::vector<valtype>& pubkeys, const CKeyStore& keystore)
|
||||
{
|
||||
for (const valtype& pubkey : pubkeys) {
|
||||
CKeyID keyID = CPubKey(pubkey).GetID();
|
||||
if (!keystore.HaveKey(keyID)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
IsMineResult IsMineInner(const CKeyStore& keystore, const CScript& scriptPubKey, IsMineSigVersion sigversion)
|
||||
{
|
||||
IsMineResult ret = IsMineResult::NO;
|
||||
|
||||
std::vector<valtype> vSolutions;
|
||||
txnouttype whichType = Solver(scriptPubKey, vSolutions);
|
||||
|
||||
CKeyID keyID;
|
||||
switch (whichType)
|
||||
{
|
||||
case TX_NONSTANDARD:
|
||||
case TX_NULL_DATA:
|
||||
case TX_WITNESS_UNKNOWN:
|
||||
break;
|
||||
case TX_PUBKEY:
|
||||
keyID = CPubKey(vSolutions[0]).GetID();
|
||||
if (!PermitsUncompressed(sigversion) && vSolutions[0].size() != 33) {
|
||||
return IsMineResult::INVALID;
|
||||
}
|
||||
if (keystore.HaveKey(keyID)) {
|
||||
ret = std::max(ret, IsMineResult::SPENDABLE);
|
||||
}
|
||||
break;
|
||||
case TX_WITNESS_V0_KEYHASH:
|
||||
{
|
||||
if (sigversion == IsMineSigVersion::WITNESS_V0) {
|
||||
// P2WPKH inside P2WSH is invalid.
|
||||
return IsMineResult::INVALID;
|
||||
}
|
||||
if (sigversion == IsMineSigVersion::TOP && !keystore.HaveCScript(CScriptID(CScript() << OP_0 << vSolutions[0]))) {
|
||||
// We do not support bare witness outputs unless the P2SH version of it would be
|
||||
// acceptable as well. This protects against matching before segwit activates.
|
||||
// This also applies to the P2WSH case.
|
||||
break;
|
||||
}
|
||||
ret = std::max(ret, IsMineInner(keystore, GetScriptForDestination(PKHash(uint160(vSolutions[0]))), IsMineSigVersion::WITNESS_V0));
|
||||
break;
|
||||
}
|
||||
case TX_PUBKEYHASH:
|
||||
keyID = CKeyID(uint160(vSolutions[0]));
|
||||
if (!PermitsUncompressed(sigversion)) {
|
||||
CPubKey pubkey;
|
||||
if (keystore.GetPubKey(keyID, pubkey) && !pubkey.IsCompressed()) {
|
||||
return IsMineResult::INVALID;
|
||||
}
|
||||
}
|
||||
if (keystore.HaveKey(keyID)) {
|
||||
ret = std::max(ret, IsMineResult::SPENDABLE);
|
||||
}
|
||||
break;
|
||||
case TX_SCRIPTHASH:
|
||||
{
|
||||
if (sigversion != IsMineSigVersion::TOP) {
|
||||
// P2SH inside P2WSH or P2SH is invalid.
|
||||
return IsMineResult::INVALID;
|
||||
}
|
||||
CScriptID scriptID = CScriptID(uint160(vSolutions[0]));
|
||||
CScript subscript;
|
||||
if (keystore.GetCScript(scriptID, subscript)) {
|
||||
ret = std::max(ret, IsMineInner(keystore, subscript, IsMineSigVersion::P2SH));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TX_WITNESS_V0_SCRIPTHASH:
|
||||
{
|
||||
if (sigversion == IsMineSigVersion::WITNESS_V0) {
|
||||
// P2WSH inside P2WSH is invalid.
|
||||
return IsMineResult::INVALID;
|
||||
}
|
||||
if (sigversion == IsMineSigVersion::TOP && !keystore.HaveCScript(CScriptID(CScript() << OP_0 << vSolutions[0]))) {
|
||||
break;
|
||||
}
|
||||
uint160 hash;
|
||||
CRIPEMD160().Write(&vSolutions[0][0], vSolutions[0].size()).Finalize(hash.begin());
|
||||
CScriptID scriptID = CScriptID(hash);
|
||||
CScript subscript;
|
||||
if (keystore.GetCScript(scriptID, subscript)) {
|
||||
ret = std::max(ret, IsMineInner(keystore, subscript, IsMineSigVersion::WITNESS_V0));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
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 involved. Multi-signature transactions that are
|
||||
// partially owned (somebody else has a key that can spend
|
||||
// them) enable spend-out-from-under-you attacks, especially
|
||||
// in shared-wallet situations.
|
||||
std::vector<valtype> keys(vSolutions.begin()+1, vSolutions.begin()+vSolutions.size()-1);
|
||||
if (!PermitsUncompressed(sigversion)) {
|
||||
for (size_t i = 0; i < keys.size(); i++) {
|
||||
if (keys[i].size() != 33) {
|
||||
return IsMineResult::INVALID;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (HaveKeys(keys, keystore)) {
|
||||
ret = std::max(ret, IsMineResult::SPENDABLE);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret == IsMineResult::NO && keystore.HaveWatchOnly(scriptPubKey)) {
|
||||
ret = std::max(ret, IsMineResult::WATCH_ONLY);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
isminetype IsMine(const CKeyStore& keystore, const CScript& scriptPubKey)
|
||||
{
|
||||
switch (IsMineInner(keystore, scriptPubKey, IsMineSigVersion::TOP)) {
|
||||
case IsMineResult::INVALID:
|
||||
case IsMineResult::NO:
|
||||
return ISMINE_NO;
|
||||
case IsMineResult::WATCH_ONLY:
|
||||
return ISMINE_WATCH_ONLY;
|
||||
case IsMineResult::SPENDABLE:
|
||||
return ISMINE_SPENDABLE;
|
||||
}
|
||||
assert(false);
|
||||
}
|
||||
|
||||
isminetype IsMine(const CKeyStore& keystore, const CTxDestination& dest)
|
||||
{
|
||||
CScript script = GetScriptForDestination(dest);
|
||||
return IsMine(keystore, script);
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2018 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef BITCOIN_SCRIPT_ISMINE_H
|
||||
#define BITCOIN_SCRIPT_ISMINE_H
|
||||
|
||||
#include <script/standard.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <bitset>
|
||||
|
||||
class CKeyStore;
|
||||
class CScript;
|
||||
|
||||
/** IsMine() return codes */
|
||||
enum isminetype
|
||||
{
|
||||
ISMINE_NO = 0,
|
||||
ISMINE_WATCH_ONLY = 1 << 0,
|
||||
ISMINE_SPENDABLE = 1 << 1,
|
||||
ISMINE_USED = 1 << 2,
|
||||
ISMINE_ALL = ISMINE_WATCH_ONLY | ISMINE_SPENDABLE,
|
||||
ISMINE_ALL_USED = ISMINE_ALL | ISMINE_USED,
|
||||
ISMINE_ENUM_ELEMENTS,
|
||||
};
|
||||
/** used for bitflags of isminetype */
|
||||
typedef uint8_t isminefilter;
|
||||
|
||||
isminetype IsMine(const CKeyStore& keystore, const CScript& scriptPubKey);
|
||||
isminetype IsMine(const CKeyStore& keystore, const CTxDestination& dest);
|
||||
|
||||
/**
|
||||
* Cachable amount subdivided into watchonly and spendable parts.
|
||||
*/
|
||||
struct CachableAmount
|
||||
{
|
||||
// NO and ALL are never (supposed to be) cached
|
||||
std::bitset<ISMINE_ENUM_ELEMENTS> m_cached;
|
||||
CAmount m_value[ISMINE_ENUM_ELEMENTS];
|
||||
inline void Reset()
|
||||
{
|
||||
m_cached.reset();
|
||||
}
|
||||
void Set(isminefilter filter, CAmount value)
|
||||
{
|
||||
m_cached.set(filter);
|
||||
m_value[filter] = value;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // BITCOIN_SCRIPT_ISMINE_H
|
||||
Reference in New Issue
Block a user