diff --git a/src/Makefile.test.include b/src/Makefile.test.include index bbc2f7888..485fe1c73 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -1,227 +1,230 @@ # Copyright (c) 2013-2016 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. bin_PROGRAMS += test/test_bitcoin noinst_PROGRAMS += test/test_bitcoin_fuzzy TEST_SRCDIR = test TEST_BINARY=test/test_bitcoin$(EXEEXT) JSON_TEST_FILES = \ test/data/base58_encode_decode.json \ test/data/blockfilters.json \ test/data/key_io_valid.json \ test/data/key_io_invalid.json \ test/data/script_tests.json \ test/data/sighash.json \ test/data/tx_invalid.json \ test/data/tx_valid.json RAW_TEST_FILES = GENERATED_TEST_FILES = $(JSON_TEST_FILES:.json=.json.h) $(RAW_TEST_FILES:.raw=.raw.h) BITCOIN_TEST_SUITE = \ test/jsonutil.cpp \ test/scriptflags.cpp \ test/sigutil.cpp \ test/test_bitcoin_main.cpp \ test/test_bitcoin.h \ test/test_bitcoin.cpp # test_bitcoin binary # BITCOIN_TESTS =\ test/scriptnum10.h \ test/activation_tests.cpp \ test/addrman_tests.cpp \ test/allocator_tests.cpp \ test/amount_tests.cpp \ test/arith_uint256_tests.cpp \ test/avalanche_tests.cpp \ test/base32_tests.cpp \ test/base58_tests.cpp \ test/base64_tests.cpp \ test/bip32_tests.cpp \ test/bitmanip_tests.cpp \ test/blockchain_tests.cpp \ test/blockcheck_tests.cpp \ test/blockencodings_tests.cpp \ test/blockfilter_tests.cpp \ test/blockindex_tests.cpp \ test/blockstatus_tests.cpp \ test/bloom_tests.cpp \ test/bswap_tests.cpp \ test/cashaddr_tests.cpp \ test/cashaddrenc_tests.cpp \ test/checkdatasig_tests.cpp \ test/checkpoints_tests.cpp \ test/checkqueue_tests.cpp \ test/coins_tests.cpp \ test/compress_tests.cpp \ test/config_tests.cpp \ test/core_io_tests.cpp \ test/crypto_tests.cpp \ test/cuckoocache_tests.cpp \ test/dbwrapper_tests.cpp \ test/denialofservice_tests.cpp \ test/descriptor_tests.cpp \ test/dstencode_tests.cpp \ test/excessiveblock_tests.cpp \ test/feerate_tests.cpp \ test/finalization_tests.cpp \ test/flatfile_tests.cpp \ test/getarg_tests.cpp \ test/hash_tests.cpp \ test/inv_tests.cpp \ test/jsonutil.h \ test/key_io_tests.cpp \ test/key_tests.cpp \ test/lcg_tests.cpp \ test/lcg.h \ test/limitedmap_tests.cpp \ test/mempool_tests.cpp \ test/merkle_tests.cpp \ test/merkleblock_tests.cpp \ test/miner_tests.cpp \ test/monolith_opcodes_tests.cpp \ test/multisig_tests.cpp \ test/net_tests.cpp \ test/netbase_tests.cpp \ test/pmt_tests.cpp \ test/policyestimator_tests.cpp \ test/pow_tests.cpp \ test/prevector_tests.cpp \ test/radix_tests.cpp \ test/raii_event_tests.cpp \ test/random_tests.cpp \ test/rcu_tests.cpp \ test/reverselock_tests.cpp \ test/rpc_tests.cpp \ test/rpc_server_tests.cpp \ test/rwcollection_tests.cpp \ test/sanity_tests.cpp \ test/scheduler_tests.cpp \ test/schnorr_tests.cpp \ test/script_commitment_tests.cpp \ test/script_bitfield_tests.cpp \ test/script_p2sh_tests.cpp \ test/script_standard_tests.cpp \ test/script_tests.cpp \ test/scriptflags.h \ test/scriptnum_tests.cpp \ test/serialize_tests.cpp \ test/sigcache_tests.cpp \ test/sigencoding_tests.cpp \ test/sighash_tests.cpp \ test/sighashtype_tests.cpp \ test/sigcheckcount_tests.cpp \ test/sigopcount_tests.cpp \ test/sigutil.h \ test/skiplist_tests.cpp \ test/streams_tests.cpp \ test/sync_tests.cpp \ test/timedata_tests.cpp \ test/torcontrol_tests.cpp \ test/transaction_tests.cpp \ test/txindex_tests.cpp \ test/txvalidation_tests.cpp \ test/txvalidationcache_tests.cpp \ test/uint256_tests.cpp \ test/undo_tests.cpp \ test/util_tests.cpp \ test/validation_block_tests.cpp \ test/validation_tests.cpp \ test/work_comparator_tests.cpp \ rpc/test/server_tests.cpp if ENABLE_WALLET BITCOIN_TESTS += \ wallet/test/accounting_tests.cpp \ wallet/test/db_tests.cpp \ wallet/test/psbt_wallet_tests.cpp \ wallet/test/wallet_tests.cpp \ wallet/test/walletdb_tests.cpp \ wallet/test/wallet_crypto_tests.cpp \ - wallet/test/coinselector_tests.cpp + wallet/test/coinselector_tests.cpp \ + wallet/test/init_tests.cpp BITCOIN_TEST_SUITE += \ wallet/test/wallet_test_fixture.cpp \ - wallet/test/wallet_test_fixture.h + wallet/test/wallet_test_fixture.h \ + wallet/test/init_test_fixture.cpp \ + wallet/test/init_test_fixture.h endif test_test_bitcoin_SOURCES = $(BITCOIN_TEST_SUITE) $(BITCOIN_TESTS) $(JSON_TEST_FILES) $(RAW_TEST_FILES) test_test_bitcoin_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(TESTDEFS) $(EVENT_CFLAGS) test_test_bitcoin_LDADD = if ENABLE_WALLET test_test_bitcoin_LDADD += $(LIBBITCOIN_WALLET) endif test_test_bitcoin_LDADD += $(LIBBITCOIN_SERVER) $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CONSENSUS) $(LIBBITCOIN_CRYPTO) $(LIBUNIVALUE) \ $(LIBLEVELDB) $(LIBLEVELDB_SSE42) $(LIBMEMENV) $(BOOST_LIBS) $(BOOST_UNIT_TEST_FRAMEWORK_LIB) $(LIBSECP256K1) $(EVENT_LIBS) $(EVENT_PTHREADS_LIBS) test_test_bitcoin_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) test_test_bitcoin_LDADD += $(LIBBITCOIN_CONSENSUS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) test_test_bitcoin_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) -static if ENABLE_ZMQ test_test_bitcoin_LDADD += $(LIBBITCOIN_ZMQ) $(ZMQ_LIBS) endif # # test_bitcoin_fuzzy binary # test_test_bitcoin_fuzzy_SOURCES = test/test_bitcoin_fuzzy.cpp test_test_bitcoin_fuzzy_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) test_test_bitcoin_fuzzy_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) test_test_bitcoin_fuzzy_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) test_test_bitcoin_fuzzy_LDADD = \ $(LIBUNIVALUE) \ $(LIBBITCOIN_SERVER) \ $(LIBBITCOIN_COMMON) \ $(LIBBITCOIN_UTIL) \ $(LIBBITCOIN_CONSENSUS) \ $(LIBBITCOIN_CRYPTO) \ $(LIBSECP256K1) test_test_bitcoin_fuzzy_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS) # nodist_test_test_bitcoin_SOURCES = $(GENERATED_TEST_FILES) $(BITCOIN_TESTS): $(GENERATED_TEST_FILES) CLEAN_BITCOIN_TEST = test/*.gcda test/*.gcno $(GENERATED_TEST_FILES) CLEANFILES += $(CLEAN_BITCOIN_TEST) bitcoin_test: $(TEST_BINARY) bitcoin_test_check: $(TEST_BINARY) FORCE $(MAKE) check-TESTS TESTS=$^ bitcoin_test_clean : FORCE rm -f $(CLEAN_BITCOIN_TEST) $(test_test_bitcoin_OBJECTS) $(TEST_BINARY) check-local: $(BITCOIN_TESTS:.cpp=.cpp.test) @echo "Running test/util/bitcoin-util-test.py..." $(top_builddir)/test/util/bitcoin-util-test.py @echo "Running test/util/rpcauth-test.py..." $(top_builddir)/test/util/rpcauth-test.py $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C secp256k1 check if EMBEDDED_UNIVALUE $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C univalue check endif %.cpp.test: %.cpp @echo Running tests: `cat $< | grep "BOOST_FIXTURE_TEST_SUITE(\|BOOST_AUTO_TEST_SUITE(" | cut -d '(' -f 2 | cut -d ',' -f 1 | cut -d ')' -f 1` from $< $(AM_V_at)$(TEST_BINARY) -l test_suite -t "`cat $< | grep "BOOST_FIXTURE_TEST_SUITE(\|BOOST_AUTO_TEST_SUITE(" | cut -d '(' -f 2 | cut -d ',' -f 1 | cut -d ')' -f 1`" > $@.log 2>&1 || (cat $@.log && false) %.json.h: %.json @$(MKDIR_P) $(@D) @{ \ echo "namespace json_tests{" && \ echo "static unsigned const char $(*F)[] = {" && \ $(HEXDUMP) -v -e '8/1 "0x%02x, "' -e '"\n"' $< | $(SED) -e 's/0x ,//g' && \ echo "};};"; \ } > "$@.new" && mv -f "$@.new" "$@" @echo "Generated $@" diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt index eaddf723e..56161aca8 100644 --- a/src/test/CMakeLists.txt +++ b/src/test/CMakeLists.txt @@ -1,189 +1,191 @@ # Copyright (c) 2018 The Bitcoin developers project(bitcoin-test) # Process json files. file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/data") function(gen_json_header NAME) set(HEADERS "") foreach(f ${ARGN}) set(h "${CMAKE_CURRENT_BINARY_DIR}/${f}.h") # Get the proper name for the test variable. get_filename_component(TEST_NAME ${f} NAME_WE) add_custom_command(OUTPUT ${h} COMMAND "${PYTHON_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/data/generate_header.py" "${TEST_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/${f}" > ${h} MAIN_DEPENDENCY ${f} DEPENDS "data/generate_header.py" VERBATIM ) list(APPEND HEADERS ${h}) endforeach(f) set(${NAME} "${HEADERS}" PARENT_SCOPE) endfunction() gen_json_header(JSON_HEADERS data/base58_encode_decode.json data/blockfilters.json data/key_io_valid.json data/key_io_invalid.json data/script_tests.json data/sighash.json data/tx_invalid.json data/tx_valid.json ) include(TestSuite) create_test_suite(bitcoin) add_dependencies(check check-bitcoin) if(BUILD_BITCOIN_WALLET) set(BITCOIN_WALLET_TEST_FIXTURE + ../wallet/test/init_test_fixture.cpp ../wallet/test/wallet_test_fixture.cpp ) set(BITCOIN_WALLET_TESTS ../wallet/test/accounting_tests.cpp ../wallet/test/db_tests.cpp ../wallet/test/coinselector_tests.cpp + ../wallet/test/init_tests.cpp ../wallet/test/psbt_wallet_tests.cpp ../wallet/test/wallet_tests.cpp ../wallet/test/walletdb_tests.cpp ../wallet/test/wallet_crypto_tests.cpp ) endif() add_boost_unit_tests_to_suite(bitcoin test_bitcoin jsonutil.cpp scriptflags.cpp sigutil.cpp test_bitcoin.cpp test_bitcoin_main.cpp # Tests generated from JSON ${JSON_HEADERS} # Wallet test fixture ${BITCOIN_WALLET_TEST_FIXTURE} TESTS activation_tests.cpp addrman_tests.cpp allocator_tests.cpp amount_tests.cpp arith_uint256_tests.cpp avalanche_tests.cpp base32_tests.cpp base58_tests.cpp base64_tests.cpp bip32_tests.cpp bitmanip_tests.cpp blockchain_tests.cpp blockcheck_tests.cpp blockencodings_tests.cpp blockfilter_tests.cpp blockindex_tests.cpp blockstatus_tests.cpp bloom_tests.cpp bswap_tests.cpp cashaddr_tests.cpp cashaddrenc_tests.cpp checkdatasig_tests.cpp checkpoints_tests.cpp checkqueue_tests.cpp coins_tests.cpp compress_tests.cpp config_tests.cpp core_io_tests.cpp crypto_tests.cpp cuckoocache_tests.cpp dbwrapper_tests.cpp denialofservice_tests.cpp descriptor_tests.cpp dstencode_tests.cpp excessiveblock_tests.cpp feerate_tests.cpp finalization_tests.cpp flatfile_tests.cpp getarg_tests.cpp hash_tests.cpp inv_tests.cpp key_io_tests.cpp key_tests.cpp lcg_tests.cpp limitedmap_tests.cpp mempool_tests.cpp merkle_tests.cpp merkleblock_tests.cpp miner_tests.cpp monolith_opcodes_tests.cpp multisig_tests.cpp net_tests.cpp netbase_tests.cpp pmt_tests.cpp policyestimator_tests.cpp pow_tests.cpp prevector_tests.cpp radix_tests.cpp raii_event_tests.cpp random_tests.cpp rcu_tests.cpp reverselock_tests.cpp rpc_tests.cpp rpc_server_tests.cpp rwcollection_tests.cpp sanity_tests.cpp scheduler_tests.cpp schnorr_tests.cpp script_bitfield_tests.cpp script_commitment_tests.cpp script_p2sh_tests.cpp script_standard_tests.cpp script_tests.cpp scriptnum_tests.cpp serialize_tests.cpp sigcache_tests.cpp sigencoding_tests.cpp sighash_tests.cpp sighashtype_tests.cpp sigcheckcount_tests.cpp sigopcount_tests.cpp skiplist_tests.cpp streams_tests.cpp sync_tests.cpp timedata_tests.cpp torcontrol_tests.cpp transaction_tests.cpp txindex_tests.cpp txvalidation_tests.cpp txvalidationcache_tests.cpp uint256_tests.cpp undo_tests.cpp util_tests.cpp validation_block_tests.cpp validation_tests.cpp work_comparator_tests.cpp # RPC Tests ../rpc/test/server_tests.cpp # Wallet tests ${BITCOIN_WALLET_TESTS} ) target_link_libraries(test_bitcoin rpcclient server) if(TARGET bitcoinconsensus-shared) target_link_libraries(test_bitcoin bitcoinconsensus-shared) else() target_link_libraries(test_bitcoin bitcoinconsensus) endif() add_executable(test_bitcoin_fuzzy EXCLUDE_FROM_ALL test_bitcoin_fuzzy.cpp ) target_link_libraries(test_bitcoin_fuzzy server) diff --git a/src/wallet/init.cpp b/src/wallet/init.cpp index 919f504b9..26d7966d7 100644 --- a/src/wallet/init.cpp +++ b/src/wallet/init.cpp @@ -1,392 +1,399 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2017 The Bitcoin Core developers // Copyright (c) 2018 The Bitcoin developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include #include #include #include #include #include #include #include #include #include #include #include class WalletInit : public WalletInitInterface { public: //! Return the wallets help message. void AddWalletOptions() const override; //! Wallets parameter interaction bool ParameterInteraction() const override; //! Register wallet RPCs. void RegisterRPC(CRPCTable &tableRPC) const override; //! Responsible for reading and validating the -wallet arguments and //! verifying the wallet database. // This function will perform salvage on the wallet if requested, as long // as only one wallet is being loaded (WalletParameterInteraction forbids // -salvagewallet, -zapwallettxes or -upgradewallet with multiwallet). bool Verify(const CChainParams &chainParams) const override; //! Load wallet databases. bool Open(const CChainParams &chainParams) const override; //! Complete startup of wallets. void Start(CScheduler &scheduler) const override; //! Flush all wallets in preparation for shutdown. void Flush() const override; //! Stop all wallets. Wallets will be flushed first. void Stop() const override; //! Close all wallets. void Close() const override; }; const WalletInitInterface &g_wallet_init_interface = WalletInit(); void WalletInit::AddWalletOptions() const { gArgs.AddArg( "-avoidpartialspends", strprintf("Group outputs by address, selecting all or none, instead of " "selecting on a per-output basis. Privacy is improved as an " "address is only used once (unless someone sends to it after " "spending from it), but may result in slightly higher fees " "as suboptimal coin selection may result due to the added " "limitation (default: %u)", DEFAULT_AVOIDPARTIALSPENDS), false, OptionsCategory::WALLET); gArgs.AddArg("-disablewallet", "Do not load the wallet and disable wallet RPC calls", false, OptionsCategory::WALLET); gArgs.AddArg("-fallbackfee=", strprintf("A fee rate (in %s/kB) that will be used when fee " "estimation has insufficient data (default: %s)", CURRENCY_UNIT, FormatMoney(DEFAULT_FALLBACK_FEE)), false, OptionsCategory::WALLET); gArgs.AddArg("-keypool=", strprintf("Set key pool size to (default: %u)", DEFAULT_KEYPOOL_SIZE), false, OptionsCategory::WALLET); gArgs.AddArg( "-maxtxfee=", strprintf("Maximum total fees (in %s) to use in a single wallet " "transaction or raw transaction; setting this too low may " "abort large transactions (default: %s)", CURRENCY_UNIT, FormatMoney(DEFAULT_TRANSACTION_MAXFEE)), false, OptionsCategory::DEBUG_TEST); gArgs.AddArg("-mintxfee=", strprintf("Fees (in %s/kB) smaller than this are considered " "zero fee for transaction creation (default: %s)", CURRENCY_UNIT, FormatMoney(DEFAULT_TRANSACTION_MINFEE_PER_KB)), false, OptionsCategory::WALLET); gArgs.AddArg( "-paytxfee=", strprintf( "Fee (in %s/kB) to add to transactions you send (default: %s)", CURRENCY_UNIT, FormatMoney(CFeeRate{DEFAULT_PAY_TX_FEE}.GetFeePerK())), false, OptionsCategory::WALLET); gArgs.AddArg( "-rescan", "Rescan the block chain for missing wallet transactions on startup", false, OptionsCategory::WALLET); gArgs.AddArg( "-salvagewallet", "Attempt to recover private keys from a corrupt wallet on startup", false, OptionsCategory::WALLET); gArgs.AddArg( "-spendzeroconfchange", strprintf( "Spend unconfirmed change when sending transactions (default: %d)", DEFAULT_SPEND_ZEROCONF_CHANGE), false, OptionsCategory::WALLET); gArgs.AddArg("-upgradewallet", "Upgrade wallet to latest format on startup", false, OptionsCategory::WALLET); gArgs.AddArg("-wallet=", "Specify wallet database path. Can be specified multiple " "times to load multiple wallets. Path is interpreted relative " "to if it is not absolute, and will be created if " "it does not exist (as a directory containing a wallet.dat " "file and log files). For backwards compatibility this will " "also accept names of existing data files in .)", false, OptionsCategory::WALLET); gArgs.AddArg( "-walletbroadcast", strprintf("Make the wallet broadcast transactions (default: %d)", DEFAULT_WALLETBROADCAST), false, OptionsCategory::WALLET); gArgs.AddArg("-walletdir=", "Specify directory to hold wallets (default: " "/wallets if it exists, otherwise )", false, OptionsCategory::WALLET); gArgs.AddArg("-walletnotify=", "Execute command when a wallet transaction changes (%s in cmd " "is replaced by TxID)", false, OptionsCategory::WALLET); gArgs.AddArg( "-zapwallettxes=", "Delete all wallet transactions and only recover those parts of the " "blockchain through -rescan on startup (1 = keep tx meta data e.g. " "account owner and payment request information, 2 = drop tx meta data)", false, OptionsCategory::WALLET); gArgs.AddArg("-dblogsize=", strprintf("Flush wallet database activity from memory to disk " "log every megabytes (default: %u)", DEFAULT_WALLET_DBLOGSIZE), true, OptionsCategory::WALLET_DEBUG_TEST); gArgs.AddArg( "-flushwallet", strprintf("Run a thread to flush wallet periodically (default: %d)", DEFAULT_FLUSHWALLET), true, OptionsCategory::WALLET_DEBUG_TEST); gArgs.AddArg("-privdb", strprintf("Sets the DB_PRIVATE flag in the wallet db " "environment (default: %d)", DEFAULT_WALLET_PRIVDB), true, OptionsCategory::WALLET_DEBUG_TEST); gArgs.AddArg("-walletrejectlongchains", strprintf("Wallet will not create transactions that violate " "mempool chain limits (default: %d)", DEFAULT_WALLET_REJECT_LONG_CHAINS), true, OptionsCategory::WALLET_DEBUG_TEST); } bool WalletInit::ParameterInteraction() const { gArgs.SoftSetArg("-wallet", ""); const bool is_multiwallet = gArgs.GetArgs("-wallet").size() > 1; if (gArgs.GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET)) { return true; } if (gArgs.GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY) && gArgs.SoftSetBoolArg("-walletbroadcast", false)) { LogPrintf("%s: parameter interaction: -blocksonly=1 -> setting " "-walletbroadcast=0\n", __func__); } if (gArgs.GetBoolArg("-salvagewallet", false) && gArgs.SoftSetBoolArg("-rescan", true)) { if (is_multiwallet) { return InitError( strprintf("%s is only allowed with a single wallet file", "-salvagewallet")); } // Rewrite just private keys: rescan to find transactions LogPrintf("%s: parameter interaction: -salvagewallet=1 -> setting " "-rescan=1\n", __func__); } int zapwallettxes = gArgs.GetArg("-zapwallettxes", 0); // -zapwallettxes implies dropping the mempool on startup if (zapwallettxes != 0 && gArgs.SoftSetBoolArg("-persistmempool", false)) { LogPrintf("%s: parameter interaction: -zapwallettxes=%s -> setting " "-persistmempool=0\n", __func__, zapwallettxes); } // -zapwallettxes implies a rescan if (zapwallettxes != 0) { if (is_multiwallet) { return InitError( strprintf("%s is only allowed with a single wallet file", "-zapwallettxes")); } if (gArgs.SoftSetBoolArg("-rescan", true)) { LogPrintf("%s: parameter interaction: -zapwallettxes=%s -> setting " "-rescan=1\n", __func__, zapwallettxes); } LogPrintf("%s: parameter interaction: -zapwallettxes= -> setting " "-rescan=1\n", __func__); } if (is_multiwallet) { if (gArgs.GetBoolArg("-upgradewallet", false)) { return InitError( strprintf("%s is only allowed with a single wallet file", "-upgradewallet")); } } if (gArgs.GetBoolArg("-sysperms", false)) { return InitError("-sysperms is not allowed in combination with enabled " "wallet functionality"); } if (gArgs.GetArg("-prune", 0) && gArgs.GetBoolArg("-rescan", false)) { return InitError( _("Rescans are not possible in pruned mode. You will need to use " "-reindex which will download the whole blockchain again.")); } if (minRelayTxFee.GetFeePerK() > HIGH_TX_FEE_PER_KB) { InitWarning( AmountHighWarn("-minrelaytxfee") + " " + _("The wallet will avoid paying less than the minimum relay fee.")); } if (gArgs.IsArgSet("-maxtxfee")) { Amount nMaxFee = Amount::zero(); if (!ParseMoney(gArgs.GetArg("-maxtxfee", ""), nMaxFee)) { return InitError( AmountErrMsg("maxtxfee", gArgs.GetArg("-maxtxfee", ""))); } if (nMaxFee > HIGH_MAX_TX_FEE) { InitWarning(_("-maxtxfee is set very high! Fees this large could " "be paid on a single transaction.")); } maxTxFee = nMaxFee; if (CFeeRate(maxTxFee, 1000) < minRelayTxFee) { return InitError(strprintf( _("Invalid amount for -maxtxfee=: '%s' (must " "be at least the minrelay fee of %s to prevent " "stuck transactions)"), gArgs.GetArg("-maxtxfee", ""), minRelayTxFee.ToString())); } } return true; } void WalletInit::RegisterRPC(CRPCTable &t) const { if (gArgs.GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET)) { return; } RegisterWalletRPCCommands(t); RegisterDumpRPCCommands(t); } bool WalletInit::Verify(const CChainParams &chainParams) const { if (gArgs.GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET)) { return true; } if (gArgs.IsArgSet("-walletdir")) { fs::path wallet_dir = gArgs.GetArg("-walletdir", ""); - if (!fs::exists(wallet_dir)) { + boost::system::error_code error; + // The canonical path cleans the path, preventing >1 Berkeley + // environment instances for the same directory + fs::path canonical_wallet_dir = fs::canonical(wallet_dir, error); + if (error || !fs::exists(wallet_dir)) { return InitError( strprintf(_("Specified -walletdir \"%s\" does not exist"), wallet_dir.string())); } else if (!fs::is_directory(wallet_dir)) { return InitError( strprintf(_("Specified -walletdir \"%s\" is not a directory"), wallet_dir.string())); + // The canonical path transforms relative paths into absolute ones, + // so we check the non-canonical version } else if (!wallet_dir.is_absolute()) { return InitError( strprintf(_("Specified -walletdir \"%s\" is a relative path"), wallet_dir.string())); } + gArgs.ForceSetArg("-walletdir", canonical_wallet_dir.string()); } LogPrintf("Using wallet directory %s\n", GetWalletDir().string()); uiInterface.InitMessage(_("Verifying wallet(s)...")); std::vector wallet_files = gArgs.GetArgs("-wallet"); // Parameter interaction code should have thrown an error if -salvagewallet // was enabled with more than wallet file, so the wallet_files size check // here should have no effect. bool salvage_wallet = gArgs.GetBoolArg("-salvagewallet", false) && wallet_files.size() <= 1; // Keep track of each wallet absolute path to detect duplicates. std::set wallet_paths; for (const auto &wallet_file : wallet_files) { WalletLocation location(wallet_file); if (!wallet_paths.insert(location.GetPath()).second) { return InitError(strprintf(_("Error loading wallet %s. Duplicate " "-wallet filename specified."), wallet_file)); } std::string error_string; std::string warning_string; bool verify_success = CWallet::Verify(chainParams, location, salvage_wallet, error_string, warning_string); if (!error_string.empty()) { InitError(error_string); } if (!warning_string.empty()) { InitWarning(warning_string); } if (!verify_success) { return false; } } return true; } bool WalletInit::Open(const CChainParams &chainParams) const { if (gArgs.GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET)) { LogPrintf("Wallet disabled!\n"); return true; } for (const std::string &walletFile : gArgs.GetArgs("-wallet")) { std::shared_ptr pwallet = CWallet::CreateWalletFromFile( chainParams, WalletLocation(walletFile)); if (!pwallet) { return false; } AddWallet(pwallet); } return true; } void WalletInit::Start(CScheduler &scheduler) const { for (const std::shared_ptr &pwallet : GetWallets()) { pwallet->postInitProcess(); } // Run a thread to flush wallet periodically scheduler.scheduleEvery( [] { MaybeCompactWalletDB(); return true; }, 500); } void WalletInit::Flush() const { for (const std::shared_ptr &pwallet : GetWallets()) { pwallet->Flush(false); } } void WalletInit::Stop() const { for (const std::shared_ptr &pwallet : GetWallets()) { pwallet->Flush(true); } } void WalletInit::Close() const { for (const std::shared_ptr &pwallet : GetWallets()) { RemoveWallet(pwallet); } } diff --git a/src/wallet/test/init_test_fixture.cpp b/src/wallet/test/init_test_fixture.cpp new file mode 100644 index 000000000..87b1a20a6 --- /dev/null +++ b/src/wallet/test/init_test_fixture.cpp @@ -0,0 +1,42 @@ +// Copyright (c) 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 + +#include +#include + +InitWalletDirTestingSetup::InitWalletDirTestingSetup( + const std::string &chainName) + : BasicTestingSetup(chainName) { + std::string sep; + sep += fs::path::preferred_separator; + + m_datadir = SetDataDir("tempdir"); + m_cwd = fs::current_path(); + + m_walletdir_path_cases["default"] = m_datadir / "wallets"; + m_walletdir_path_cases["custom"] = m_datadir / "my_wallets"; + m_walletdir_path_cases["nonexistent"] = m_datadir / "path_does_not_exist"; + m_walletdir_path_cases["file"] = m_datadir / "not_a_directory.dat"; + m_walletdir_path_cases["trailing"] = m_datadir / "wallets" / sep; + m_walletdir_path_cases["trailing2"] = m_datadir / "wallets" / sep / sep; + + fs::current_path(m_datadir); + m_walletdir_path_cases["relative"] = "wallets"; + + fs::create_directories(m_walletdir_path_cases["default"]); + fs::create_directories(m_walletdir_path_cases["custom"]); + fs::create_directories(m_walletdir_path_cases["relative"]); + std::ofstream f(m_walletdir_path_cases["file"].BOOST_FILESYSTEM_C_STR); + f.close(); +} + +InitWalletDirTestingSetup::~InitWalletDirTestingSetup() { + fs::current_path(m_cwd); +} + +void InitWalletDirTestingSetup::SetWalletDir(const fs::path &walletdir_path) { + gArgs.ForceSetArg("-walletdir", walletdir_path.string()); +} diff --git a/src/wallet/test/init_test_fixture.h b/src/wallet/test/init_test_fixture.h new file mode 100644 index 000000000..3307da7c0 --- /dev/null +++ b/src/wallet/test/init_test_fixture.h @@ -0,0 +1,21 @@ +// Copyright (c) 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_WALLET_TEST_INIT_TEST_FIXTURE_H +#define BITCOIN_WALLET_TEST_INIT_TEST_FIXTURE_H + +#include + +struct InitWalletDirTestingSetup : public BasicTestingSetup { + explicit InitWalletDirTestingSetup( + const std::string &chainName = CBaseChainParams::MAIN); + ~InitWalletDirTestingSetup(); + void SetWalletDir(const fs::path &walletdir_path); + + fs::path m_datadir; + fs::path m_cwd; + std::map m_walletdir_path_cases; +}; + +#endif // BITCOIN_WALLET_TEST_INIT_TEST_FIXTURE_H diff --git a/src/wallet/test/init_tests.cpp b/src/wallet/test/init_tests.cpp new file mode 100644 index 000000000..f01ed2cb0 --- /dev/null +++ b/src/wallet/test/init_tests.cpp @@ -0,0 +1,71 @@ +// Copyright (c) 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 +#include +#include +#include + +#include +#include + +#include + +BOOST_FIXTURE_TEST_SUITE(init_tests, InitWalletDirTestingSetup) + +BOOST_AUTO_TEST_CASE(walletinit_verify_walletdir_default) { + SetWalletDir(m_walletdir_path_cases["default"]); + bool result = g_wallet_init_interface.Verify(Params()); + BOOST_CHECK(result == true); + fs::path walletdir = gArgs.GetArg("-walletdir", ""); + fs::path expected_path = fs::canonical(m_walletdir_path_cases["default"]); + BOOST_CHECK(walletdir == expected_path); +} + +BOOST_AUTO_TEST_CASE(walletinit_verify_walletdir_custom) { + SetWalletDir(m_walletdir_path_cases["custom"]); + bool result = g_wallet_init_interface.Verify(Params()); + BOOST_CHECK(result == true); + fs::path walletdir = gArgs.GetArg("-walletdir", ""); + fs::path expected_path = fs::canonical(m_walletdir_path_cases["custom"]); + BOOST_CHECK(walletdir == expected_path); +} + +BOOST_AUTO_TEST_CASE(walletinit_verify_walletdir_does_not_exist) { + SetWalletDir(m_walletdir_path_cases["nonexistent"]); + bool result = g_wallet_init_interface.Verify(Params()); + BOOST_CHECK(result == false); +} + +BOOST_AUTO_TEST_CASE(walletinit_verify_walletdir_is_not_directory) { + SetWalletDir(m_walletdir_path_cases["file"]); + bool result = g_wallet_init_interface.Verify(Params()); + BOOST_CHECK(result == false); +} + +BOOST_AUTO_TEST_CASE(walletinit_verify_walletdir_is_not_relative) { + SetWalletDir(m_walletdir_path_cases["relative"]); + bool result = g_wallet_init_interface.Verify(Params()); + BOOST_CHECK(result == false); +} + +BOOST_AUTO_TEST_CASE(walletinit_verify_walletdir_no_trailing) { + SetWalletDir(m_walletdir_path_cases["trailing"]); + bool result = g_wallet_init_interface.Verify(Params()); + BOOST_CHECK(result == true); + fs::path walletdir = gArgs.GetArg("-walletdir", ""); + fs::path expected_path = fs::canonical(m_walletdir_path_cases["default"]); + BOOST_CHECK(walletdir == expected_path); +} + +BOOST_AUTO_TEST_CASE(walletinit_verify_walletdir_no_trailing2) { + SetWalletDir(m_walletdir_path_cases["trailing2"]); + bool result = g_wallet_init_interface.Verify(Params()); + BOOST_CHECK(result == true); + fs::path walletdir = gArgs.GetArg("-walletdir", ""); + fs::path expected_path = fs::canonical(m_walletdir_path_cases["default"]); + BOOST_CHECK(walletdir == expected_path); +} + +BOOST_AUTO_TEST_SUITE_END()