aboutsummaryrefslogtreecommitdiff
path: root/src/wallet/wallet.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/wallet/wallet.cpp')
-rw-r--r--src/wallet/wallet.cpp84
1 files changed, 52 insertions, 32 deletions
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index b709bd9650..daddd6446d 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -35,6 +35,7 @@
#include <util/moneystr.h>
#include <util/rbf.h>
#include <util/string.h>
+#include <util/system.h>
#include <util/translation.h>
#include <wallet/coincontrol.h>
#include <wallet/context.h>
@@ -551,7 +552,7 @@ bool CWallet::ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase,
bool fWasLocked = IsLocked();
{
- LOCK(cs_wallet);
+ LOCK2(m_relock_mutex, cs_wallet);
Lock();
CCrypter crypter;
@@ -786,7 +787,7 @@ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase)
return false;
{
- LOCK(cs_wallet);
+ LOCK2(m_relock_mutex, cs_wallet);
mapMasterKeys[++nMasterKeyMaxID] = kMasterKey;
WalletBatch* encrypted_batch = new WalletBatch(GetDatabase());
if (!encrypted_batch->TxnBegin()) {
@@ -1109,7 +1110,7 @@ CWalletTx* CWallet::AddToWallet(CTransactionRef tx, const TxState& state, const
#if HAVE_SYSTEM
// notify an external script when a wallet transaction comes in or is updated
- std::string strCmd = m_args.GetArg("-walletnotify", "");
+ std::string strCmd = m_notify_tx_changed_script;
if (!strCmd.empty())
{
@@ -2914,7 +2915,11 @@ std::shared_ptr<CWallet> CWallet::Create(WalletContext& context, const std::stri
const auto start{SteadyClock::now()};
// TODO: Can't use std::make_shared because we need a custom deleter but
// should be possible to use std::allocate_shared.
- std::shared_ptr<CWallet> walletInstance(new CWallet(chain, name, args, std::move(database)), ReleaseWallet);
+ std::shared_ptr<CWallet> walletInstance(new CWallet(chain, name, std::move(database)), ReleaseWallet);
+ walletInstance->m_keypool_size = std::max(args.GetIntArg("-keypool", DEFAULT_KEYPOOL_SIZE), int64_t{1});
+ walletInstance->m_notify_tx_changed_script = args.GetArg("-walletnotify", "");
+
+ // Load wallet
bool rescan_required = false;
DBErrors nLoadWalletRet = walletInstance->LoadWallet();
if (nLoadWalletRet != DBErrors::LOAD_OK) {
@@ -3407,7 +3412,7 @@ bool CWallet::Lock()
return false;
{
- LOCK(cs_wallet);
+ LOCK2(m_relock_mutex, cs_wallet);
if (!vMasterKey.empty()) {
memory_cleanse(vMasterKey.data(), vMasterKey.size() * sizeof(decltype(vMasterKey)::value_type));
vMasterKey.clear();
@@ -3538,7 +3543,7 @@ void CWallet::SetupLegacyScriptPubKeyMan()
return;
}
- auto spk_manager = std::unique_ptr<ScriptPubKeyMan>(new LegacyScriptPubKeyMan(*this));
+ auto spk_manager = std::unique_ptr<ScriptPubKeyMan>(new LegacyScriptPubKeyMan(*this, m_keypool_size));
for (const auto& type : LEGACY_OUTPUT_TYPES) {
m_internal_spk_managers[type] = spk_manager.get();
m_external_spk_managers[type] = spk_manager.get();
@@ -3567,10 +3572,10 @@ void CWallet::ConnectScriptPubKeyManNotifiers()
void CWallet::LoadDescriptorScriptPubKeyMan(uint256 id, WalletDescriptor& desc)
{
if (IsWalletFlagSet(WALLET_FLAG_EXTERNAL_SIGNER)) {
- auto spk_manager = std::unique_ptr<ScriptPubKeyMan>(new ExternalSignerScriptPubKeyMan(*this, desc));
+ auto spk_manager = std::unique_ptr<ScriptPubKeyMan>(new ExternalSignerScriptPubKeyMan(*this, desc, m_keypool_size));
m_spk_managers[id] = std::move(spk_manager);
} else {
- auto spk_manager = std::unique_ptr<ScriptPubKeyMan>(new DescriptorScriptPubKeyMan(*this, desc));
+ auto spk_manager = std::unique_ptr<ScriptPubKeyMan>(new DescriptorScriptPubKeyMan(*this, desc, m_keypool_size));
m_spk_managers[id] = std::move(spk_manager);
}
}
@@ -3581,7 +3586,7 @@ void CWallet::SetupDescriptorScriptPubKeyMans(const CExtKey& master_key)
for (bool internal : {false, true}) {
for (OutputType t : OUTPUT_TYPES) {
- auto spk_manager = std::unique_ptr<DescriptorScriptPubKeyMan>(new DescriptorScriptPubKeyMan(*this));
+ auto spk_manager = std::unique_ptr<DescriptorScriptPubKeyMan>(new DescriptorScriptPubKeyMan(*this, m_keypool_size));
if (IsCrypted()) {
if (IsLocked()) {
throw std::runtime_error(std::string(__func__) + ": Wallet is locked, cannot setup new descriptors");
@@ -3637,7 +3642,7 @@ void CWallet::SetupDescriptorScriptPubKeyMans()
continue;
}
OutputType t = *desc->GetOutputType();
- auto spk_manager = std::unique_ptr<ExternalSignerScriptPubKeyMan>(new ExternalSignerScriptPubKeyMan(*this));
+ auto spk_manager = std::unique_ptr<ExternalSignerScriptPubKeyMan>(new ExternalSignerScriptPubKeyMan(*this, m_keypool_size));
spk_manager->SetupDescriptor(std::move(desc));
uint256 id = spk_manager->GetID();
m_spk_managers[id] = std::move(spk_manager);
@@ -3753,7 +3758,7 @@ ScriptPubKeyMan* CWallet::AddWalletDescriptor(WalletDescriptor& desc, const Flat
WalletLogPrintf("Update existing descriptor: %s\n", desc.descriptor->ToString());
spk_man->UpdateWalletDescriptor(desc);
} else {
- auto new_spk_man = std::unique_ptr<DescriptorScriptPubKeyMan>(new DescriptorScriptPubKeyMan(*this, desc));
+ auto new_spk_man = std::unique_ptr<DescriptorScriptPubKeyMan>(new DescriptorScriptPubKeyMan(*this, desc, m_keypool_size));
spk_man = new_spk_man.get();
// Save the descriptor to memory
@@ -3879,7 +3884,7 @@ std::optional<MigrationData> CWallet::GetDescriptorsForLegacy(bilingual_str& err
std::optional<MigrationData> res = legacy_spkm->MigrateToDescriptor();
if (res == std::nullopt) {
- error = _("Error: Unable to produce descriptors for this legacy wallet. Make sure the wallet is unlocked first");
+ error = _("Error: Unable to produce descriptors for this legacy wallet. Make sure to provide the wallet's passphrase if it is encrypted.");
return std::nullopt;
}
return res;
@@ -4169,32 +4174,19 @@ bool DoMigration(CWallet& wallet, WalletContext& context, bilingual_str& error,
return true;
}
-util::Result<MigrationResult> MigrateLegacyToDescriptor(std::shared_ptr<CWallet>&& wallet, WalletContext& context)
+util::Result<MigrationResult> MigrateLegacyToDescriptor(const std::string& wallet_name, const SecureString& passphrase, WalletContext& context)
{
- // Before anything else, check if there is something to migrate.
- if (!wallet->GetLegacyScriptPubKeyMan()) {
- return util::Error{_("Error: This wallet is already a descriptor wallet")};
- }
-
MigrationResult res;
bilingual_str error;
std::vector<bilingual_str> warnings;
- // Make a backup of the DB
- std::string wallet_name = wallet->GetName();
- fs::path this_wallet_dir = fs::absolute(fs::PathFromString(wallet->GetDatabase().Filename())).parent_path();
- fs::path backup_filename = fs::PathFromString(strprintf("%s-%d.legacy.bak", wallet_name, GetTime()));
- fs::path backup_path = this_wallet_dir / backup_filename;
- if (!wallet->BackupWallet(fs::PathToString(backup_path))) {
- return util::Error{_("Error: Unable to make a backup of your wallet")};
- }
- res.backup_path = backup_path;
-
- // Unload the wallet so that nothing else tries to use it while we're changing it
- if (!RemoveWallet(context, wallet, /*load_on_start=*/std::nullopt, warnings)) {
- return util::Error{_("Unable to unload the wallet before migrating")};
+ // If the wallet is still loaded, unload it so that nothing else tries to use it while we're changing it
+ if (auto wallet = GetWallet(context, wallet_name)) {
+ if (!RemoveWallet(context, wallet, /*load_on_start=*/std::nullopt, warnings)) {
+ return util::Error{_("Unable to unload the wallet before migrating")};
+ }
+ UnloadWallet(std::move(wallet));
}
- UnloadWallet(std::move(wallet));
// Load the wallet but only in the context of this function.
// No signals should be connected nor should anything else be aware of this wallet
@@ -4208,15 +4200,43 @@ util::Result<MigrationResult> MigrateLegacyToDescriptor(std::shared_ptr<CWallet>
return util::Error{Untranslated("Wallet file verification failed.") + Untranslated(" ") + error};
}
+ // Make the local wallet
std::shared_ptr<CWallet> local_wallet = CWallet::Create(empty_context, wallet_name, std::move(database), options.create_flags, error, warnings);
if (!local_wallet) {
return util::Error{Untranslated("Wallet loading failed.") + Untranslated(" ") + error};
}
+ // Before anything else, check if there is something to migrate.
+ if (!local_wallet->GetLegacyScriptPubKeyMan()) {
+ return util::Error{_("Error: This wallet is already a descriptor wallet")};
+ }
+
+ // Make a backup of the DB
+ fs::path this_wallet_dir = fs::absolute(fs::PathFromString(local_wallet->GetDatabase().Filename())).parent_path();
+ fs::path backup_filename = fs::PathFromString(strprintf("%s-%d.legacy.bak", wallet_name, GetTime()));
+ fs::path backup_path = this_wallet_dir / backup_filename;
+ if (!local_wallet->BackupWallet(fs::PathToString(backup_path))) {
+ return util::Error{_("Error: Unable to make a backup of your wallet")};
+ }
+ res.backup_path = backup_path;
+
bool success = false;
{
LOCK(local_wallet->cs_wallet);
+ // Unlock the wallet if needed
+ if (local_wallet->IsLocked() && !local_wallet->Unlock(passphrase)) {
+ if (passphrase.find('\0') == std::string::npos) {
+ return util::Error{Untranslated("Error: Wallet decryption failed, the wallet passphrase was not provided or was incorrect.")};
+ } else {
+ return util::Error{Untranslated("Error: Wallet decryption failed, the wallet passphrase entered was incorrect. "
+ "The passphrase contains a null character (ie - a zero byte). "
+ "If this passphrase was set with a version of this software prior to 25.0, "
+ "please try again with only the characters up to — but not including — "
+ "the first null character.")};
+ }
+ }
+
// First change to using SQLite
if (!local_wallet->MigrateToSQLite(error)) return util::Error{error};