mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-04-29 14:59:39 -04:00
Merge 3356805e70
into c5e44a0435
This commit is contained in:
commit
dcc3a82063
8 changed files with 177 additions and 166 deletions
|
@ -21,7 +21,8 @@
|
||||||
using common::PSBTError;
|
using common::PSBTError;
|
||||||
|
|
||||||
namespace wallet {
|
namespace wallet {
|
||||||
bool ExternalSignerScriptPubKeyMan::SetupDescriptor(WalletBatch& batch, std::unique_ptr<Descriptor> desc)
|
ExternalSignerScriptPubKeyMan::ExternalSignerScriptPubKeyMan(WalletStorage& storage, WalletBatch& batch, int64_t keypool_size, std::unique_ptr<Descriptor> desc)
|
||||||
|
: DescriptorScriptPubKeyMan(storage, keypool_size)
|
||||||
{
|
{
|
||||||
LOCK(cs_desc_man);
|
LOCK(cs_desc_man);
|
||||||
assert(m_storage.IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS));
|
assert(m_storage.IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS));
|
||||||
|
@ -42,7 +43,6 @@ bool ExternalSignerScriptPubKeyMan::SetupDescriptor(WalletBatch& batch, std::uni
|
||||||
TopUpWithDB(batch);
|
TopUpWithDB(batch);
|
||||||
|
|
||||||
m_storage.UnsetBlankWalletFlag(batch);
|
m_storage.UnsetBlankWalletFlag(batch);
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ExternalSigner ExternalSignerScriptPubKeyMan::GetExternalSigner() {
|
ExternalSigner ExternalSignerScriptPubKeyMan::GetExternalSigner() {
|
||||||
|
|
|
@ -14,18 +14,13 @@ struct bilingual_str;
|
||||||
namespace wallet {
|
namespace wallet {
|
||||||
class ExternalSignerScriptPubKeyMan : public DescriptorScriptPubKeyMan
|
class ExternalSignerScriptPubKeyMan : public DescriptorScriptPubKeyMan
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ExternalSignerScriptPubKeyMan(WalletStorage& storage, WalletDescriptor& descriptor, int64_t keypool_size)
|
//! Create an ExternalSPKM from existing wallet data
|
||||||
: DescriptorScriptPubKeyMan(storage, descriptor, keypool_size)
|
ExternalSignerScriptPubKeyMan(WalletStorage& storage, const uint256& id, WalletDescriptor& descriptor, int64_t keypool_size, const KeyMap& keys, const CryptedKeyMap& ckeys)
|
||||||
|
: DescriptorScriptPubKeyMan(storage, id, descriptor, keypool_size, keys, ckeys)
|
||||||
{}
|
{}
|
||||||
ExternalSignerScriptPubKeyMan(WalletStorage& storage, int64_t keypool_size)
|
//! Create a new ExternalSPKM from just a descriptor
|
||||||
: DescriptorScriptPubKeyMan(storage, keypool_size)
|
ExternalSignerScriptPubKeyMan(WalletStorage& storage, WalletBatch& batch, int64_t keypool_size, std::unique_ptr<Descriptor> desc);
|
||||||
{}
|
|
||||||
|
|
||||||
/** Provide a descriptor at setup time
|
|
||||||
* Returns false if already setup or setup fails, true if setup is successful
|
|
||||||
*/
|
|
||||||
bool SetupDescriptor(WalletBatch& batch, std::unique_ptr<Descriptor>desc);
|
|
||||||
|
|
||||||
static ExternalSigner GetExternalSigner();
|
static ExternalSigner GetExternalSigner();
|
||||||
|
|
||||||
|
|
|
@ -1851,9 +1851,8 @@ std::optional<MigrationData> LegacyDataSPKM::MigrateToDescriptor()
|
||||||
WalletDescriptor w_desc(std::move(descs.at(0)), creation_time, 0, 0, 0);
|
WalletDescriptor w_desc(std::move(descs.at(0)), creation_time, 0, 0, 0);
|
||||||
|
|
||||||
// Make the DescriptorScriptPubKeyMan and get the scriptPubKeys
|
// Make the DescriptorScriptPubKeyMan and get the scriptPubKeys
|
||||||
auto desc_spk_man = std::make_unique<DescriptorScriptPubKeyMan>(m_storage, w_desc, /*keypool_size=*/0);
|
keys.keys.emplace(key.GetPubKey().GetID(), key);
|
||||||
WITH_LOCK(desc_spk_man->cs_desc_man, desc_spk_man->AddDescriptorKeyWithDB(batch, key, key.GetPubKey()));
|
auto desc_spk_man = std::make_unique<DescriptorScriptPubKeyMan>(batch, m_storage, w_desc, /*keypool_size=*/0, keys);
|
||||||
desc_spk_man->TopUpWithDB(batch);
|
|
||||||
auto desc_spks = desc_spk_man->GetScriptPubKeys();
|
auto desc_spks = desc_spk_man->GetScriptPubKeys();
|
||||||
|
|
||||||
// Remove the scriptPubKeys from our current set
|
// Remove the scriptPubKeys from our current set
|
||||||
|
@ -1897,9 +1896,8 @@ std::optional<MigrationData> LegacyDataSPKM::MigrateToDescriptor()
|
||||||
WalletDescriptor w_desc(std::move(descs.at(0)), 0, 0, chain_counter, 0);
|
WalletDescriptor w_desc(std::move(descs.at(0)), 0, 0, chain_counter, 0);
|
||||||
|
|
||||||
// Make the DescriptorScriptPubKeyMan and get the scriptPubKeys
|
// Make the DescriptorScriptPubKeyMan and get the scriptPubKeys
|
||||||
auto desc_spk_man = std::make_unique<DescriptorScriptPubKeyMan>(m_storage, w_desc, /*keypool_size=*/0);
|
keys.keys.emplace(master_key.key.GetPubKey().GetID(), master_key.key);
|
||||||
WITH_LOCK(desc_spk_man->cs_desc_man, desc_spk_man->AddDescriptorKeyWithDB(batch, master_key.key, master_key.key.GetPubKey()));
|
auto desc_spk_man = std::make_unique<DescriptorScriptPubKeyMan>(batch, m_storage, w_desc, /*keypool_size=*/0, keys);
|
||||||
desc_spk_man->TopUpWithDB(batch);
|
|
||||||
auto desc_spks = desc_spk_man->GetScriptPubKeys();
|
auto desc_spks = desc_spk_man->GetScriptPubKeys();
|
||||||
|
|
||||||
// Remove the scriptPubKeys from our current set
|
// Remove the scriptPubKeys from our current set
|
||||||
|
@ -1973,16 +1971,15 @@ std::optional<MigrationData> LegacyDataSPKM::MigrateToDescriptor()
|
||||||
desc->Expand(0, provider, desc_spks, provider);
|
desc->Expand(0, provider, desc_spks, provider);
|
||||||
} else {
|
} else {
|
||||||
// Make the DescriptorScriptPubKeyMan and get the scriptPubKeys
|
// Make the DescriptorScriptPubKeyMan and get the scriptPubKeys
|
||||||
WalletDescriptor w_desc(std::move(desc), creation_time, 0, 0, 0);
|
|
||||||
auto desc_spk_man = std::make_unique<DescriptorScriptPubKeyMan>(m_storage, w_desc, /*keypool_size=*/0);
|
|
||||||
for (const auto& keyid : privkeyids) {
|
for (const auto& keyid : privkeyids) {
|
||||||
CKey key;
|
CKey key;
|
||||||
if (!GetKey(keyid, key)) {
|
if (!GetKey(keyid, key)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
WITH_LOCK(desc_spk_man->cs_desc_man, desc_spk_man->AddDescriptorKeyWithDB(batch, key, key.GetPubKey()));
|
keys.keys.emplace(key.GetPubKey().GetID(), key);
|
||||||
}
|
}
|
||||||
desc_spk_man->TopUpWithDB(batch);
|
WalletDescriptor w_desc(std::move(desc), creation_time, 0, 0, 0);
|
||||||
|
auto desc_spk_man = std::make_unique<DescriptorScriptPubKeyMan>(batch, m_storage, w_desc, /*keypool_size=*/0, keys);
|
||||||
auto desc_spks_set = desc_spk_man->GetScriptPubKeys();
|
auto desc_spks_set = desc_spk_man->GetScriptPubKeys();
|
||||||
desc_spks.insert(desc_spks.end(), desc_spks_set.begin(), desc_spks_set.end());
|
desc_spks.insert(desc_spks.end(), desc_spks_set.begin(), desc_spks_set.end());
|
||||||
|
|
||||||
|
@ -2074,6 +2071,48 @@ bool LegacyDataSPKM::DeleteRecordsWithDB(WalletBatch& batch)
|
||||||
return batch.EraseRecords(DBKeys::LEGACY_TYPES);
|
return batch.EraseRecords(DBKeys::LEGACY_TYPES);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DescriptorScriptPubKeyMan::DescriptorScriptPubKeyMan(WalletStorage& storage, WalletDescriptor& descriptor, int64_t keypool_size, const FlatSigningProvider& provider)
|
||||||
|
: ScriptPubKeyMan(storage),
|
||||||
|
m_keypool_size(keypool_size),
|
||||||
|
m_wallet_descriptor(descriptor)
|
||||||
|
{
|
||||||
|
LOCK(cs_desc_man);
|
||||||
|
WalletBatch batch(m_storage.GetDatabase());
|
||||||
|
UpdateWithSigningProvider(batch, provider);
|
||||||
|
}
|
||||||
|
|
||||||
|
DescriptorScriptPubKeyMan::DescriptorScriptPubKeyMan(WalletBatch& batch, WalletStorage& storage, WalletDescriptor& descriptor, int64_t keypool_size, const FlatSigningProvider& provider)
|
||||||
|
: ScriptPubKeyMan(storage),
|
||||||
|
m_keypool_size(keypool_size),
|
||||||
|
m_wallet_descriptor(descriptor)
|
||||||
|
{
|
||||||
|
LOCK(cs_desc_man);
|
||||||
|
UpdateWithSigningProvider(batch, provider);
|
||||||
|
}
|
||||||
|
|
||||||
|
DescriptorScriptPubKeyMan::DescriptorScriptPubKeyMan(WalletStorage& storage, const uint256& id, WalletDescriptor& descriptor, int64_t keypool_size, const KeyMap& keys, const CryptedKeyMap& ckeys)
|
||||||
|
: ScriptPubKeyMan(storage),
|
||||||
|
m_map_keys(keys),
|
||||||
|
m_map_crypted_keys(ckeys),
|
||||||
|
m_keypool_size(keypool_size),
|
||||||
|
m_wallet_descriptor(descriptor)
|
||||||
|
{
|
||||||
|
if (!m_map_keys.empty() && !m_map_crypted_keys.empty()) {
|
||||||
|
throw std::runtime_error("Error: Wallet contains both unencrypted and encrypted keys");
|
||||||
|
}
|
||||||
|
if (id != GetID()) {
|
||||||
|
throw std::runtime_error("The descriptor ID calculated by the wallet differs from the one in DB");
|
||||||
|
}
|
||||||
|
SetCache(m_wallet_descriptor.cache);
|
||||||
|
}
|
||||||
|
|
||||||
|
DescriptorScriptPubKeyMan::DescriptorScriptPubKeyMan(WalletStorage& storage, WalletBatch& batch, int64_t keypool_size, const CExtKey& master_key, OutputType addr_type, bool internal)
|
||||||
|
: ScriptPubKeyMan(storage),
|
||||||
|
m_keypool_size(keypool_size)
|
||||||
|
{
|
||||||
|
SetupDescriptorGeneration(batch, master_key, addr_type, internal);
|
||||||
|
}
|
||||||
|
|
||||||
util::Result<CTxDestination> DescriptorScriptPubKeyMan::GetNewDestination(const OutputType type)
|
util::Result<CTxDestination> DescriptorScriptPubKeyMan::GetNewDestination(const OutputType type)
|
||||||
{
|
{
|
||||||
// Returns true if this descriptor supports getting new addresses. Conditions where we may be unable to fetch them (e.g. locked) are caught later
|
// Returns true if this descriptor supports getting new addresses. Conditions where we may be unable to fetch them (e.g. locked) are caught later
|
||||||
|
@ -2721,24 +2760,6 @@ void DescriptorScriptPubKeyMan::SetCache(const DescriptorCache& cache)
|
||||||
m_storage.TopUpCallback(new_spks, this);
|
m_storage.TopUpCallback(new_spks, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DescriptorScriptPubKeyMan::AddKey(const CKeyID& key_id, const CKey& key)
|
|
||||||
{
|
|
||||||
LOCK(cs_desc_man);
|
|
||||||
m_map_keys[key_id] = key;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DescriptorScriptPubKeyMan::AddCryptedKey(const CKeyID& key_id, const CPubKey& pubkey, const std::vector<unsigned char>& crypted_key)
|
|
||||||
{
|
|
||||||
LOCK(cs_desc_man);
|
|
||||||
if (!m_map_keys.empty()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_map_crypted_keys[key_id] = make_pair(pubkey, crypted_key);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DescriptorScriptPubKeyMan::HasWalletDescriptor(const WalletDescriptor& desc) const
|
bool DescriptorScriptPubKeyMan::HasWalletDescriptor(const WalletDescriptor& desc) const
|
||||||
{
|
{
|
||||||
LOCK(cs_desc_man);
|
LOCK(cs_desc_man);
|
||||||
|
@ -2827,7 +2848,7 @@ void DescriptorScriptPubKeyMan::UpgradeDescriptorCache()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
util::Result<void> DescriptorScriptPubKeyMan::UpdateWalletDescriptor(WalletDescriptor& descriptor)
|
util::Result<void> DescriptorScriptPubKeyMan::UpdateWalletDescriptor(WalletDescriptor& descriptor, const FlatSigningProvider& provider)
|
||||||
{
|
{
|
||||||
LOCK(cs_desc_man);
|
LOCK(cs_desc_man);
|
||||||
std::string error;
|
std::string error;
|
||||||
|
@ -2840,10 +2861,27 @@ util::Result<void> DescriptorScriptPubKeyMan::UpdateWalletDescriptor(WalletDescr
|
||||||
m_max_cached_index = -1;
|
m_max_cached_index = -1;
|
||||||
m_wallet_descriptor = descriptor;
|
m_wallet_descriptor = descriptor;
|
||||||
|
|
||||||
|
WalletBatch batch(m_storage.GetDatabase());
|
||||||
|
UpdateWithSigningProvider(batch, provider);
|
||||||
NotifyFirstKeyTimeChanged(this, m_wallet_descriptor.creation_time);
|
NotifyFirstKeyTimeChanged(this, m_wallet_descriptor.creation_time);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DescriptorScriptPubKeyMan::UpdateWithSigningProvider(WalletBatch& batch, const FlatSigningProvider& signing_provider)
|
||||||
|
{
|
||||||
|
AssertLockHeld(cs_desc_man);
|
||||||
|
// Add the private keys to the descriptor
|
||||||
|
for (const auto& entry : signing_provider.keys) {
|
||||||
|
const CKey& key = entry.second;
|
||||||
|
AddDescriptorKeyWithDB(batch, key, key.GetPubKey());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Top up key pool, to generate scriptPubKeys
|
||||||
|
if (!TopUpWithDB(batch)) {
|
||||||
|
throw std::runtime_error("Could not top up scriptPubKeys");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool DescriptorScriptPubKeyMan::CanUpdateToWalletDescriptor(const WalletDescriptor& descriptor, std::string& error)
|
bool DescriptorScriptPubKeyMan::CanUpdateToWalletDescriptor(const WalletDescriptor& descriptor, std::string& error)
|
||||||
{
|
{
|
||||||
LOCK(cs_desc_man);
|
LOCK(cs_desc_man);
|
||||||
|
|
|
@ -205,12 +205,6 @@ public:
|
||||||
*/
|
*/
|
||||||
virtual std::vector<WalletDestination> MarkUnusedAddresses(const CScript& script) { return {}; }
|
virtual std::vector<WalletDestination> MarkUnusedAddresses(const CScript& script) { return {}; }
|
||||||
|
|
||||||
/** Sets up the key generation stuff, i.e. generates new HD seeds and sets them as active.
|
|
||||||
* Returns false if already setup or setup fails, true if setup is successful
|
|
||||||
* Set force=true to make it re-setup if already setup, used for upgrades
|
|
||||||
*/
|
|
||||||
virtual bool SetupGeneration(bool force = false) { return false; }
|
|
||||||
|
|
||||||
/* Returns true if HD is enabled */
|
/* Returns true if HD is enabled */
|
||||||
virtual bool IsHDEnabled() const { return false; }
|
virtual bool IsHDEnabled() const { return false; }
|
||||||
|
|
||||||
|
@ -279,15 +273,18 @@ static const std::unordered_set<OutputType> LEGACY_OUTPUT_TYPES {
|
||||||
|
|
||||||
class DescriptorScriptPubKeyMan;
|
class DescriptorScriptPubKeyMan;
|
||||||
|
|
||||||
|
using WatchOnlySet = std::set<CScript>;
|
||||||
|
using WatchKeyMap = std::map<CKeyID, CPubKey>;
|
||||||
|
using KeyMap = std::map<CKeyID, CKey>;
|
||||||
|
using CryptedKeyMap = std::map<CKeyID, std::pair<CPubKey, std::vector<unsigned char>>>;
|
||||||
|
using ScriptPubKeyMap = std::map<CScript, int32_t>; // Map of scripts to descriptor range index
|
||||||
|
using PubKeyMap = std::map<CPubKey, int32_t>; // Map of pubkeys involved in scripts to descriptor range index
|
||||||
|
|
||||||
// Manages the data for a LegacyScriptPubKeyMan.
|
// Manages the data for a LegacyScriptPubKeyMan.
|
||||||
// This is the minimum necessary to load a legacy wallet so that it can be migrated.
|
// This is the minimum necessary to load a legacy wallet so that it can be migrated.
|
||||||
class LegacyDataSPKM : public ScriptPubKeyMan, public FillableSigningProvider
|
class LegacyDataSPKM : public ScriptPubKeyMan, public FillableSigningProvider
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
using WatchOnlySet = std::set<CScript>;
|
|
||||||
using WatchKeyMap = std::map<CKeyID, CPubKey>;
|
|
||||||
using CryptedKeyMap = std::map<CKeyID, std::pair<CPubKey, std::vector<unsigned char>>>;
|
|
||||||
|
|
||||||
CryptedKeyMap mapCryptedKeys GUARDED_BY(cs_KeyStore);
|
CryptedKeyMap mapCryptedKeys GUARDED_BY(cs_KeyStore);
|
||||||
WatchOnlySet setWatchOnly GUARDED_BY(cs_KeyStore);
|
WatchOnlySet setWatchOnly GUARDED_BY(cs_KeyStore);
|
||||||
WatchKeyMap mapWatchKeys GUARDED_BY(cs_KeyStore);
|
WatchKeyMap mapWatchKeys GUARDED_BY(cs_KeyStore);
|
||||||
|
@ -474,7 +471,11 @@ public:
|
||||||
|
|
||||||
bool IsHDEnabled() const override;
|
bool IsHDEnabled() const override;
|
||||||
|
|
||||||
bool SetupGeneration(bool force = false) override;
|
/** Sets up the key generation stuff, i.e. generates new HD seeds and sets them as active.
|
||||||
|
* Returns false if already setup or setup fails, true if setup is successful
|
||||||
|
* Set force=true to make it re-setup if already setup, used for upgrades
|
||||||
|
*/
|
||||||
|
bool SetupGeneration(bool force = false);
|
||||||
|
|
||||||
bool Upgrade(int prev_version, int new_version, bilingual_str& error) override;
|
bool Upgrade(int prev_version, int new_version, bilingual_str& error) override;
|
||||||
|
|
||||||
|
@ -590,11 +591,6 @@ class DescriptorScriptPubKeyMan : public ScriptPubKeyMan
|
||||||
{
|
{
|
||||||
friend class LegacyDataSPKM;
|
friend class LegacyDataSPKM;
|
||||||
private:
|
private:
|
||||||
using ScriptPubKeyMap = std::map<CScript, int32_t>; // Map of scripts to descriptor range index
|
|
||||||
using PubKeyMap = std::map<CPubKey, int32_t>; // Map of pubkeys involved in scripts to descriptor range index
|
|
||||||
using CryptedKeyMap = std::map<CKeyID, std::pair<CPubKey, std::vector<unsigned char>>>;
|
|
||||||
using KeyMap = std::map<CKeyID, CKey>;
|
|
||||||
|
|
||||||
ScriptPubKeyMap m_map_script_pub_keys GUARDED_BY(cs_desc_man);
|
ScriptPubKeyMap m_map_script_pub_keys GUARDED_BY(cs_desc_man);
|
||||||
PubKeyMap m_map_pubkeys GUARDED_BY(cs_desc_man);
|
PubKeyMap m_map_pubkeys GUARDED_BY(cs_desc_man);
|
||||||
int32_t m_max_cached_index = -1;
|
int32_t m_max_cached_index = -1;
|
||||||
|
@ -619,22 +615,33 @@ private:
|
||||||
// Fetch the SigningProvider for a given index and optionally include private keys. Called by the above functions.
|
// Fetch the SigningProvider for a given index and optionally include private keys. Called by the above functions.
|
||||||
std::unique_ptr<FlatSigningProvider> GetSigningProvider(int32_t index, bool include_private = false) const EXCLUSIVE_LOCKS_REQUIRED(cs_desc_man);
|
std::unique_ptr<FlatSigningProvider> GetSigningProvider(int32_t index, bool include_private = false) const EXCLUSIVE_LOCKS_REQUIRED(cs_desc_man);
|
||||||
|
|
||||||
|
void SetCache(const DescriptorCache& cache);
|
||||||
|
|
||||||
|
void AddDescriptorKey(const CKey& key, const CPubKey &pubkey);
|
||||||
|
void UpdateWithSigningProvider(WalletBatch& batch, const FlatSigningProvider& signing_provider) EXCLUSIVE_LOCKS_REQUIRED(cs_desc_man);
|
||||||
|
|
||||||
|
//! Setup descriptors based on the given CExtkey
|
||||||
|
bool SetupDescriptorGeneration(WalletBatch& batch, const CExtKey& master_key, OutputType addr_type, bool internal);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
DescriptorScriptPubKeyMan(WalletStorage& storage, int64_t keypool_size)
|
||||||
|
: ScriptPubKeyMan(storage),
|
||||||
|
m_keypool_size(keypool_size)
|
||||||
|
{}
|
||||||
|
|
||||||
WalletDescriptor m_wallet_descriptor GUARDED_BY(cs_desc_man);
|
WalletDescriptor m_wallet_descriptor GUARDED_BY(cs_desc_man);
|
||||||
|
|
||||||
//! Same as 'TopUp' but designed for use within a batch transaction context
|
//! Same as 'TopUp' but designed for use within a batch transaction context
|
||||||
bool TopUpWithDB(WalletBatch& batch, unsigned int size = 0);
|
bool TopUpWithDB(WalletBatch& batch, unsigned int size = 0);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DescriptorScriptPubKeyMan(WalletStorage& storage, WalletDescriptor& descriptor, int64_t keypool_size)
|
//! Create a new DescriptorScriptPubKeyMan from an existing descriptor (i.e. from an import)
|
||||||
: ScriptPubKeyMan(storage),
|
DescriptorScriptPubKeyMan(WalletStorage& storage, WalletDescriptor& descriptor, int64_t keypool_size, const FlatSigningProvider& provider);
|
||||||
m_keypool_size(keypool_size),
|
DescriptorScriptPubKeyMan(WalletBatch& batch, WalletStorage& storage, WalletDescriptor& descriptor, int64_t keypool_size, const FlatSigningProvider& provider);
|
||||||
m_wallet_descriptor(descriptor)
|
//! Create a DescriptorScriptPubKeyMan from existing data (i.e. during loading)
|
||||||
{}
|
DescriptorScriptPubKeyMan(WalletStorage& storage, const uint256& id, WalletDescriptor& descriptor, int64_t keypool_size, const KeyMap& keys, const CryptedKeyMap& ckeys);
|
||||||
DescriptorScriptPubKeyMan(WalletStorage& storage, int64_t keypool_size)
|
//! Create an automatically generated DescriptorScriptPubKeyMan
|
||||||
: ScriptPubKeyMan(storage),
|
DescriptorScriptPubKeyMan(WalletStorage& storage, WalletBatch& batch, int64_t keypool_size, const CExtKey& master_key, OutputType addr_type, bool internal);
|
||||||
m_keypool_size(keypool_size)
|
|
||||||
{}
|
|
||||||
|
|
||||||
mutable RecursiveMutex cs_desc_man;
|
mutable RecursiveMutex cs_desc_man;
|
||||||
|
|
||||||
|
@ -657,9 +664,6 @@ public:
|
||||||
|
|
||||||
bool IsHDEnabled() const override;
|
bool IsHDEnabled() const override;
|
||||||
|
|
||||||
//! Setup descriptors based on the given CExtkey
|
|
||||||
bool SetupDescriptorGeneration(WalletBatch& batch, const CExtKey& master_key, OutputType addr_type, bool internal);
|
|
||||||
|
|
||||||
bool HavePrivateKeys() const override;
|
bool HavePrivateKeys() const override;
|
||||||
bool HasPrivKey(const CKeyID& keyid) const EXCLUSIVE_LOCKS_REQUIRED(cs_desc_man);
|
bool HasPrivKey(const CKeyID& keyid) const EXCLUSIVE_LOCKS_REQUIRED(cs_desc_man);
|
||||||
//! Retrieve the particular key if it is available. Returns nullopt if the key is not in the wallet, or if the wallet is locked.
|
//! Retrieve the particular key if it is available. Returns nullopt if the key is not in the wallet, or if the wallet is locked.
|
||||||
|
@ -688,15 +692,9 @@ public:
|
||||||
|
|
||||||
uint256 GetID() const override;
|
uint256 GetID() const override;
|
||||||
|
|
||||||
void SetCache(const DescriptorCache& cache);
|
|
||||||
|
|
||||||
bool AddKey(const CKeyID& key_id, const CKey& key);
|
|
||||||
bool AddCryptedKey(const CKeyID& key_id, const CPubKey& pubkey, const std::vector<unsigned char>& crypted_key);
|
|
||||||
|
|
||||||
bool HasWalletDescriptor(const WalletDescriptor& desc) const;
|
bool HasWalletDescriptor(const WalletDescriptor& desc) const;
|
||||||
util::Result<void> UpdateWalletDescriptor(WalletDescriptor& descriptor);
|
util::Result<void> UpdateWalletDescriptor(WalletDescriptor& descriptor, const FlatSigningProvider& provider);
|
||||||
bool CanUpdateToWalletDescriptor(const WalletDescriptor& descriptor, std::string& error);
|
bool CanUpdateToWalletDescriptor(const WalletDescriptor& descriptor, std::string& error);
|
||||||
void AddDescriptorKey(const CKey& key, const CPubKey &pubkey);
|
|
||||||
void WriteDescriptor();
|
void WriteDescriptor();
|
||||||
|
|
||||||
WalletDescriptor GetWalletDescriptor() const EXCLUSIVE_LOCKS_REQUIRED(cs_desc_man);
|
WalletDescriptor GetWalletDescriptor() const EXCLUSIVE_LOCKS_REQUIRED(cs_desc_man);
|
||||||
|
|
|
@ -73,6 +73,11 @@ static std::optional<std::pair<WalletDescriptor, FlatSigningProvider>> CreateWal
|
||||||
std::vector<std::unique_ptr<Descriptor>> parsed_descs = Parse(desc_str.value(), keys, error, false);
|
std::vector<std::unique_ptr<Descriptor>> parsed_descs = Parse(desc_str.value(), keys, error, false);
|
||||||
if (parsed_descs.empty()) return std::nullopt;
|
if (parsed_descs.empty()) return std::nullopt;
|
||||||
|
|
||||||
|
FlatSigningProvider out_keys;
|
||||||
|
std::vector<CScript> scripts_temp;
|
||||||
|
DescriptorCache temp_cache;
|
||||||
|
if (!parsed_descs.at(0)->Expand(0, keys, scripts_temp, out_keys, &temp_cache)) return std::nullopt;
|
||||||
|
|
||||||
WalletDescriptor w_desc{std::move(parsed_descs.at(0)), /*creation_time=*/0, /*range_start=*/0, /*range_end=*/1, /*next_index=*/1};
|
WalletDescriptor w_desc{std::move(parsed_descs.at(0)), /*creation_time=*/0, /*range_start=*/0, /*range_end=*/1, /*next_index=*/1};
|
||||||
return std::make_pair(w_desc, keys);
|
return std::make_pair(w_desc, keys);
|
||||||
}
|
}
|
||||||
|
|
|
@ -438,6 +438,11 @@ std::shared_ptr<CWallet> CreateWallet(WalletContext& context, const std::string&
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Unset the blank flag if not specified by the user
|
||||||
|
if (!create_blank) {
|
||||||
|
wallet->UnsetWalletFlag(WALLET_FLAG_BLANK_WALLET);
|
||||||
|
}
|
||||||
|
|
||||||
// Encrypt the wallet
|
// Encrypt the wallet
|
||||||
if (!passphrase.empty() && !(wallet_creation_flags & WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
|
if (!passphrase.empty() && !(wallet_creation_flags & WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
|
||||||
if (!wallet->EncryptWallet(passphrase)) {
|
if (!wallet->EncryptWallet(passphrase)) {
|
||||||
|
@ -445,33 +450,6 @@ std::shared_ptr<CWallet> CreateWallet(WalletContext& context, const std::string&
|
||||||
status = DatabaseStatus::FAILED_ENCRYPT;
|
status = DatabaseStatus::FAILED_ENCRYPT;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
if (!create_blank) {
|
|
||||||
// Unlock the wallet
|
|
||||||
if (!wallet->Unlock(passphrase)) {
|
|
||||||
error = Untranslated("Error: Wallet was encrypted but could not be unlocked");
|
|
||||||
status = DatabaseStatus::FAILED_ENCRYPT;
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set a seed for the wallet
|
|
||||||
{
|
|
||||||
LOCK(wallet->cs_wallet);
|
|
||||||
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");
|
|
||||||
status = DatabaseStatus::FAILED_CREATE;
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Relock the wallet
|
|
||||||
wallet->Lock();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
NotifyWalletLoaded(context, wallet);
|
NotifyWalletLoaded(context, wallet);
|
||||||
|
@ -882,16 +860,9 @@ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase)
|
||||||
Lock();
|
Lock();
|
||||||
Unlock(strWalletPassphrase);
|
Unlock(strWalletPassphrase);
|
||||||
|
|
||||||
// If we are using descriptors, make new descriptors with a new seed
|
// Generate new descriptors or seed if not blank or disable private keys
|
||||||
if (IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS) && !IsWalletFlagSet(WALLET_FLAG_BLANK_WALLET)) {
|
if (!SetupWalletGeneration()) {
|
||||||
SetupDescriptorScriptPubKeyMans();
|
return false;
|
||||||
} else if (auto spk_man = GetLegacyScriptPubKeyMan()) {
|
|
||||||
// if we are using HD, replace the HD seed with a new one
|
|
||||||
if (spk_man->IsHDEnabled()) {
|
|
||||||
if (!spk_man->SetupGeneration(true)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Lock();
|
Lock();
|
||||||
|
|
||||||
|
@ -3075,20 +3046,9 @@ std::shared_ptr<CWallet> CWallet::Create(WalletContext& context, const std::stri
|
||||||
// Only descriptor wallets can be created
|
// Only descriptor wallets can be created
|
||||||
assert(walletInstance->IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS));
|
assert(walletInstance->IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS));
|
||||||
|
|
||||||
if ((wallet_creation_flags & WALLET_FLAG_EXTERNAL_SIGNER) || !(wallet_creation_flags & (WALLET_FLAG_DISABLE_PRIVATE_KEYS | WALLET_FLAG_BLANK_WALLET))) {
|
if (!walletInstance->SetupWalletGeneration()) {
|
||||||
LOCK(walletInstance->cs_wallet);
|
error = _("Unable to generate initial keys");
|
||||||
if (walletInstance->IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS)) {
|
return nullptr;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (chain) {
|
if (chain) {
|
||||||
|
@ -3746,22 +3706,21 @@ void CWallet::ConnectScriptPubKeyManNotifiers()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DescriptorScriptPubKeyMan& CWallet::LoadDescriptorScriptPubKeyMan(uint256 id, WalletDescriptor& desc)
|
void CWallet::LoadDescriptorScriptPubKeyMan(uint256 id, WalletDescriptor& desc, const KeyMap& keys, const CryptedKeyMap& ckeys)
|
||||||
{
|
{
|
||||||
DescriptorScriptPubKeyMan* spk_manager;
|
DescriptorScriptPubKeyMan* spk_manager;
|
||||||
if (IsWalletFlagSet(WALLET_FLAG_EXTERNAL_SIGNER)) {
|
if (IsWalletFlagSet(WALLET_FLAG_EXTERNAL_SIGNER)) {
|
||||||
spk_manager = new ExternalSignerScriptPubKeyMan(*this, desc, m_keypool_size);
|
spk_manager = new ExternalSignerScriptPubKeyMan(*this, id, desc, m_keypool_size, keys, ckeys);
|
||||||
} else {
|
} else {
|
||||||
spk_manager = new DescriptorScriptPubKeyMan(*this, desc, m_keypool_size);
|
spk_manager = new DescriptorScriptPubKeyMan(*this, id, desc, m_keypool_size, keys, ckeys);
|
||||||
}
|
}
|
||||||
AddScriptPubKeyMan(id, std::unique_ptr<ScriptPubKeyMan>(spk_manager));
|
AddScriptPubKeyMan(id, std::unique_ptr<ScriptPubKeyMan>(spk_manager));
|
||||||
return *spk_manager;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DescriptorScriptPubKeyMan& CWallet::SetupDescriptorScriptPubKeyMan(WalletBatch& batch, const CExtKey& master_key, const OutputType& output_type, bool internal)
|
DescriptorScriptPubKeyMan& CWallet::SetupDescriptorScriptPubKeyMan(WalletBatch& batch, const CExtKey& master_key, const OutputType& output_type, bool internal)
|
||||||
{
|
{
|
||||||
AssertLockHeld(cs_wallet);
|
AssertLockHeld(cs_wallet);
|
||||||
auto spk_manager = std::unique_ptr<DescriptorScriptPubKeyMan>(new DescriptorScriptPubKeyMan(*this, m_keypool_size));
|
auto spk_manager = std::unique_ptr<DescriptorScriptPubKeyMan>(new DescriptorScriptPubKeyMan(*this, batch, m_keypool_size, master_key, output_type, internal));
|
||||||
if (IsCrypted()) {
|
if (IsCrypted()) {
|
||||||
if (IsLocked()) {
|
if (IsLocked()) {
|
||||||
throw std::runtime_error(std::string(__func__) + ": Wallet is locked, cannot setup new descriptors");
|
throw std::runtime_error(std::string(__func__) + ": Wallet is locked, cannot setup new descriptors");
|
||||||
|
@ -3770,7 +3729,6 @@ DescriptorScriptPubKeyMan& CWallet::SetupDescriptorScriptPubKeyMan(WalletBatch&
|
||||||
throw std::runtime_error(std::string(__func__) + ": Could not encrypt new descriptors");
|
throw std::runtime_error(std::string(__func__) + ": Could not encrypt new descriptors");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
spk_manager->SetupDescriptorGeneration(batch, master_key, output_type, internal);
|
|
||||||
DescriptorScriptPubKeyMan* out = spk_manager.get();
|
DescriptorScriptPubKeyMan* out = spk_manager.get();
|
||||||
uint256 id = spk_manager->GetID();
|
uint256 id = spk_manager->GetID();
|
||||||
AddScriptPubKeyMan(id, std::move(spk_manager));
|
AddScriptPubKeyMan(id, std::move(spk_manager));
|
||||||
|
@ -3841,8 +3799,7 @@ void CWallet::SetupDescriptorScriptPubKeyMans()
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
OutputType t = *desc->GetOutputType();
|
OutputType t = *desc->GetOutputType();
|
||||||
auto spk_manager = std::unique_ptr<ExternalSignerScriptPubKeyMan>(new ExternalSignerScriptPubKeyMan(*this, m_keypool_size));
|
auto spk_manager = std::unique_ptr<ExternalSignerScriptPubKeyMan>(new ExternalSignerScriptPubKeyMan(*this, batch, m_keypool_size, std::move(desc)));
|
||||||
spk_manager->SetupDescriptor(batch, std::move(desc));
|
|
||||||
uint256 id = spk_manager->GetID();
|
uint256 id = spk_manager->GetID();
|
||||||
AddScriptPubKeyMan(id, std::move(spk_manager));
|
AddScriptPubKeyMan(id, std::move(spk_manager));
|
||||||
AddActiveScriptPubKeyManWithDb(batch, id, t, internal);
|
AddActiveScriptPubKeyManWithDb(batch, id, t, internal);
|
||||||
|
@ -3854,6 +3811,33 @@ void CWallet::SetupDescriptorScriptPubKeyMans()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CWallet::SetupWalletGeneration()
|
||||||
|
{
|
||||||
|
LOCK(cs_wallet);
|
||||||
|
// Skip if blank or no privkeys
|
||||||
|
if (!IsWalletFlagSet(WALLET_FLAG_EXTERNAL_SIGNER) &&
|
||||||
|
(IsWalletFlagSet(WALLET_FLAG_BLANK_WALLET) || IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS))) {
|
||||||
|
// Just make sure that there's a legacy spkm if this wallet is legacy
|
||||||
|
if (!IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS)) {
|
||||||
|
SetupLegacyScriptPubKeyMan();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// If we are using descriptors, make new descriptors with a new seed
|
||||||
|
if (IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS)) {
|
||||||
|
SetupDescriptorScriptPubKeyMans();
|
||||||
|
} else if (auto spk_man = GetOrCreateLegacyScriptPubKeyMan()) {
|
||||||
|
// if we are using HD, set or replace the HD seed with a new one
|
||||||
|
// non-HD always has key generation enabled by default
|
||||||
|
if (CanSupportFeature(FEATURE_HD)) {
|
||||||
|
if (!spk_man->SetupGeneration(true)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void CWallet::AddActiveScriptPubKeyMan(uint256 id, OutputType type, bool internal)
|
void CWallet::AddActiveScriptPubKeyMan(uint256 id, OutputType type, bool internal)
|
||||||
{
|
{
|
||||||
WalletBatch batch(GetDatabase());
|
WalletBatch batch(GetDatabase());
|
||||||
|
@ -3961,11 +3945,11 @@ util::Result<ScriptPubKeyMan*> CWallet::AddWalletDescriptor(WalletDescriptor& de
|
||||||
auto spk_man = GetDescriptorScriptPubKeyMan(desc);
|
auto spk_man = GetDescriptorScriptPubKeyMan(desc);
|
||||||
if (spk_man) {
|
if (spk_man) {
|
||||||
WalletLogPrintf("Update existing descriptor: %s\n", desc.descriptor->ToString());
|
WalletLogPrintf("Update existing descriptor: %s\n", desc.descriptor->ToString());
|
||||||
if (auto spkm_res = spk_man->UpdateWalletDescriptor(desc); !spkm_res) {
|
if (auto spkm_res = spk_man->UpdateWalletDescriptor(desc, signing_provider); !spkm_res) {
|
||||||
return util::Error{util::ErrorString(spkm_res)};
|
return util::Error{util::ErrorString(spkm_res)};
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
auto new_spk_man = std::unique_ptr<DescriptorScriptPubKeyMan>(new DescriptorScriptPubKeyMan(*this, desc, m_keypool_size));
|
auto new_spk_man = std::unique_ptr<DescriptorScriptPubKeyMan>(new DescriptorScriptPubKeyMan(*this, desc, m_keypool_size, signing_provider));
|
||||||
spk_man = new_spk_man.get();
|
spk_man = new_spk_man.get();
|
||||||
|
|
||||||
// Save the descriptor to memory
|
// Save the descriptor to memory
|
||||||
|
@ -3973,18 +3957,6 @@ util::Result<ScriptPubKeyMan*> CWallet::AddWalletDescriptor(WalletDescriptor& de
|
||||||
AddScriptPubKeyMan(id, std::move(new_spk_man));
|
AddScriptPubKeyMan(id, std::move(new_spk_man));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the private keys to the descriptor
|
|
||||||
for (const auto& entry : signing_provider.keys) {
|
|
||||||
const CKey& key = entry.second;
|
|
||||||
spk_man->AddDescriptorKey(key, key.GetPubKey());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Top up key pool, the manager will generate new scriptPubKeys internally
|
|
||||||
if (!spk_man->TopUp()) {
|
|
||||||
WalletLogPrintf("Could not top up scriptPubKeys\n");
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apply the label if necessary
|
// Apply the label if necessary
|
||||||
// Note: we disable labels for ranged descriptors
|
// Note: we disable labels for ranged descriptors
|
||||||
if (!desc.descriptor->IsRange()) {
|
if (!desc.descriptor->IsRange()) {
|
||||||
|
|
|
@ -1001,7 +1001,7 @@ public:
|
||||||
void ConnectScriptPubKeyManNotifiers();
|
void ConnectScriptPubKeyManNotifiers();
|
||||||
|
|
||||||
//! Instantiate a descriptor ScriptPubKeyMan from the WalletDescriptor and load it
|
//! Instantiate a descriptor ScriptPubKeyMan from the WalletDescriptor and load it
|
||||||
DescriptorScriptPubKeyMan& LoadDescriptorScriptPubKeyMan(uint256 id, WalletDescriptor& desc);
|
void LoadDescriptorScriptPubKeyMan(uint256 id, WalletDescriptor& desc, const KeyMap& keys, const CryptedKeyMap& ckeys);
|
||||||
|
|
||||||
//! Adds the active ScriptPubKeyMan for the specified type and internal. Writes it to the wallet file
|
//! Adds the active ScriptPubKeyMan for the specified type and internal. Writes it to the wallet file
|
||||||
//! @param[in] id The unique id for the ScriptPubKeyMan
|
//! @param[in] id The unique id for the ScriptPubKeyMan
|
||||||
|
@ -1030,6 +1030,9 @@ public:
|
||||||
//! Create new seed and default DescriptorScriptPubKeyMans for this wallet
|
//! Create new seed and default DescriptorScriptPubKeyMans for this wallet
|
||||||
void SetupOwnDescriptorScriptPubKeyMans(WalletBatch& batch) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
void SetupOwnDescriptorScriptPubKeyMans(WalletBatch& batch) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
||||||
|
|
||||||
|
//! Setup new descriptors or seed for new address generation
|
||||||
|
bool SetupWalletGeneration();
|
||||||
|
|
||||||
//! Return the DescriptorScriptPubKeyMan for a WalletDescriptor if it is already in the wallet
|
//! Return the DescriptorScriptPubKeyMan for a WalletDescriptor if it is already in the wallet
|
||||||
DescriptorScriptPubKeyMan* GetDescriptorScriptPubKeyMan(const WalletDescriptor& desc) const;
|
DescriptorScriptPubKeyMan* GetDescriptorScriptPubKeyMan(const WalletDescriptor& desc) const;
|
||||||
|
|
||||||
|
|
|
@ -841,13 +841,6 @@ static DBErrors LoadDescriptorWalletRecords(CWallet* pwallet, DatabaseBatch& bat
|
||||||
strErr = strprintf("%s\nDetails: %s", strErr, e.what());
|
strErr = strprintf("%s\nDetails: %s", strErr, e.what());
|
||||||
return DBErrors::UNKNOWN_DESCRIPTOR;
|
return DBErrors::UNKNOWN_DESCRIPTOR;
|
||||||
}
|
}
|
||||||
DescriptorScriptPubKeyMan& spkm = pwallet->LoadDescriptorScriptPubKeyMan(id, desc);
|
|
||||||
|
|
||||||
// Prior to doing anything with this spkm, verify ID compatibility
|
|
||||||
if (id != spkm.GetID()) {
|
|
||||||
strErr = "The descriptor ID calculated by the wallet differs from the one in DB";
|
|
||||||
return DBErrors::CORRUPT;
|
|
||||||
}
|
|
||||||
|
|
||||||
DescriptorCache cache;
|
DescriptorCache cache;
|
||||||
|
|
||||||
|
@ -903,15 +896,14 @@ static DBErrors LoadDescriptorWalletRecords(CWallet* pwallet, DatabaseBatch& bat
|
||||||
});
|
});
|
||||||
result = std::max(result, lh_cache_res.m_result);
|
result = std::max(result, lh_cache_res.m_result);
|
||||||
|
|
||||||
// Set the cache for this descriptor
|
// Set the cache to the WalletDescriptor
|
||||||
auto spk_man = (DescriptorScriptPubKeyMan*)pwallet->GetScriptPubKeyMan(id);
|
desc.cache = cache;
|
||||||
assert(spk_man);
|
|
||||||
spk_man->SetCache(cache);
|
|
||||||
|
|
||||||
// Get unencrypted keys
|
// Get unencrypted keys
|
||||||
|
std::map<CKeyID, CKey> keys;
|
||||||
prefix = PrefixStream(DBKeys::WALLETDESCRIPTORKEY, id);
|
prefix = PrefixStream(DBKeys::WALLETDESCRIPTORKEY, id);
|
||||||
LoadResult key_res = LoadRecords(pwallet, batch, DBKeys::WALLETDESCRIPTORKEY, prefix,
|
LoadResult key_res = LoadRecords(pwallet, batch, DBKeys::WALLETDESCRIPTORKEY, prefix,
|
||||||
[&id, &spk_man] (CWallet* pwallet, DataStream& key, DataStream& value, std::string& strErr) {
|
[&id, &keys] (CWallet* pwallet, DataStream& key, DataStream& value, std::string& strErr) {
|
||||||
uint256 desc_id;
|
uint256 desc_id;
|
||||||
CPubKey pubkey;
|
CPubKey pubkey;
|
||||||
key >> desc_id;
|
key >> desc_id;
|
||||||
|
@ -946,16 +938,17 @@ static DBErrors LoadDescriptorWalletRecords(CWallet* pwallet, DatabaseBatch& bat
|
||||||
strErr = "Error reading wallet database: descriptor unencrypted key CPrivKey corrupt";
|
strErr = "Error reading wallet database: descriptor unencrypted key CPrivKey corrupt";
|
||||||
return DBErrors::CORRUPT;
|
return DBErrors::CORRUPT;
|
||||||
}
|
}
|
||||||
spk_man->AddKey(pubkey.GetID(), privkey);
|
keys[pubkey.GetID()] = privkey;
|
||||||
return DBErrors::LOAD_OK;
|
return DBErrors::LOAD_OK;
|
||||||
});
|
});
|
||||||
result = std::max(result, key_res.m_result);
|
result = std::max(result, key_res.m_result);
|
||||||
num_keys = key_res.m_records;
|
num_keys = key_res.m_records;
|
||||||
|
|
||||||
// Get encrypted keys
|
// Get encrypted keys
|
||||||
|
std::map<CKeyID, std::pair<CPubKey, std::vector<unsigned char>>> ckeys;
|
||||||
prefix = PrefixStream(DBKeys::WALLETDESCRIPTORCKEY, id);
|
prefix = PrefixStream(DBKeys::WALLETDESCRIPTORCKEY, id);
|
||||||
LoadResult ckey_res = LoadRecords(pwallet, batch, DBKeys::WALLETDESCRIPTORCKEY, prefix,
|
LoadResult ckey_res = LoadRecords(pwallet, batch, DBKeys::WALLETDESCRIPTORCKEY, prefix,
|
||||||
[&id, &spk_man] (CWallet* pwallet, DataStream& key, DataStream& value, std::string& err) {
|
[&id, &ckeys] (CWallet* pwallet, DataStream& key, DataStream& value, std::string& err) {
|
||||||
uint256 desc_id;
|
uint256 desc_id;
|
||||||
CPubKey pubkey;
|
CPubKey pubkey;
|
||||||
key >> desc_id;
|
key >> desc_id;
|
||||||
|
@ -969,12 +962,19 @@ static DBErrors LoadDescriptorWalletRecords(CWallet* pwallet, DatabaseBatch& bat
|
||||||
std::vector<unsigned char> privkey;
|
std::vector<unsigned char> privkey;
|
||||||
value >> privkey;
|
value >> privkey;
|
||||||
|
|
||||||
spk_man->AddCryptedKey(pubkey.GetID(), pubkey, privkey);
|
ckeys[pubkey.GetID()] = make_pair(pubkey, privkey);
|
||||||
return DBErrors::LOAD_OK;
|
return DBErrors::LOAD_OK;
|
||||||
});
|
});
|
||||||
result = std::max(result, ckey_res.m_result);
|
result = std::max(result, ckey_res.m_result);
|
||||||
num_ckeys = ckey_res.m_records;
|
num_ckeys = ckey_res.m_records;
|
||||||
|
|
||||||
|
try {
|
||||||
|
pwallet->LoadDescriptorScriptPubKeyMan(id, desc, keys, ckeys);
|
||||||
|
} catch (std::runtime_error& e) {
|
||||||
|
strErr = e.what();
|
||||||
|
return DBErrors::CORRUPT;
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue