Merge #16226: Move ismine to the wallet module

e61de6306f Change ismine to take a CWallet instead of CKeyStore (Andrew Chow)
7c611e2000 Move ismine to wallet module (Andrew Chow)

Pull request description:

  `IsMine` isn't used outside of the wallet except for the tests. It also doesn't make sense to be outside of the wallet. This PR moves `IsMine` into the wallet module and for it to take a `CWallet` instead of `CKeyStore`. The test that used `IsMine` is also moved to the wallet tests.

  This is first [prerequisites](https://github.com/bitcoin-core/bitcoin-devwiki/wiki/Wallet-Class-Structure-Changes#ismine) for the wallet structure changes.

ACKs for commit e61de6:
  MarcoFalke:
    re-ACK e61de6306f (only change is rebase with git auto-merge)
  meshcollider:
    Very light code review ACK e61de6306f

Tree-SHA512: 1cb4ad12652aef7922ab7460c6d413e8b9d1855dca78c0a286ae49d5c0765bc7996c55f262c742001d434eb9bd4215dc2cc7aae1b371ee1a82d46b32c17e6341
This commit is contained in:
MeshCollider 2019-06-21 19:58:18 +12:00
commit fd333e15a5
No known key found for this signature in database
GPG key ID: D300116E1C875A3D
14 changed files with 425 additions and 385 deletions

View file

@ -181,7 +181,6 @@ BITCOIN_CORE_H = \
rpc/util.h \ rpc/util.h \
scheduler.h \ scheduler.h \
script/descriptor.h \ script/descriptor.h \
script/ismine.h \
script/sigcache.h \ script/sigcache.h \
script/sign.h \ script/sign.h \
script/standard.h \ script/standard.h \
@ -223,6 +222,7 @@ BITCOIN_CORE_H = \
wallet/db.h \ wallet/db.h \
wallet/feebumper.h \ wallet/feebumper.h \
wallet/fees.h \ wallet/fees.h \
wallet/ismine.h \
wallet/load.h \ wallet/load.h \
wallet/psbtwallet.h \ wallet/psbtwallet.h \
wallet/rpcwallet.h \ wallet/rpcwallet.h \
@ -328,6 +328,7 @@ libbitcoin_wallet_a_SOURCES = \
wallet/db.cpp \ wallet/db.cpp \
wallet/feebumper.cpp \ wallet/feebumper.cpp \
wallet/fees.cpp \ wallet/fees.cpp \
wallet/ismine.cpp \
wallet/load.cpp \ wallet/load.cpp \
wallet/psbtwallet.cpp \ wallet/psbtwallet.cpp \
wallet/rpcdump.cpp \ wallet/rpcdump.cpp \
@ -458,7 +459,6 @@ libbitcoin_common_a_SOURCES = \
rpc/util.cpp \ rpc/util.cpp \
scheduler.cpp \ scheduler.cpp \
script/descriptor.cpp \ script/descriptor.cpp \
script/ismine.cpp \
script/sign.cpp \ script/sign.cpp \
script/standard.cpp \ script/standard.cpp \
versionbitsinfo.cpp \ versionbitsinfo.cpp \

View file

@ -167,7 +167,8 @@ BITCOIN_TESTS += \
wallet/test/wallet_tests.cpp \ wallet/test/wallet_tests.cpp \
wallet/test/wallet_crypto_tests.cpp \ wallet/test/wallet_crypto_tests.cpp \
wallet/test/coinselector_tests.cpp \ wallet/test/coinselector_tests.cpp \
wallet/test/init_tests.cpp wallet/test/init_tests.cpp \
wallet/test/ismine_tests.cpp
BITCOIN_TEST_SUITE += \ BITCOIN_TEST_SUITE += \
wallet/test/wallet_test_fixture.cpp \ wallet/test/wallet_test_fixture.cpp \

View file

@ -11,7 +11,6 @@
#include <policy/feerate.h> #include <policy/feerate.h>
#include <policy/fees.h> #include <policy/fees.h>
#include <primitives/transaction.h> #include <primitives/transaction.h>
#include <script/ismine.h>
#include <script/standard.h> #include <script/standard.h>
#include <support/allocators/secure.h> #include <support/allocators/secure.h>
#include <sync.h> #include <sync.h>
@ -20,6 +19,7 @@
#include <util/system.h> #include <util/system.h>
#include <wallet/feebumper.h> #include <wallet/feebumper.h>
#include <wallet/fees.h> #include <wallet/fees.h>
#include <wallet/ismine.h>
#include <wallet/rpcwallet.h> #include <wallet/rpcwallet.h>
#include <wallet/load.h> #include <wallet/load.h>
#include <wallet/wallet.h> #include <wallet/wallet.h>

View file

@ -7,7 +7,6 @@
#include <amount.h> // For CAmount #include <amount.h> // For CAmount
#include <pubkey.h> // For CKeyID and CScriptID (definitions needed in CTxDestination instantiation) #include <pubkey.h> // For CKeyID and CScriptID (definitions needed in CTxDestination instantiation)
#include <script/ismine.h> // For isminefilter, isminetype
#include <script/standard.h> // For CTxDestination #include <script/standard.h> // For CTxDestination
#include <support/allocators/secure.h> // For SecureString #include <support/allocators/secure.h> // For SecureString
#include <ui_interface.h> // For ChangeType #include <ui_interface.h> // For ChangeType
@ -25,7 +24,10 @@ class CCoinControl;
class CFeeRate; class CFeeRate;
class CKey; class CKey;
class CWallet; class CWallet;
enum isminetype : unsigned int;
enum class FeeReason; enum class FeeReason;
typedef uint8_t isminefilter;
enum class OutputType; enum class OutputType;
struct CRecipient; struct CRecipient;

View file

@ -21,6 +21,7 @@
#include <timedata.h> #include <timedata.h>
#include <util/system.h> #include <util/system.h>
#include <policy/policy.h> #include <policy/policy.h>
#include <wallet/ismine.h>
#include <stdint.h> #include <stdint.h>
#include <string> #include <string>

View file

@ -7,6 +7,7 @@
#include <chain.h> #include <chain.h>
#include <interfaces/wallet.h> #include <interfaces/wallet.h>
#include <key_io.h> #include <key_io.h>
#include <wallet/ismine.h>
#include <stdint.h> #include <stdint.h>

View file

@ -11,7 +11,6 @@
#include <script/script_error.h> #include <script/script_error.h>
#include <policy/settings.h> #include <policy/settings.h>
#include <script/sign.h> #include <script/sign.h>
#include <script/ismine.h>
#include <test/setup_common.h> #include <test/setup_common.h>
#include <vector> #include <vector>
@ -98,7 +97,6 @@ BOOST_AUTO_TEST_CASE(sign)
txTo[i].vin[0].prevout.n = i; txTo[i].vin[0].prevout.n = i;
txTo[i].vin[0].prevout.hash = txFrom.GetHash(); txTo[i].vin[0].prevout.hash = txFrom.GetHash();
txTo[i].vout[0].nValue = 1; txTo[i].vout[0].nValue = 1;
BOOST_CHECK_MESSAGE(IsMine(keystore, txFrom.vout[i].scriptPubKey), strprintf("IsMine %d", i));
} }
for (int i = 0; i < 8; i++) for (int i = 0; i < 8; i++)
{ {
@ -195,7 +193,6 @@ BOOST_AUTO_TEST_CASE(set)
txTo[i].vin[0].prevout.hash = txFrom.GetHash(); txTo[i].vin[0].prevout.hash = txFrom.GetHash();
txTo[i].vout[0].nValue = 1*CENT; txTo[i].vout[0].nValue = 1*CENT;
txTo[i].vout[0].scriptPubKey = inner[i]; txTo[i].vout[0].scriptPubKey = inner[i];
BOOST_CHECK_MESSAGE(IsMine(keystore, txFrom.vout[i].scriptPubKey), strprintf("IsMine %d", i));
} }
for (int i = 0; i < 4; i++) for (int i = 0; i < 4; i++)
{ {

View file

@ -4,7 +4,6 @@
#include <key.h> #include <key.h>
#include <keystore.h> #include <keystore.h>
#include <script/ismine.h>
#include <script/script.h> #include <script/script.h>
#include <script/script_error.h> #include <script/script_error.h>
#include <script/standard.h> #include <script/standard.h>
@ -372,364 +371,4 @@ BOOST_AUTO_TEST_CASE(script_standard_GetScriptFor_)
BOOST_CHECK(result == expected); BOOST_CHECK(result == expected);
} }
BOOST_AUTO_TEST_CASE(script_standard_IsMine)
{
CKey keys[2];
CPubKey pubkeys[2];
for (int i = 0; i < 2; i++) {
keys[i].MakeNewKey(true);
pubkeys[i] = keys[i].GetPubKey();
}
CKey uncompressedKey;
uncompressedKey.MakeNewKey(false);
CPubKey uncompressedPubkey = uncompressedKey.GetPubKey();
CScript scriptPubKey;
isminetype result;
// P2PK compressed
{
CBasicKeyStore keystore;
scriptPubKey = GetScriptForRawPubKey(pubkeys[0]);
// Keystore does not have key
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
// Keystore has key
BOOST_CHECK(keystore.AddKey(keys[0]));
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
}
// P2PK uncompressed
{
CBasicKeyStore keystore;
scriptPubKey = GetScriptForRawPubKey(uncompressedPubkey);
// Keystore does not have key
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
// Keystore has key
BOOST_CHECK(keystore.AddKey(uncompressedKey));
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
}
// P2PKH compressed
{
CBasicKeyStore keystore;
scriptPubKey = GetScriptForDestination(PKHash(pubkeys[0]));
// Keystore does not have key
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
// Keystore has key
BOOST_CHECK(keystore.AddKey(keys[0]));
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
}
// P2PKH uncompressed
{
CBasicKeyStore keystore;
scriptPubKey = GetScriptForDestination(PKHash(uncompressedPubkey));
// Keystore does not have key
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
// Keystore has key
BOOST_CHECK(keystore.AddKey(uncompressedKey));
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
}
// P2SH
{
CBasicKeyStore keystore;
CScript redeemScript = GetScriptForDestination(PKHash(pubkeys[0]));
scriptPubKey = GetScriptForDestination(ScriptHash(redeemScript));
// Keystore does not have redeemScript or key
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
// Keystore has redeemScript but no key
BOOST_CHECK(keystore.AddCScript(redeemScript));
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
// Keystore has redeemScript and key
BOOST_CHECK(keystore.AddKey(keys[0]));
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
}
// (P2PKH inside) P2SH inside P2SH (invalid)
{
CBasicKeyStore keystore;
CScript redeemscript_inner = GetScriptForDestination(PKHash(pubkeys[0]));
CScript redeemscript = GetScriptForDestination(ScriptHash(redeemscript_inner));
scriptPubKey = GetScriptForDestination(ScriptHash(redeemscript));
BOOST_CHECK(keystore.AddCScript(redeemscript));
BOOST_CHECK(keystore.AddCScript(redeemscript_inner));
BOOST_CHECK(keystore.AddCScript(scriptPubKey));
BOOST_CHECK(keystore.AddKey(keys[0]));
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
}
// (P2PKH inside) P2SH inside P2WSH (invalid)
{
CBasicKeyStore keystore;
CScript redeemscript = GetScriptForDestination(PKHash(pubkeys[0]));
CScript witnessscript = GetScriptForDestination(ScriptHash(redeemscript));
scriptPubKey = GetScriptForDestination(WitnessV0ScriptHash(witnessscript));
BOOST_CHECK(keystore.AddCScript(witnessscript));
BOOST_CHECK(keystore.AddCScript(redeemscript));
BOOST_CHECK(keystore.AddCScript(scriptPubKey));
BOOST_CHECK(keystore.AddKey(keys[0]));
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
}
// P2WPKH inside P2WSH (invalid)
{
CBasicKeyStore keystore;
CScript witnessscript = GetScriptForDestination(WitnessV0KeyHash(PKHash(pubkeys[0])));
scriptPubKey = GetScriptForDestination(WitnessV0ScriptHash(witnessscript));
BOOST_CHECK(keystore.AddCScript(witnessscript));
BOOST_CHECK(keystore.AddCScript(scriptPubKey));
BOOST_CHECK(keystore.AddKey(keys[0]));
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
}
// (P2PKH inside) P2WSH inside P2WSH (invalid)
{
CBasicKeyStore keystore;
CScript witnessscript_inner = GetScriptForDestination(PKHash(pubkeys[0]));
CScript witnessscript = GetScriptForDestination(WitnessV0ScriptHash(witnessscript_inner));
scriptPubKey = GetScriptForDestination(WitnessV0ScriptHash(witnessscript));
BOOST_CHECK(keystore.AddCScript(witnessscript_inner));
BOOST_CHECK(keystore.AddCScript(witnessscript));
BOOST_CHECK(keystore.AddCScript(scriptPubKey));
BOOST_CHECK(keystore.AddKey(keys[0]));
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
}
// P2WPKH compressed
{
CBasicKeyStore keystore;
BOOST_CHECK(keystore.AddKey(keys[0]));
scriptPubKey = GetScriptForDestination(WitnessV0KeyHash(PKHash(pubkeys[0])));
// Keystore implicitly has key and P2SH redeemScript
BOOST_CHECK(keystore.AddCScript(scriptPubKey));
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
}
// P2WPKH uncompressed
{
CBasicKeyStore keystore;
BOOST_CHECK(keystore.AddKey(uncompressedKey));
scriptPubKey = GetScriptForDestination(WitnessV0KeyHash(PKHash(uncompressedPubkey)));
// Keystore has key, but no P2SH redeemScript
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
// Keystore has key and P2SH redeemScript
BOOST_CHECK(keystore.AddCScript(scriptPubKey));
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
}
// scriptPubKey multisig
{
CBasicKeyStore keystore;
scriptPubKey = GetScriptForMultisig(2, {uncompressedPubkey, pubkeys[1]});
// Keystore does not have any keys
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
// Keystore has 1/2 keys
BOOST_CHECK(keystore.AddKey(uncompressedKey));
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
// Keystore has 2/2 keys
BOOST_CHECK(keystore.AddKey(keys[1]));
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
// Keystore has 2/2 keys and the script
BOOST_CHECK(keystore.AddCScript(scriptPubKey));
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
}
// P2SH multisig
{
CBasicKeyStore keystore;
BOOST_CHECK(keystore.AddKey(uncompressedKey));
BOOST_CHECK(keystore.AddKey(keys[1]));
CScript redeemScript = GetScriptForMultisig(2, {uncompressedPubkey, pubkeys[1]});
scriptPubKey = GetScriptForDestination(ScriptHash(redeemScript));
// Keystore has no redeemScript
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
// Keystore has redeemScript
BOOST_CHECK(keystore.AddCScript(redeemScript));
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
}
// P2WSH multisig with compressed keys
{
CBasicKeyStore keystore;
BOOST_CHECK(keystore.AddKey(keys[0]));
BOOST_CHECK(keystore.AddKey(keys[1]));
CScript witnessScript = GetScriptForMultisig(2, {pubkeys[0], pubkeys[1]});
scriptPubKey = GetScriptForDestination(WitnessV0ScriptHash(witnessScript));
// Keystore has keys, but no witnessScript or P2SH redeemScript
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
// Keystore has keys and witnessScript, but no P2SH redeemScript
BOOST_CHECK(keystore.AddCScript(witnessScript));
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
// Keystore has keys, witnessScript, P2SH redeemScript
BOOST_CHECK(keystore.AddCScript(scriptPubKey));
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
}
// P2WSH multisig with uncompressed key
{
CBasicKeyStore keystore;
BOOST_CHECK(keystore.AddKey(uncompressedKey));
BOOST_CHECK(keystore.AddKey(keys[1]));
CScript witnessScript = GetScriptForMultisig(2, {uncompressedPubkey, pubkeys[1]});
scriptPubKey = GetScriptForDestination(WitnessV0ScriptHash(witnessScript));
// Keystore has keys, but no witnessScript or P2SH redeemScript
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
// Keystore has keys and witnessScript, but no P2SH redeemScript
BOOST_CHECK(keystore.AddCScript(witnessScript));
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
// Keystore has keys, witnessScript, P2SH redeemScript
BOOST_CHECK(keystore.AddCScript(scriptPubKey));
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
}
// P2WSH multisig wrapped in P2SH
{
CBasicKeyStore keystore;
CScript witnessScript = GetScriptForMultisig(2, {pubkeys[0], pubkeys[1]});
CScript redeemScript = GetScriptForDestination(WitnessV0ScriptHash(witnessScript));
scriptPubKey = GetScriptForDestination(ScriptHash(redeemScript));
// Keystore has no witnessScript, P2SH redeemScript, or keys
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
// Keystore has witnessScript and P2SH redeemScript, but no keys
BOOST_CHECK(keystore.AddCScript(redeemScript));
BOOST_CHECK(keystore.AddCScript(witnessScript));
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
// Keystore has keys, witnessScript, P2SH redeemScript
BOOST_CHECK(keystore.AddKey(keys[0]));
BOOST_CHECK(keystore.AddKey(keys[1]));
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
}
// OP_RETURN
{
CBasicKeyStore keystore;
BOOST_CHECK(keystore.AddKey(keys[0]));
scriptPubKey.clear();
scriptPubKey << OP_RETURN << ToByteVector(pubkeys[0]);
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
}
// witness unspendable
{
CBasicKeyStore keystore;
BOOST_CHECK(keystore.AddKey(keys[0]));
scriptPubKey.clear();
scriptPubKey << OP_0 << ToByteVector(ParseHex("aabb"));
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
}
// witness unknown
{
CBasicKeyStore keystore;
BOOST_CHECK(keystore.AddKey(keys[0]));
scriptPubKey.clear();
scriptPubKey << OP_16 << ToByteVector(ParseHex("aabb"));
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
}
// Nonstandard
{
CBasicKeyStore keystore;
BOOST_CHECK(keystore.AddKey(keys[0]));
scriptPubKey.clear();
scriptPubKey << OP_9 << OP_ADD << OP_11 << OP_EQUAL;
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
}
}
BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END()

