-
Notifications
You must be signed in to change notification settings - Fork 38.2k
Wallet: "listreceivedby*" fix #30972
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
base: master
Are you sure you want to change the base?
Wallet: "listreceivedby*" fix #30972
Conversation
|
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers. Code Coverage & BenchmarksFor details see: https://corecheck.dev/bitcoin/bitcoin/pulls/30972. ReviewsSee the guideline for information on the review process.
If your review is incorrectly listed, please react with 👎 to this comment and the bot will ignore it on the next update. ConflictsNo conflicts as of last run. LLM Linter (✨ experimental)Possible typos and grammar issues:
drahtbot_id_4_m |
|
🚧 At least one of the CI tasks failed. HintsMake sure to run all tests locally, according to the documentation. The failure may happen due to a number of reasons, for example:
Leave a comment here, if you need help tracking down a confusing failure. |
209303b to
a35115f
Compare
|
Lgtm I ran the unit test and functional test (without bdb) and all pass. |
src/wallet/rpc/transactions.cpp
Outdated
| LOCK(wallet.cs_wallet); | ||
| if (!wallet.IsMine(address)) return; // no send addresses | ||
|
|
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.
Since the mapTally loading procedure already performs the IsMine check, we could use that instead of executing it again for the addresses that received some coins.
In other words, if an element exists in mapTally, we can be certain that everything inside it belongs to the wallet.
So, ideally, we could decouple the mapTally existence check from the "include empty" check (the one that is just below this line), which would avoid this second IsMine() call for the non-empty addresses (we would need to execute it for the addresses that have no associated value in mapTally).
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 have updated the code to only do the second IsMine check if the address is not in mapTally
|
Concept ACK |
a35115f to
61098f2
Compare
Co-authored-by: Andreas Kouloumos <[email protected]>
Co-authored-by: Andreas Kouloumos <[email protected]>
61098f2 to
486cd47
Compare
|
Rebased and updated to address #30972 (comment) |
rkrux
left a 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.
| if (it == mapTally.end() && !fIncludeEmpty) { | ||
| return; | ||
| } else if (it == mapTally.end()) { | ||
| LOCK(wallet.cs_wallet); |
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.
In a1d90fb "wallet: 'Filter' out 'send' addresses from 'listreceivedby*'"
Instead of trying to lock again, assert that the function is already holding the lock? I checked that both the callers of the ListReceived function are acquiring the required lock.
--- a/src/wallet/rpc/transactions.cpp
+++ b/src/wallet/rpc/transactions.cpp
@@ -73,6 +73,8 @@ struct tallyitem
static UniValue ListReceived(const CWallet& wallet, const UniValue& params, const bool by_label, const bool include_immature_coinbase) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet)
{
+ AssertLockHeld(wallet.cs_wallet);
+
// Minimum confirmations
int nMinDepth = 1;
if (!params[0].isNull())
@@ -131,14 +133,13 @@ static UniValue ListReceived(const CWallet& wallet, const UniValue& params, cons
UniValue ret(UniValue::VARR);
std::map<std::string, tallyitem> label_tally;
- const auto& func = [&](const CTxDestination& address, const std::string& label, bool is_change, const std::optional<AddressPurpose>& purpose) {
+ const auto& func = [&](const CTxDestination& address, const std::string& label, bool is_change, const std::optional<AddressPurpose>& purpose) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet) {
if (is_change) return; // no change addresses
auto it = mapTally.find(address);
if (it == mapTally.end() && !fIncludeEmpty) {
return;
} else if (it == mapTally.end()) {
- LOCK(wallet.cs_wallet);
if (!wallet.IsMine(address)) return; // no send addresses
}
|
|
||
| auto it = mapTally.find(address); | ||
| if (it == mapTally.end() && !fIncludeEmpty) | ||
| if (it == mapTally.end() && !fIncludeEmpty) { |
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.
In a1d90fb "wallet: 'Filter' out 'send' addresses from 'listreceivedby*'"
For making it concise.
--- a/src/wallet/rpc/transactions.cpp
+++ b/src/wallet/rpc/transactions.cpp
@@ -73,6 +73,8 @@ struct tallyitem
auto it = mapTally.find(address);
- if (it == mapTally.end() && !fIncludeEmpty) {
- return;
- } else if (it == mapTally.end()) {
- LOCK(wallet.cs_wallet);
+ if (it == mapTally.end()) {
+ if (!fIncludeEmpty) return;
if (!wallet.IsMine(address)) return; // no send addresses
}| assert_array_result(self.nodes[1].listreceivedbyaddress(minconf=0, include_empty=True), {"address": address}, {}, True) | ||
|
|
||
| self.log.info("Tests listreceivedbylabel does not return label of address with 'send' purpose") | ||
| expected = {"label": label, "amount": Decimal("0.1")} | ||
| assert_array_result(self.nodes[0].listreceivedbylabel(minconf=0, include_empty=True), {"label": label}, expected) | ||
| assert_array_result(self.nodes[1].listreceivedbylabel(minconf=0, include_empty=True), {"label": label}, {}, True) |
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.
In 486cd47 "test: 'listreceivedby*' does not return send address"
Nit (feel free to ignore): For expressiveness.
--- a/test/functional/wallet_listreceivedby.py
+++ b/test/functional/wallet_listreceivedby.py
@@ -119,12 +119,12 @@ class ReceivedByTest(BitcoinTestFramework):
expected = {"address": address, "label": label, "amount": Decimal("0.1"), "confirmations": 0, "txids": [txid, ]}
assert_array_result(self.nodes[0].listreceivedbyaddress(minconf=0, include_empty=True), {"address": address}, expected)
- assert_array_result(self.nodes[1].listreceivedbyaddress(minconf=0, include_empty=True), {"address": address}, {}, True)
+ assert_array_result(self.nodes[1].listreceivedbyaddress(minconf=0, include_empty=True), {"address": address}, {}, should_not_find=True)
self.log.info("Tests listreceivedbylabel does not return label of address with 'send' purpose")
expected = {"label": label, "amount": Decimal("0.1")}
assert_array_result(self.nodes[0].listreceivedbylabel(minconf=0, include_empty=True), {"label": label}, expected)
- assert_array_result(self.nodes[1].listreceivedbylabel(minconf=0, include_empty=True), {"label": label}, {}, True)
+ assert_array_result(self.nodes[1].listreceivedbylabel(minconf=0, include_empty=True), {"label": label}, {}, should_not_find=True)
| label = "node0address" | ||
| address = self.nodes[0].getnewaddress(label) | ||
| # using setlabel for an address that does not belong to the wallet assigns a "send" purpose to that address | ||
| self.nodes[1].setlabel(address, label) # address has now assigned a "send" purpose on node1 |
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.
In 486cd47 "test: 'listreceivedby*' does not return send address"
- self.nodes[1].setlabel(address, label) # address has now assigned a "send" purpose on node1
+ self.nodes[1].setlabel(address, label) # address has now been assigned a "send" purpose in node1's wallet| assert_array_result(self.nodes[1].listreceivedbyaddress(0, True), {"address": empty_addr}, expected_tx) | ||
|
|
||
| # No returned addy should be a change addr | ||
| self.log.info("- does not return changes addresses") |
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.
“changes addresses” -> “change addresses” [“change addresses” is the correct term for output addresses, “changes” is a verb here and incorrect]
Fixes #16159,
This PR builds on #25973, fixing
listreceivedby*RPCs by filtering outsendaddresses usingIsMine(see #25973 (comment)). It also breaks down thelistreceivedbytests into subtests and adds a test to verify 'listreceivedby*' does not returnsendaddresses