wallet: cache descriptor ID to avoid repeated descriptor string creation

Right now a wallet descriptor is converted to it's string representation
(via `Descriptor::ToString`) repeatedly at different instances:
- on finding a `DescriptorScriptPubKeyMan` for a given descriptor
  (`CWallet::GetDescriptorScriptPubKeyMan`, e.g. used by the
  `importdescriptors` RPC); the string representation is created once
  for each spkm in the wallet and at each iteration again for
  the searched descriptor (`DescriptorScriptPubKeyMan::HasWalletDescriptor`)
- whenever `DescriptorScriptPubKeyMan::GetID()` is called, e.g. in
  `TopUp` or any instances where a descriptor is written to the DB
  to determine the database key etc.

As there is no good reason to calculate a fixed descriptor's string/ID
more than once, add the ID as a field to `WalletDescriptor` and
calculate it immediately at initialization (or deserialization).
`HasWalletDescriptor` is changed to compare the spkm's and searched
descriptor's ID instead of the string to take use of that.

This speeds up the functional test `wallet_miniscript.py` by a factor of
5-6x on my machine (3m30.95s on master vs. 0m38.02s on PR). The recently
introduced "max-size TapMiniscript" test-case introduced a descriptor
that takes 2-3 seconds to create a string representation, so the
repeated calls to that were significantly hurting the performance.
This commit is contained in:
Sebastian Falbesoner
2023-11-05 23:01:32 +01:00
parent 953d302a24
commit f811a24421
2 changed files with 5 additions and 3 deletions

View File

@@ -2601,7 +2601,7 @@ std::unique_ptr<CKeyMetadata> DescriptorScriptPubKeyMan::GetMetadata(const CTxDe
uint256 DescriptorScriptPubKeyMan::GetID() const
{
LOCK(cs_desc_man);
return DescriptorID(*m_wallet_descriptor.descriptor);
return m_wallet_descriptor.id;
}
void DescriptorScriptPubKeyMan::SetCache(const DescriptorCache& cache)
@@ -2655,7 +2655,7 @@ bool DescriptorScriptPubKeyMan::AddCryptedKey(const CKeyID& key_id, const CPubKe
bool DescriptorScriptPubKeyMan::HasWalletDescriptor(const WalletDescriptor& desc) const
{
LOCK(cs_desc_man);
return m_wallet_descriptor.descriptor != nullptr && desc.descriptor != nullptr && m_wallet_descriptor.descriptor->ToString() == desc.descriptor->ToString();
return !m_wallet_descriptor.id.IsNull() && !desc.id.IsNull() && m_wallet_descriptor.id == desc.id;
}
void DescriptorScriptPubKeyMan::WriteDescriptor()