View file

@ -3,13 +3,12 @@
// 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 <wallet/ismine.h>
#include <key.h> #include <key.h>
#include <keystore.h>
#include <script/script.h> #include <script/script.h>
#include <script/sign.h> #include <script/sign.h>
#include <wallet/wallet.h>
typedef std::vector<unsigned char> valtype; typedef std::vector<unsigned char> valtype;
@ -46,7 +45,7 @@ bool PermitsUncompressed(IsMineSigVersion sigversion)
return sigversion == IsMineSigVersion::TOP || sigversion == IsMineSigVersion::P2SH; return sigversion == IsMineSigVersion::TOP || sigversion == IsMineSigVersion::P2SH;
} }
bool HaveKeys(const std::vector<valtype>& pubkeys, const CKeyStore& keystore) bool HaveKeys(const std::vector<valtype>& pubkeys, const CWallet& keystore)
{ {
for (const valtype& pubkey : pubkeys) { for (const valtype& pubkey : pubkeys) {
CKeyID keyID = CPubKey(pubkey).GetID(); CKeyID keyID = CPubKey(pubkey).GetID();
@ -55,7 +54,7 @@ bool HaveKeys(const std::vector<valtype>& pubkeys, const CKeyStore& keystore)
return true; return true;
} }
IsMineResult IsMineInner(const CKeyStore& keystore, const CScript& scriptPubKey, IsMineSigVersion sigversion) IsMineResult IsMineInner(const CWallet& keystore, const CScript& scriptPubKey, IsMineSigVersion sigversion)
{ {
IsMineResult ret = IsMineResult::NO; IsMineResult ret = IsMineResult::NO;
@ -172,7 +171,7 @@ IsMineResult IsMineInner(const CKeyStore& keystore, const CScript& scriptPubKey,
} // namespace } // namespace
isminetype IsMine(const CKeyStore& keystore, const CScript& scriptPubKey) isminetype IsMine(const CWallet& keystore, const CScript& scriptPubKey)
{ {
switch (IsMineInner(keystore, scriptPubKey, IsMineSigVersion::TOP)) { switch (IsMineInner(keystore, scriptPubKey, IsMineSigVersion::TOP)) {
case IsMineResult::INVALID: case IsMineResult::INVALID:
@ -186,7 +185,7 @@ isminetype IsMine(const CKeyStore& keystore, const CScript& scriptPubKey)
assert(false); assert(false);
} }
isminetype IsMine(const CKeyStore& keystore, const CTxDestination& dest) isminetype IsMine(const CWallet& keystore, const CTxDestination& dest)
{ {
CScript script = GetScriptForDestination(dest); CScript script = GetScriptForDestination(dest);
return IsMine(keystore, script); return IsMine(keystore, script);

View file

@ -3,19 +3,19 @@
// 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.
#ifndef BITCOIN_SCRIPT_ISMINE_H #ifndef BITCOIN_WALLET_ISMINE_H
#define BITCOIN_SCRIPT_ISMINE_H #define BITCOIN_WALLET_ISMINE_H
#include <script/standard.h> #include <script/standard.h>
#include <stdint.h> #include <stdint.h>
#include <bitset> #include <bitset>
class CKeyStore; class CWallet;
class CScript; class CScript;
/** IsMine() return codes */ /** IsMine() return codes */
enum isminetype enum isminetype : unsigned int
{ {
ISMINE_NO = 0, ISMINE_NO = 0,
ISMINE_WATCH_ONLY = 1 << 0, ISMINE_WATCH_ONLY = 1 << 0,
@ -28,8 +28,8 @@ enum isminetype
/** used for bitflags of isminetype */ /** used for bitflags of isminetype */
typedef uint8_t isminefilter; typedef uint8_t isminefilter;
isminetype IsMine(const CKeyStore& keystore, const CScript& scriptPubKey); isminetype IsMine(const CWallet& wallet, const CScript& scriptPubKey);
isminetype IsMine(const CKeyStore& keystore, const CTxDestination& dest); isminetype IsMine(const CWallet& wallet, const CTxDestination& dest);
/** /**
* Cachable amount subdivided into watchonly and spendable parts. * Cachable amount subdivided into watchonly and spendable parts.
@ -50,4 +50,4 @@ struct CachableAmount
} }
}; };
#endif // BITCOIN_SCRIPT_ISMINE_H #endif // BITCOIN_WALLET_ISMINE_H

View file

@ -0,0 +1,399 @@
// Copyright (c) 2017-2019 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 <key.h>
#include <script/script.h>
#include <script/script_error.h>
#include <script/standard.h>
#include <test/setup_common.h>
#include <wallet/ismine.h>
#include <wallet/wallet.h>
#include <boost/test/unit_test.hpp>
BOOST_FIXTURE_TEST_SUITE(ismine_tests, BasicTestingSetup)
BOOST_AUTO_TEST_CASE(ismine_standard)
{
CKey keys[2];
CPubKey pubkeys[2];
for (int i = 0; i < 2; i++) {
keys[i].MakeNewKey(true);
pubkeys[i] = keys[i].GetPubKey();
}
CKey uncompressedKey;
uncompressedKey.MakeNewKey(false);
CPubKey uncompressedPubkey = uncompressedKey.GetPubKey();
std::unique_ptr<interfaces::Chain> chain = interfaces::MakeChain();
CScript scriptPubKey;
isminetype result;
// P2PK compressed
{
CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
LOCK(keystore.cs_wallet);
scriptPubKey = GetScriptForRawPubKey(pubkeys[0]);
// Keystore does not have key
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
// Keystore has key
BOOST_CHECK(keystore.AddKey(keys[0]));
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
}
// P2PK uncompressed
{
CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
LOCK(keystore.cs_wallet);
scriptPubKey = GetScriptForRawPubKey(uncompressedPubkey);
// Keystore does not have key
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
// Keystore has key
BOOST_CHECK(keystore.AddKey(uncompressedKey));
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
}
// P2PKH compressed
{
CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
LOCK(keystore.cs_wallet);
scriptPubKey = GetScriptForDestination(PKHash(pubkeys[0]));
// Keystore does not have key
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
// Keystore has key
BOOST_CHECK(keystore.AddKey(keys[0]));
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
}
// P2PKH uncompressed
{
CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
LOCK(keystore.cs_wallet);
scriptPubKey = GetScriptForDestination(PKHash(uncompressedPubkey));
// Keystore does not have key
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
// Keystore has key
BOOST_CHECK(keystore.AddKey(uncompressedKey));
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
}
// P2SH
{
CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
LOCK(keystore.cs_wallet);
CScript redeemScript = GetScriptForDestination(PKHash(pubkeys[0]));
scriptPubKey = GetScriptForDestination(ScriptHash(redeemScript));
// Keystore does not have redeemScript or key
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
// Keystore has redeemScript but no key
BOOST_CHECK(keystore.AddCScript(redeemScript));
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
// Keystore has redeemScript and key
BOOST_CHECK(keystore.AddKey(keys[0]));
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
}
// (P2PKH inside) P2SH inside P2SH (invalid)
{
CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
LOCK(keystore.cs_wallet);
CScript redeemscript_inner = GetScriptForDestination(PKHash(pubkeys[0]));
CScript redeemscript = GetScriptForDestination(ScriptHash(redeemscript_inner));
scriptPubKey = GetScriptForDestination(ScriptHash(redeemscript));
BOOST_CHECK(keystore.AddCScript(redeemscript));
BOOST_CHECK(keystore.AddCScript(redeemscript_inner));
BOOST_CHECK(keystore.AddCScript(scriptPubKey));
BOOST_CHECK(keystore.AddKey(keys[0]));
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
}
// (P2PKH inside) P2SH inside P2WSH (invalid)
{
CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
LOCK(keystore.cs_wallet);
CScript redeemscript = GetScriptForDestination(PKHash(pubkeys[0]));
CScript witnessscript = GetScriptForDestination(ScriptHash(redeemscript));
scriptPubKey = GetScriptForDestination(WitnessV0ScriptHash(witnessscript));
BOOST_CHECK(keystore.AddCScript(witnessscript));
BOOST_CHECK(keystore.AddCScript(redeemscript));
BOOST_CHECK(keystore.AddCScript(scriptPubKey));
BOOST_CHECK(keystore.AddKey(keys[0]));
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
}
// P2WPKH inside P2WSH (invalid)
{
CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
LOCK(keystore.cs_wallet);
CScript witnessscript = GetScriptForDestination(WitnessV0KeyHash(PKHash(pubkeys[0])));
scriptPubKey = GetScriptForDestination(WitnessV0ScriptHash(witnessscript));
BOOST_CHECK(keystore.AddCScript(witnessscript));
BOOST_CHECK(keystore.AddCScript(scriptPubKey));
BOOST_CHECK(keystore.AddKey(keys[0]));
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
}
// (P2PKH inside) P2WSH inside P2WSH (invalid)
{
CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
LOCK(keystore.cs_wallet);
CScript witnessscript_inner = GetScriptForDestination(PKHash(pubkeys[0]));
CScript witnessscript = GetScriptForDestination(WitnessV0ScriptHash(witnessscript_inner));
scriptPubKey = GetScriptForDestination(WitnessV0ScriptHash(witnessscript));
BOOST_CHECK(keystore.AddCScript(witnessscript_inner));
BOOST_CHECK(keystore.AddCScript(witnessscript));
BOOST_CHECK(keystore.AddCScript(scriptPubKey));
BOOST_CHECK(keystore.AddKey(keys[0]));
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
}
// P2WPKH compressed
{
CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
LOCK(keystore.cs_wallet);
BOOST_CHECK(keystore.AddKey(keys[0]));
scriptPubKey = GetScriptForDestination(WitnessV0KeyHash(PKHash(pubkeys[0])));
// Keystore implicitly has key and P2SH redeemScript
BOOST_CHECK(keystore.AddCScript(scriptPubKey));
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
}
// P2WPKH uncompressed
{
CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
LOCK(keystore.cs_wallet);
BOOST_CHECK(keystore.AddKey(uncompressedKey));
scriptPubKey = GetScriptForDestination(WitnessV0KeyHash(PKHash(uncompressedPubkey)));
// Keystore has key, but no P2SH redeemScript
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
// Keystore has key and P2SH redeemScript
BOOST_CHECK(keystore.AddCScript(scriptPubKey));
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
}
// scriptPubKey multisig
{
CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
LOCK(keystore.cs_wallet);
scriptPubKey = GetScriptForMultisig(2, {uncompressedPubkey, pubkeys[1]});
// Keystore does not have any keys
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
// Keystore has 1/2 keys
BOOST_CHECK(keystore.AddKey(uncompressedKey));
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
// Keystore has 2/2 keys
BOOST_CHECK(keystore.AddKey(keys[1]));
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
// Keystore has 2/2 keys and the script
BOOST_CHECK(keystore.AddCScript(scriptPubKey));
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
}
// P2SH multisig
{
CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
LOCK(keystore.cs_wallet);
BOOST_CHECK(keystore.AddKey(uncompressedKey));
BOOST_CHECK(keystore.AddKey(keys[1]));
CScript redeemScript = GetScriptForMultisig(2, {uncompressedPubkey, pubkeys[1]});
scriptPubKey = GetScriptForDestination(ScriptHash(redeemScript));
// Keystore has no redeemScript
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
// Keystore has redeemScript
BOOST_CHECK(keystore.AddCScript(redeemScript));
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
}
// P2WSH multisig with compressed keys
{
CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
LOCK(keystore.cs_wallet);
BOOST_CHECK(keystore.AddKey(keys[0]));
BOOST_CHECK(keystore.AddKey(keys[1]));
CScript witnessScript = GetScriptForMultisig(2, {pubkeys[0], pubkeys[1]});
scriptPubKey = GetScriptForDestination(WitnessV0ScriptHash(witnessScript));
// Keystore has keys, but no witnessScript or P2SH redeemScript
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
// Keystore has keys and witnessScript, but no P2SH redeemScript
BOOST_CHECK(keystore.AddCScript(witnessScript));
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
// Keystore has keys, witnessScript, P2SH redeemScript
BOOST_CHECK(keystore.AddCScript(scriptPubKey));
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
}
// P2WSH multisig with uncompressed key
{
CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
LOCK(keystore.cs_wallet);
BOOST_CHECK(keystore.AddKey(uncompressedKey));
BOOST_CHECK(keystore.AddKey(keys[1]));
CScript witnessScript = GetScriptForMultisig(2, {uncompressedPubkey, pubkeys[1]});
scriptPubKey = GetScriptForDestination(WitnessV0ScriptHash(witnessScript));
// Keystore has keys, but no witnessScript or P2SH redeemScript
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
// Keystore has keys and witnessScript, but no P2SH redeemScript
BOOST_CHECK(keystore.AddCScript(witnessScript));
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
// Keystore has keys, witnessScript, P2SH redeemScript
BOOST_CHECK(keystore.AddCScript(scriptPubKey));
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
}
// P2WSH multisig wrapped in P2SH
{
CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
LOCK(keystore.cs_wallet);
CScript witnessScript = GetScriptForMultisig(2, {pubkeys[0], pubkeys[1]});
CScript redeemScript = GetScriptForDestination(WitnessV0ScriptHash(witnessScript));
scriptPubKey = GetScriptForDestination(ScriptHash(redeemScript));
// Keystore has no witnessScript, P2SH redeemScript, or keys
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
// Keystore has witnessScript and P2SH redeemScript, but no keys
BOOST_CHECK(keystore.AddCScript(redeemScript));
BOOST_CHECK(keystore.AddCScript(witnessScript));
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
// Keystore has keys, witnessScript, P2SH redeemScript
BOOST_CHECK(keystore.AddKey(keys[0]));
BOOST_CHECK(keystore.AddKey(keys[1]));
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
}
// OP_RETURN
{
CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
LOCK(keystore.cs_wallet);
BOOST_CHECK(keystore.AddKey(keys[0]));
scriptPubKey.clear();
scriptPubKey << OP_RETURN << ToByteVector(pubkeys[0]);
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
}
// witness unspendable
{
CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
LOCK(keystore.cs_wallet);
BOOST_CHECK(keystore.AddKey(keys[0]));
scriptPubKey.clear();
scriptPubKey << OP_0 << ToByteVector(ParseHex("aabb"));
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
}
// witness unknown
{
CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
LOCK(keystore.cs_wallet);
BOOST_CHECK(keystore.AddKey(keys[0]));
scriptPubKey.clear();
scriptPubKey << OP_16 << ToByteVector(ParseHex("aabb"));
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
}
// Nonstandard
{
CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
LOCK(keystore.cs_wallet);
BOOST_CHECK(keystore.AddKey(keys[0]));
scriptPubKey.clear();
scriptPubKey << OP_9 << OP_ADD << OP_11 << OP_EQUAL;
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
}
}
BOOST_AUTO_TEST_SUITE_END()

View file

@ -11,7 +11,6 @@
#include <interfaces/handler.h> #include <interfaces/handler.h>
#include <outputtype.h> #include <outputtype.h>
#include <policy/feerate.h> #include <policy/feerate.h>
#include <script/ismine.h>
#include <script/sign.h> #include <script/sign.h>
#include <streams.h> #include <streams.h>
#include <tinyformat.h> #include <tinyformat.h>
@ -21,6 +20,7 @@
#include <validationinterface.h> #include <validationinterface.h>
#include <wallet/coinselection.h> #include <wallet/coinselection.h>
#include <wallet/crypter.h> #include <wallet/crypter.h>
#include <wallet/ismine.h>
#include <wallet/walletdb.h> #include <wallet/walletdb.h>
#include <wallet/walletutil.h> #include <wallet/walletutil.h>

View file

@ -5,7 +5,7 @@
#ifndef BITCOIN_WALLET_WALLETTOOL_H #ifndef BITCOIN_WALLET_WALLETTOOL_H
#define BITCOIN_WALLET_WALLETTOOL_H #define BITCOIN_WALLET_WALLETTOOL_H
#include <script/ismine.h> #include <wallet/ismine.h>
#include <wallet/wallet.h> #include <wallet/wallet.h>
namespace WalletTool { namespace WalletTool {

View file

@ -30,6 +30,7 @@ EXPECTED_CIRCULAR_DEPENDENCIES=(
"policy/fees -> txmempool -> validation -> policy/fees" "policy/fees -> txmempool -> validation -> policy/fees"
"qt/guiutil -> qt/walletmodel -> qt/optionsmodel -> qt/guiutil" "qt/guiutil -> qt/walletmodel -> qt/optionsmodel -> qt/guiutil"
"txmempool -> validation -> validationinterface -> txmempool" "txmempool -> validation -> validationinterface -> txmempool"
"wallet/ismine -> wallet/wallet -> wallet/ismine"
) )
EXIT_CODE=0 EXIT_CODE=0