aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core_read.cpp26
-rw-r--r--src/dummywallet.cpp4
-rw-r--r--src/init/bitcoin-gui.cpp4
-rw-r--r--src/init/bitcoin-node.cpp4
-rw-r--r--src/init/bitcoin-qt.cpp4
-rw-r--r--src/init/bitcoind.cpp4
-rw-r--r--src/interfaces/init.cpp2
-rw-r--r--src/interfaces/init.h4
-rw-r--r--src/interfaces/node.h8
-rw-r--r--src/interfaces/wallet.h9
-rw-r--r--src/node/context.h4
-rw-r--r--src/node/interfaces.cpp6
-rw-r--r--src/node/ui_interface.h2
-rw-r--r--src/qt/bitcoingui.cpp2
-rw-r--r--src/qt/forms/receivecoinsdialog.ui10
-rw-r--r--src/qt/receivecoinsdialog.cpp26
-rw-r--r--src/qt/splashscreen.cpp2
-rw-r--r--src/qt/test/addressbooktests.cpp6
-rw-r--r--src/qt/test/wallettests.cpp6
-rw-r--r--src/qt/walletcontroller.cpp10
-rw-r--r--src/qt/walletmodel.cpp2
-rw-r--r--src/test/fuzz/block.cpp2
-rw-r--r--src/test/util/setup_common.cpp10
-rw-r--r--src/wallet/feebumper.cpp4
-rw-r--r--src/wallet/init.cpp6
-rw-r--r--src/wallet/interfaces.cpp19
-rw-r--r--src/wallet/rpc/addresses.cpp7
-rw-r--r--src/wallet/test/init_test_fixture.cpp2
-rw-r--r--src/wallet/test/init_test_fixture.h2
-rw-r--r--src/wallet/test/init_tests.cpp14
-rw-r--r--src/wallet/test/wallet_test_fixture.cpp2
-rw-r--r--src/wallet/test/wallet_test_fixture.h2
-rw-r--r--src/wallet/wallet.cpp61
-rw-r--r--src/wallet/wallet.h2
34 files changed, 164 insertions, 114 deletions
diff --git a/src/core_read.cpp b/src/core_read.cpp
index 484f41f262..1f9227bf0b 100644
--- a/src/core_read.cpp
+++ b/src/core_read.cpp
@@ -21,13 +21,15 @@
#include <string>
namespace {
-
-opcodetype ParseOpCode(const std::string& s)
+class OpCodeParser
{
- static std::map<std::string, opcodetype> mapOpNames;
+private:
+ std::map<std::string, opcodetype> mapOpNames;
- if (mapOpNames.empty()) {
- for (unsigned int op = 0; op <= MAX_OPCODE; op++) {
+public:
+ OpCodeParser()
+ {
+ for (unsigned int op = 0; op <= MAX_OPCODE; ++op) {
// Allow OP_RESERVED to get into mapOpNames
if (op < OP_NOP && op != OP_RESERVED) {
continue;
@@ -44,10 +46,18 @@ opcodetype ParseOpCode(const std::string& s)
}
}
}
+ opcodetype Parse(const std::string& s) const
+ {
+ auto it = mapOpNames.find(s);
+ if (it == mapOpNames.end()) throw std::runtime_error("script parse error: unknown opcode");
+ return it->second;
+ }
+};
- auto it = mapOpNames.find(s);
- if (it == mapOpNames.end()) throw std::runtime_error("script parse error: unknown opcode");
- return it->second;
+opcodetype ParseOpCode(const std::string& s)
+{
+ static const OpCodeParser ocp;
+ return ocp.Parse(s);
}
} // namespace
diff --git a/src/dummywallet.cpp b/src/dummywallet.cpp
index 7f6471740f..6aa89a2402 100644
--- a/src/dummywallet.cpp
+++ b/src/dummywallet.cpp
@@ -12,7 +12,7 @@ namespace interfaces {
class Chain;
class Handler;
class Wallet;
-class WalletClient;
+class WalletLoader;
}
class DummyWalletInit : public WalletInitInterface {
@@ -64,7 +64,7 @@ std::unique_ptr<Wallet> MakeWallet(const std::shared_ptr<CWallet>& wallet)
throw std::logic_error("Wallet function called in non-wallet build.");
}
-std::unique_ptr<WalletClient> MakeWalletClient(Chain& chain, ArgsManager& args)
+std::unique_ptr<WalletLoader> MakeWalletLoader(Chain& chain, ArgsManager& args)
{
throw std::logic_error("Wallet function called in non-wallet build.");
}
diff --git a/src/init/bitcoin-gui.cpp b/src/init/bitcoin-gui.cpp
index c549ed3cc0..f13bd4a05d 100644
--- a/src/init/bitcoin-gui.cpp
+++ b/src/init/bitcoin-gui.cpp
@@ -27,9 +27,9 @@ public:
}
std::unique_ptr<interfaces::Node> makeNode() override { return interfaces::MakeNode(m_node); }
std::unique_ptr<interfaces::Chain> makeChain() override { return interfaces::MakeChain(m_node); }
- std::unique_ptr<interfaces::WalletClient> makeWalletClient(interfaces::Chain& chain) override
+ std::unique_ptr<interfaces::WalletLoader> makeWalletLoader(interfaces::Chain& chain) override
{
- return MakeWalletClient(chain, *Assert(m_node.args));
+ return MakeWalletLoader(chain, *Assert(m_node.args));
}
std::unique_ptr<interfaces::Echo> makeEcho() override { return interfaces::MakeEcho(); }
interfaces::Ipc* ipc() override { return m_ipc.get(); }
diff --git a/src/init/bitcoin-node.cpp b/src/init/bitcoin-node.cpp
index fa56153745..be6dfefe7d 100644
--- a/src/init/bitcoin-node.cpp
+++ b/src/init/bitcoin-node.cpp
@@ -29,9 +29,9 @@ public:
}
std::unique_ptr<interfaces::Node> makeNode() override { return interfaces::MakeNode(m_node); }
std::unique_ptr<interfaces::Chain> makeChain() override { return interfaces::MakeChain(m_node); }
- std::unique_ptr<interfaces::WalletClient> makeWalletClient(interfaces::Chain& chain) override
+ std::unique_ptr<interfaces::WalletLoader> makeWalletLoader(interfaces::Chain& chain) override
{
- return MakeWalletClient(chain, *Assert(m_node.args));
+ return MakeWalletLoader(chain, *Assert(m_node.args));
}
std::unique_ptr<interfaces::Echo> makeEcho() override { return interfaces::MakeEcho(); }
interfaces::Ipc* ipc() override { return m_ipc.get(); }
diff --git a/src/init/bitcoin-qt.cpp b/src/init/bitcoin-qt.cpp
index d71177e885..17a074cb8d 100644
--- a/src/init/bitcoin-qt.cpp
+++ b/src/init/bitcoin-qt.cpp
@@ -24,9 +24,9 @@ public:
}
std::unique_ptr<interfaces::Node> makeNode() override { return interfaces::MakeNode(m_node); }
std::unique_ptr<interfaces::Chain> makeChain() override { return interfaces::MakeChain(m_node); }
- std::unique_ptr<interfaces::WalletClient> makeWalletClient(interfaces::Chain& chain) override
+ std::unique_ptr<interfaces::WalletLoader> makeWalletLoader(interfaces::Chain& chain) override
{
- return MakeWalletClient(chain, *Assert(m_node.args));
+ return MakeWalletLoader(chain, *Assert(m_node.args));
}
std::unique_ptr<interfaces::Echo> makeEcho() override { return interfaces::MakeEcho(); }
NodeContext m_node;
diff --git a/src/init/bitcoind.cpp b/src/init/bitcoind.cpp
index 9c8d5bd9bb..9c2e44569a 100644
--- a/src/init/bitcoind.cpp
+++ b/src/init/bitcoind.cpp
@@ -24,9 +24,9 @@ public:
}
std::unique_ptr<interfaces::Node> makeNode() override { return interfaces::MakeNode(m_node); }
std::unique_ptr<interfaces::Chain> makeChain() override { return interfaces::MakeChain(m_node); }
- std::unique_ptr<interfaces::WalletClient> makeWalletClient(interfaces::Chain& chain) override
+ std::unique_ptr<interfaces::WalletLoader> makeWalletLoader(interfaces::Chain& chain) override
{
- return MakeWalletClient(chain, *Assert(m_node.args));
+ return MakeWalletLoader(chain, *Assert(m_node.args));
}
std::unique_ptr<interfaces::Echo> makeEcho() override { return interfaces::MakeEcho(); }
NodeContext& m_node;
diff --git a/src/interfaces/init.cpp b/src/interfaces/init.cpp
index a3c949e616..f0f8aa5fed 100644
--- a/src/interfaces/init.cpp
+++ b/src/interfaces/init.cpp
@@ -11,7 +11,7 @@
namespace interfaces {
std::unique_ptr<Node> Init::makeNode() { return {}; }
std::unique_ptr<Chain> Init::makeChain() { return {}; }
-std::unique_ptr<WalletClient> Init::makeWalletClient(Chain& chain) { return {}; }
+std::unique_ptr<WalletLoader> Init::makeWalletLoader(Chain& chain) { return {}; }
std::unique_ptr<Echo> Init::makeEcho() { return {}; }
Ipc* Init::ipc() { return nullptr; }
} // namespace interfaces
diff --git a/src/interfaces/init.h b/src/interfaces/init.h
index 2a38054a17..a4ecf4b5d1 100644
--- a/src/interfaces/init.h
+++ b/src/interfaces/init.h
@@ -14,7 +14,7 @@ class Chain;
class Echo;
class Ipc;
class Node;
-class WalletClient;
+class WalletLoader;
//! Initial interface created when a process is first started, and used to give
//! and get access to other interfaces (Node, Chain, Wallet, etc).
@@ -29,7 +29,7 @@ public:
virtual ~Init() = default;
virtual std::unique_ptr<Node> makeNode();
virtual std::unique_ptr<Chain> makeChain();
- virtual std::unique_ptr<WalletClient> makeWalletClient(Chain& chain);
+ virtual std::unique_ptr<WalletLoader> makeWalletLoader(Chain& chain);
virtual std::unique_ptr<Echo> makeEcho();
virtual Ipc* ipc();
};
diff --git a/src/interfaces/node.h b/src/interfaces/node.h
index 974156e6e1..cf45b0b392 100644
--- a/src/interfaces/node.h
+++ b/src/interfaces/node.h
@@ -37,7 +37,7 @@ struct bilingual_str;
namespace interfaces {
class Handler;
-class WalletClient;
+class WalletLoader;
struct BlockTip;
//! Block and header tip information
@@ -187,8 +187,8 @@ public:
//! Broadcast transaction.
virtual TransactionError broadcastTransaction(CTransactionRef tx, CAmount max_tx_fee, std::string& err_string) = 0;
- //! Get wallet client.
- virtual WalletClient& walletClient() = 0;
+ //! Get wallet loader.
+ virtual WalletLoader& walletLoader() = 0;
//! Register handler for init messages.
using InitMessageFn = std::function<void(const std::string& message)>;
@@ -210,7 +210,7 @@ public:
using ShowProgressFn = std::function<void(const std::string& title, int progress, bool resume_possible)>;
virtual std::unique_ptr<Handler> handleShowProgress(ShowProgressFn fn) = 0;
- //! Register handler for wallet client constructed messages.
+ //! Register handler for wallet loader constructed messages.
using InitWalletFn = std::function<void()>;
virtual std::unique_ptr<Handler> handleInitWallet(InitWalletFn fn) = 0;
diff --git a/src/interfaces/wallet.h b/src/interfaces/wallet.h
index 4213a22749..a02134f2b2 100644
--- a/src/interfaces/wallet.h
+++ b/src/interfaces/wallet.h
@@ -256,6 +256,9 @@ public:
// Return whether private keys enabled.
virtual bool privateKeysDisabled() = 0;
+ // Return whether the wallet contains a Taproot scriptPubKeyMan
+ virtual bool taprootEnabled() = 0;
+
// Return whether wallet uses an external signer.
virtual bool hasExternalSigner() = 0;
@@ -310,7 +313,7 @@ public:
//! Wallet chain client that in addition to having chain client methods for
//! starting up, shutting down, and registering RPCs, also has additional
//! methods (called by the GUI) to load and create wallets.
-class WalletClient : public ChainClient
+class WalletLoader : public ChainClient
{
public:
//! Create new wallet.
@@ -419,9 +422,9 @@ struct WalletTxOut
//! dummywallet.cpp and throws if the wallet component is not compiled.
std::unique_ptr<Wallet> MakeWallet(WalletContext& context, const std::shared_ptr<CWallet>& wallet);
-//! Return implementation of ChainClient interface for a wallet client. This
+//! Return implementation of ChainClient interface for a wallet loader. This
//! function will be undefined in builds where ENABLE_WALLET is false.
-std::unique_ptr<WalletClient> MakeWalletClient(Chain& chain, ArgsManager& args);
+std::unique_ptr<WalletLoader> MakeWalletLoader(Chain& chain, ArgsManager& args);
} // namespace interfaces
diff --git a/src/node/context.h b/src/node/context.h
index 26873345b4..e0f85ec6fc 100644
--- a/src/node/context.h
+++ b/src/node/context.h
@@ -23,7 +23,7 @@ namespace interfaces {
class Chain;
class ChainClient;
class Init;
-class WalletClient;
+class WalletLoader;
} // namespace interfaces
//! NodeContext struct containing references to chain state and connection
@@ -52,7 +52,7 @@ struct NodeContext {
std::vector<std::unique_ptr<interfaces::ChainClient>> chain_clients;
//! Reference to chain client that should used to load or create wallets
//! opened by the gui.
- interfaces::WalletClient* wallet_client{nullptr};
+ interfaces::WalletLoader* wallet_loader{nullptr};
std::unique_ptr<CScheduler> scheduler;
std::function<void()> rpc_interruption_point = [] {};
diff --git a/src/node/interfaces.cpp b/src/node/interfaces.cpp
index 8109dce2c0..21bfdff5da 100644
--- a/src/node/interfaces.cpp
+++ b/src/node/interfaces.cpp
@@ -63,7 +63,7 @@ using interfaces::FoundBlock;
using interfaces::Handler;
using interfaces::MakeHandler;
using interfaces::Node;
-using interfaces::WalletClient;
+using interfaces::WalletLoader;
namespace node {
namespace {
@@ -280,9 +280,9 @@ public:
{
return BroadcastTransaction(*m_context, std::move(tx), err_string, max_tx_fee, /*relay=*/ true, /*wait_callback=*/ false);
}
- WalletClient& walletClient() override
+ WalletLoader& walletLoader() override
{
- return *Assert(m_context->wallet_client);
+ return *Assert(m_context->wallet_loader);
}
std::unique_ptr<Handler> handleInitMessage(InitMessageFn fn) override
{
diff --git a/src/node/ui_interface.h b/src/node/ui_interface.h
index f969bcde21..5e11b08976 100644
--- a/src/node/ui_interface.h
+++ b/src/node/ui_interface.h
@@ -82,7 +82,7 @@ public:
/** Progress message during initialization. */
ADD_SIGNALS_DECL_WRAPPER(InitMessage, void, const std::string& message);
- /** Wallet client created. */
+ /** Wallet loader created. */
ADD_SIGNALS_DECL_WRAPPER(InitWallet, void, );
/** Number of network connections changed. */
diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp
index 81a1d88d20..e7d4006a70 100644
--- a/src/qt/bitcoingui.cpp
+++ b/src/qt/bitcoingui.cpp
@@ -1242,7 +1242,7 @@ void BitcoinGUI::incomingTransaction(const QString& date, int unit, const CAmoun
// On new transaction, make an info balloon
QString msg = tr("Date: %1\n").arg(date) +
tr("Amount: %1\n").arg(BitcoinUnits::formatWithUnit(unit, amount, true));
- if (m_node.walletClient().getWallets().size() > 1 && !walletName.isEmpty()) {
+ if (m_node.walletLoader().getWallets().size() > 1 && !walletName.isEmpty()) {
msg += tr("Wallet: %1\n").arg(walletName);
}
msg += tr("Type: %1\n").arg(type);
diff --git a/src/qt/forms/receivecoinsdialog.ui b/src/qt/forms/receivecoinsdialog.ui
index 06d39426c9..4b2c3ed434 100644
--- a/src/qt/forms/receivecoinsdialog.ui
+++ b/src/qt/forms/receivecoinsdialog.ui
@@ -195,7 +195,7 @@
</widget>
</item>
<item>
- <widget class="QCheckBox" name="useBech32">
+ <widget class="QComboBox" name="addressType">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
@@ -211,12 +211,6 @@
<property name="focusPolicy">
<enum>Qt::StrongFocus</enum>
</property>
- <property name="toolTip">
- <string>Native segwit addresses (aka Bech32 or BIP-173) reduce your transaction fees later on and offer better protection against typos, but old wallets don't support them. When unchecked, an address compatible with older wallets will be created instead.</string>
- </property>
- <property name="text">
- <string>Generate native segwit (Bech32) address</string>
- </property>
</widget>
</item>
<item>
@@ -366,7 +360,7 @@
<tabstops>
<tabstop>reqLabel</tabstop>
<tabstop>reqAmount</tabstop>
- <tabstop>useBech32</tabstop>
+ <tabstop>addressType</tabstop>
<tabstop>reqMessage</tabstop>
<tabstop>receiveButton</tabstop>
<tabstop>clearButton</tabstop>
diff --git a/src/qt/receivecoinsdialog.cpp b/src/qt/receivecoinsdialog.cpp
index d47ee95826..0d859a8253 100644
--- a/src/qt/receivecoinsdialog.cpp
+++ b/src/qt/receivecoinsdialog.cpp
@@ -87,10 +87,18 @@ void ReceiveCoinsDialog::setModel(WalletModel *_model)
&QItemSelectionModel::selectionChanged, this,
&ReceiveCoinsDialog::recentRequestsView_selectionChanged);
- if (model->wallet().getDefaultAddressType() == OutputType::BECH32) {
- ui->useBech32->setCheckState(Qt::Checked);
- } else {
- ui->useBech32->setCheckState(Qt::Unchecked);
+ // Populate address type dropdown and select default
+ auto add_address_type = [&](OutputType type, const QString& text, const QString& tooltip) {
+ const auto index = ui->addressType->count();
+ ui->addressType->addItem(text, (int) type);
+ ui->addressType->setItemData(index, tooltip, Qt::ToolTipRole);
+ if (model->wallet().getDefaultAddressType() == type) ui->addressType->setCurrentIndex(index);
+ };
+ add_address_type(OutputType::LEGACY, "Base58 (Legacy)", "Not recommended due to higher fees and less protection against typos.");
+ add_address_type(OutputType::P2SH_SEGWIT, "Base58 (P2SH-SegWit)", "Generates an address compatible with older wallets.");
+ add_address_type(OutputType::BECH32, "Bech32 (SegWit)", "Generates a native segwit address (BIP-173). Some old wallets don't support it.");
+ if (model->wallet().taprootEnabled()) {
+ add_address_type(OutputType::BECH32M, "Bech32m (Taproot)", "Bech32m (BIP-350) is an upgrade to Bech32, wallet support is still limited.");
}
// Set the button to be enabled or disabled based on whether the wallet can give out new addresses.
@@ -144,15 +152,7 @@ void ReceiveCoinsDialog::on_receiveButton_clicked()
QString address;
QString label = ui->reqLabel->text();
/* Generate new receiving address */
- OutputType address_type;
- if (ui->useBech32->isChecked()) {
- address_type = OutputType::BECH32;
- } else {
- address_type = model->wallet().getDefaultAddressType();
- if (address_type == OutputType::BECH32) {
- address_type = OutputType::P2SH_SEGWIT;
- }
- }
+ const OutputType address_type = (OutputType)ui->addressType->currentData().toInt();
address = model->getAddressTableModel()->addRow(AddressTableModel::Receive, label, "", address_type);
switch(model->getAddressTableModel()->getEditStatus())
diff --git a/src/qt/splashscreen.cpp b/src/qt/splashscreen.cpp
index 85703b3350..558ec41bd8 100644
--- a/src/qt/splashscreen.cpp
+++ b/src/qt/splashscreen.cpp
@@ -201,7 +201,7 @@ void SplashScreen::handleLoadWallet()
{
#ifdef ENABLE_WALLET
if (!WalletModel::isWalletEnabled()) return;
- m_handler_load_wallet = m_node->walletClient().handleLoadWallet([this](std::unique_ptr<interfaces::Wallet> wallet) {
+ m_handler_load_wallet = m_node->walletLoader().handleLoadWallet([this](std::unique_ptr<interfaces::Wallet> wallet) {
m_connected_wallet_handlers.emplace_back(wallet->handleShowProgress(std::bind(ShowProgress, this, std::placeholders::_1, std::placeholders::_2, false)));
m_connected_wallets.emplace_back(std::move(wallet));
});
diff --git a/src/qt/test/addressbooktests.cpp b/src/qt/test/addressbooktests.cpp
index 39cc1c1e1d..e814452907 100644
--- a/src/qt/test/addressbooktests.cpp
+++ b/src/qt/test/addressbooktests.cpp
@@ -60,8 +60,8 @@ void EditAddressAndSubmit(
void TestAddAddressesToSendBook(interfaces::Node& node)
{
TestChain100Setup test;
- auto wallet_client = interfaces::MakeWalletClient(*test.m_node.chain, *Assert(test.m_node.args));
- test.m_node.wallet_client = wallet_client.get();
+ auto wallet_loader = interfaces::MakeWalletLoader(*test.m_node.chain, *Assert(test.m_node.args));
+ test.m_node.wallet_loader = wallet_loader.get();
node.setContext(&test.m_node);
const std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(node.context()->chain.get(), "", gArgs, CreateMockWalletDatabase());
wallet->LoadWallet();
@@ -115,7 +115,7 @@ void TestAddAddressesToSendBook(interfaces::Node& node)
std::unique_ptr<const PlatformStyle> platformStyle(PlatformStyle::instantiate("other"));
OptionsModel optionsModel;
ClientModel clientModel(node, &optionsModel);
- WalletContext& context = *node.walletClient().context();
+ WalletContext& context = *node.walletLoader().context();
AddWallet(context, wallet);
WalletModel walletModel(interfaces::MakeWallet(context, wallet), clientModel, platformStyle.get());
RemoveWallet(context, wallet, /* load_on_start= */ std::nullopt);
diff --git a/src/qt/test/wallettests.cpp b/src/qt/test/wallettests.cpp
index 93d6aa805f..dff69058e5 100644
--- a/src/qt/test/wallettests.cpp
+++ b/src/qt/test/wallettests.cpp
@@ -138,8 +138,8 @@ void TestGUI(interfaces::Node& node)
for (int i = 0; i < 5; ++i) {
test.CreateAndProcessBlock({}, GetScriptForRawPubKey(test.coinbaseKey.GetPubKey()));
}
- auto wallet_client = interfaces::MakeWalletClient(*test.m_node.chain, *Assert(test.m_node.args));
- test.m_node.wallet_client = wallet_client.get();
+ auto wallet_loader = interfaces::MakeWalletLoader(*test.m_node.chain, *Assert(test.m_node.args));
+ test.m_node.wallet_loader = wallet_loader.get();
node.setContext(&test.m_node);
const std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(node.context()->chain.get(), "", gArgs, CreateMockWalletDatabase());
wallet->LoadWallet();
@@ -175,7 +175,7 @@ void TestGUI(interfaces::Node& node)
TransactionView transactionView(platformStyle.get());
OptionsModel optionsModel;
ClientModel clientModel(node, &optionsModel);
- WalletContext& context = *node.walletClient().context();
+ WalletContext& context = *node.walletLoader().context();
AddWallet(context, wallet);
WalletModel walletModel(interfaces::MakeWallet(context, wallet), clientModel, platformStyle.get());
RemoveWallet(context, wallet, /* load_on_start= */ std::nullopt);
diff --git a/src/qt/walletcontroller.cpp b/src/qt/walletcontroller.cpp
index b9a9fcf3d1..6cf7ec36c2 100644
--- a/src/qt/walletcontroller.cpp
+++ b/src/qt/walletcontroller.cpp
@@ -37,7 +37,7 @@ WalletController::WalletController(ClientModel& client_model, const PlatformStyl
, m_platform_style(platform_style)
, m_options_model(client_model.getOptionsModel())
{
- m_handler_load_wallet = m_node.walletClient().handleLoadWallet([this](std::unique_ptr<interfaces::Wallet> wallet) {
+ m_handler_load_wallet = m_node.walletLoader().handleLoadWallet([this](std::unique_ptr<interfaces::Wallet> wallet) {
getOrCreateWallet(std::move(wallet));
});
@@ -61,7 +61,7 @@ std::map<std::string, bool> WalletController::listWalletDir() const
{
QMutexLocker locker(&m_mutex);
std::map<std::string, bool> wallets;
- for (const std::string& name : m_node.walletClient().listWalletDir()) {
+ for (const std::string& name : m_node.walletLoader().listWalletDir()) {
wallets[name] = false;
}
for (WalletModel* wallet_model : m_wallets) {
@@ -255,7 +255,7 @@ void CreateWalletActivity::createWallet()
}
QTimer::singleShot(500, worker(), [this, name, flags] {
- std::unique_ptr<interfaces::Wallet> wallet = node().walletClient().createWallet(name, m_passphrase, flags, m_error_message, m_warning_message);
+ std::unique_ptr<interfaces::Wallet> wallet = node().walletLoader().createWallet(name, m_passphrase, flags, m_error_message, m_warning_message);
if (wallet) m_wallet_model = m_wallet_controller->getOrCreateWallet(std::move(wallet));
@@ -336,7 +336,7 @@ void OpenWalletActivity::open(const std::string& path)
tr("Opening Wallet <b>%1</b>…").arg(name.toHtmlEscaped()));
QTimer::singleShot(0, worker(), [this, path] {
- std::unique_ptr<interfaces::Wallet> wallet = node().walletClient().loadWallet(path, m_error_message, m_warning_message);
+ std::unique_ptr<interfaces::Wallet> wallet = node().walletLoader().loadWallet(path, m_error_message, m_warning_message);
if (wallet) m_wallet_model = m_wallet_controller->getOrCreateWallet(std::move(wallet));
@@ -359,7 +359,7 @@ void LoadWalletsActivity::load()
tr("Loading wallets…"));
QTimer::singleShot(0, worker(), [this] {
- for (auto& wallet : node().walletClient().getWallets()) {
+ for (auto& wallet : node().walletLoader().getWallets()) {
m_wallet_controller->getOrCreateWallet(std::move(wallet));
}
diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp
index 052453cf65..5f9c0d6a12 100644
--- a/src/qt/walletmodel.cpp
+++ b/src/qt/walletmodel.cpp
@@ -583,7 +583,7 @@ QString WalletModel::getDisplayName() const
bool WalletModel::isMultiwallet()
{
- return m_node.walletClient().getWallets().size() > 1;
+ return m_node.walletLoader().getWallets().size() > 1;
}
void WalletModel::refresh(bool pk_hash_only)
diff --git a/src/test/fuzz/block.cpp b/src/test/fuzz/block.cpp
index 65a33de4b4..c750f7ee3a 100644
--- a/src/test/fuzz/block.cpp
+++ b/src/test/fuzz/block.cpp
@@ -58,8 +58,6 @@ FUZZ_TARGET_INIT(block, initialize_block)
(void)block.ToString();
(void)BlockMerkleRoot(block);
if (!block.vtx.empty()) {
- // TODO: Avoid array index out of bounds error in BlockWitnessMerkleRoot
- // when block.vtx.empty().
(void)BlockWitnessMerkleRoot(block);
}
(void)GetBlockWeight(block);
diff --git a/src/test/util/setup_common.cpp b/src/test/util/setup_common.cpp
index d0be9fe73a..eb23e8725f 100644
--- a/src/test/util/setup_common.cpp
+++ b/src/test/util/setup_common.cpp
@@ -195,6 +195,16 @@ TestingSetup::TestingSetup(const std::string& chainName, const std::vector<const
true);
assert(!rv.has_value());
+ auto maybe_verify_failure = VerifyLoadedChainstate(
+ *Assert(m_node.chainman),
+ fReindex.load(),
+ m_args.GetBoolArg("-reindex-chainstate", false),
+ chainparams.GetConsensus(),
+ m_args.GetIntArg("-checkblocks", DEFAULT_CHECKBLOCKS),
+ m_args.GetIntArg("-checklevel", DEFAULT_CHECKLEVEL),
+ static_cast<int64_t(*)()>(GetTime));
+ assert(!maybe_verify_failure.has_value());
+
BlockValidationState state;
if (!m_node.chainman->ActiveChainstate().ActivateBestChain(state)) {
throw std::runtime_error(strprintf("ActivateBestChain failed. (%s)", state.ToString()));
diff --git a/src/wallet/feebumper.cpp b/src/wallet/feebumper.cpp
index f2de68295e..57edba4c7d 100644
--- a/src/wallet/feebumper.cpp
+++ b/src/wallet/feebumper.cpp
@@ -276,10 +276,6 @@ Result CommitTransaction(CWallet& wallet, const uint256& txid, CMutableTransacti
// mark the original tx as bumped
bumped_txid = tx->GetHash();
if (!wallet.MarkReplaced(oldWtx.GetHash(), bumped_txid)) {
- // TODO: see if JSON-RPC has a standard way of returning a response
- // along with an exception. It would be good to return information about
- // wtxBumped to the caller even if marking the original transaction
- // replaced does not succeed for some reason.
errors.push_back(Untranslated("Created new bumpfee transaction but could not mark the original transaction as replaced"));
}
return Result::OK;
diff --git a/src/wallet/init.cpp b/src/wallet/init.cpp
index 8e7fc95f44..7368f87574 100644
--- a/src/wallet/init.cpp
+++ b/src/wallet/init.cpp
@@ -133,7 +133,7 @@ void WalletInit::Construct(NodeContext& node) const
LogPrintf("Wallet disabled!\n");
return;
}
- auto wallet_client = node.init->makeWalletClient(*node.chain);
- node.wallet_client = wallet_client.get();
- node.chain_clients.emplace_back(std::move(wallet_client));
+ auto wallet_loader = node.init->makeWalletLoader(*node.chain);
+ node.wallet_loader = wallet_loader.get();
+ node.chain_clients.emplace_back(std::move(wallet_loader));
}
diff --git a/src/wallet/interfaces.cpp b/src/wallet/interfaces.cpp
index bba909b807..54986413d6 100644
--- a/src/wallet/interfaces.cpp
+++ b/src/wallet/interfaces.cpp
@@ -40,7 +40,7 @@ using interfaces::MakeHandler;
using interfaces::Wallet;
using interfaces::WalletAddress;
using interfaces::WalletBalances;
-using interfaces::WalletClient;
+using interfaces::WalletLoader;
using interfaces::WalletOrderForm;
using interfaces::WalletTx;
using interfaces::WalletTxOut;
@@ -461,6 +461,11 @@ public:
bool canGetAddresses() override { return m_wallet->CanGetAddresses(); }
bool hasExternalSigner() override { return m_wallet->IsWalletFlagSet(WALLET_FLAG_EXTERNAL_SIGNER); }
bool privateKeysDisabled() override { return m_wallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS); }
+ bool taprootEnabled() override {
+ if (m_wallet->IsLegacy()) return false;
+ auto spk_man = m_wallet->GetScriptPubKeyMan(OutputType::BECH32M, /*internal=*/false);
+ return spk_man != nullptr;
+ }
OutputType getDefaultAddressType() override { return m_wallet->m_default_address_type; }
CAmount getDefaultMaxTxFee() override { return m_wallet->m_default_max_tx_fee; }
void remove() override
@@ -505,15 +510,15 @@ public:
std::shared_ptr<CWallet> m_wallet;
};
-class WalletClientImpl : public WalletClient
+class WalletLoaderImpl : public WalletLoader
{
public:
- WalletClientImpl(Chain& chain, ArgsManager& args)
+ WalletLoaderImpl(Chain& chain, ArgsManager& args)
{
m_context.chain = &chain;
m_context.args = &args;
}
- ~WalletClientImpl() override { UnloadWallets(m_context); }
+ ~WalletLoaderImpl() override { UnloadWallets(m_context); }
//! ChainClient methods
void registerRpcs() override
@@ -534,7 +539,7 @@ public:
void stop() override { return StopWallets(m_context); }
void setMockTime(int64_t time) override { return SetMockTime(time); }
- //! WalletClient methods
+ //! WalletLoader methods
std::unique_ptr<Wallet> createWallet(const std::string& name, const SecureString& passphrase, uint64_t wallet_creation_flags, bilingual_str& error, std::vector<bilingual_str>& warnings) override
{
std::shared_ptr<CWallet> wallet;
@@ -595,8 +600,8 @@ public:
namespace interfaces {
std::unique_ptr<Wallet> MakeWallet(WalletContext& context, const std::shared_ptr<CWallet>& wallet) { return wallet ? std::make_unique<wallet::WalletImpl>(context, wallet) : nullptr; }
-std::unique_ptr<WalletClient> MakeWalletClient(Chain& chain, ArgsManager& args)
+std::unique_ptr<WalletLoader> MakeWalletLoader(Chain& chain, ArgsManager& args)
{
- return std::make_unique<wallet::WalletClientImpl>(chain, args);
+ return std::make_unique<wallet::WalletLoaderImpl>(chain, args);
}
} // namespace interfaces
diff --git a/src/wallet/rpc/addresses.cpp b/src/wallet/rpc/addresses.cpp
index c7400cafe7..2db47bc855 100644
--- a/src/wallet/rpc/addresses.cpp
+++ b/src/wallet/rpc/addresses.cpp
@@ -359,7 +359,12 @@ RPCHelpMan keypoolrefill()
RPCHelpMan newkeypool()
{
return RPCHelpMan{"newkeypool",
- "\nEntirely clears and refills the keypool."+
+ "\nEntirely clears and refills the keypool.\n"
+ "WARNING: On non-HD wallets, this will require a new backup immediately, to include the new keys.\n"
+ "When restoring a backup of an HD wallet created before the newkeypool command is run, funds received to\n"
+ "new addresses may not appear automatically. They have not been lost, but the wallet may not find them.\n"
+ "This can be fixed by running the newkeypool command on the backup and then rescanning, so the wallet\n"
+ "re-generates the required keys." +
HELP_REQUIRING_PASSPHRASE,
{},
RPCResult{RPCResult::Type::NONE, "", ""},
diff --git a/src/wallet/test/init_test_fixture.cpp b/src/wallet/test/init_test_fixture.cpp
index 170675c035..ade2813e0a 100644
--- a/src/wallet/test/init_test_fixture.cpp
+++ b/src/wallet/test/init_test_fixture.cpp
@@ -11,7 +11,7 @@
InitWalletDirTestingSetup::InitWalletDirTestingSetup(const std::string& chainName) : BasicTestingSetup(chainName)
{
- m_wallet_client = MakeWalletClient(*m_node.chain, *Assert(m_node.args));
+ m_wallet_loader = MakeWalletLoader(*m_node.chain, *Assert(m_node.args));
std::string sep;
sep += fs::path::preferred_separator;
diff --git a/src/wallet/test/init_test_fixture.h b/src/wallet/test/init_test_fixture.h
index 37ae907de5..485aa50658 100644
--- a/src/wallet/test/init_test_fixture.h
+++ b/src/wallet/test/init_test_fixture.h
@@ -19,7 +19,7 @@ struct InitWalletDirTestingSetup: public BasicTestingSetup {
fs::path m_datadir;
fs::path m_cwd;
std::map<std::string, fs::path> m_walletdir_path_cases;
- std::unique_ptr<interfaces::WalletClient> m_wallet_client;
+ std::unique_ptr<interfaces::WalletLoader> m_wallet_loader;
};
#endif // BITCOIN_WALLET_TEST_INIT_TEST_FIXTURE_H
diff --git a/src/wallet/test/init_tests.cpp b/src/wallet/test/init_tests.cpp
index 222c2bf4b7..3bbf18043d 100644
--- a/src/wallet/test/init_tests.cpp
+++ b/src/wallet/test/init_tests.cpp
@@ -15,7 +15,7 @@ BOOST_FIXTURE_TEST_SUITE(init_tests, InitWalletDirTestingSetup)
BOOST_AUTO_TEST_CASE(walletinit_verify_walletdir_default)
{
SetWalletDir(m_walletdir_path_cases["default"]);
- bool result = m_wallet_client->verify();
+ bool result = m_wallet_loader->verify();
BOOST_CHECK(result == true);
fs::path walletdir = fs::PathFromString(gArgs.GetArg("-walletdir", ""));
fs::path expected_path = fs::canonical(m_walletdir_path_cases["default"]);
@@ -25,7 +25,7 @@ BOOST_AUTO_TEST_CASE(walletinit_verify_walletdir_default)
BOOST_AUTO_TEST_CASE(walletinit_verify_walletdir_custom)
{
SetWalletDir(m_walletdir_path_cases["custom"]);
- bool result = m_wallet_client->verify();
+ bool result = m_wallet_loader->verify();
BOOST_CHECK(result == true);
fs::path walletdir = fs::PathFromString(gArgs.GetArg("-walletdir", ""));
fs::path expected_path = fs::canonical(m_walletdir_path_cases["custom"]);
@@ -37,7 +37,7 @@ BOOST_AUTO_TEST_CASE(walletinit_verify_walletdir_does_not_exist)
SetWalletDir(m_walletdir_path_cases["nonexistent"]);
{
ASSERT_DEBUG_LOG("does not exist");
- bool result = m_wallet_client->verify();
+ bool result = m_wallet_loader->verify();
BOOST_CHECK(result == false);
}
}
@@ -47,7 +47,7 @@ BOOST_AUTO_TEST_CASE(walletinit_verify_walletdir_is_not_directory)
SetWalletDir(m_walletdir_path_cases["file"]);
{
ASSERT_DEBUG_LOG("is not a directory");
- bool result = m_wallet_client->verify();
+ bool result = m_wallet_loader->verify();
BOOST_CHECK(result == false);
}
}
@@ -57,7 +57,7 @@ BOOST_AUTO_TEST_CASE(walletinit_verify_walletdir_is_not_relative)
SetWalletDir(m_walletdir_path_cases["relative"]);
{
ASSERT_DEBUG_LOG("is a relative path");
- bool result = m_wallet_client->verify();
+ bool result = m_wallet_loader->verify();
BOOST_CHECK(result == false);
}
}
@@ -65,7 +65,7 @@ BOOST_AUTO_TEST_CASE(walletinit_verify_walletdir_is_not_relative)
BOOST_AUTO_TEST_CASE(walletinit_verify_walletdir_no_trailing)
{
SetWalletDir(m_walletdir_path_cases["trailing"]);
- bool result = m_wallet_client->verify();
+ bool result = m_wallet_loader->verify();
BOOST_CHECK(result == true);
fs::path walletdir = fs::PathFromString(gArgs.GetArg("-walletdir", ""));
fs::path expected_path = fs::canonical(m_walletdir_path_cases["default"]);
@@ -75,7 +75,7 @@ BOOST_AUTO_TEST_CASE(walletinit_verify_walletdir_no_trailing)
BOOST_AUTO_TEST_CASE(walletinit_verify_walletdir_no_trailing2)
{
SetWalletDir(m_walletdir_path_cases["trailing2"]);
- bool result = m_wallet_client->verify();
+ bool result = m_wallet_loader->verify();
BOOST_CHECK(result == true);
fs::path walletdir = fs::PathFromString(gArgs.GetArg("-walletdir", ""));
fs::path expected_path = fs::canonical(m_walletdir_path_cases["default"]);
diff --git a/src/wallet/test/wallet_test_fixture.cpp b/src/wallet/test/wallet_test_fixture.cpp
index 762702522e..83bc75528d 100644
--- a/src/wallet/test/wallet_test_fixture.cpp
+++ b/src/wallet/test/wallet_test_fixture.cpp
@@ -12,7 +12,7 @@ WalletTestingSetup::WalletTestingSetup(const std::string& chainName)
{
m_wallet.LoadWallet();
m_chain_notifications_handler = m_node.chain->handleNotifications({ &m_wallet, [](CWallet*) {} });
- m_wallet_client->registerRpcs();
+ m_wallet_loader->registerRpcs();
}
WalletTestingSetup::~WalletTestingSetup()
diff --git a/src/wallet/test/wallet_test_fixture.h b/src/wallet/test/wallet_test_fixture.h
index 8bf2d36227..02d5707e36 100644
--- a/src/wallet/test/wallet_test_fixture.h
+++ b/src/wallet/test/wallet_test_fixture.h
@@ -21,7 +21,7 @@ struct WalletTestingSetup : public TestingSetup {
explicit WalletTestingSetup(const std::string& chainName = CBaseChainParams::MAIN);
~WalletTestingSetup();
- std::unique_ptr<interfaces::WalletClient> m_wallet_client = interfaces::MakeWalletClient(*m_node.chain, *Assert(m_node.args));
+ std::unique_ptr<interfaces::WalletLoader> m_wallet_loader = interfaces::MakeWalletLoader(*m_node.chain, *Assert(m_node.args));
CWallet m_wallet;
std::unique_ptr<interfaces::Handler> m_chain_notifications_handler;
};
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index decdbc7090..6e1552abd7 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -1967,29 +1967,58 @@ OutputType CWallet::TransactionChangeType(const std::optional<OutputType>& chang
return *change_type;
}
- // if m_default_address_type is legacy, use legacy address as change (even
- // if some of the outputs are P2WPKH or P2WSH).
+ // if m_default_address_type is legacy, use legacy address as change.
if (m_default_address_type == OutputType::LEGACY) {
return OutputType::LEGACY;
}
- // if any destination is P2WPKH or P2WSH, use P2WPKH for the change
- // output.
+ bool any_tr{false};
+ bool any_wpkh{false};
+ bool any_sh{false};
+ bool any_pkh{false};
+
for (const auto& recipient : vecSend) {
- // Check if any destination contains a witness program:
- int witnessversion = 0;
- std::vector<unsigned char> witnessprogram;
- if (recipient.scriptPubKey.IsWitnessProgram(witnessversion, witnessprogram)) {
- if (GetScriptPubKeyMan(OutputType::BECH32M, true)) {
- return OutputType::BECH32M;
- } else if (GetScriptPubKeyMan(OutputType::BECH32, true)) {
- return OutputType::BECH32;
- } else {
- return m_default_address_type;
- }
- }
+ std::vector<std::vector<uint8_t>> dummy;
+ const TxoutType type{Solver(recipient.scriptPubKey, dummy)};
+ if (type == TxoutType::WITNESS_V1_TAPROOT) {
+ any_tr = true;
+ } else if (type == TxoutType::WITNESS_V0_KEYHASH) {
+ any_wpkh = true;
+ } else if (type == TxoutType::SCRIPTHASH) {
+ any_sh = true;
+ } else if (type == TxoutType::PUBKEYHASH) {
+ any_pkh = true;
+ }
+ }
+
+ const bool has_bech32m_spkman(GetScriptPubKeyMan(OutputType::BECH32M, /*internal=*/true));
+ if (has_bech32m_spkman && any_tr) {
+ // Currently tr is the only type supported by the BECH32M spkman
+ return OutputType::BECH32M;
+ }
+ const bool has_bech32_spkman(GetScriptPubKeyMan(OutputType::BECH32, /*internal=*/true));
+ if (has_bech32_spkman && any_wpkh) {
+ // Currently wpkh is the only type supported by the BECH32 spkman
+ return OutputType::BECH32;
+ }
+ const bool has_p2sh_segwit_spkman(GetScriptPubKeyMan(OutputType::P2SH_SEGWIT, /*internal=*/true));
+ if (has_p2sh_segwit_spkman && any_sh) {
+ // Currently sh_wpkh is the only type supported by the P2SH_SEGWIT spkman
+ // As of 2021 about 80% of all SH are wrapping WPKH, so use that
+ return OutputType::P2SH_SEGWIT;
+ }
+ const bool has_legacy_spkman(GetScriptPubKeyMan(OutputType::LEGACY, /*internal=*/true));
+ if (has_legacy_spkman && any_pkh) {
+ // Currently pkh is the only type supported by the LEGACY spkman
+ return OutputType::LEGACY;
}
+ if (has_bech32m_spkman) {
+ return OutputType::BECH32M;
+ }
+ if (has_bech32_spkman) {
+ return OutputType::BECH32;
+ }
// else use m_default_address_type for change
return m_default_address_type;
}
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index e2a2aebeb5..30777dbe2c 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -48,7 +48,7 @@ struct bilingual_str;
//! Explicitly unload and delete the wallet.
//! Blocks the current thread after signaling the unload intent so that all
-//! wallet clients release the wallet.
+//! wallet pointer owners release the wallet.
//! Note that, when blocking is not required, the wallet is implicitly unloaded
//! by the shared pointer deleter.
void UnloadWallet(std::shared_ptr<CWallet>&& wallet);