Skip to content

Commit 1f65241

Browse files
committed
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.
1 parent 3eb769f commit 1f65241

File tree

4 files changed

+20
-10
lines changed

4 files changed

+20
-10
lines changed

src/wallet/scriptpubkeyman.cpp

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2275,7 +2275,7 @@ bool DescriptorScriptPubKeyMan::AddDescriptorKeyWithDB(WalletBatch& batch, const
22752275
}
22762276
}
22772277

2278-
bool DescriptorScriptPubKeyMan::SetupDescriptorGeneration(const CExtKey& master_key, OutputType addr_type, bool internal)
2278+
bool DescriptorScriptPubKeyMan::SetupDescriptorGeneration(WalletBatch& batch, const CExtKey& master_key, OutputType addr_type, bool internal)
22792279
{
22802280
LOCK(cs_desc_man);
22812281
assert(m_storage.IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS));
@@ -2336,9 +2336,6 @@ bool DescriptorScriptPubKeyMan::SetupDescriptorGeneration(const CExtKey& master_
23362336
m_wallet_descriptor = w_desc;
23372337

23382338
// Store the master private key, and descriptor
2339-
WalletBatch batch(m_storage.GetDatabase());
2340-
if (!batch.TxnBegin()) throw std::runtime_error(std::string(__func__) + ": cannot start db transaction");
2341-
23422339
if (!AddDescriptorKeyWithDB(batch, master_key.key, master_key.key.GetPubKey())) {
23432340
throw std::runtime_error(std::string(__func__) + ": writing descriptor master private key failed");
23442341
}
@@ -2350,8 +2347,6 @@ bool DescriptorScriptPubKeyMan::SetupDescriptorGeneration(const CExtKey& master_
23502347
TopUpWithDB(batch);
23512348

23522349
m_storage.UnsetBlankWalletFlag(batch);
2353-
2354-
if (!batch.TxnCommit()) throw std::runtime_error(std::string(__func__) + ": error committing db transaction");
23552350
return true;
23562351
}
23572352

src/wallet/scriptpubkeyman.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -621,7 +621,7 @@ class DescriptorScriptPubKeyMan : public ScriptPubKeyMan
621621
bool IsHDEnabled() const override;
622622

623623
//! Setup descriptors based on the given CExtkey
624-
bool SetupDescriptorGeneration(const CExtKey& master_key, OutputType addr_type, bool internal);
624+
bool SetupDescriptorGeneration(WalletBatch& batch, const CExtKey& master_key, OutputType addr_type, bool internal);
625625

626626
/** Provide a descriptor at setup time
627627
* Returns false if already setup or setup fails, true if setup is successful

src/wallet/wallet.cpp

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3535,23 +3535,30 @@ void CWallet::SetupDescriptorScriptPubKeyMans(const CExtKey& master_key)
35353535
{
35363536
AssertLockHeld(cs_wallet);
35373537

3538+
// Create single batch txn
3539+
WalletBatch batch(GetDatabase());
3540+
if (!batch.TxnBegin()) throw std::runtime_error("Error: cannot create db transaction for descriptors setup");
3541+
35383542
for (bool internal : {false, true}) {
35393543
for (OutputType t : OUTPUT_TYPES) {
35403544
auto spk_manager = std::unique_ptr<DescriptorScriptPubKeyMan>(new DescriptorScriptPubKeyMan(*this, m_keypool_size));
35413545
if (IsCrypted()) {
35423546
if (IsLocked()) {
35433547
throw std::runtime_error(std::string(__func__) + ": Wallet is locked, cannot setup new descriptors");
35443548
}
3545-
if (!spk_manager->CheckDecryptionKey(vMasterKey) && !spk_manager->Encrypt(vMasterKey, nullptr)) {
3549+
if (!spk_manager->CheckDecryptionKey(vMasterKey) && !spk_manager->Encrypt(vMasterKey, &batch)) {
35463550
throw std::runtime_error(std::string(__func__) + ": Could not encrypt new descriptors");
35473551
}
35483552
}
3549-
spk_manager->SetupDescriptorGeneration(master_key, t, internal);
3553+
spk_manager->SetupDescriptorGeneration(batch, master_key, t, internal);
35503554
uint256 id = spk_manager->GetID();
35513555
AddScriptPubKeyMan(id, std::move(spk_manager));
3552-
AddActiveScriptPubKeyMan(id, t, internal);
3556+
AddActiveScriptPubKeyManWithDb(batch, id, t, internal);
35533557
}
35543558
}
3559+
3560+
// Ensure information is committed to disk
3561+
if (!batch.TxnCommit()) throw std::runtime_error("Error: cannot commit db transaction for descriptors setup");
35553562
}
35563563

35573564
void CWallet::SetupDescriptorScriptPubKeyMans()
@@ -3606,6 +3613,11 @@ void CWallet::SetupDescriptorScriptPubKeyMans()
36063613
void CWallet::AddActiveScriptPubKeyMan(uint256 id, OutputType type, bool internal)
36073614
{
36083615
WalletBatch batch(GetDatabase());
3616+
return AddActiveScriptPubKeyManWithDb(batch, id, type, internal);
3617+
}
3618+
3619+
void CWallet::AddActiveScriptPubKeyManWithDb(WalletBatch& batch, uint256 id, OutputType type, bool internal)
3620+
{
36093621
if (!batch.WriteActiveScriptPubKeyMan(static_cast<uint8_t>(type), id, internal)) {
36103622
throw std::runtime_error(std::string(__func__) + ": writing active ScriptPubKeyMan id failed");
36113623
}

src/wallet/wallet.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -419,6 +419,9 @@ class CWallet final : public WalletStorage, public interfaces::Chain::Notificati
419419
// Must be the only method adding data to it.
420420
void AddScriptPubKeyMan(const uint256& id, std::unique_ptr<ScriptPubKeyMan> spkm_man);
421421

422+
// Same as 'AddActiveScriptPubKeyMan' but designed for use within a batch transaction context
423+
void AddActiveScriptPubKeyManWithDb(WalletBatch& batch, uint256 id, OutputType type, bool internal);
424+
422425
/**
423426
* Catch wallet up to current chain, scanning new blocks, updating the best
424427
* block locator and m_last_block_processed, and registering for

0 commit comments

Comments
 (0)