diff --git a/src/qt/createwalletdialog.h b/src/qt/createwalletdialog.h
--- a/src/qt/createwalletdialog.h
+++ b/src/qt/createwalletdialog.h
@@ -27,6 +27,7 @@
bool isEncryptWalletChecked() const;
bool isDisablePrivateKeysChecked() const;
bool isMakeBlankWalletChecked() const;
+ bool isDescriptorWalletChecked() const;
private:
Ui::CreateWalletDialog *ui;
diff --git a/src/qt/createwalletdialog.cpp b/src/qt/createwalletdialog.cpp
--- a/src/qt/createwalletdialog.cpp
+++ b/src/qt/createwalletdialog.cpp
@@ -57,3 +57,7 @@
bool CreateWalletDialog::isMakeBlankWalletChecked() const {
return ui->blank_wallet_checkbox->isChecked();
}
+
+bool CreateWalletDialog::isDescriptorWalletChecked() const {
+ return ui->descriptor_checkbox->isChecked();
+}
diff --git a/src/qt/forms/createwalletdialog.ui b/src/qt/forms/createwalletdialog.ui
--- a/src/qt/forms/createwalletdialog.ui
+++ b/src/qt/forms/createwalletdialog.ui
@@ -7,7 +7,7 @@
0
0
364
- 185
+ 213
@@ -17,7 +17,7 @@
10
- 140
+ 170
341
32
@@ -106,6 +106,22 @@
Make Blank Wallet
+
+
+
+ 20
+ 140
+ 171
+ 22
+
+
+
+ Use descriptors for scriptPubKey management
+
+
+ Descriptor Wallet
+
+
wallet_name_line_edit
diff --git a/src/qt/walletcontroller.cpp b/src/qt/walletcontroller.cpp
--- a/src/qt/walletcontroller.cpp
+++ b/src/qt/walletcontroller.cpp
@@ -221,6 +221,9 @@
if (m_create_wallet_dialog->isMakeBlankWalletChecked()) {
flags |= WALLET_FLAG_BLANK_WALLET;
}
+ if (m_create_wallet_dialog->isDescriptorWalletChecked()) {
+ flags |= WALLET_FLAG_DESCRIPTORS;
+ }
QTimer::singleShot(500, worker(), [this, name, flags] {
WalletCreationStatus status;
diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp
--- a/src/rpc/client.cpp
+++ b/src/rpc/client.cpp
@@ -156,6 +156,7 @@
{"createwallet", 1, "disable_private_keys"},
{"createwallet", 2, "blank"},
{"createwallet", 4, "avoid_reuse"},
+ {"createwallet", 5, "descriptors"},
{"getnodeaddresses", 0, "count"},
{"stop", 0, "wait"},
// Avalanche
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -3304,6 +3304,9 @@
{"avoid_reuse", RPCArg::Type::BOOL, /* default */ "false",
"Keep track of coin reuse, and treat dirty and clean coins "
"differently with privacy considerations in mind."},
+ {"descriptors", RPCArg::Type::BOOL, /* default */ "false",
+ "Create a native descriptor wallet. The wallet will use "
+ "descriptors internally to handle address creation"},
},
RPCResult{RPCResult::Type::OBJ,
"",
@@ -3346,6 +3349,9 @@
if (!request.params[4].isNull() && request.params[4].get_bool()) {
flags |= WALLET_FLAG_AVOID_REUSE;
}
+ if (!request.params[5].isNull() && request.params[5].get_bool()) {
+ flags |= WALLET_FLAG_DESCRIPTORS;
+ }
bilingual_str error;
std::shared_ptr wallet;
@@ -4995,7 +5001,7 @@
{ "wallet", "abandontransaction", abandontransaction, {"txid"} },
{ "wallet", "addmultisigaddress", addmultisigaddress, {"nrequired","keys","label"} },
{ "wallet", "backupwallet", backupwallet, {"destination"} },
- { "wallet", "createwallet", createwallet, {"wallet_name", "disable_private_keys", "blank", "passphrase", "avoid_reuse"} },
+ { "wallet", "createwallet", createwallet, {"wallet_name", "disable_private_keys", "blank", "passphrase", "avoid_reuse", "descriptors"} },
{ "wallet", "encryptwallet", encryptwallet, {"passphrase"} },
{ "wallet", "getaddressesbylabel", getaddressesbylabel, {"label"} },
{ "wallet", "getaddressinfo", getaddressinfo, {"address"} },
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -1523,6 +1523,9 @@
//! updating the wallet.
void SetActiveScriptPubKeyMan(uint256 id, OutputType type, bool internal,
bool memonly = false);
+
+ //! Create new DescriptorScriptPubKeyMans and add them to the wallet
+ void SetupDescriptorScriptPubKeyMans();
};
/**
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -255,10 +255,15 @@
// Set a seed for the wallet
{
LOCK(wallet->cs_wallet);
- for (auto spk_man : wallet->GetActiveScriptPubKeyMans()) {
- if (!spk_man->SetupGeneration()) {
- error = Untranslated("Unable to generate initial keys");
- return WalletCreationStatus::CREATION_FAILED;
+ if (wallet->IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS)) {
+ wallet->SetupDescriptorScriptPubKeyMans();
+ } else {
+ for (auto spk_man : wallet->GetActiveScriptPubKeyMans()) {
+ if (!spk_man->SetupGeneration()) {
+ error =
+ Untranslated("Unable to generate initial keys");
+ return WalletCreationStatus::CREATION_FAILED;
+ }
}
}
}
@@ -4224,10 +4229,18 @@
if (!(wallet_creation_flags &
(WALLET_FLAG_DISABLE_PRIVATE_KEYS | WALLET_FLAG_BLANK_WALLET))) {
LOCK(walletInstance->cs_wallet);
- for (auto spk_man : walletInstance->GetActiveScriptPubKeyMans()) {
- if (!spk_man->SetupGeneration()) {
- error = _("Unable to generate initial keys");
- return nullptr;
+ if (walletInstance->IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS)) {
+ walletInstance->SetupDescriptorScriptPubKeyMans();
+ // SetupDescriptorScriptPubKeyMans already calls SetupGeneration
+ // for us so we don't need to call SetupGeneration separately
+ } else {
+ // Legacy wallets need SetupGeneration here.
+ for (auto spk_man :
+ walletInstance->GetActiveScriptPubKeyMans()) {
+ if (!spk_man->SetupGeneration()) {
+ error = _("Unable to generate initial keys");
+ return nullptr;
+ }
}
}
}
@@ -4860,6 +4873,44 @@
m_spk_managers[id] = std::move(spk_manager);
}
+void CWallet::SetupDescriptorScriptPubKeyMans() {
+ AssertLockHeld(cs_wallet);
+
+ // Make a seed
+ CKey seed_key;
+ seed_key.MakeNewKey(true);
+ CPubKey seed = seed_key.GetPubKey();
+ assert(seed_key.VerifyPubKey(seed));
+
+ // Get the extended key
+ CExtKey master_key;
+ master_key.SetSeed(seed_key.begin(), seed_key.size());
+
+ for (bool internal : {false, true}) {
+ for (OutputType t : OUTPUT_TYPES) {
+ auto spk_manager =
+ std::make_unique(*this, t, internal);
+ if (IsCrypted()) {
+ if (IsLocked()) {
+ throw std::runtime_error(
+ std::string(__func__) +
+ ": Wallet is locked, cannot setup new descriptors");
+ }
+ if (!spk_manager->CheckDecryptionKey(vMasterKey) &&
+ !spk_manager->Encrypt(vMasterKey, nullptr)) {
+ throw std::runtime_error(
+ std::string(__func__) +
+ ": Could not encrypt new descriptors");
+ }
+ }
+ spk_manager->SetupDescriptorGeneration(master_key);
+ uint256 id = spk_manager->GetID();
+ m_spk_managers[id] = std::move(spk_manager);
+ SetActiveScriptPubKeyMan(id, t, internal);
+ }
+ }
+}
+
void CWallet::SetActiveScriptPubKeyMan(uint256 id, OutputType type,
bool internal, bool memonly) {
auto &spk_mans =