diff --git a/ci/lint/06_script.sh b/ci/lint/06_script.sh index 72d0e1c1e5..8da9744bcd 100755 --- a/ci/lint/06_script.sh +++ b/ci/lint/06_script.sh @@ -25,7 +25,7 @@ test/lint/lint-all.sh if [ "$CIRRUS_REPO_FULL_NAME" = "dashpay/dash" ] && [ -n "$CIRRUS_CRON" ]; then git log --merges --before="2 days ago" -1 --format='%H' > ./contrib/verify-commits/trusted-sha512-root-commit - ${CI_RETRY_EXE} gpg --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys $( + int f(){ assert(false); }]])]) + AX_CHECK_COMPILE_FLAG([-Werror=conditional-uninitialized],[ERROR_CXXFLAGS="$ERROR_CXXFLAGS -Werror=conditional-uninitialized"],,[[$CXXFLAG_WERROR]]) AX_CHECK_COMPILE_FLAG([-Werror=sign-compare],[ERROR_CXXFLAGS="$ERROR_CXXFLAGS -Werror=sign-compare"],,[[$CXXFLAG_WERROR]]) dnl -Wsuggest-override is broken with GCC before 9.2 diff --git a/contrib/builder-keys/README.md b/contrib/builder-keys/README.md index c883b3fa6f..8b4303d00a 100644 --- a/contrib/builder-keys/README.md +++ b/contrib/builder-keys/README.md @@ -1,15 +1,26 @@ -PGP keys -======== +## PGP keys of builders and Developers -This folder contains the public keys of developers and active contributors. +The file `keys.txt` contains fingerprints of the public keys of builders and +active developers. The keys are mainly used to sign git commits or the build results of builds. -You can import the keys into gpg as follows. Also, make sure to fetch the -latest version from the key server to see if any key was revoked in the -meantime. +The most recent version of each pgp key can be found on most pgp key servers. + +Fetch the latest version from the key server to see if any key was revoked in +the meantime. +To fetch the latest version of all pgp keys in your gpg homedir, ```sh -gpg --import ./*.pgp gpg --refresh-keys ``` + +To fetch keys of builders and active developers, feed the list of fingerprints +of the primary keys into gpg: + +```sh +while read fingerprint keyholder_name; do gpg --keyserver hkps://keys.openpgp.org --recv-keys ${fingerprint}; done < ./keys.txt +``` + +Add your key to the list if you provided Guix attestations for two major or +minor releases of Dash Core. diff --git a/contrib/verify-commits/README.md b/contrib/verify-commits/README.md index e95a57586f..b8b15280ba 100644 --- a/contrib/verify-commits/README.md +++ b/contrib/verify-commits/README.md @@ -40,7 +40,7 @@ Import trusted keys In order to check the commit signatures, you must add the trusted PGP keys to your machine. [GnuPG](https://gnupg.org/) may be used to import the trusted keys by running the following command: ```sh -gpg --keyserver hkp://keyserver.ubuntu.com --recv-keys $( -#include #include #include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include +#include #include -#include #include #include #include #include #include +#include +#include #include +#include +#include +#include +#include #ifdef ENABLE_WALLET #include @@ -30,19 +43,6 @@ #include #endif // ENABLE_WALLET -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - #include #include @@ -52,7 +52,6 @@ #include #include #include -#include #include #include #include @@ -208,72 +207,11 @@ void DebugMessageHandler(QtMsgType type, const QMessageLogContext& context, cons } } -BitcoinCore::BitcoinCore(interfaces::Node& node) : - QObject(), m_node(node) -{ -} - -void BitcoinCore::handleRunawayException(const std::exception_ptr e) -{ - PrintExceptionContinue(e, "Runaway exception"); - Q_EMIT runawayException(QString::fromStdString(m_node.getWarnings().translated)); -} - -void BitcoinCore::initialize() -{ - try - { - util::ThreadRename("qt-init"); - qDebug() << __func__ << ": Running initialization in thread"; - interfaces::BlockAndHeaderTipInfo tip_info; - bool rv = m_node.appInitMain(&tip_info); - Q_EMIT initializeResult(rv, tip_info); - } catch (...) { - handleRunawayException(std::current_exception()); - } -} - -void BitcoinCore::restart(QStringList args) -{ - static bool executing_restart{false}; - - if(!executing_restart) { // Only restart 1x, no matter how often a user clicks on a restart-button - executing_restart = true; - try - { - qDebug() << __func__ << ": Running Restart in thread"; - m_node.appPrepareShutdown(); - qDebug() << __func__ << ": Shutdown finished"; - Q_EMIT shutdownResult(); - CExplicitNetCleanup::callCleanup(); - QProcess::startDetached(QApplication::applicationFilePath(), args); - qDebug() << __func__ << ": Restart initiated..."; - QApplication::quit(); - } catch (...) { - handleRunawayException(std::current_exception()); - } - } -} - -void BitcoinCore::shutdown() -{ - try - { - qDebug() << __func__ << ": Running Shutdown in thread"; - m_node.appShutdown(); - qDebug() << __func__ << ": Shutdown finished"; - Q_EMIT shutdownResult(); - } catch (...) { - handleRunawayException(std::current_exception()); - } -} - static int qt_argc = 1; static const char* qt_argv = "dash-qt"; BitcoinApplication::BitcoinApplication(): QApplication(qt_argc, const_cast(&qt_argv)), - coreThread(nullptr), optionsModel(nullptr), clientModel(nullptr), window(nullptr), @@ -287,13 +225,7 @@ BitcoinApplication::BitcoinApplication(): BitcoinApplication::~BitcoinApplication() { - if(coreThread) - { - qDebug() << __func__ << ": Stopping thread"; - coreThread->quit(); - coreThread->wait(); - qDebug() << __func__ << ": Stopped thread"; - } + m_executor.reset(); delete window; window = nullptr; @@ -350,23 +282,16 @@ bool BitcoinApplication::baseInitialize() void BitcoinApplication::startThread() { - if(coreThread) - return; - coreThread = new QThread(this); - BitcoinCore *executor = new BitcoinCore(node()); - executor->moveToThread(coreThread); + assert(!m_executor); + m_executor.emplace(node()); /* communication to and from thread */ - connect(executor, &BitcoinCore::initializeResult, this, &BitcoinApplication::initializeResult); - connect(executor, &BitcoinCore::shutdownResult, this, &BitcoinApplication::shutdownResult); - connect(executor, &BitcoinCore::runawayException, this, &BitcoinApplication::handleRunawayException); - connect(this, &BitcoinApplication::requestedInitialize, executor, &BitcoinCore::initialize); - connect(this, &BitcoinApplication::requestedShutdown, executor, &BitcoinCore::shutdown); - connect(window, &BitcoinGUI::requestedRestart, executor, &BitcoinCore::restart); - /* make sure executor object is deleted in its own thread */ - connect(coreThread, &QThread::finished, executor, &QObject::deleteLater); - - coreThread->start(); + connect(&m_executor.value(), &InitExecutor::initializeResult, this, &BitcoinApplication::initializeResult); + connect(&m_executor.value(), &InitExecutor::shutdownResult, this, &BitcoinApplication::shutdownResult); + connect(&m_executor.value(), &InitExecutor::runawayException, this, &BitcoinApplication::handleRunawayException); + connect(this, &BitcoinApplication::requestedInitialize, &m_executor.value(), &InitExecutor::initialize); + connect(this, &BitcoinApplication::requestedShutdown, &m_executor.value(), &InitExecutor::shutdown); + connect(window, &BitcoinGUI::requestedRestart, &m_executor.value(), &InitExecutor::restart); } void BitcoinApplication::parameterSetup() @@ -399,7 +324,6 @@ void BitcoinApplication::requestShutdown() shutdownWindow.reset(ShutdownWindow::showShutdownWindow(window)); qDebug() << __func__ << ": Requesting shutdown"; - startThread(); window->hide(); // Must disconnect node signals otherwise current thread can deadlock since // no event loop is running. diff --git a/src/qt/bitcoin.h b/src/qt/bitcoin.h index 76ebdb4486..934b841795 100644 --- a/src/qt/bitcoin.h +++ b/src/qt/bitcoin.h @@ -9,11 +9,14 @@ #include #endif -#include +#include +#include + #include #include +#include -#include +#include class BitcoinGUI; class ClientModel; @@ -25,32 +28,6 @@ class WalletController; class WalletModel; -/** Class encapsulating Bitcoin Core startup and shutdown. - * Allows running startup and shutdown in a different thread from the UI thread. - */ -class BitcoinCore: public QObject -{ - Q_OBJECT -public: - explicit BitcoinCore(interfaces::Node& node); - -public Q_SLOTS: - void initialize(); - void shutdown(); - void restart(QStringList args); - -Q_SIGNALS: - void initializeResult(bool success, interfaces::BlockAndHeaderTipInfo tip_info); - void shutdownResult(); - void runawayException(const QString &message); - -private: - /// Pass fatal exception message to UI thread - void handleRunawayException(const std::exception_ptr e); - - interfaces::Node& m_node; -}; - /** Main Bitcoin application object */ class BitcoinApplication: public QApplication { @@ -113,7 +90,7 @@ protected: bool event(QEvent* e) override; private: - QThread *coreThread; + std::optional m_executor; OptionsModel *optionsModel; ClientModel *clientModel; BitcoinGUI *window; diff --git a/src/qt/forms/optionsdialog.ui b/src/qt/forms/optionsdialog.ui index 8f53b2fa8c..300e2520e9 100644 --- a/src/qt/forms/optionsdialog.ui +++ b/src/qt/forms/optionsdialog.ui @@ -139,7 +139,7 @@ true - + @@ -315,6 +315,16 @@ + + + + Whether to set subtract fee from amount as default or not. + + + Subtract &fee from amount by default + + + diff --git a/src/qt/initexecutor.cpp b/src/qt/initexecutor.cpp new file mode 100644 index 0000000000..87d9ecda5b --- /dev/null +++ b/src/qt/initexecutor.cpp @@ -0,0 +1,85 @@ +// Copyright (c) 2014-2021 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 +#include +#include +#include +#include + +InitExecutor::InitExecutor(interfaces::Node& node) + : QObject(), m_node(node) +{ + this->moveToThread(&m_thread); + m_thread.start(); +} + +InitExecutor::~InitExecutor() +{ + qDebug() << __func__ << ": Stopping thread"; + m_thread.quit(); + m_thread.wait(); + qDebug() << __func__ << ": Stopped thread"; +} + +void InitExecutor::handleRunawayException(const std::exception_ptr e) +{ + PrintExceptionContinue(e, "Runaway exception"); + Q_EMIT runawayException(QString::fromStdString(m_node.getWarnings().translated)); +} + +void InitExecutor::initialize() +{ + try { + util::ThreadRename("qt-init"); + qDebug() << __func__ << ": Running initialization in thread"; + interfaces::BlockAndHeaderTipInfo tip_info; + bool rv = m_node.appInitMain(&tip_info); + Q_EMIT initializeResult(rv, tip_info); + } catch (...) { + handleRunawayException(std::current_exception()); + } +} + +void InitExecutor::restart(QStringList args) +{ + static bool executing_restart{false}; + + if(!executing_restart) { // Only restart 1x, no matter how often a user clicks on a restart-button + executing_restart = true; + try { + qDebug() << __func__ << ": Running Restart in thread"; + m_node.appPrepareShutdown(); + qDebug() << __func__ << ": Shutdown finished"; + Q_EMIT shutdownResult(); + CExplicitNetCleanup::callCleanup(); + QProcess::startDetached(QApplication::applicationFilePath(), args); + qDebug() << __func__ << ": Restart initiated..."; + QApplication::quit(); + } catch (...) { + handleRunawayException(std::current_exception()); + } + } +} + +void InitExecutor::shutdown() +{ + try { + qDebug() << __func__ << ": Running Shutdown in thread"; + m_node.appShutdown(); + qDebug() << __func__ << ": Shutdown finished"; + Q_EMIT shutdownResult(); + } catch (...) { + handleRunawayException(std::current_exception()); + } +} diff --git a/src/qt/initexecutor.h b/src/qt/initexecutor.h new file mode 100644 index 0000000000..f4f11fca8b --- /dev/null +++ b/src/qt/initexecutor.h @@ -0,0 +1,47 @@ +// Copyright (c) 2014-2021 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_QT_INITEXECUTOR_H +#define BITCOIN_QT_INITEXECUTOR_H + +#include + +#include + +#include +#include + +QT_BEGIN_NAMESPACE +class QString; +QT_END_NAMESPACE + +/** Class encapsulating Bitcoin Core startup and shutdown. + * Allows running startup and shutdown in a different thread from the UI thread. + */ +class InitExecutor : public QObject +{ + Q_OBJECT +public: + explicit InitExecutor(interfaces::Node& node); + ~InitExecutor(); + +public Q_SLOTS: + void initialize(); + void shutdown(); + void restart(QStringList args); + +Q_SIGNALS: + void initializeResult(bool success, interfaces::BlockAndHeaderTipInfo tip_info); + void shutdownResult(); + void runawayException(const QString& message); + +private: + /// Pass fatal exception message to UI thread + void handleRunawayException(const std::exception_ptr e); + + interfaces::Node& m_node; + QThread m_thread; +}; + +#endif // BITCOIN_QT_INITEXECUTOR_H diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp index a5587373bb..5337fb163c 100644 --- a/src/qt/optionsdialog.cpp +++ b/src/qt/optionsdialog.cpp @@ -325,6 +325,7 @@ void OptionsDialog::setMapper() /* Wallet */ mapper->addMapping(ui->coinControlFeatures, OptionsModel::CoinControlFeatures); + mapper->addMapping(ui->subFeeFromAmount, OptionsModel::SubFeeFromAmount); mapper->addMapping(ui->keepChangeAddress, OptionsModel::KeepChangeAddress); mapper->addMapping(ui->showMasternodesTab, OptionsModel::ShowMasternodesTab); mapper->addMapping(ui->showGovernanceTab, OptionsModel::ShowGovernanceTab); diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp index 874a255b84..fcf84bf5ec 100644 --- a/src/qt/optionsmodel.cpp +++ b/src/qt/optionsmodel.cpp @@ -222,6 +222,11 @@ void OptionsModel::Init(bool resetSettings) if (!gArgs.SoftSetBoolArg("-spendzeroconfchange", settings.value("bSpendZeroConfChange").toBool())) addOverriddenOption("-spendzeroconfchange"); + if (!settings.contains("SubFeeFromAmount")) { + settings.setValue("SubFeeFromAmount", false); + } + m_sub_fee_from_amount = settings.value("SubFeeFromAmount", false).toBool(); + // CoinJoin if (!settings.contains("nCoinJoinSessions")) settings.setValue("nCoinJoinSessions", DEFAULT_COINJOIN_SESSIONS); @@ -458,6 +463,8 @@ QVariant OptionsModel::data(const QModelIndex & index, int role) const #ifdef ENABLE_WALLET case SpendZeroConfChange: return settings.value("bSpendZeroConfChange"); + case SubFeeFromAmount: + return m_sub_fee_from_amount; case ShowMasternodesTab: return settings.value("fShowMasternodesTab"); case ShowGovernanceTab: @@ -633,6 +640,10 @@ bool OptionsModel::setData(const QModelIndex & index, const QVariant & value, in setRestartRequired(true); } break; + case SubFeeFromAmount: + m_sub_fee_from_amount = value.toBool(); + settings.setValue("SubFeeFromAmount", m_sub_fee_from_amount); + break; case ShowGovernanceTab: if (settings.value("fShowGovernanceTab") != value) { settings.setValue("fShowGovernanceTab", value); diff --git a/src/qt/optionsmodel.h b/src/qt/optionsmodel.h index b34804ed21..eaf4a8f6f8 100644 --- a/src/qt/optionsmodel.h +++ b/src/qt/optionsmodel.h @@ -67,6 +67,7 @@ public: FontWeightBold, // int Language, // QString CoinControlFeatures, // bool + SubFeeFromAmount, // bool KeepChangeAddress, // bool ThreadsScriptVerif, // int Prune, // bool @@ -105,6 +106,7 @@ public: int getDisplayUnit() const { return nDisplayUnit; } QString getThirdPartyTxUrls() const { return strThirdPartyTxUrls; } bool getCoinControlFeatures() const { return fCoinControlFeatures; } + bool getSubFeeFromAmount() const { return m_sub_fee_from_amount; } bool getKeepChangeAddress() const { return fKeepChangeAddress; } bool getShowAdvancedCJUI() { return fShowAdvancedCJUI; } const QString& getOverriddenByCommandLine() { return strOverriddenByCommandLine; } @@ -132,6 +134,7 @@ private: int nDisplayUnit; QString strThirdPartyTxUrls; bool fCoinControlFeatures; + bool m_sub_fee_from_amount; bool fKeepChangeAddress; bool fShowAdvancedCJUI; /* settings that were overridden by command-line */ diff --git a/src/qt/sendcoinsentry.cpp b/src/qt/sendcoinsentry.cpp index 7fea4dcbec..004c7853c0 100644 --- a/src/qt/sendcoinsentry.cpp +++ b/src/qt/sendcoinsentry.cpp @@ -103,7 +103,9 @@ void SendCoinsEntry::clear() ui->payTo->clear(); ui->addAsLabel->clear(); ui->payAmount->clear(); - ui->checkboxSubtractFeeFromAmount->setCheckState(Qt::Unchecked); + if (model && model->getOptionsModel()) { + ui->checkboxSubtractFeeFromAmount->setChecked(model->getOptionsModel()->getSubFeeFromAmount()); + } ui->messageTextLabel->clear(); ui->messageTextLabel->hide(); ui->messageLabel->hide(); diff --git a/src/qt/test/test_main.cpp b/src/qt/test/test_main.cpp index 4bf49ba8a0..465bc62060 100644 --- a/src/qt/test/test_main.cpp +++ b/src/qt/test/test_main.cpp @@ -9,6 +9,7 @@ #include #include +#include #include #include #include diff --git a/src/qt/winshutdownmonitor.h b/src/qt/winshutdownmonitor.h index 365e83b9eb..f095d53f44 100644 --- a/src/qt/winshutdownmonitor.h +++ b/src/qt/winshutdownmonitor.h @@ -17,7 +17,7 @@ class WinShutdownMonitor : public QAbstractNativeEventFilter { public: /** Implements QAbstractNativeEventFilter interface for processing Windows messages */ - bool nativeEventFilter(const QByteArray &eventType, void *pMessage, long *pnResult); + bool nativeEventFilter(const QByteArray &eventType, void *pMessage, long *pnResult) override; /** Register the reason for blocking shutdown on Windows to allow clean client exit */ static void registerShutdownBlockReason(const QString& strReason, const HWND& mainWinId); diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp index c97421afd2..2479040381 100644 --- a/src/rpc/client.cpp +++ b/src/rpc/client.cpp @@ -164,6 +164,7 @@ static const CRPCConvertParam vRPCConvertParams[] = { "importmulti", 0, "requests" }, { "importmulti", 1, "options" }, { "importdescriptors", 0, "requests" }, + { "listdescriptors", 0, "private" }, { "verifychain", 0, "checklevel" }, { "verifychain", 1, "nblocks" }, { "getblockstats", 0, "hash_or_height" }, diff --git a/src/txorphanage.h b/src/txorphanage.h index d8ef7a5c44..d3d06c8e53 100644 --- a/src/txorphanage.h +++ b/src/txorphanage.h @@ -50,6 +50,13 @@ public: * (ie orphans that may have found their final missing parent, and so should be reconsidered for the mempool) */ void AddChildrenToWorkSet(const CTransaction& tx, std::set& orphan_work_set) const EXCLUSIVE_LOCKS_REQUIRED(g_cs_orphans); + /** Return how many entries exist in the orphange */ + size_t Size() LOCKS_EXCLUDED(::g_cs_orphans) + { + LOCK(::g_cs_orphans); + return m_orphans.size(); + } + protected: struct OrphanTx { CTransactionRef tx; diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp index d4e93d5d15..3a69d4337f 100644 --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -1941,8 +1941,10 @@ RPCHelpMan listdescriptors() { return RPCHelpMan{ "listdescriptors", - "\nList descriptors imported into a descriptor-enabled wallet.", - {}, + "\nList descriptors imported into a descriptor-enabled wallet.\n", + { + {"private", RPCArg::Type::BOOL, RPCArg::Default{false}, "Show private descriptors."} + }, RPCResult{RPCResult::Type::OBJ, "", "", { {RPCResult::Type::STR, "wallet_name", "Name of wallet this operation was performed on"}, {RPCResult::Type::ARR, "descriptors", "Array of descriptor objects", @@ -1962,6 +1964,7 @@ RPCHelpMan listdescriptors() }}, RPCExamples{ HelpExampleCli("listdescriptors", "") + HelpExampleRpc("listdescriptors", "") + + HelpExampleCli("listdescriptors", "true") + HelpExampleRpc("listdescriptors", "true") }, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { @@ -1972,6 +1975,11 @@ RPCHelpMan listdescriptors() throw JSONRPCError(RPC_WALLET_ERROR, "listdescriptors is not available for non-descriptor wallets"); } + const bool priv = !request.params[0].isNull() && request.params[0].get_bool(); + if (priv) { + EnsureWalletIsUnlocked(*wallet); + } + LOCK(wallet->cs_wallet); UniValue descriptors(UniValue::VARR); @@ -1985,8 +1993,9 @@ RPCHelpMan listdescriptors() LOCK(desc_spk_man->cs_desc_man); const auto& wallet_descriptor = desc_spk_man->GetWalletDescriptor(); std::string descriptor; - if (!desc_spk_man->GetDescriptorString(descriptor)) { - throw JSONRPCError(RPC_WALLET_ERROR, "Can't get normalized descriptor string."); + + if (!desc_spk_man->GetDescriptorString(descriptor, priv)) { + throw JSONRPCError(RPC_WALLET_ERROR, "Can't get descriptor string."); } spk.pushKV("desc", descriptor); spk.pushKV("timestamp", wallet_descriptor.creation_time); diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 4c48f4621d..cbd98674a4 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -4009,7 +4009,7 @@ RPCHelpMan getaddressinfo() DescriptorScriptPubKeyMan* desc_spk_man = dynamic_cast(pwallet->GetScriptPubKeyMan(scriptPubKey)); if (desc_spk_man) { std::string desc_str; - if (desc_spk_man->GetDescriptorString(desc_str)) { + if (desc_spk_man->GetDescriptorString(desc_str, /* priv */ false)) { ret.pushKV("parent_desc", desc_str); } } diff --git a/src/wallet/scriptpubkeyman.cpp b/src/wallet/scriptpubkeyman.cpp index 2a0a19a5da..29ad2f0df8 100644 --- a/src/wallet/scriptpubkeyman.cpp +++ b/src/wallet/scriptpubkeyman.cpp @@ -2403,13 +2403,20 @@ const std::vector DescriptorScriptPubKeyMan::GetScriptPubKeys() const return script_pub_keys; } -bool DescriptorScriptPubKeyMan::GetDescriptorString(std::string& out) const +bool DescriptorScriptPubKeyMan::GetDescriptorString(std::string& out, const bool priv) const { LOCK(cs_desc_man); FlatSigningProvider provider; provider.keys = GetKeys(); + if (priv) { + // For the private version, always return the master key to avoid + // exposing child private keys. The risk implications of exposing child + // private keys together with the parent xpub may be non-obvious for users. + return m_wallet_descriptor.descriptor->ToPrivateString(provider, out); + } + return m_wallet_descriptor.descriptor->ToNormalizedString(provider, out, &m_wallet_descriptor.cache); } diff --git a/src/wallet/scriptpubkeyman.h b/src/wallet/scriptpubkeyman.h index 7b248d7736..0c833a207d 100644 --- a/src/wallet/scriptpubkeyman.h +++ b/src/wallet/scriptpubkeyman.h @@ -600,7 +600,7 @@ public: const WalletDescriptor GetWalletDescriptor() const EXCLUSIVE_LOCKS_REQUIRED(cs_desc_man); const std::vector GetScriptPubKeys() const; - bool GetDescriptorString(std::string& out) const; + bool GetDescriptorString(std::string& out, const bool priv) const; void UpgradeDescriptorCache(); }; diff --git a/test/functional/feature_block.py b/test/functional/feature_block.py index 9776a549d0..973f7d0fa8 100755 --- a/test/functional/feature_block.py +++ b/test/functional/feature_block.py @@ -329,24 +329,24 @@ class FullBlockTest(BitcoinTestFramework): self.move_tip(15) b23 = self.next_block(23, spend=out[6]) tx = CTransaction() - script_length = MAX_BLOCK_SIZE - len(b23.serialize()) - 69 + script_length = MAX_BLOCK_SIZE - b23.get_weight() - 69 script_output = CScript([b'\x00' * script_length]) tx.vout.append(CTxOut(0, script_output)) tx.vin.append(CTxIn(COutPoint(b23.vtx[1].sha256, 0))) b23 = self.update_block(23, [tx]) # Make sure the math above worked out to produce a max-sized block - assert_equal(len(b23.serialize()), MAX_BLOCK_SIZE) + assert_equal(b23.get_weight(), MAX_BLOCK_SIZE) self.send_blocks([b23], True) self.save_spendable_output() self.log.info("Reject a block of size MAX_BLOCK_SIZE + 1") self.move_tip(15) b24 = self.next_block(24, spend=out[6]) - script_length = MAX_BLOCK_SIZE - len(b24.serialize()) - 69 + script_length = MAX_BLOCK_SIZE - b24.get_weight() - 69 script_output = CScript([b'\x00' * (script_length + 1)]) tx.vout = [CTxOut(0, script_output)] b24 = self.update_block(24, [tx]) - assert_equal(len(b24.serialize()), MAX_BLOCK_SIZE + 1) + assert_equal(b24.get_weight(), MAX_BLOCK_SIZE + 1) self.send_blocks([b24], success=False, reject_reason='bad-blk-length', reconnect=True) b25 = self.next_block(25, spend=out[7]) @@ -500,13 +500,13 @@ class FullBlockTest(BitcoinTestFramework): # Until block is full, add tx's with 1 satoshi to p2sh_script, the rest to OP_TRUE tx_new = None tx_last = tx - total_size = len(b39.serialize()) - while(total_size < MAX_BLOCK_SIZE): + total_weight = b39.get_weight() + while total_weight < MAX_BLOCK_SIZE: tx_new = self.create_tx(tx_last, 1, 1, p2sh_script) tx_new.vout.append(CTxOut(tx_last.vout[1].nValue - 1, CScript([OP_TRUE]))) tx_new.rehash() - total_size += len(tx_new.serialize()) - if total_size >= MAX_BLOCK_SIZE: + total_weight += tx_new.get_weight() + if total_weight >= MAX_BLOCK_SIZE: break b39.vtx.append(tx_new) # add tx to block tx_last = tx_new @@ -517,7 +517,7 @@ class FullBlockTest(BitcoinTestFramework): # Make sure we didn't accidentally make too big a block. Note that the # size of the block has non-determinism due to the ECDSA signature in # the first transaction. - while (len(b39.serialize()) >= MAX_BLOCK_SIZE): + while b39.get_weight() >= MAX_BLOCK_SIZE: del b39.vtx[-1] b39 = self.update_block(39, []) @@ -938,7 +938,7 @@ class FullBlockTest(BitcoinTestFramework): tx.vout.append(CTxOut(0, script_output)) tx.vin.append(CTxIn(COutPoint(b64a.vtx[1].sha256, 0))) b64a = self.update_block("64a", [tx]) - assert_equal(len(b64a.serialize()), MAX_BLOCK_SIZE + 8) + assert_equal(b64a.get_weight(), MAX_BLOCK_SIZE + 8) self.send_blocks([b64a], success=False, reject_reason='non-canonical ReadCompactSize()') # dashd doesn't disconnect us for sending a bloated block, but if we subsequently @@ -952,7 +952,7 @@ class FullBlockTest(BitcoinTestFramework): b64 = CBlock(b64a) b64.vtx = copy.deepcopy(b64a.vtx) assert_equal(b64.hash, b64a.hash) - assert_equal(len(b64.serialize()), MAX_BLOCK_SIZE) + assert_equal(b64.get_weight(), MAX_BLOCK_SIZE) self.blocks[64] = b64 b64 = self.update_block(64, []) self.send_blocks([b64], True) @@ -1290,12 +1290,12 @@ class FullBlockTest(BitcoinTestFramework): for i in range(89, LARGE_REORG_SIZE + 89): b = self.next_block(i, spend) tx = CTransaction() - script_length = MAX_BLOCK_SIZE - len(b.serialize()) - 69 + script_length = MAX_BLOCK_SIZE - b.get_weight() - 69 script_output = CScript([b'\x00' * script_length]) tx.vout.append(CTxOut(0, script_output)) tx.vin.append(CTxIn(COutPoint(b.vtx[1].sha256, 0))) b = self.update_block(i, [tx]) - assert_equal(len(b.serialize()), MAX_BLOCK_SIZE) + assert_equal(b.get_weight(), MAX_BLOCK_SIZE) blocks.append(b) self.save_spendable_output() spend = self.get_spendable_output() diff --git a/test/functional/mining_prioritisetransaction.py b/test/functional/mining_prioritisetransaction.py index 31b0c15adb..6fee0e876e 100755 --- a/test/functional/mining_prioritisetransaction.py +++ b/test/functional/mining_prioritisetransaction.py @@ -55,8 +55,8 @@ class PrioritiseTransactionTest(BitcoinTestFramework): txids[i] = create_lots_of_big_transactions(self.nodes[0], self.txouts, utxos[start_range:end_range], end_range - start_range, (i+1)*base_fee) # Make sure that the size of each group of transactions exceeds - # MAX_BLOCK_SIZE -- otherwise the test needs to be revised to create - # more transactions. + # MAX_BLOCK_SIZE -- otherwise the test needs to be revised to + # create more transactions. mempool = self.nodes[0].getrawmempool(True) sizes = [0, 0, 0] for i in range(3): diff --git a/test/functional/p2p_permissions.py b/test/functional/p2p_permissions.py index e7e82eccb5..71ebfd38f9 100755 --- a/test/functional/p2p_permissions.py +++ b/test/functional/p2p_permissions.py @@ -133,7 +133,7 @@ class P2PPermissionsTests(BitcoinTestFramework): tx.vout[0].nValue += 1 txid = tx.rehash() # Send the transaction twice. The first time, it'll be rejected by ATMP because it conflicts - # with a mempool transaction. The second time, it'll be in the recentRejects filter. + # with a mempool transaction. The second time, it'll be in the m_recent_rejects filter. p2p_rebroadcast_wallet.send_txs_and_test( [tx], self.nodes[1], diff --git a/test/functional/test_framework/messages.py b/test/functional/test_framework/messages.py index 100b91c9a2..7611ec118c 100755 --- a/test/functional/test_framework/messages.py +++ b/test/functional/test_framework/messages.py @@ -546,6 +546,7 @@ class CTransaction: def get_vsize(self): return len(self.serialize()) + # it's just a helper that return vsize to reduce conflicts during backporting def get_weight(self): return self.get_vsize() @@ -681,6 +682,10 @@ class CBlock(CBlockHeader): self.nNonce += 1 self.rehash() + # it's just a helper that return vsize to reduce conflicts during backporting + def get_weight(self): + return len(self.serialize()) + def __repr__(self): return "CBlock(nVersion=%i hashPrevBlock=%064x hashMerkleRoot=%064x nTime=%s nBits=%08x nNonce=%08x vtx=%s)" \ % (self.nVersion, self.hashPrevBlock, self.hashMerkleRoot, diff --git a/test/functional/wallet_listdescriptors.py b/test/functional/wallet_listdescriptors.py index 8896a765f0..b6c82e64e9 100755 --- a/test/functional/wallet_listdescriptors.py +++ b/test/functional/wallet_listdescriptors.py @@ -72,11 +72,39 @@ class ListDescriptorsTest(BitcoinTestFramework): ], } assert_equal(expected, wallet.listdescriptors()) + assert_equal(expected, wallet.listdescriptors(False)) + + self.log.info('Test list private descriptors') + expected_private = { + 'wallet_name': 'w2', + 'descriptors': [ + {'desc': descsum_create('pkh(' + xprv + hardened_path + '/0/*)'), + 'timestamp': 1296688602, + 'active': False, + 'range': [0, 0], + 'next': 0}, + ], + } + assert_equal(expected_private, wallet.listdescriptors(True)) self.log.info("Test listdescriptors with encrypted wallet") wallet.encryptwallet("pass") assert_equal(expected, wallet.listdescriptors()) + self.log.info('Test list private descriptors with encrypted wallet') + assert_raises_rpc_error(-13, 'Please enter the wallet passphrase with walletpassphrase first.', wallet.listdescriptors, True) + wallet.walletpassphrase(passphrase="pass", timeout=1000000) + assert_equal(expected_private, wallet.listdescriptors(True)) + + self.log.info('Test list private descriptors with watch-only wallet') + node.createwallet(wallet_name='watch-only', descriptors=True, disable_private_keys=True) + watch_only_wallet = node.get_wallet_rpc('watch-only') + watch_only_wallet.importdescriptors([{ + 'desc': descsum_create('pkh(' + xpub_acc + ')'), + 'timestamp': 1296688602, + }]) + assert_raises_rpc_error(-4, 'Can\'t get descriptor string', watch_only_wallet.listdescriptors, True) + self.log.info('Test non-active non-range combo descriptor') node.createwallet(wallet_name='w4', blank=True, descriptors=True) wallet = node.get_wallet_rpc('w4')