mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-07-28 21:33:11 +02:00
Merge bitcoin/bitcoin#24699: wallet: Improve AvailableCoins performance by reducing duplicated operations
bc886fcb31
Change mapWallet to be a std::unordered_map (Andrew Chow)272356024d
Change getWalletTxs to return a set instead of a vector (Andrew Chow)97532867cf
Change mapTxSpends to be a std::unordered_multimap (Andrew Chow)1f798fe85b
wallet: Cache SigningProviders (Andrew Chow)8a105ecd1a
wallet: Use CalculateMaximumSignedInputSize to indicate solvability (Andrew Chow) Pull request description: While running my coin selection simulations, I noticed that towards the end of the simulation, the wallet would become slow to make new transactions. The wallet generally performs much more slowly when there are a large number of transactions and/or a large number of keys. The improvements here are focused on wallets with a large number of transactions as that is what the simulations produce. Most of the slowdown I observed was due to `DescriptorScriptPubKeyMan::GetSigningProvider` re-deriving keys every time it is called. To avoid this, it will now cache the `SigningProvider` produced so that repeatedly fetching the `SigningProvider` for the same script will not result in the same key being derived over and over. This has a side effect of making the function non-const, which makes a lot of other functions non-const as well. This helps with wallets with lots of address reuse (as my coin selection simulations are), but not if addresses are not reused as keys will end up needing to be derived the first time `GetSigningProvider` is called for a script. The `GetSigningProvider` problem was also exacerbated by unnecessarily fetching a `SigningProvider` for the same script multiple times. A `SigningProvider` is retrieved to be used inside of `IsSolvable`. A few lines later, we use `GetTxSpendSize` which fetches a `SigningProvider` and then calls `CalculateMaximumSignedInputSize`. We can avoid a second call to `GetSigningProvider` by using `CalculateMaximumSignedInputSize` directly with the `SigningProvider` already retrieved for `IsSolvable`. There is an additional slowdown where `ProduceSignature` with a dummy signer is called twice for each output. The first time is `IsSolvable` checks that `ProduceSignature` succeeds, thereby informing whether we have solving data. The second is `CalculateMaximumSignedInputSize` which returns -1 if `ProduceSignature` fails, and returns the input size otherwise. We can reduce this to one call of `ProduceSignature` by using `CalculateMaximumSignedInputSize`'s result to set `solvable`. Lastly, a lot of time is spent looking in `mapWallet` and `mapTxSpends` to determine whether an output is already spent. The performance of these lookups is slightly improved by changing those maps to use `std::unordered_map` and `std::unordered_multimap` respectively. ACKs for top commit: Xekyo: ACKbc886fcb31
furszy: diff re-reACKbc886fcb
Tree-SHA512: fd710fe1224ef67d2bb83d6ac9e7428d9f76a67f14085915f9d80e1a492d2c51cb912edfcaad1db11c2edf8d2d97eb7ddd95bfb364587fb1f143490fd72c9ec1
This commit is contained in:
@@ -183,7 +183,7 @@ public:
|
||||
virtual WalletTx getWalletTx(const uint256& txid) = 0;
|
||||
|
||||
//! Get list of all wallet transactions.
|
||||
virtual std::vector<WalletTx> getWalletTxs() = 0;
|
||||
virtual std::set<WalletTx> getWalletTxs() = 0;
|
||||
|
||||
//! Try to get updated status for a particular transaction, if possible without blocking.
|
||||
virtual bool tryGetTxStatus(const uint256& txid,
|
||||
@@ -395,6 +395,8 @@ struct WalletTx
|
||||
int64_t time;
|
||||
std::map<std::string, std::string> value_map;
|
||||
bool is_coinbase;
|
||||
|
||||
bool operator<(const WalletTx& a) const { return tx->GetHash() < a.tx->GetHash(); }
|
||||
};
|
||||
|
||||
//! Updated transaction status.
|
||||
|
Reference in New Issue
Block a user