-
Notifications
You must be signed in to change notification settings - Fork 38.6k
Diagnose unsuitable outputs in lockunspent(). #11087
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
promag
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.
Read developer notes and update accordingly.
src/wallet/rpcwallet.cpp
Outdated
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.
bool is_locked = ...;
src/wallet/rpcwallet.cpp
Outdated
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.
No need to chain:
if (fUnlock && !is_locked) {
throw ...;
}
if (!fUnlock && is_locked) {
throw ...;
}
...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.
Thanks for the review! Are you absolutely sure that attempting to lock an already locked output should be an error?
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.
IMO yes, it indicates it was locked by other client and as such it is not yours to use?
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.
Ok, makes sense!
src/wallet/rpcwallet.cpp
Outdated
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 is must be either ISMINE_SPENDABLE or ISMINE_WATCH_SOLVABLE?
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.
Do we really have to test IsMine and all? In the wallet it's just a std::set<COutPoint>, so IMO is enough to check:
- if the input is valid output
- if the lock state is compatible with the argument.
But if there is interest in doing these tests, then perform the cheapest 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.
I'll remove the check for now. It can always be added later.
fae526d to
764ab3a
Compare
|
Amended to:
|
src/wallet/rpcwallet.cpp
Outdated
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.
Missing {} and { is one the same line. Same below. See developer notes.
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.
Will do! Thanks for caring about consistent style. :)
764ab3a to
918b6db
Compare
|
Amended to use curly brackets in accordance with developer notes. |
|
utACK 918b6db |
1 similar comment
|
utACK 918b6db |
test/functional/wallet.py
Outdated
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.
Assert complete error message? cc @jnewbery
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.
Personally, I don't think the complete error message needs to be asserted, as long as the string is long enough to disambiguate. But also fine to change this to the complete string.
test/functional/wallet.py
Outdated
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.
Same as above.
test/functional/wallet.py
Outdated
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.
Same as above.
test/functional/wallet.py
Outdated
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.
Same as above.
test/functional/wallet.py
Outdated
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.
Same as above.
ryanofsky
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.
utACK 918b6db42b12d86a01bdb70a4fc50244aa2ce623
You could modernize the code a little more: adding a range for loop instead of an index loop, and using UniValue directly instead of adding adding new find_value calls. Also I'm not sure if it's useful to make locking an already locked output or unlocked an already unlocked one errors. But overall, this change seems like an improvement and looks good to merge.
jnewbery
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.
Looks good, and great test coverage. A couple of nits inline.
Maybe out of the scope of this PR, but this RPC returns true if called with false but no list of transactions. A user might expect that with that call all outputs have been locked, but in fact it's a no-op. I think that if (request.params.size() == 1 && !fUnlock) then we should return false or throw.
src/wallet/rpcwallet.cpp
Outdated
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.
Why are these three checks ("expected unspent", "unknown transaction" and "vout index out of bounds") only done when trying to lock? Isn't it equally invalid to try to unlock bad txouts? Can you place these three checks above the const bool is_locked = pwallet->IsLockedCoin(outpt.hash, outpt.n); line?
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.
The idea was that in all three of those cases (already spent output, unknown transaction, and vout index out of bounds), IsLockedCoin should already have returned false, so checking !is_locked should be enough.
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 agree that the function will correctly return an error, but I think that it's better to return the more precise error if possible. expected unspent output, unknown transaction and vout index out of bounds are better to return than expected locked output (the last could infer that the outpoint exists but is unlocked).
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.
Makes sense, I'll make the errors more precise.
src/wallet/rpcwallet.cpp
Outdated
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.
You could save reparsing the json by saving a vector of COutPoints in the first pass.
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.
These loops don't do any json parsing, because the data is already in a UniValue. The find_value calls find the desired value in UniValue's internal std::vector of values.
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.
You're right. There's no reparsing the JSON, just rereading the string and reconstructing the COutPoint.
I think either way is fine. Whichever you prefer.
918b6db to
82937c0
Compare
|
Amended to:
@ryanofsky Unfortunately, range-for cannot be used to iterate over a UniValue because it does not provide begin()/end(). Thanks for the feedback! |
jnewbery
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.
Looks great! One bug in the test code and one nit in the RPC method.
src/wallet/rpcwallet.cpp
Outdated
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.
You can remove this check entirely. Type checking is done by the UniValue.get_xxx() functions, and returns almost an identical error to that given by this explicit check.
With the explicit check:
→ bitcoin-cli -rpcwallet=w1 lockunspent true [\"string\"]
error code: -8
error message:
Invalid parameter, expected
without:
→ bitcoin-cli -rpcwallet=w1 lockunspent true [\"string\"]
error code: -1
error message:
JSON value is not an object as expected
The implicit get_xxx() check is used extensively in other RPCs.
You can also combine the line below with above:
const UniValue& o = request.params[1].get_obj();
src/wallet/rpcwallet.cpp
Outdated
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 contrast to my comment above, it makes sense to keep these. RPCTypeCheckObj provides slightly more information (both the type expected and type received)
test/functional/wallet.py
Outdated
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.
This is the bug. lockunspent() should be called on self.nodes[0], not self.nodes[2]
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.
Thanks! This one stumped me because for some reason when I ran the wallet tests locally, they didn't fail..
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.
Yes! I saw the same thing. Very odd. h/t @sdaftuar for spotting the bug.
test/functional/wallet.py
Outdated
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 personally don't like this indentation style. It looks like something between a new line and a new code block.
Would you mind aligning this continuation line with the opening parens:
assert_raises_jsonrpc(-8, "Invalid parameter, unknown transaction",
self.nodes[2].lockunspent, False, [{"txid": "0000000000000000000000000000000000", "vout": 0}])same below
82937c0 to
fe2c95b
Compare
|
Amended to:
|
|
Tested ACK fe2c95bda22c21252709cc1088d7e61a8c8b1df8. Looks great. Thanks for being receptive to all my feedback! |
test/functional/wallet.py
Outdated
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.
Needs rebase and replace with "assert_raises_rpc_error"
ryanofsky
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.
utACK fe2c95bda22c21252709cc1088d7e61a8c8b1df8. No significant changes since last review. Left minor comments (feel free to ignore them), but this does need to be rebased.
src/wallet/rpcwallet.cpp
Outdated
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.
Could declare as const UniValue& to avoid copying params.
src/wallet/rpcwallet.cpp
Outdated
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.
Could declare as const std::string& to avoid copying string.
fe2c95b to
28f8b66
Compare
|
Amended/rebased to:
|
ryanofsky
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.
utACK 28f8b66. Only changes since last review are rebase & adding const refs.
sipa
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.
utACK 28f8b66
|
|
||
| // Atomically set (un)locked status for the outputs. | ||
| for (const COutPoint& outpt : outputs) { | ||
| if (fUnlock) pwallet->UnlockCoin(outpt); |
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.
Coding style nit; if with else always needs braces/indentation (I know the original code you're rewriting wasn't following this convention, but in new code we try to).
28f8b66 Diagnose unsuitable outputs in lockunspent(). (Eelis) Pull request description: Fixes #2667. This is a simplified version of pull request #3574, which was abandoned by its author. I added some tests as well. Tree-SHA512: e63e00dec8b1b232079380183805cb0b0b18c78ea6bea769837949aab984689d7f68b2ccfe66b1873517b040b9e616ce0eb058575c3d4382aa8c26eebcf1f14e
- qualify as constants the arguments of CWallet's functions: IsLockedCoin, LockCoin and UnlockCoin. - Diagnose unsuitable outputs in lockunspent (backports bitcoin/bitcoin bitcoin#11087)
328bad7 [Wallet][RPC] Lock/UnlockCoin const argument + checks in lockunspent (random-zebra) Pull request description: - qualify as constants the arguments of CWallet's functions: `IsLockedCoin`, `LockCoin` and `UnlockCoin`. - Diagnose unsuitable outputs in lockunspent (backports bitcoin#11087) NOTE: the update to `wallet_basic` functional test for this particular changes will be included in a successive PR (which collects updates for the whole test suite). ACKs for top commit: Fuzzbawls: utACK 328bad7 furszy: utACK 328bad7 Tree-SHA512: 43e973d6423dc2d65a9b40ec181c6a6eb96903d4518bfcfa9d39ffeb2cca5866b9630815bb3a83065cd497a00fe39375ad1304c4371cfb2b560b6ac30c5c45ba
328bad7 [Wallet][RPC] Lock/UnlockCoin const argument + checks in lockunspent (random-zebra) Pull request description: - qualify as constants the arguments of CWallet's functions: `IsLockedCoin`, `LockCoin` and `UnlockCoin`. - Diagnose unsuitable outputs in lockunspent (backports bitcoin/bitcoin#11087) NOTE: the update to `wallet_basic` functional test for this particular changes will be included in a successive PR (which collects updates for the whole test suite). ACKs for top commit: Fuzzbawls: utACK 328bad7 furszy: utACK 328bad7 Tree-SHA512: 43e973d6423dc2d65a9b40ec181c6a6eb96903d4518bfcfa9d39ffeb2cca5866b9630815bb3a83065cd497a00fe39375ad1304c4371cfb2b560b6ac30c5c45ba
28f8b66 Diagnose unsuitable outputs in lockunspent(). (Eelis) Pull request description: Fixes dashpay#2667. This is a simplified version of pull request dashpay#3574, which was abandoned by its author. I added some tests as well. Tree-SHA512: e63e00dec8b1b232079380183805cb0b0b18c78ea6bea769837949aab984689d7f68b2ccfe66b1873517b040b9e616ce0eb058575c3d4382aa8c26eebcf1f14e
328bad7a403abd5d179cbec0c92afd55230ddc87 [Wallet][RPC] Lock/UnlockCoin const argument + checks in lockunspent (random-zebra) Pull request description: - qualify as constants the arguments of CWallet's functions: `IsLockedCoin`, `LockCoin` and `UnlockCoin`. - Diagnose unsuitable outputs in lockunspent (backports bitcoin/bitcoin#11087) NOTE: the update to `wallet_basic` functional test for this particular changes will be included in a successive PR (which collects updates for the whole test suite). ACKs for top commit: Fuzzbawls: utACK 328bad7a403abd5d179cbec0c92afd55230ddc87 furszy: utACK 328bad7 Tree-SHA512: 43e973d6423dc2d65a9b40ec181c6a6eb96903d4518bfcfa9d39ffeb2cca5866b9630815bb3a83065cd497a00fe39375ad1304c4371cfb2b560b6ac30c5c45ba
- qualify as constants the arguments of CWallet's functions: IsLockedCoin, LockCoin and UnlockCoin. - Diagnose unsuitable outputs in lockunspent (backports bitcoin/bitcoin bitcoin#11087)
Fixes #2667.
This is a simplified version of pull request #3574, which was abandoned by its author.
I added some tests as well.