Be able to create new wallets with DescriptorScriptPubKeyMans as backing

This commit is contained in:
Andrew Chow 2019-07-11 18:21:21 -04:00
parent b713baa75a
commit 82ae02b165
8 changed files with 87 additions and 11 deletions

View file

@ -60,3 +60,8 @@ bool CreateWalletDialog::isMakeBlankWalletChecked() const
{
return ui->blank_wallet_checkbox->isChecked();
}
bool CreateWalletDialog::isDescriptorWalletChecked() const
{
return ui->descriptor_checkbox->isChecked();
}

View file

@ -27,6 +27,7 @@ public:
bool isEncryptWalletChecked() const;
bool isDisablePrivateKeysChecked() const;
bool isMakeBlankWalletChecked() const;
bool isDescriptorWalletChecked() const;
private:
Ui::CreateWalletDialog *ui;

View file

@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>364</width>
<height>185</height>
<height>213</height>
</rect>
</property>
<property name="windowTitle">
@ -17,7 +17,7 @@
<property name="geometry">
<rect>
<x>10</x>
<y>140</y>
<y>170</y>
<width>341</width>
<height>32</height>
</rect>
@ -106,6 +106,22 @@
<string>Make Blank Wallet</string>
</property>
</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>
<tabstops>
<tabstop>wallet_name_line_edit</tabstop>

View file

@ -226,6 +226,9 @@ void CreateWalletActivity::createWallet()
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;

View file

@ -170,6 +170,7 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "createwallet", 1, "disable_private_keys"},
{ "createwallet", 2, "blank"},
{ "createwallet", 4, "avoid_reuse"},
{ "createwallet", 5, "descriptors"},
{ "getnodeaddresses", 0, "count"},
{ "stop", 0, "wait" },
};

View file

@ -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."},
{"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."},
{"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, "", "",
@ -2742,6 +2743,9 @@ static UniValue createwallet(const JSONRPCRequest& request)
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;
}
std::string error;
std::shared_ptr<CWallet> wallet;
@ -4298,7 +4302,7 @@ static const CRPCCommand commands[] =
{ "wallet", "addmultisigaddress", &addmultisigaddress, {"nrequired","keys","label","address_type"} },
{ "wallet", "backupwallet", &backupwallet, {"destination"} },
{ "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", "dumpwallet", &dumpwallet, {"filename"} },
{ "wallet", "encryptwallet", &encryptwallet, {"passphrase"} },

View file

@ -228,10 +228,14 @@ WalletCreationStatus CreateWallet(interfaces::Chain& chain, const SecureString&
// Set a seed for the wallet
{
LOCK(wallet->cs_wallet);
for (auto spk_man : wallet->GetActiveScriptPubKeyMans()) {
if (!spk_man->SetupGeneration()) {
error = "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 = "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))) {
LOCK(walletInstance->cs_wallet);
for (auto spk_man : walletInstance->GetActiveScriptPubKeyMans()) {
if (!spk_man->SetupGeneration()) {
error = _("Unable to generate initial keys").translated;
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").translated;
return nullptr;
}
}
}
}
@ -4351,6 +4361,39 @@ void CWallet::LoadDescriptorScriptPubKeyMan(uint256 id, WalletDescriptor& desc)
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)
{
auto& spk_mans = internal ? m_internal_spk_managers : m_external_spk_managers;

View file

@ -1244,6 +1244,9 @@ public:
//! @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.
void SetActiveScriptPubKeyMan(uint256 id, OutputType type, bool internal, bool memonly = false);
//! Create new DescriptorScriptPubKeyMans and add them to the wallet
void SetupDescriptorScriptPubKeyMans();
};
/**