diff --git a/src/interfaces/wallet.h b/src/interfaces/wallet.h --- a/src/interfaces/wallet.h +++ b/src/interfaces/wallet.h @@ -223,6 +223,9 @@ // Get default address type. virtual OutputType getDefaultAddressType() = 0; + // Get default change type. + virtual OutputType getDefaultChangeType() = 0; + //! Register handler for show progress messages. using ShowProgressFn = std::function; diff --git a/src/interfaces/wallet.cpp b/src/interfaces/wallet.cpp --- a/src/interfaces/wallet.cpp +++ b/src/interfaces/wallet.cpp @@ -381,7 +381,12 @@ return result; } bool hdEnabled() override { return m_wallet.IsHDEnabled(); } - OutputType getDefaultAddressType() override { return g_address_type; } + OutputType getDefaultAddressType() override { + return m_wallet.m_default_address_type; + } + OutputType getDefaultChangeType() override { + return m_wallet.m_default_change_type; + } std::unique_ptr handleShowProgress(ShowProgressFn fn) override { return MakeHandler(m_wallet.ShowProgress.connect(fn)); diff --git a/src/qt/addresstablemodel.h b/src/qt/addresstablemodel.h --- a/src/qt/addresstablemodel.h +++ b/src/qt/addresstablemodel.h @@ -95,6 +95,8 @@ EditStatus getEditStatus() const { return editStatus; } + OutputType GetDefaultAddressType() const; + private: WalletModel *walletModel; AddressTablePriv *priv; diff --git a/src/qt/addresstablemodel.cpp b/src/qt/addresstablemodel.cpp --- a/src/qt/addresstablemodel.cpp +++ b/src/qt/addresstablemodel.cpp @@ -403,6 +403,10 @@ } } +OutputType AddressTableModel::GetDefaultAddressType() const { + return walletModel->wallet().getDefaultAddressType(); +}; + void AddressTableModel::emitDataChanged(int idx) { Q_EMIT dataChanged(index(idx, 0, QModelIndex()), index(idx, columns.length() - 1, QModelIndex())); diff --git a/src/qt/editaddressdialog.cpp b/src/qt/editaddressdialog.cpp --- a/src/qt/editaddressdialog.cpp +++ b/src/qt/editaddressdialog.cpp @@ -11,8 +11,6 @@ #include #include -extern OutputType g_address_type; - EditAddressDialog::EditAddressDialog(Mode _mode, QWidget *parent) : QDialog(parent), ui(new Ui::EditAddressDialog), mapper(0), mode(_mode), model(0) { @@ -71,7 +69,8 @@ address = model->addRow( mode == NewSendingAddress ? AddressTableModel::Send : AddressTableModel::Receive, - ui->labelEdit->text(), ui->addressEdit->text(), g_address_type); + ui->labelEdit->text(), ui->addressEdit->text(), + model->GetDefaultAddressType()); break; case EditReceivingAddress: case EditSendingAddress: diff --git a/src/qt/paymentserver.cpp b/src/qt/paymentserver.cpp --- a/src/qt/paymentserver.cpp +++ b/src/qt/paymentserver.cpp @@ -707,7 +707,9 @@ // type we use subject to privacy issues, but not restricted by what // other software supports. const OutputType change_type = - g_change_type != OutputType::NONE ? g_change_type : g_address_type; + walletModel->wallet().getDefaultChangeType() != OutputType::NONE + ? walletModel->wallet().getDefaultChangeType() + : walletModel->wallet().getDefaultAddressType(); walletModel->wallet().learnRelatedScripts(newKey, change_type); CTxDestination dest = GetDestinationForKey(newKey, change_type); std::string label = tr("Refund from %1") diff --git a/src/qt/test/wallettests.cpp b/src/qt/test/wallettests.cpp --- a/src/qt/test/wallettests.cpp +++ b/src/qt/test/wallettests.cpp @@ -114,9 +114,6 @@ } #endif - g_address_type = OutputType::LEGACY; - g_change_type = OutputType::LEGACY; - // Set up wallet and chain with 105 blocks (5 mature blocks for spending). TestChain100Setup test; for (int i = 0; i < 5; ++i) { @@ -129,7 +126,8 @@ { LOCK(wallet.cs_wallet); wallet.SetAddressBook( - GetDestinationForKey(test.coinbaseKey.GetPubKey(), g_address_type), + GetDestinationForKey(test.coinbaseKey.GetPubKey(), + wallet.m_default_address_type), "", "receive"); wallet.AddKeyPubKey(test.coinbaseKey, test.coinbaseKey.GetPubKey()); } diff --git a/src/wallet/coincontrol.h b/src/wallet/coincontrol.h --- a/src/wallet/coincontrol.h +++ b/src/wallet/coincontrol.h @@ -13,11 +13,9 @@ /** Coin Control Features. */ class CCoinControl { public: - //! Custom change destination, if not set an address is generated CTxDestination destChange; - //! Custom change type, ignored if destChange is set, defaults to - //! g_change_type - OutputType change_type; + //! Override the default change type if set, ignored if destChange is set + boost::optional m_change_type; //! If false, allows unselected inputs, but requires all selected inputs be //! used bool fAllowOtherInputs; diff --git a/src/wallet/coincontrol.cpp b/src/wallet/coincontrol.cpp --- a/src/wallet/coincontrol.cpp +++ b/src/wallet/coincontrol.cpp @@ -8,7 +8,7 @@ void CCoinControl::SetNull() { destChange = CNoDestination(); - change_type = g_change_type; + m_change_type.reset(); fAllowOtherInputs = false; fAllowWatchOnly = false; m_avoid_partial_spends = diff --git a/src/wallet/init.cpp b/src/wallet/init.cpp --- a/src/wallet/init.cpp +++ b/src/wallet/init.cpp @@ -265,9 +265,6 @@ } } - g_address_type = OutputType::DEFAULT; - g_change_type = OutputType::DEFAULT; - return true; } diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -85,7 +85,9 @@ } if (!fLabelFound) { strAddr = EncodeDestination( - GetDestinationForKey(key.GetPubKey(), g_address_type), config); + GetDestinationForKey(key.GetPubKey(), + pwallet->m_default_address_type), + config); } return fLabelFound; } diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -180,10 +180,10 @@ label = LabelFromValue(request.params[0]); } - OutputType output_type = g_address_type; + OutputType output_type = pwallet->m_default_address_type; if (!request.params[1].isNull()) { - output_type = - ParseOutputType(request.params[1].get_str(), g_address_type); + output_type = ParseOutputType(request.params[1].get_str(), + pwallet->m_default_address_type); if (output_type == OutputType::NONE) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Unknown address type '%s'", @@ -285,8 +285,9 @@ pwallet->TopUpKeyPool(); } - OutputType output_type = - g_change_type != OutputType::NONE ? g_change_type : g_address_type; + OutputType output_type = pwallet->m_default_change_type != OutputType::NONE + ? pwallet->m_default_change_type + : pwallet->m_default_address_type; if (!request.params[0].isNull()) { output_type = ParseOutputType(request.params[0].get_str(), output_type); if (output_type == OutputType::NONE) { @@ -1450,12 +1451,14 @@ } } + OutputType output_type = pwallet->m_default_address_type; + // Construct using pay-to-script-hash: CScript inner = CreateMultisigRedeemscript(required, pubkeys); pwallet->AddCScript(inner); CTxDestination dest = - pwallet->AddAndGetDestinationForScript(inner, g_address_type); + pwallet->AddAndGetDestinationForScript(inner, output_type); pwallet->SetAddressBook(dest, label, "send"); diff --git a/src/wallet/test/wallet_test_fixture.cpp b/src/wallet/test/wallet_test_fixture.cpp --- a/src/wallet/test/wallet_test_fixture.cpp +++ b/src/wallet/test/wallet_test_fixture.cpp @@ -14,8 +14,6 @@ : TestingSetup(chainName), m_wallet(Params(), "mock", WalletDatabase::CreateMock()) { bool fFirstRun; - g_address_type = OutputType::DEFAULT; - g_change_type = OutputType::DEFAULT; m_wallet.LoadWallet(fFirstRun); RegisterValidationInterface(&m_wallet); diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp --- a/src/wallet/test/wallet_tests.cpp +++ b/src/wallet/test/wallet_tests.cpp @@ -122,9 +122,6 @@ // importwallet RPC would start the scan at the latest block with timestamp less // than or equal to key birthday. BOOST_FIXTURE_TEST_CASE(importwallet_rescan, TestChain100Setup) { - g_address_type = OutputType::DEFAULT; - g_change_type = OutputType::DEFAULT; - // Create two blocks with same timestamp to verify that importwallet rescan // will pick up both blocks, not just the first. const int64_t BLOCK_TIME = chainActive.Tip()->GetBlockTimeMax() + 5; @@ -290,8 +287,6 @@ ListCoinsTestingSetup() { CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())); - g_address_type = OutputType::DEFAULT; - g_change_type = OutputType::DEFAULT; wallet = std::make_unique(Params(), "mock", WalletDatabase::CreateMock()); bool firstRun; diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -37,6 +37,7 @@ std::vector GetWallets(); CWallet *GetWallet(const std::string &name); +//! Default for -keypool static const unsigned int DEFAULT_KEYPOOL_SIZE = 1000; //! -paytxfee default constexpr Amount DEFAULT_PAY_TX_FEE = Amount::zero(); @@ -93,12 +94,10 @@ enum class OutputType { NONE, LEGACY, - - DEFAULT = LEGACY, }; -extern OutputType g_address_type; -extern OutputType g_change_type; +//! Default for -addresstype +constexpr OutputType DEFAULT_ADDRESS_TYPE{OutputType::LEGACY}; /** A key pool entry */ class CKeyPool { @@ -1067,6 +1066,9 @@ * -fallbackfee */ CFeeRate m_fallback_fee{DEFAULT_FALLBACK_FEE}; + OutputType m_default_address_type{DEFAULT_ADDRESS_TYPE}; + // Default to OutputType::NONE if not set by -changetype + OutputType m_default_change_type{OutputType::NONE}; bool NewKeyPool(); size_t KeypoolCountExternalKeys(); @@ -1322,8 +1324,7 @@ } }; -OutputType ParseOutputType(const std::string &str, - OutputType default_type = OutputType::DEFAULT); +OutputType ParseOutputType(const std::string &str, OutputType default_type); const std::string &FormatOutputType(OutputType type); /** diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -91,9 +91,6 @@ static const size_t OUTPUT_GROUP_MAX_ENTRIES = 10; -OutputType g_address_type = OutputType::NONE; -OutputType g_change_type = OutputType::NONE; - const uint32_t BIP32_HARDENED_KEY_LIMIT = 0x80000000; const uint256 CMerkleTx::ABANDON_HASH(uint256S( @@ -940,8 +937,8 @@ } else { // Check if the current key has been used (TODO: check other // addresses with the same key) - CScript scriptPubKey = GetScriptForDestination( - GetDestinationForKey(account.vchPubKey, g_address_type)); + CScript scriptPubKey = GetScriptForDestination(GetDestinationForKey( + account.vchPubKey, m_default_address_type)); for (std::map::iterator it = mapWallet.begin(); it != mapWallet.end() && account.vchPubKey.IsValid(); ++it) { for (const CTxOut &txout : (*it).second.tx->vout) { @@ -960,12 +957,12 @@ return false; } - LearnRelatedScripts(account.vchPubKey, g_address_type); - dest = GetDestinationForKey(account.vchPubKey, g_address_type); + LearnRelatedScripts(account.vchPubKey, m_default_address_type); + dest = GetDestinationForKey(account.vchPubKey, m_default_address_type); SetAddressBook(dest, label, "receive"); batch.WriteAccount(label, account); } else { - dest = GetDestinationForKey(account.vchPubKey, g_address_type); + dest = GetDestinationForKey(account.vchPubKey, m_default_address_type); } return true; @@ -2897,13 +2894,13 @@ return change_type; } - // if g_address_type is legacy, use legacy address as change. - if (g_address_type == OutputType::LEGACY) { + // if m_default_address_type is legacy, use legacy address as change. + if (m_default_address_type == OutputType::LEGACY) { return OutputType::LEGACY; } - // else use g_address_type for change - return g_address_type; + // else use m_default_address_type for change + return m_default_address_type; } bool CWallet::CreateTransaction(const std::vector &vecSend, @@ -3006,8 +3003,10 @@ return false; } - const OutputType change_type = - TransactionChangeType(coinControl.change_type, vecSend); + const OutputType change_type = TransactionChangeType( + coinControl.m_change_type ? *coinControl.m_change_type + : m_default_change_type, + vecSend); LearnRelatedScripts(vchPubKey, change_type); scriptChange = GetScriptForDestination( @@ -4484,6 +4483,9 @@ walletInstance->m_spend_zero_conf_change = gArgs.GetBoolArg("-spendzeroconfchange", DEFAULT_SPEND_ZEROCONF_CHANGE); + walletInstance->m_default_address_type = DEFAULT_ADDRESS_TYPE; + walletInstance->m_default_change_type = OutputType::NONE; + LogPrintf(" wallet %15dms\n", GetTimeMillis() - nStart); // Try to top up keypool. No-op if the wallet is locked.