Diagnose unsuitable outputs in lockunspent().#11087
Conversation
promag
left a comment
There was a problem hiding this comment.
Read developer notes and update accordingly.
src/wallet/rpcwallet.cpp
Outdated
src/wallet/rpcwallet.cpp
Outdated
There was a problem hiding this comment.
No need to chain:
if (fUnlock && !is_locked) {
throw ...;
}
if (!fUnlock && is_locked) {
throw ...;
}
...There was a problem hiding this comment.
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.
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.
Ok, makes sense!
src/wallet/rpcwallet.cpp
Outdated
There was a problem hiding this comment.
I think is must be either ISMINE_SPENDABLE or ISMINE_WATCH_SOLVABLE?
There was a problem hiding this comment.
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.
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.
Missing {} and { is one the same line. Same below. See developer notes.
There was a problem hiding this comment.
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.
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
test/functional/wallet.py
Outdated
test/functional/wallet.py
Outdated
test/functional/wallet.py
Outdated
ryanofsky
left a comment
There was a problem hiding this comment.
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.
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.
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.
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.
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.
Makes sense, I'll make the errors more precise.
src/wallet/rpcwallet.cpp
Outdated
There was a problem hiding this comment.
You could save reparsing the json by saving a vector of COutPoints in the first pass.
There was a problem hiding this comment.
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.
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.
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.
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.
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.
This is the bug. lockunspent() should be called on self.nodes[0], not self.nodes[2]
There was a problem hiding this comment.
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.
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.
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.
Needs rebase and replace with "assert_raises_rpc_error"
ryanofsky
left a comment
There was a problem hiding this comment.
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.
Could declare as const UniValue& to avoid copying params.
src/wallet/rpcwallet.cpp
Outdated
There was a problem hiding this comment.
Could declare as const std::string& to avoid copying string.
fe2c95b to
28f8b66
Compare
|
Amended/rebased to:
|
|
|
||
| // 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.
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.