-
Notifications
You must be signed in to change notification settings - Fork 37.7k
wallet: Reset reused transactions cache #17843
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers. ConflictsReviewers, this pull request conflicts with the following ones:
If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Concept ACK.
src/wallet/wallet.cpp
Outdated
if (AddDestData(batch, dst, "used", "p")) { | ||
// mark all other outputs to the same destination as dirty | ||
// so they pick up the new "used" state as quickly as possible | ||
MarkDestinationTransactionsDirty(dst); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like we should have std::multimap<CTxDestination, CWalletTx*>
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
concept ACK
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM with a few nits
Github spazzing out, but #17843 (comment) is in response to @instagibbs suggestion to |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think current approach is really bad - SetUsedDestinationState
is called for each spent TXO which in turn will iterate all wallet transaction outputs.
I see 2 options to improve:
- have an index like
std::multimap<CTxDestination, CWalletTx*>
- accumulate all
CTxDestination
to be marked dirty and then iterate the wallet transactions just once.
@promag You may be right. Would love to see worst case scenario analysis (is this O(n) or O(n^2) or worse?). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@kallewoof I think it's O(n). Problem is that for big wallets, all transaction outputs will be scanned as much as the input count of the new transaction.
So if |
This might make a good topic for IRC meeting. I think making this slower is ok provided it's opt-in, which it appears to be based on the required avoid_reuse wallet flag guarding |
I agree with @promag. I think we should use |
I also think it's fine to improve in a follow up and have the fix merged. In that case I'd just change this to do as suggested:
which is pretty simple. |
Thanks for the feedback everyone! I can improve the PR as suggested by @promag shortly, no need to have a separate follow-up for that. But a further improvement using an index could be a follow-up. |
Pushed update including most of the feedback and implementing the simpler solution suggestion by @promag:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ACK 88291a5
Rebased and addressed feedback. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code reviewed, looks good aside from outdated comment.
If a destination is reused we mark the cache of the other transactions going to that destination dirty so they are not accidentally reported as trusted when the cache is hit.
Thanks a lot for running these! Pushed update to outdated comment. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ACK 6fc554f.
Code review re-ACK 6fc554f |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Re-ACK 6fc554f
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code review ACK 6fc554f
Thanks!
6fc554f wallet: Reset reused transactions cache (Fabian Jahr) Pull request description: Fixes #17603 (together with #17824) `getbalances` is using the cache within `GetAvailableCredit` under certain conditions [here](https://github.com/bitcoin/bitcoin/blob/35fff5be60e853455abc24713481544e91adfedb/src/wallet/wallet.cpp#L1826). For a wallet with `avoid_reuse` activated this can lead to inconsistent reporting of `used` transactions/balances between `getbalances` and `listunspent` as pointed out in #17603. When an address is reused before the first transaction is spending from this address, the cache is not updated even after the transaction is sent. This means the remaining outputs at the reused address are not showing up as `used` in `getbalances`. With this change, any newly incoming transaction belonging to the wallet marks all the other outputs at the same address as dirty. ACKs for top commit: kallewoof: Code review re-ACK 6fc554f promag: ACK 6fc554f. achow101: Re-ACK 6fc554f meshcollider: Code review ACK 6fc554f Tree-SHA512: c4cad2c752176d16d77b4a4202291d20baddf9f27250896a40274d74a6945e0f6b34be04c2f9b1b2e756d3ac669b794969df8f82a98e0b16f10e92f276649ea2
6fc554f wallet: Reset reused transactions cache (Fabian Jahr) Pull request description: Fixes bitcoin#17603 (together with bitcoin#17824) `getbalances` is using the cache within `GetAvailableCredit` under certain conditions [here](https://github.com/bitcoin/bitcoin/blob/35fff5be60e853455abc24713481544e91adfedb/src/wallet/wallet.cpp#L1826). For a wallet with `avoid_reuse` activated this can lead to inconsistent reporting of `used` transactions/balances between `getbalances` and `listunspent` as pointed out in bitcoin#17603. When an address is reused before the first transaction is spending from this address, the cache is not updated even after the transaction is sent. This means the remaining outputs at the reused address are not showing up as `used` in `getbalances`. With this change, any newly incoming transaction belonging to the wallet marks all the other outputs at the same address as dirty. ACKs for top commit: kallewoof: Code review re-ACK 6fc554f promag: ACK 6fc554f. achow101: Re-ACK 6fc554f meshcollider: Code review ACK 6fc554f Tree-SHA512: c4cad2c752176d16d77b4a4202291d20baddf9f27250896a40274d74a6945e0f6b34be04c2f9b1b2e756d3ac669b794969df8f82a98e0b16f10e92f276649ea2
@meshcollider does this need backporting to 0.19? |
If a destination is reused we mark the cache of the other transactions going to that destination dirty so they are not accidentally reported as trusted when the cache is hit. Github-Pull: bitcoin#17843 Rebased-From: 6fc554f
Being backported in #18083. |
f11872c wallet: Reset reused transactions cache (Fabian Jahr) Pull request description: Backport of #17843 Required porting to pre-`WalletBatch` ACKs for top commit: kallewoof: Code review ACK f11872c laanwj: code review ACK f11872c meshcollider: utACK f11872c Tree-SHA512: 5cf5f136d1eafb0783c2e6799e3675ebc50997ebb56b379d8a198ac35eb3b32f6b98656760a8b1c821eeac665eb80efb1723dd4e9eb58d2b4d45c4674499bedf
[0.19] Backports bitcoin#17858 Unbreak build with Boost 1.72.0 bitcoin#17654 cli: fix Fatal LevelDB error when specifying -blockfilterindex=basic twice bitcoin#17687 rpc: require second argument only for scantxoutset start action bitcoin#17728 wallet: Fix origfee return for bumpfee with feerate arg bitcoin#17643 test: fix "bitcoind already running" warnings on macOS bitcoin#17488 net: Log to net category for exceptions in ProcessMessages bitcoin#17762 Updates to appveyor config for VS2019 and Qt5.9.8 + msvc project fixes bitcoin#17364 Appveyor improvement - text file for vcpkg package list bitcoin#17416 Update msvc build for Visual Studio 2019 v16.4 bitcoin#17736 scripts: fix symbol-check & security-check argument passing bitcoin#17857 qt: Periodic translations update for 0.19 branch IsUsedDestination should count any known single-key address bitcoin#17621 init: Stop indexes on shutdown after ChainStateFlushed callback. bitcoin#17897 qt: Translations update pre-rc1 wallet: Reset reused transactions cache bitcoin#17843 Squashed 'src/univalue/' changes from 7890db9..98261b1 0.19: Update univalue subtree bitcoin#18100 qt: Pre-rc2 translations update
[0.19] Backports bitcoin#17858 Unbreak build with Boost 1.72.0 bitcoin#17654 cli: fix Fatal LevelDB error when specifying -blockfilterindex=basic twice bitcoin#17687 rpc: require second argument only for scantxoutset start action bitcoin#17728 wallet: Fix origfee return for bumpfee with feerate arg bitcoin#17643 test: fix "bitcoind already running" warnings on macOS bitcoin#17488 net: Log to net category for exceptions in ProcessMessages bitcoin#17762 Updates to appveyor config for VS2019 and Qt5.9.8 + msvc project fixes bitcoin#17364 Appveyor improvement - text file for vcpkg package list bitcoin#17416 Update msvc build for Visual Studio 2019 v16.4 bitcoin#17736 scripts: fix symbol-check & security-check argument passing bitcoin#17857 qt: Periodic translations update for 0.19 branch IsUsedDestination should count any known single-key address bitcoin#17621 init: Stop indexes on shutdown after ChainStateFlushed callback. bitcoin#17897 qt: Translations update pre-rc1 wallet: Reset reused transactions cache bitcoin#17843 Squashed 'src/univalue/' changes from 7890db9..98261b1 0.19: Update univalue subtree bitcoin#18100 qt: Pre-rc2 translations update [0.19] Further 0.19 backports bitcoin#18218 build: don't embed a build-id when building libdmg-hfsplus bitcoin#18004
a2324e4 test: Improve naming and logging of avoid_reuse tests (Fabian Jahr) 1abbdac wallet: Prefer full destination groups in coin selection (Fabian Jahr) Pull request description: Fixes #17603 (together with #17843) In the case of destination groups of >10 outputs existing in a wallet with `avoid_reuse` enabled, the grouping algorithm is adding left-over outputs as an "incomplete" group to the list of groups even when a full group has already been added. This leads to the strange behavior that if there are >10 outputs for a destination the transaction spending from that will effectively use `len(outputs) % 10` as inputs for that transaction. From the original PR and the code comment I understand the correct behavior should be the usage of 10 outputs. I opted for minimal changes in the current code although there maybe optimizations possible for cases with >20 outputs on a destination this sounds like too much of an edge case right now. ACKs for top commit: jonatack: Re-ACK a2324e4 achow101: ACK a2324e4 kallewoof: ACK a2324e4 meshcollider: Tested ACK a2324e4 (verified the new test fails on master without this change) Tree-SHA512: 4743779c5d469fcd16df5baf166024b1d3c8eaca151df1e8281b71df62b29541cf7bfee3f8ab48d83e3b34c9256e53fd38a7b146a54c79f9caa44cce3636971a
…election a2324e4 test: Improve naming and logging of avoid_reuse tests (Fabian Jahr) 1abbdac wallet: Prefer full destination groups in coin selection (Fabian Jahr) Pull request description: Fixes bitcoin#17603 (together with bitcoin#17843) In the case of destination groups of >10 outputs existing in a wallet with `avoid_reuse` enabled, the grouping algorithm is adding left-over outputs as an "incomplete" group to the list of groups even when a full group has already been added. This leads to the strange behavior that if there are >10 outputs for a destination the transaction spending from that will effectively use `len(outputs) % 10` as inputs for that transaction. From the original PR and the code comment I understand the correct behavior should be the usage of 10 outputs. I opted for minimal changes in the current code although there maybe optimizations possible for cases with >20 outputs on a destination this sounds like too much of an edge case right now. ACKs for top commit: jonatack: Re-ACK a2324e4 achow101: ACK a2324e4 kallewoof: ACK a2324e4 meshcollider: Tested ACK a2324e4 (verified the new test fails on master without this change) Tree-SHA512: 4743779c5d469fcd16df5baf166024b1d3c8eaca151df1e8281b71df62b29541cf7bfee3f8ab48d83e3b34c9256e53fd38a7b146a54c79f9caa44cce3636971a
Summary: If a destination is reused we mark the cache of the other transactions going to that destination dirty so they are not accidentally reported as trusted when the cache is hit. --- Backport of Core [[bitcoin/bitcoin#17843 | PR17843]] Test Plan: ninja check check-functional Reviewers: #bitcoin_abc, deadalnix Reviewed By: #bitcoin_abc, deadalnix Differential Revision: https://reviews.bitcoinabc.org/D7685
6fc554f wallet: Reset reused transactions cache (Fabian Jahr) Pull request description: Fixes bitcoin#17603 (together with bitcoin#17824) `getbalances` is using the cache within `GetAvailableCredit` under certain conditions [here](https://github.com/bitcoin/bitcoin/blob/35fff5be60e853455abc24713481544e91adfedb/src/wallet/wallet.cpp#L1826). For a wallet with `avoid_reuse` activated this can lead to inconsistent reporting of `used` transactions/balances between `getbalances` and `listunspent` as pointed out in bitcoin#17603. When an address is reused before the first transaction is spending from this address, the cache is not updated even after the transaction is sent. This means the remaining outputs at the reused address are not showing up as `used` in `getbalances`. With this change, any newly incoming transaction belonging to the wallet marks all the other outputs at the same address as dirty. ACKs for top commit: kallewoof: Code review re-ACK 6fc554f promag: ACK 6fc554f. achow101: Re-ACK 6fc554f meshcollider: Code review ACK 6fc554f Tree-SHA512: c4cad2c752176d16d77b4a4202291d20baddf9f27250896a40274d74a6945e0f6b34be04c2f9b1b2e756d3ac669b794969df8f82a98e0b16f10e92f276649ea2
f11872c wallet: Reset reused transactions cache (Fabian Jahr) Pull request description: Backport of bitcoin#17843 Required porting to pre-`WalletBatch` ACKs for top commit: kallewoof: Code review ACK f11872c laanwj: code review ACK f11872c meshcollider: utACK f11872c Tree-SHA512: 5cf5f136d1eafb0783c2e6799e3675ebc50997ebb56b379d8a198ac35eb3b32f6b98656760a8b1c821eeac665eb80efb1723dd4e9eb58d2b4d45c4674499bedf
Fixes #17603 (together with #17824)
getbalances
is using the cache withinGetAvailableCredit
under certain conditions here. For a wallet withavoid_reuse
activated this can lead to inconsistent reporting ofused
transactions/balances betweengetbalances
andlistunspent
as pointed out in #17603. When an address is reused before the first transaction is spending from this address, the cache is not updated even after the transaction is sent. This means the remaining outputs at the reused address are not showing up asused
ingetbalances
.With this change, any newly incoming transaction belonging to the wallet marks all the other outputs at the same address as dirty.