diff options
-rw-r--r-- | .cirrus.yml | 11 | ||||
-rw-r--r-- | Makefile.am | 2 | ||||
-rw-r--r-- | build_msvc/common.init.vcxproj | 2 | ||||
-rw-r--r-- | src/Makefile.am | 4 | ||||
-rw-r--r-- | src/Makefile.test.include | 3 | ||||
-rw-r--r-- | src/interfaces/wallet.cpp | 2 | ||||
-rw-r--r-- | src/interfaces/wallet.h | 4 | ||||
-rw-r--r-- | src/qt/transactiondesc.cpp | 1 | ||||
-rw-r--r-- | src/qt/transactionrecord.cpp | 1 | ||||
-rw-r--r-- | src/rpc/misc.cpp | 4 | ||||
-rw-r--r-- | src/rpc/util.cpp | 24 | ||||
-rw-r--r-- | src/rpc/util.h | 3 | ||||
-rw-r--r-- | src/test/script_p2sh_tests.cpp | 3 | ||||
-rw-r--r-- | src/test/script_standard_tests.cpp | 361 | ||||
-rw-r--r-- | src/wallet/ismine.cpp (renamed from src/script/ismine.cpp) | 13 | ||||
-rw-r--r-- | src/wallet/ismine.h (renamed from src/script/ismine.h) | 14 | ||||
-rw-r--r-- | src/wallet/rpcwallet.cpp | 4 | ||||
-rw-r--r-- | src/wallet/test/ismine_tests.cpp | 399 | ||||
-rw-r--r-- | src/wallet/wallet.h | 2 | ||||
-rw-r--r-- | src/wallet/wallettool.h | 2 | ||||
-rwxr-xr-x | test/functional/feature_config_args.py | 10 | ||||
-rwxr-xr-x | test/functional/rpc_createmultisig.py | 30 | ||||
-rwxr-xr-x | test/lint/lint-circular-dependencies.sh | 1 |
23 files changed, 498 insertions, 402 deletions
diff --git a/.cirrus.yml b/.cirrus.yml index 9104a0a3d1..ce17a223b1 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -2,15 +2,18 @@ task: name: "FreeBsd 12.0 amd64 [GOAL: install] [no depends, only system libs]" freebsd_instance: image: freebsd-12-0-release-amd64 - ccache_cache: - folder: "/tmp/ccache_dir" + cpu: 8 + memory: 8G + timeout_in: 60m env: - MAKEJOBS: "-j3" + MAKEJOBS: "-j9" CONFIGURE_OPTS: "--disable-dependency-tracking" GOAL: "install" CCACHE_SIZE: "200M" CCACHE_COMPRESS: 1 CCACHE_DIR: "/tmp/ccache_dir" + ccache_cache: + folder: "/tmp/ccache_dir" install_script: - pkg install -y autoconf automake boost-libs git gmake libevent libtool openssl pkgconf python3 ccache - ./contrib/install_db4.sh $(pwd) @@ -23,4 +26,4 @@ task: check_script: - gmake check ${MAKEJOBS} VERBOSE=1 functional_test_script: - - ./test/functional/test_runner.py --ci --combinedlogslen=1000 --quiet --failfast + - ./test/functional/test_runner.py --jobs 9 --ci --extended --exclude feature_dbcrash --combinedlogslen=1000 --quiet --failfast diff --git a/Makefile.am b/Makefile.am index ec0743c3fa..712f2a454d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -198,7 +198,7 @@ test_bitcoin_filtered.info: test_bitcoin.info $(LCOV) -a $@ $(LCOV_OPTS) -o $@ functional_test.info: test_bitcoin_filtered.info - -@TIMEOUT=15 test/functional/test_runner.py $(EXTENDED_FUNCTIONAL_TESTS) + @TIMEOUT=15 test/functional/test_runner.py $(EXTENDED_FUNCTIONAL_TESTS) $(LCOV) -c $(LCOV_OPTS) -d $(abs_builddir)/src --t functional-tests -o $@ $(LCOV) -z $(LCOV_OPTS) -d $(abs_builddir)/src diff --git a/build_msvc/common.init.vcxproj b/build_msvc/common.init.vcxproj index 2b2afcdf13..8b6217e2b0 100644 --- a/build_msvc/common.init.vcxproj +++ b/build_msvc/common.init.vcxproj @@ -73,6 +73,7 @@ <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> <SDLCheck>true</SDLCheck> <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> + <AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions> </ClCompile> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> @@ -94,6 +95,7 @@ <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> <SDLCheck>true</SDLCheck> <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> + <AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions> </ClCompile> </ItemDefinitionGroup> diff --git a/src/Makefile.am b/src/Makefile.am index ec3d81b76f..39e8d3d689 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -181,7 +181,6 @@ BITCOIN_CORE_H = \ rpc/util.h \ scheduler.h \ script/descriptor.h \ - script/ismine.h \ script/sigcache.h \ script/sign.h \ script/standard.h \ @@ -223,6 +222,7 @@ BITCOIN_CORE_H = \ wallet/db.h \ wallet/feebumper.h \ wallet/fees.h \ + wallet/ismine.h \ wallet/load.h \ wallet/psbtwallet.h \ wallet/rpcwallet.h \ @@ -328,6 +328,7 @@ libbitcoin_wallet_a_SOURCES = \ wallet/db.cpp \ wallet/feebumper.cpp \ wallet/fees.cpp \ + wallet/ismine.cpp \ wallet/load.cpp \ wallet/psbtwallet.cpp \ wallet/rpcdump.cpp \ @@ -458,7 +459,6 @@ libbitcoin_common_a_SOURCES = \ rpc/util.cpp \ scheduler.cpp \ script/descriptor.cpp \ - script/ismine.cpp \ script/sign.cpp \ script/standard.cpp \ versionbitsinfo.cpp \ diff --git a/src/Makefile.test.include b/src/Makefile.test.include index c9c029818e..d3fe138133 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -167,7 +167,8 @@ BITCOIN_TESTS += \ wallet/test/wallet_tests.cpp \ wallet/test/wallet_crypto_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 += \ wallet/test/wallet_test_fixture.cpp \ diff --git a/src/interfaces/wallet.cpp b/src/interfaces/wallet.cpp index 240670cbe7..34c982e1e6 100644 --- a/src/interfaces/wallet.cpp +++ b/src/interfaces/wallet.cpp @@ -11,7 +11,6 @@ #include <policy/feerate.h> #include <policy/fees.h> #include <primitives/transaction.h> -#include <script/ismine.h> #include <script/standard.h> #include <support/allocators/secure.h> #include <sync.h> @@ -20,6 +19,7 @@ #include <util/system.h> #include <wallet/feebumper.h> #include <wallet/fees.h> +#include <wallet/ismine.h> #include <wallet/rpcwallet.h> #include <wallet/load.h> #include <wallet/wallet.h> diff --git a/src/interfaces/wallet.h b/src/interfaces/wallet.h index 7096f54047..9c9b29a813 100644 --- a/src/interfaces/wallet.h +++ b/src/interfaces/wallet.h @@ -7,7 +7,6 @@ #include <amount.h> // For CAmount #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 <support/allocators/secure.h> // For SecureString #include <ui_interface.h> // For ChangeType @@ -25,7 +24,10 @@ class CCoinControl; class CFeeRate; class CKey; class CWallet; +enum isminetype : unsigned int; enum class FeeReason; +typedef uint8_t isminefilter; + enum class OutputType; struct CRecipient; diff --git a/src/qt/transactiondesc.cpp b/src/qt/transactiondesc.cpp index aabe9dfb58..ebe7925368 100644 --- a/src/qt/transactiondesc.cpp +++ b/src/qt/transactiondesc.cpp @@ -21,6 +21,7 @@ #include <timedata.h> #include <util/system.h> #include <policy/policy.h> +#include <wallet/ismine.h> #include <stdint.h> #include <string> diff --git a/src/qt/transactionrecord.cpp b/src/qt/transactionrecord.cpp index 7d6d84aa7b..9de90759fa 100644 --- a/src/qt/transactionrecord.cpp +++ b/src/qt/transactionrecord.cpp @@ -7,6 +7,7 @@ #include <chain.h> #include <interfaces/wallet.h> #include <key_io.h> +#include <wallet/ismine.h> #include <stdint.h> diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp index 2b29fd543b..7a1bdec7b9 100644 --- a/src/rpc/misc.cpp +++ b/src/rpc/misc.cpp @@ -122,9 +122,9 @@ static UniValue createmultisig(const JSONRPCRequest& request) } // Construct using pay-to-script-hash: - const CScript inner = CreateMultisigRedeemscript(required, pubkeys); CBasicKeyStore keystore; - const CTxDestination dest = AddAndGetDestinationForScript(keystore, inner, output_type); + CScript inner; + const CTxDestination dest = AddAndGetMultisigDestination(required, pubkeys, output_type, keystore, inner); UniValue result(UniValue::VOBJ); result.pushKV("address", EncodeDestination(dest)); diff --git a/src/rpc/util.cpp b/src/rpc/util.cpp index 9cdb22001f..4642cf16b1 100644 --- a/src/rpc/util.cpp +++ b/src/rpc/util.cpp @@ -4,6 +4,7 @@ #include <key_io.h> #include <keystore.h> +#include <outputtype.h> #include <rpc/util.h> #include <tinyformat.h> #include <util/strencodings.h> @@ -150,8 +151,8 @@ CPubKey AddrToPubKey(CKeyStore* const keystore, const std::string& addr_in) return vchPubKey; } -// Creates a multisig redeemscript from a given list of public keys and number required. -CScript CreateMultisigRedeemscript(const int required, const std::vector<CPubKey>& pubkeys) +// Creates a multisig address from a given list of public keys, number of signatures required, and the address type +CTxDestination AddAndGetMultisigDestination(const int required, const std::vector<CPubKey>& pubkeys, OutputType type, CKeyStore& keystore, CScript& script_out) { // Gather public keys if (required < 1) { @@ -164,13 +165,24 @@ CScript CreateMultisigRedeemscript(const int required, const std::vector<CPubKey throw JSONRPCError(RPC_INVALID_PARAMETER, "Number of keys involved in the multisignature address creation > 16\nReduce the number"); } - CScript result = GetScriptForMultisig(required, pubkeys); + script_out = GetScriptForMultisig(required, pubkeys); - if (result.size() > MAX_SCRIPT_ELEMENT_SIZE) { - throw JSONRPCError(RPC_INVALID_PARAMETER, (strprintf("redeemScript exceeds size limit: %d > %d", result.size(), MAX_SCRIPT_ELEMENT_SIZE))); + if (script_out.size() > MAX_SCRIPT_ELEMENT_SIZE) { + throw JSONRPCError(RPC_INVALID_PARAMETER, (strprintf("redeemScript exceeds size limit: %d > %d", script_out.size(), MAX_SCRIPT_ELEMENT_SIZE))); } - return result; + // Check if any keys are uncompressed. If so, the type is legacy + for (const CPubKey& pk : pubkeys) { + if (!pk.IsCompressed()) { + type = OutputType::LEGACY; + break; + } + } + + // Make the address + CTxDestination dest = AddAndGetDestinationForScript(keystore, script_out, type); + + return dest; } class DescribeAddressVisitor : public boost::static_visitor<UniValue> diff --git a/src/rpc/util.h b/src/rpc/util.h index e4fa8fc3d7..0eb2fef5c3 100644 --- a/src/rpc/util.h +++ b/src/rpc/util.h @@ -6,6 +6,7 @@ #define BITCOIN_RPC_UTIL_H #include <node/transaction.h> +#include <outputtype.h> #include <pubkey.h> #include <rpc/protocol.h> #include <script/standard.h> @@ -70,7 +71,7 @@ extern std::string HelpExampleRpc(const std::string& methodname, const std::stri CPubKey HexToPubKey(const std::string& hex_in); CPubKey AddrToPubKey(CKeyStore* const keystore, const std::string& addr_in); -CScript CreateMultisigRedeemscript(const int required, const std::vector<CPubKey>& pubkeys); +CTxDestination AddAndGetMultisigDestination(const int required, const std::vector<CPubKey>& pubkeys, OutputType type, CKeyStore& keystore, CScript& script_out); UniValue DescribeAddress(const CTxDestination& dest); diff --git a/src/test/script_p2sh_tests.cpp b/src/test/script_p2sh_tests.cpp index aa9c98c173..735b67c06e 100644 --- a/src/test/script_p2sh_tests.cpp +++ b/src/test/script_p2sh_tests.cpp @@ -11,7 +11,6 @@ #include <script/script_error.h> #include <policy/settings.h> #include <script/sign.h> -#include <script/ismine.h> #include <test/setup_common.h> #include <vector> @@ -98,7 +97,6 @@ BOOST_AUTO_TEST_CASE(sign) txTo[i].vin[0].prevout.n = i; txTo[i].vin[0].prevout.hash = txFrom.GetHash(); 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++) { @@ -195,7 +193,6 @@ BOOST_AUTO_TEST_CASE(set) txTo[i].vin[0].prevout.hash = txFrom.GetHash(); txTo[i].vout[0].nValue = 1*CENT; 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++) { diff --git a/src/test/script_standard_tests.cpp b/src/test/script_standard_tests.cpp index 9f50083335..195283f89f 100644 --- a/src/test/script_standard_tests.cpp +++ b/src/test/script_standard_tests.cpp @@ -4,7 +4,6 @@ #include <key.h> #include <keystore.h> -#include <script/ismine.h> #include <script/script.h> #include <script/script_error.h> #include <script/standard.h> @@ -372,364 +371,4 @@ BOOST_AUTO_TEST_CASE(script_standard_GetScriptFor_) 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() diff --git a/src/script/ismine.cpp b/src/wallet/ismine.cpp index 75fc2e84f1..6138d4ae44 100644 --- a/src/script/ismine.cpp +++ b/src/wallet/ismine.cpp @@ -3,13 +3,12 @@ // 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 <wallet/ismine.h> #include <key.h> -#include <keystore.h> #include <script/script.h> #include <script/sign.h> - +#include <wallet/wallet.h> typedef std::vector<unsigned char> valtype; @@ -46,7 +45,7 @@ bool PermitsUncompressed(IsMineSigVersion sigversion) 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) { CKeyID keyID = CPubKey(pubkey).GetID(); @@ -55,7 +54,7 @@ bool HaveKeys(const std::vector<valtype>& pubkeys, const CKeyStore& keystore) 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; @@ -172,7 +171,7 @@ IsMineResult IsMineInner(const CKeyStore& keystore, const CScript& scriptPubKey, } // namespace -isminetype IsMine(const CKeyStore& keystore, const CScript& scriptPubKey) +isminetype IsMine(const CWallet& keystore, const CScript& scriptPubKey) { switch (IsMineInner(keystore, scriptPubKey, IsMineSigVersion::TOP)) { case IsMineResult::INVALID: @@ -186,7 +185,7 @@ isminetype IsMine(const CKeyStore& keystore, const CScript& scriptPubKey) assert(false); } -isminetype IsMine(const CKeyStore& keystore, const CTxDestination& dest) +isminetype IsMine(const CWallet& keystore, const CTxDestination& dest) { CScript script = GetScriptForDestination(dest); return IsMine(keystore, script); diff --git a/src/script/ismine.h b/src/wallet/ismine.h index da3da7e324..41555fcb93 100644 --- a/src/script/ismine.h +++ b/src/wallet/ismine.h @@ -3,19 +3,19 @@ // 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 +#ifndef BITCOIN_WALLET_ISMINE_H +#define BITCOIN_WALLET_ISMINE_H #include <script/standard.h> #include <stdint.h> #include <bitset> -class CKeyStore; +class CWallet; class CScript; /** IsMine() return codes */ -enum isminetype +enum isminetype : unsigned int { ISMINE_NO = 0, ISMINE_WATCH_ONLY = 1 << 0, @@ -28,8 +28,8 @@ enum isminetype /** 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); +isminetype IsMine(const CWallet& wallet, const CScript& scriptPubKey); +isminetype IsMine(const CWallet& wallet, const CTxDestination& dest); /** * Cachable amount subdivided into watchonly and spendable parts. @@ -50,4 +50,4 @@ struct CachableAmount } }; -#endif // BITCOIN_SCRIPT_ISMINE_H +#endif // BITCOIN_WALLET_ISMINE_H diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index cfa36ad40c..3232c65bca 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -1036,8 +1036,8 @@ static UniValue addmultisigaddress(const JSONRPCRequest& request) } // Construct using pay-to-script-hash: - CScript inner = CreateMultisigRedeemscript(required, pubkeys); - CTxDestination dest = AddAndGetDestinationForScript(*pwallet, inner, output_type); + CScript inner; + CTxDestination dest = AddAndGetMultisigDestination(required, pubkeys, output_type, *pwallet, inner); pwallet->SetAddressBook(dest, label, "send"); UniValue result(UniValue::VOBJ); diff --git a/src/wallet/test/ismine_tests.cpp b/src/wallet/test/ismine_tests.cpp new file mode 100644 index 0000000000..0cae055676 --- /dev/null +++ b/src/wallet/test/ismine_tests.cpp @@ -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() diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index c2d1102c33..7b5465c219 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -11,7 +11,6 @@ #include <interfaces/handler.h> #include <outputtype.h> #include <policy/feerate.h> -#include <script/ismine.h> #include <script/sign.h> #include <streams.h> #include <tinyformat.h> @@ -21,6 +20,7 @@ #include <validationinterface.h> #include <wallet/coinselection.h> #include <wallet/crypter.h> +#include <wallet/ismine.h> #include <wallet/walletdb.h> #include <wallet/walletutil.h> diff --git a/src/wallet/wallettool.h b/src/wallet/wallettool.h index da848a747b..7ee2505631 100644 --- a/src/wallet/wallettool.h +++ b/src/wallet/wallettool.h @@ -5,7 +5,7 @@ #ifndef BITCOIN_WALLET_WALLETTOOL_H #define BITCOIN_WALLET_WALLETTOOL_H -#include <script/ismine.h> +#include <wallet/ismine.h> #include <wallet/wallet.h> namespace WalletTool { diff --git a/test/functional/feature_config_args.py b/test/functional/feature_config_args.py index 074a832594..f0d6bc21e6 100755 --- a/test/functional/feature_config_args.py +++ b/test/functional/feature_config_args.py @@ -21,6 +21,16 @@ class ConfArgsTest(BitcoinTestFramework): with open(os.path.join(self.nodes[0].datadir, 'bitcoin.conf'), 'a', encoding='utf-8') as conf: conf.write('includeconf={}\n'.format(inc_conf_file_path)) + self.nodes[0].assert_start_raises_init_error( + expected_msg='Error parsing command line arguments: Invalid parameter -dash_cli', + extra_args=['-dash_cli=1'], + ) + with open(inc_conf_file_path, 'w', encoding='utf-8') as conf: + conf.write('dash_conf=1\n') + with self.nodes[0].assert_debug_log(expected_msgs=['Ignoring unknown configuration value dash_conf']): + self.start_node(0) + self.stop_node(0) + with open(inc_conf_file_path, 'w', encoding='utf-8') as conf: conf.write('-dash=1\n') self.nodes[0].assert_start_raises_init_error(expected_msg='Error reading configuration file: parse error on line 1: -dash=1, options in configuration file must be specified without leading -') diff --git a/test/functional/rpc_createmultisig.py b/test/functional/rpc_createmultisig.py index 7abcd71bb8..58010f7c2e 100755 --- a/test/functional/rpc_createmultisig.py +++ b/test/functional/rpc_createmultisig.py @@ -7,9 +7,13 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( assert_raises_rpc_error, + assert_equal, ) -import decimal +from test_framework.key import ECPubKey +import binascii +import decimal +import itertools class RpcCreateMultiSigTest(BitcoinTestFramework): def set_test_params(self): @@ -44,6 +48,30 @@ class RpcCreateMultiSigTest(BitcoinTestFramework): self.checkbalances() + # Test mixed compressed and uncompressed pubkeys + self.log.info('Mixed compressed and uncompressed multisigs are not allowed') + pk0 = node0.getaddressinfo(node0.getnewaddress())['pubkey'] + pk1 = node1.getaddressinfo(node1.getnewaddress())['pubkey'] + pk2 = node2.getaddressinfo(node2.getnewaddress())['pubkey'] + + # decompress pk2 + pk_obj = ECPubKey() + pk_obj.set(binascii.unhexlify(pk2)) + pk_obj.compressed = False + pk2 = binascii.hexlify(pk_obj.get_bytes()).decode() + + # Check all permutations of keys because order matters apparently + for keys in itertools.permutations([pk0, pk1, pk2]): + # Results should be the same as this legacy one + legacy_addr = node0.createmultisig(2, keys, 'legacy')['address'] + assert_equal(legacy_addr, node0.addmultisigaddress(2, keys, '', 'legacy')['address']) + + # Generate addresses with the segwit types. These should all make legacy addresses + assert_equal(legacy_addr, node0.createmultisig(2, keys, 'bech32')['address']) + assert_equal(legacy_addr, node0.createmultisig(2, keys, 'p2sh-segwit')['address']) + assert_equal(legacy_addr, node0.addmultisigaddress(2, keys, '', 'bech32')['address']) + assert_equal(legacy_addr, node0.addmultisigaddress(2, keys, '', 'p2sh-segwit')['address']) + def check_addmultisigaddress_errors(self): self.log.info('Check that addmultisigaddress fails when the private keys are missing') addresses = [self.nodes[1].getnewaddress(address_type='legacy') for _ in range(2)] diff --git a/test/lint/lint-circular-dependencies.sh b/test/lint/lint-circular-dependencies.sh index 2701015c79..70cc16337e 100755 --- a/test/lint/lint-circular-dependencies.sh +++ b/test/lint/lint-circular-dependencies.sh @@ -30,6 +30,7 @@ EXPECTED_CIRCULAR_DEPENDENCIES=( "policy/fees -> txmempool -> validation -> policy/fees" "qt/guiutil -> qt/walletmodel -> qt/optionsmodel -> qt/guiutil" "txmempool -> validation -> validationinterface -> txmempool" + "wallet/ismine -> wallet/wallet -> wallet/ismine" ) EXIT_CODE=0 |