wallet: descriptors setup, batch db operations
Instead of doing one db transaction per descriptor setup, batch all descriptors' setup writes in a single db txn. Speeding up the process and preventing the wallet from entering an inconsistent state if any of the intermediate transactions fail.
This commit is contained in:
4 files changed
+20
-10
No files matched your search
@@ -2275,7 +2275,7 @@ bool DescriptorScriptPubKeyMan::AddDescriptorKeyWithDB(WalletBatch& batch, const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DescriptorScriptPubKeyMan::SetupDescriptorGeneration(const CExtKey& master_key, OutputType addr_type, bool internal)
|
bool DescriptorScriptPubKeyMan::SetupDescriptorGeneration(WalletBatch& batch, const CExtKey& master_key, OutputType addr_type, bool internal)
|
||||||
{
|
{
|
||||||
LOCK(cs_desc_man);
|
LOCK(cs_desc_man);
|
||||||
assert(m_storage.IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS));
|
assert(m_storage.IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS));
|
||||||
@@ -2336,9 +2336,6 @@ bool DescriptorScriptPubKeyMan::SetupDescriptorGeneration(const CExtKey& master_
|
|||||||
m_wallet_descriptor = w_desc;
|
m_wallet_descriptor = w_desc;
|
||||||
|
|
||||||
// Store the master private key, and descriptor
|
// Store the master private key, and descriptor
|
||||||
WalletBatch batch(m_storage.GetDatabase());
|
|
||||||
if (!batch.TxnBegin()) throw std::runtime_error(std::string(__func__) + ": cannot start db transaction");
|
|
||||||
|
|
||||||
if (!AddDescriptorKeyWithDB(batch, master_key.key, master_key.key.GetPubKey())) {
|
if (!AddDescriptorKeyWithDB(batch, master_key.key, master_key.key.GetPubKey())) {
|
||||||
throw std::runtime_error(std::string(__func__) + ": writing descriptor master private key failed");
|
throw std::runtime_error(std::string(__func__) + ": writing descriptor master private key failed");
|
||||||
}
|
}
|
||||||
@@ -2350,8 +2347,6 @@ bool DescriptorScriptPubKeyMan::SetupDescriptorGeneration(const CExtKey& master_
|
|||||||
TopUpWithDB(batch);
|
TopUpWithDB(batch);
|
||||||
|
|
||||||
m_storage.UnsetBlankWalletFlag(batch);
|
m_storage.UnsetBlankWalletFlag(batch);
|
||||||
|
|
||||||
if (!batch.TxnCommit()) throw std::runtime_error(std::string(__func__) + ": error committing db transaction");
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -621,7 +621,7 @@ public:
|
|||||||
bool IsHDEnabled() const override;
|
bool IsHDEnabled() const override;
|
||||||
|
|
||||||
//! Setup descriptors based on the given CExtkey
|
//! Setup descriptors based on the given CExtkey
|
||||||
bool SetupDescriptorGeneration(const CExtKey& master_key, OutputType addr_type, bool internal);
|
bool SetupDescriptorGeneration(WalletBatch& batch, const CExtKey& master_key, OutputType addr_type, bool internal);
|
||||||
|
|
||||||
/** Provide a descriptor at setup time
|
/** Provide a descriptor at setup time
|
||||||
* Returns false if already setup or setup fails, true if setup is successful
|
* Returns false if already setup or setup fails, true if setup is successful
|
||||||
|
|||||||
+15
-3
@@ -3535,6 +3535,10 @@ void CWallet::SetupDescriptorScriptPubKeyMans(const CExtKey& master_key)
|
|||||||
{
|
{
|
||||||
AssertLockHeld(cs_wallet);
|
AssertLockHeld(cs_wallet);
|
||||||
|
|
||||||
|
// Create single batch txn
|
||||||
|
WalletBatch batch(GetDatabase());
|
||||||
|
if (!batch.TxnBegin()) throw std::runtime_error("Error: cannot create db transaction for descriptors setup");
|
||||||
|
|
||||||
for (bool internal : {false, true}) {
|
for (bool internal : {false, true}) {
|
||||||
for (OutputType t : OUTPUT_TYPES) {
|
for (OutputType t : OUTPUT_TYPES) {
|
||||||
auto spk_manager = std::unique_ptr<DescriptorScriptPubKeyMan>(new DescriptorScriptPubKeyMan(*this, m_keypool_size));
|
auto spk_manager = std::unique_ptr<DescriptorScriptPubKeyMan>(new DescriptorScriptPubKeyMan(*this, m_keypool_size));
|
||||||
@@ -3542,16 +3546,19 @@ void CWallet::SetupDescriptorScriptPubKeyMans(const CExtKey& master_key)
|
|||||||
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");
|
||||||
}
|
}
|
||||||
if (!spk_manager->CheckDecryptionKey(vMasterKey) && !spk_manager->Encrypt(vMasterKey, nullptr)) {
|
if (!spk_manager->CheckDecryptionKey(vMasterKey) && !spk_manager->Encrypt(vMasterKey, &batch)) {
|
||||||
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(master_key, t, internal);
|
spk_manager->SetupDescriptorGeneration(batch, master_key, t, internal);
|
||||||
uint256 id = spk_manager->GetID();
|
uint256 id = spk_manager->GetID();
|
||||||
AddScriptPubKeyMan(id, std::move(spk_manager));
|
AddScriptPubKeyMan(id, std::move(spk_manager));
|
||||||
AddActiveScriptPubKeyMan(id, t, internal);
|
AddActiveScriptPubKeyManWithDb(batch, id, t, internal);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ensure information is committed to disk
|
||||||
|
if (!batch.TxnCommit()) throw std::runtime_error("Error: cannot commit db transaction for descriptors setup");
|
||||||
}
|
}
|
||||||
|
|
||||||
void CWallet::SetupDescriptorScriptPubKeyMans()
|
void CWallet::SetupDescriptorScriptPubKeyMans()
|
||||||
@@ -3606,6 +3613,11 @@ void CWallet::SetupDescriptorScriptPubKeyMans()
|
|||||||
void CWallet::AddActiveScriptPubKeyMan(uint256 id, OutputType type, bool internal)
|
void CWallet::AddActiveScriptPubKeyMan(uint256 id, OutputType type, bool internal)
|
||||||
{
|
{
|
||||||
WalletBatch batch(GetDatabase());
|
WalletBatch batch(GetDatabase());
|
||||||
|
return AddActiveScriptPubKeyManWithDb(batch, id, type, internal);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CWallet::AddActiveScriptPubKeyManWithDb(WalletBatch& batch, uint256 id, OutputType type, bool internal)
|
||||||
|
{
|
||||||
if (!batch.WriteActiveScriptPubKeyMan(static_cast<uint8_t>(type), id, internal)) {
|
if (!batch.WriteActiveScriptPubKeyMan(static_cast<uint8_t>(type), id, internal)) {
|
||||||
throw std::runtime_error(std::string(__func__) + ": writing active ScriptPubKeyMan id failed");
|
throw std::runtime_error(std::string(__func__) + ": writing active ScriptPubKeyMan id failed");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -419,6 +419,9 @@ private:
|
|||||||
// Must be the only method adding data to it.
|
// Must be the only method adding data to it.
|
||||||
void AddScriptPubKeyMan(const uint256& id, std::unique_ptr<ScriptPubKeyMan> spkm_man);
|
void AddScriptPubKeyMan(const uint256& id, std::unique_ptr<ScriptPubKeyMan> spkm_man);
|
||||||
|
|
||||||
|
// Same as 'AddActiveScriptPubKeyMan' but designed for use within a batch transaction context
|
||||||
|
void AddActiveScriptPubKeyManWithDb(WalletBatch& batch, uint256 id, OutputType type, bool internal);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Catch wallet up to current chain, scanning new blocks, updating the best
|
* Catch wallet up to current chain, scanning new blocks, updating the best
|
||||||
* block locator and m_last_block_processed, and registering for
|
* block locator and m_last_block_processed, and registering for
|
||||||
|
|||||||
Reference in new issue
Block a user