Be able to create new wallets with DescriptorScriptPubKeyMans as backing
This commit is contained in:
1 parent
b713baa75a
commit
82ae02b165
8 files changed
+87
-11
No files matched your search
@@ -60,3 +60,8 @@ bool CreateWalletDialog::isMakeBlankWalletChecked() const
|
|||||||
{
|
{
|
||||||
return ui->blank_wallet_checkbox->isChecked();
|
return ui->blank_wallet_checkbox->isChecked();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CreateWalletDialog::isDescriptorWalletChecked() const
|
||||||
|
{
|
||||||
|
return ui->descriptor_checkbox->isChecked();
|
||||||
|
}
|
||||||
@@ -27,6 +27,7 @@ public:
|
|||||||
bool isEncryptWalletChecked() const;
|
bool isEncryptWalletChecked() const;
|
||||||
bool isDisablePrivateKeysChecked() const;
|
bool isDisablePrivateKeysChecked() const;
|
||||||
bool isMakeBlankWalletChecked() const;
|
bool isMakeBlankWalletChecked() const;
|
||||||
|
bool isDescriptorWalletChecked() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Ui::CreateWalletDialog *ui;
|
Ui::CreateWalletDialog *ui;
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>364</width>
|
<width>364</width>
|
||||||
<height>185</height>
|
<height>213</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
@@ -17,7 +17,7 @@
|
|||||||
<property name="geometry">
|
<property name="geometry">
|
||||||
<rect>
|
<rect>
|
||||||
<x>10</x>
|
<x>10</x>
|
||||||
<y>140</y>
|
<y>170</y>
|
||||||
<width>341</width>
|
<width>341</width>
|
||||||
<height>32</height>
|
<height>32</height>
|
||||||
</rect>
|
</rect>
|
||||||
@@ -106,6 +106,22 @@
|
|||||||
<string>Make Blank Wallet</string>
|
<string>Make Blank Wallet</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
|
<widget class="QCheckBox" name="descriptor_checkbox">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>20</x>
|
||||||
|
<y>140</y>
|
||||||
|
<width>171</width>
|
||||||
|
<height>22</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Use descriptors for scriptPubKey management</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Descriptor Wallet</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
</widget>
|
</widget>
|
||||||
<tabstops>
|
<tabstops>
|
||||||
<tabstop>wallet_name_line_edit</tabstop>
|
<tabstop>wallet_name_line_edit</tabstop>
|
||||||
|
|||||||
@@ -226,6 +226,9 @@ void CreateWalletActivity::createWallet()
|
|||||||
if (m_create_wallet_dialog->isMakeBlankWalletChecked()) {
|
if (m_create_wallet_dialog->isMakeBlankWalletChecked()) {
|
||||||
flags |= WALLET_FLAG_BLANK_WALLET;
|
flags |= WALLET_FLAG_BLANK_WALLET;
|
||||||
}
|
}
|
||||||
|
if (m_create_wallet_dialog->isDescriptorWalletChecked()) {
|
||||||
|
flags |= WALLET_FLAG_DESCRIPTORS;
|
||||||
|
}
|
||||||
|
|
||||||
QTimer::singleShot(500, worker(), [this, name, flags] {
|
QTimer::singleShot(500, worker(), [this, name, flags] {
|
||||||
WalletCreationStatus status;
|
WalletCreationStatus status;
|
||||||
|
|||||||
@@ -170,6 +170,7 @@ static const CRPCConvertParam vRPCConvertParams[] =
|
|||||||
{ "createwallet", 1, "disable_private_keys"},
|
{ "createwallet", 1, "disable_private_keys"},
|
||||||
{ "createwallet", 2, "blank"},
|
{ "createwallet", 2, "blank"},
|
||||||
{ "createwallet", 4, "avoid_reuse"},
|
{ "createwallet", 4, "avoid_reuse"},
|
||||||
|
{ "createwallet", 5, "descriptors"},
|
||||||
{ "getnodeaddresses", 0, "count"},
|
{ "getnodeaddresses", 0, "count"},
|
||||||
{ "stop", 0, "wait" },
|
{ "stop", 0, "wait" },
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -2706,6 +2706,7 @@ static UniValue createwallet(const JSONRPCRequest& request)
|
|||||||
{"blank", RPCArg::Type::BOOL, /* default */ "false", "Create a blank wallet. A blank wallet has no keys or HD seed. One can be set using sethdseed."},
|
{"blank", RPCArg::Type::BOOL, /* default */ "false", "Create a blank wallet. A blank wallet has no keys or HD seed. One can be set using sethdseed."},
|
||||||
{"passphrase", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "Encrypt the wallet with this passphrase."},
|
{"passphrase", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "Encrypt the wallet with this passphrase."},
|
||||||
{"avoid_reuse", RPCArg::Type::BOOL, /* default */ "false", "Keep track of coin reuse, and treat dirty and clean coins differently with privacy considerations in mind."},
|
{"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{
|
||||||
RPCResult::Type::OBJ, "", "",
|
RPCResult::Type::OBJ, "", "",
|
||||||
@@ -2742,6 +2743,9 @@ static UniValue createwallet(const JSONRPCRequest& request)
|
|||||||
if (!request.params[4].isNull() && request.params[4].get_bool()) {
|
if (!request.params[4].isNull() && request.params[4].get_bool()) {
|
||||||
flags |= WALLET_FLAG_AVOID_REUSE;
|
flags |= WALLET_FLAG_AVOID_REUSE;
|
||||||
}
|
}
|
||||||
|
if (!request.params[5].isNull() && request.params[5].get_bool()) {
|
||||||
|
flags |= WALLET_FLAG_DESCRIPTORS;
|
||||||
|
}
|
||||||
|
|
||||||
std::string error;
|
std::string error;
|
||||||
std::shared_ptr<CWallet> wallet;
|
std::shared_ptr<CWallet> wallet;
|
||||||
@@ -4298,7 +4302,7 @@ static const CRPCCommand commands[] =
|
|||||||
{ "wallet", "addmultisigaddress", &addmultisigaddress, {"nrequired","keys","label","address_type"} },
|
{ "wallet", "addmultisigaddress", &addmultisigaddress, {"nrequired","keys","label","address_type"} },
|
||||||
{ "wallet", "backupwallet", &backupwallet, {"destination"} },
|
{ "wallet", "backupwallet", &backupwallet, {"destination"} },
|
||||||
{ "wallet", "bumpfee", &bumpfee, {"txid", "options"} },
|
{ "wallet", "bumpfee", &bumpfee, {"txid", "options"} },
|
||||||
{ "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", "dumpprivkey", &dumpprivkey, {"address"} },
|
{ "wallet", "dumpprivkey", &dumpprivkey, {"address"} },
|
||||||
{ "wallet", "dumpwallet", &dumpwallet, {"filename"} },
|
{ "wallet", "dumpwallet", &dumpwallet, {"filename"} },
|
||||||
{ "wallet", "encryptwallet", &encryptwallet, {"passphrase"} },
|
{ "wallet", "encryptwallet", &encryptwallet, {"passphrase"} },
|
||||||
|
|||||||
+51
-8
@@ -228,10 +228,14 @@ WalletCreationStatus CreateWallet(interfaces::Chain& chain, const SecureString&
|
|||||||
// Set a seed for the wallet
|
// Set a seed for the wallet
|
||||||
{
|
{
|
||||||
LOCK(wallet->cs_wallet);
|
LOCK(wallet->cs_wallet);
|
||||||
for (auto spk_man : wallet->GetActiveScriptPubKeyMans()) {
|
if (wallet->IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS)) {
|
||||||
if (!spk_man->SetupGeneration()) {
|
wallet->SetupDescriptorScriptPubKeyMans();
|
||||||
error = "Unable to generate initial keys";
|
} else {
|
||||||
return WalletCreationStatus::CREATION_FAILED;
|
for (auto spk_man : wallet->GetActiveScriptPubKeyMans()) {
|
||||||
|
if (!spk_man->SetupGeneration()) {
|
||||||
|
error = "Unable to generate initial keys";
|
||||||
|
return WalletCreationStatus::CREATION_FAILED;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3783,10 +3787,16 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain,
|
|||||||
|
|
||||||
if (!(wallet_creation_flags & (WALLET_FLAG_DISABLE_PRIVATE_KEYS | WALLET_FLAG_BLANK_WALLET))) {
|
if (!(wallet_creation_flags & (WALLET_FLAG_DISABLE_PRIVATE_KEYS | WALLET_FLAG_BLANK_WALLET))) {
|
||||||
LOCK(walletInstance->cs_wallet);
|
LOCK(walletInstance->cs_wallet);
|
||||||
for (auto spk_man : walletInstance->GetActiveScriptPubKeyMans()) {
|
if (walletInstance->IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS)) {
|
||||||
if (!spk_man->SetupGeneration()) {
|
walletInstance->SetupDescriptorScriptPubKeyMans();
|
||||||
error = _("Unable to generate initial keys").translated;
|
// SetupDescriptorScriptPubKeyMans already calls SetupGeneration for us so we don't need to call SetupGeneration separately
|
||||||
return nullptr;
|
} else {
|
||||||
|
// Legacy wallets need SetupGeneration here.
|
||||||
|
for (auto spk_man : walletInstance->GetActiveScriptPubKeyMans()) {
|
||||||
|
if (!spk_man->SetupGeneration()) {
|
||||||
|
error = _("Unable to generate initial keys").translated;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4351,6 +4361,39 @@ void CWallet::LoadDescriptorScriptPubKeyMan(uint256 id, WalletDescriptor& desc)
|
|||||||
m_spk_managers[id] = std::move(spk_manager);
|
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::unique_ptr<DescriptorScriptPubKeyMan>(new DescriptorScriptPubKeyMan(*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)
|
void CWallet::SetActiveScriptPubKeyMan(uint256 id, OutputType type, bool internal, bool memonly)
|
||||||
{
|
{
|
||||||
auto& spk_mans = internal ? m_internal_spk_managers : m_external_spk_managers;
|
auto& spk_mans = internal ? m_internal_spk_managers : m_external_spk_managers;
|
||||||
|
|||||||
@@ -1244,6 +1244,9 @@ public:
|
|||||||
//! @param[in] internal Whether this ScriptPubKeyMan provides change addresses
|
//! @param[in] internal Whether this ScriptPubKeyMan provides change addresses
|
||||||
//! @param[in] memonly Whether to record this update to the database. Set to true for wallet loading, normally false when actually updating the wallet.
|
//! @param[in] memonly Whether to record this update to the database. Set to true for wallet loading, normally false when actually updating the wallet.
|
||||||
void SetActiveScriptPubKeyMan(uint256 id, OutputType type, bool internal, bool memonly = false);
|
void SetActiveScriptPubKeyMan(uint256 id, OutputType type, bool internal, bool memonly = false);
|
||||||
|
|
||||||
|
//! Create new DescriptorScriptPubKeyMans and add them to the wallet
|
||||||
|
void SetupDescriptorScriptPubKeyMans();
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in new issue
Block a user