diff --git a/configure.ac b/configure.ac index 206b4935b1..bc003af93c 100644 --- a/configure.ac +++ b/configure.ac @@ -691,7 +691,7 @@ case $host in AC_MSG_ERROR("windres not found") fi - CPPFLAGS="$CPPFLAGS -D_MT -DWIN32 -D_WINDOWS -DBOOST_THREAD_USE_LIB -D_WIN32_WINNT=0x0601" + CPPFLAGS="$CPPFLAGS -D_MT -DWIN32 -D_WINDOWS -DBOOST_THREAD_USE_LIB -D_WIN32_WINNT=0x0601 -D_WIN32_IE=0x0501 -DWIN32_LEAN_AND_MEAN" dnl libtool insists upon adding -nostdlib and a list of objects/libs to link against. dnl That breaks our ability to build dll's with static libgcc/libstdc++/libssp. Override diff --git a/doc/build-openbsd.md b/doc/build-openbsd.md index 9ad2dd006b..addfe4c8b2 100644 --- a/doc/build-openbsd.md +++ b/doc/build-openbsd.md @@ -2,9 +2,7 @@ OpenBSD build guide ====================== (updated for OpenBSD 6.2) -This guide describes how to build dashd and command-line utilities on OpenBSD. - -OpenBSD is most commonly used as a server OS, so this guide does not contain instructions for building the GUI. +This guide describes how to build dashd, dash-qt, and command-line utilities on OpenBSD. Preparation ------------- @@ -13,6 +11,7 @@ Run the following as root to install the base dependencies for building: ```bash pkg_add git gmake libevent libtool +pkg_add qt5 # (optional for enabling the GUI) pkg_add autoconf # (select highest version, e.g. 2.69) pkg_add automake # (select highest version, e.g. 1.15) pkg_add python # (select highest version, e.g. 3.6) @@ -75,6 +74,14 @@ To configure without wallet: ./configure --disable-wallet --with-gui=no CC=cc CXX=c++ MAKE=gmake ``` +To configure with GUI: +```bash +./configure --with-gui=yes CC=cc CXX=c++ \ + BDB_LIBS="-L${BDB_PREFIX}/lib -ldb_cxx-4.8" \ + BDB_CFLAGS="-I${BDB_PREFIX}/include" \ + MAKE=gmake +``` + Build and run the tests: ```bash gmake # use -jX here for parallelism diff --git a/src/base58.cpp b/src/base58.cpp index 1454cc6f87..dd2f9eea9a 100644 --- a/src/base58.cpp +++ b/src/base58.cpp @@ -35,7 +35,7 @@ static const int8_t mapBase58[256] = { -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, }; -bool DecodeBase58(const char* psz, std::vector& vch, int max_ret_len) +[[nodiscard]] static bool DecodeBase58(const char* psz, std::vector& vch, int max_ret_len) { // Skip leading spaces. while (*psz && IsSpace(*psz)) @@ -141,7 +141,7 @@ std::string EncodeBase58Check(Span input) return EncodeBase58(vch); } -bool DecodeBase58Check(const char* psz, std::vector& vchRet, int max_ret_len) +[[nodiscard]] static bool DecodeBase58Check(const char* psz, std::vector& vchRet, int max_ret_len) { if (!DecodeBase58(psz, vchRet, max_ret_len > std::numeric_limits::max() - 4 ? std::numeric_limits::max() : max_ret_len + 4) || (vchRet.size() < 4)) { diff --git a/src/base58.h b/src/base58.h index d339e48ceb..60551a12ae 100644 --- a/src/base58.h +++ b/src/base58.h @@ -25,13 +25,6 @@ */ std::string EncodeBase58(Span input); -/** - * Decode a base58-encoded string (psz) into a byte vector (vchRet). - * return true if decoding is successful. - * psz cannot be nullptr. - */ -[[nodiscard]] bool DecodeBase58(const char* psz, std::vector& vchRet, int max_ret_len); - /** * Decode a base58-encoded string (str) into a byte vector (vchRet). * return true if decoding is successful. @@ -43,12 +36,6 @@ std::string EncodeBase58(Span input); */ std::string EncodeBase58Check(Span input); -/** - * Decode a base58-encoded string (psz) that includes a checksum into a byte - * vector (vchRet), return true if decoding is successful - */ -[[nodiscard]] bool DecodeBase58Check(const char* psz, std::vector& vchRet, int max_ret_len); - /** * Decode a base58-encoded string (str) that includes a checksum into a byte * vector (vchRet), return true if decoding is successful diff --git a/src/chainparams.h b/src/chainparams.h index bf36b4b851..e665b6aaf5 100644 --- a/src/chainparams.h +++ b/src/chainparams.h @@ -23,6 +23,11 @@ typedef std::map MapCheckpoints; struct CCheckpointData { MapCheckpoints mapCheckpoints; + + int GetHeight() const { + const auto& final_checkpoint = mapCheckpoints.rbegin(); + return final_checkpoint->first /* height */; + } }; struct AssumeutxoHash : public BaseHash { diff --git a/src/compat.h b/src/compat.h index 39650bfe51..61399a7a2a 100644 --- a/src/compat.h +++ b/src/compat.h @@ -11,9 +11,6 @@ #endif #ifdef WIN32 -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN 1 -#endif #ifndef NOMINMAX #define NOMINMAX #endif diff --git a/src/init.cpp b/src/init.cpp index df6f3c4a95..9548a6573c 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -705,7 +705,7 @@ void SetupServerArgs(NodeContext& node) argsman.AddArg("-checkblocks=", strprintf("How many blocks to check at startup (default: %u, 0 = all)", DEFAULT_CHECKBLOCKS), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); argsman.AddArg("-checklevel=", strprintf("How thorough the block verification of -checkblocks is: %s (0-4, default: %u)", Join(CHECKLEVEL_DOC, ", "), DEFAULT_CHECKLEVEL), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); argsman.AddArg("-checkmempool=", strprintf("Run checks every transactions (default: %u, regtest: %u)", defaultChainParams->DefaultConsistencyChecks(), regtestChainParams->DefaultConsistencyChecks()), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); - argsman.AddArg("-checkpoints", strprintf("Enable rejection of any forks from the known historical chain until block 1450000 (default: %u)", DEFAULT_CHECKPOINTS_ENABLED), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); + argsman.AddArg("-checkpoints", strprintf("Enable rejection of any forks from the known historical chain until block %s (default: %u)", defaultChainParams->Checkpoints().GetHeight(), DEFAULT_CHECKPOINTS_ENABLED), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); argsman.AddArg("-deprecatedrpc=", "Allows deprecated RPC method(s) to be used", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); argsman.AddArg("-limitancestorcount=", strprintf("Do not accept transactions if number of in-mempool ancestors is or more (default: %u)", DEFAULT_ANCESTOR_LIMIT), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); argsman.AddArg("-limitancestorsize=", strprintf("Do not accept transactions whose size with all in-mempool ancestors exceeds kilobytes (default: %u)", DEFAULT_ANCESTOR_SIZE_LIMIT), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); @@ -1419,6 +1419,10 @@ bool AppInitParameterInteraction(const ArgsManager& args) nMaxTipAge = args.GetArg("-maxtipage", DEFAULT_MAX_TIP_AGE); + if (args.IsArgSet("-proxy") && args.GetArg("-proxy", "").empty()) { + return InitError(_("No proxy server specified. Use -proxy= or -proxy=.")); + } + try { const bool fRecoveryEnabled{llmq::utils::QuorumDataRecoveryEnabled()}; const bool fQuorumVvecRequestsEnabled{llmq::utils::GetEnabledQuorumVvecSyncEntries().size() > 0}; diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp index 8eb39b501d..4b8d564701 100644 --- a/src/qt/guiutil.cpp +++ b/src/qt/guiutil.cpp @@ -27,11 +27,6 @@ #include #ifdef WIN32 -#ifdef _WIN32_IE -#undef _WIN32_IE -#endif -#define _WIN32_IE 0x0501 -#define WIN32_LEAN_AND_MEAN 1 #ifndef NOMINMAX #define NOMINMAX #endif diff --git a/src/support/lockedpool.cpp b/src/support/lockedpool.cpp index a0ba8ed142..bd4f64234b 100644 --- a/src/support/lockedpool.cpp +++ b/src/support/lockedpool.cpp @@ -10,7 +10,6 @@ #endif #ifdef WIN32 -#define WIN32_LEAN_AND_MEAN 1 #ifndef NOMINMAX #define NOMINMAX #endif diff --git a/src/util/system.cpp b/src/util/system.cpp index f68d7ccb7e..55dd227270 100644 --- a/src/util/system.cpp +++ b/src/util/system.cpp @@ -52,12 +52,6 @@ #pragma warning(disable:4717) #endif -#ifdef _WIN32_IE -#undef _WIN32_IE -#endif -#define _WIN32_IE 0x0501 - -#define WIN32_LEAN_AND_MEAN 1 #ifndef NOMINMAX #define NOMINMAX #endif diff --git a/src/validation.cpp b/src/validation.cpp index 8a39c3b439..ca12e0f20e 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -1374,12 +1374,12 @@ void CChainState::InvalidChainFound(CBlockIndex* pindexNew) pindexBestHeader = m_chain.Tip(); } - LogPrintf("%s: invalid block=%s height=%d log2_work=%.8f date=%s\n", __func__, + LogPrintf("%s: invalid block=%s height=%d log2_work=%f date=%s\n", __func__, pindexNew->GetBlockHash().ToString(), pindexNew->nHeight, log(pindexNew->nChainWork.getdouble())/log(2.0), FormatISO8601DateTime(pindexNew->GetBlockTime())); CBlockIndex *tip = m_chain.Tip(); assert (tip); - LogPrintf("%s: current best=%s height=%d log2_work=%.8f date=%s\n", __func__, + LogPrintf("%s: current best=%s height=%d log2_work=%f date=%s\n", __func__, tip->GetBlockHash().ToString(), m_chain.Height(), log(tip->nChainWork.getdouble())/log(2.0), FormatISO8601DateTime(tip->GetBlockTime())); CheckForkWarningConditions(); @@ -1391,12 +1391,12 @@ void CChainState::ConflictingChainFound(CBlockIndex* pindexNew) statsClient.inc("warnings.ConflictingChainFound", 1.0f); - LogPrintf("%s: conflicting block=%s height=%d log2_work=%.8f date=%s\n", __func__, + LogPrintf("%s: conflicting block=%s height=%d log2_work=%f date=%s\n", __func__, pindexNew->GetBlockHash().ToString(), pindexNew->nHeight, log(pindexNew->nChainWork.getdouble())/log(2.0), FormatISO8601DateTime(pindexNew->GetBlockTime())); CBlockIndex *tip = m_chain.Tip(); assert (tip); - LogPrintf("%s: current best=%s height=%d log2_work=%.8f date=%s\n", __func__, + LogPrintf("%s: current best=%s height=%d log2_work=%f date=%s\n", __func__, tip->GetBlockHash().ToString(), m_chain.Height(), log(tip->nChainWork.getdouble())/log(2.0), FormatISO8601DateTime(tip->GetBlockTime())); CheckForkWarningConditions(); @@ -2704,7 +2704,7 @@ void CChainState::UpdateTip(const CBlockIndex* pindexNew) } } assert(std::addressof(::ChainstateActive()) == std::addressof(*this)); - LogPrintf("%s: new best=%s height=%d version=0x%08x log2_work=%.8g tx=%lu date='%s' progress=%f cache=%.1fMiB(%utxo) evodb_cache=%.1fMiB%s\n", __func__, + LogPrintf("%s: new best=%s height=%d version=0x%08x log2_work=%f tx=%lu date='%s' progress=%f cache=%.1fMiB(%utxo) evodb_cache=%.1fMiB%s\n", __func__, pindexNew->GetBlockHash().ToString(), pindexNew->nHeight, pindexNew->nVersion, log(pindexNew->nChainWork.getdouble())/log(2.0), (unsigned long)pindexNew->nChainTx, FormatISO8601DateTime(pindexNew->GetBlockTime()), diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp index 4f88664d53..8639db32cf 100644 --- a/src/wallet/test/wallet_tests.cpp +++ b/src/wallet/test/wallet_tests.cpp @@ -1360,4 +1360,37 @@ BOOST_FIXTURE_TEST_CASE(dummy_input_size_test, TestChain100Setup) BOOST_CHECK_EQUAL(CalculateNestedKeyhashInputSize(true), DUMMY_NESTED_P2PKH_INPUT_SIZE + 1); } +BOOST_FIXTURE_TEST_CASE(ZapSelectTx, TestChain100Setup) +{ + auto chain = interfaces::MakeChain(m_node); + auto wallet = TestLoadWallet(m_node); + CKey key; + key.MakeNewKey(true); + AddKey(*wallet, key); + + std::string error; + m_coinbase_txns.push_back(CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())).vtx[0]); + auto block_tx = TestSimpleSpend(*m_coinbase_txns[0], 0, coinbaseKey, GetScriptForRawPubKey(key.GetPubKey())); + CreateAndProcessBlock({block_tx}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())); + + SyncWithValidationInterfaceQueue(); + + { + auto block_hash = block_tx.GetHash(); + auto prev_hash = m_coinbase_txns[0]->GetHash(); + + LOCK(wallet->cs_wallet); + BOOST_CHECK(wallet->HasWalletSpend(prev_hash)); + BOOST_CHECK_EQUAL(wallet->mapWallet.count(block_hash), 1u); + + std::vector vHashIn{ block_hash }, vHashOut; + BOOST_CHECK_EQUAL(wallet->ZapSelectTx(vHashIn, vHashOut), DBErrors::LOAD_OK); + + BOOST_CHECK(!wallet->HasWalletSpend(prev_hash)); + BOOST_CHECK_EQUAL(wallet->mapWallet.count(block_hash), 0u); + } + + TestUnloadWallet(std::move(wallet)); +} + BOOST_AUTO_TEST_SUITE_END() diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 1737d6b515..9d52273549 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -495,6 +495,13 @@ std::set CWallet::GetConflicts(const uint256& txid) const return result; } +bool CWallet::HasWalletSpend(const uint256& txid) const +{ + AssertLockHeld(cs_wallet); + auto iter = mapTxSpends.lower_bound(COutPoint(txid, 0)); + return (iter != mapTxSpends.end() && iter->first.hash == txid); +} + void CWallet::Flush() { GetDatabase().Flush(); @@ -3912,9 +3919,11 @@ DBErrors CWallet::ZapSelectTx(std::vector& vHashIn, std::vectorsecond.m_it_wtxOrdered); + for (const auto& txin : it->second.tx->vin) + mapTxSpends.erase(txin.prevout); mapWallet.erase(it); NotifyTransactionChanged(this, hash, CT_DELETED); } diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 55024c86c4..3db4953c20 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -1190,6 +1190,9 @@ public: //! Get wallet transactions that conflict with given transaction (spend same outputs) std::set GetConflicts(const uint256& txid) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); + //! Check if a given transaction has any of its outputs spent by another transaction in the wallet + bool HasWalletSpend(const uint256& txid) const; + //! Flush wallet (bitdb flush) void Flush(); diff --git a/test/functional/feature_config_args.py b/test/functional/feature_config_args.py index f7e913320f..fd161bf4ae 100755 --- a/test/functional/feature_config_args.py +++ b/test/functional/feature_config_args.py @@ -81,6 +81,11 @@ class ConfArgsTest(BitcoinTestFramework): with open(inc_conf_file2_path, 'w', encoding='utf-8') as conf: conf.write('') # clear + def test_invalid_command_line_options(self): + self.nodes[0].assert_start_raises_init_error( + expected_msg='Error: No proxy server specified. Use -proxy= or -proxy=.', + extra_args=['-proxy'], + ) def test_log_buffer(self): with self.nodes[0].assert_debug_log(expected_msgs=['Warning: parsed potentially confusing double-negative -connect=0\n']): @@ -124,6 +129,7 @@ class ConfArgsTest(BitcoinTestFramework): self.test_config_file_parser() + self.test_invalid_command_line_options() # Remove the -datadir argument so it doesn't override the config file self.nodes[0].args = [arg for arg in self.nodes[0].args if not arg.startswith("-datadir")]