Skip to content

Conversation

@BitonicEelis
Copy link
Contributor

Fixes #2667.

This is a simplified version of pull request #3574, which was abandoned by its author.

I added some tests as well.

Copy link
Contributor

@promag promag left a 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.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bool is_locked = ...;

Copy link
Contributor

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 ...;
}

...

Copy link
Contributor Author

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?

Copy link
Contributor

@promag promag Aug 18, 2017

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?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, makes sense!

Copy link
Contributor

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?

Copy link
Contributor

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.

Copy link
Contributor Author

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.

@BitonicEelis
Copy link
Contributor Author

Amended to:

  • comply with variable naming policy
  • reject attempts to lock already locked outputs
  • remove MINE check

Copy link
Contributor

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.

Copy link
Contributor Author

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. :)

@BitonicEelis
Copy link
Contributor Author

Amended to use curly brackets in accordance with developer notes.

@meshcollider
Copy link
Contributor

utACK 918b6db

1 similar comment
@laanwj
Copy link
Member

laanwj commented Aug 22, 2017

utACK 918b6db

Copy link
Contributor

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

Copy link
Contributor

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.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above.

Copy link
Contributor

@ryanofsky ryanofsky left a 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.

Copy link
Contributor

@jnewbery jnewbery left a 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.

Copy link
Contributor

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?

Copy link

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.

Copy link
Contributor

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).

Copy link

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.

Copy link
Contributor

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.

Copy link

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.

Copy link
Contributor

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.

@BitonicEelis
Copy link
Contributor Author

Amended to:

  • store COutPoints in vector instead of recomputing them
  • include "invalid parameter:" error prefix in expectations in test
  • make unlock errors more precise

@ryanofsky Unfortunately, range-for cannot be used to iterate over a UniValue because it does not provide begin()/end().

Thanks for the feedback!

Copy link
Contributor

@jnewbery jnewbery left a 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.

Copy link
Contributor

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();

Copy link
Contributor

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)

Copy link
Contributor

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]

Copy link
Contributor Author

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..

Copy link
Contributor

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.

Copy link
Contributor

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

@BitonicEelis
Copy link
Contributor Author

Amended to:

  • remove isObject check
  • indent continued function call lines to match opening parenthesis
  • call lockunspent on correct node in test

@jnewbery
Copy link
Contributor

jnewbery commented Sep 1, 2017

Tested ACK fe2c95bda22c21252709cc1088d7e61a8c8b1df8. Looks great. Thanks for being receptive to all my feedback!

Copy link
Member

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"

Copy link
Contributor

@ryanofsky ryanofsky left a 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.

Copy link
Contributor

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.

Copy link
Contributor

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.

@BitonicEelis
Copy link
Contributor Author

Amended/rebased to:

  • use assert_raises_rpc_error;
  • use references to avoid copying a UniValue and std::string, as suggested by ryanofsky.

Copy link
Contributor

@ryanofsky ryanofsky left a 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.

Copy link
Member

@sipa sipa left a 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);
Copy link
Member

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).

@laanwj laanwj merged commit 28f8b66 into bitcoin:master Nov 16, 2017
laanwj added a commit that referenced this pull request Nov 16, 2017
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
@BitonicEelis BitonicEelis deleted the lockunspent branch November 16, 2017 11:26
random-zebra added a commit to random-zebra/PIVX that referenced this pull request Oct 28, 2019
- qualify as constants the arguments of CWallet's functions:
IsLockedCoin, LockCoin and UnlockCoin.

- Diagnose unsuitable outputs in lockunspent (backports bitcoin/bitcoin
bitcoin#11087)
furszy added a commit to PIVX-Project/PIVX that referenced this pull request Nov 19, 2019
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
akshaynexus added a commit to dogecash/dogecash-old that referenced this pull request Nov 19, 2019
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
PastaPastaPasta pushed a commit to PastaPastaPasta/dash that referenced this pull request Jan 29, 2020
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
wqking pushed a commit to wqking-temp/Vitae that referenced this pull request May 31, 2020
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
KolbyML pushed a commit to KolbyML/bitcoin that referenced this pull request Nov 21, 2020
- qualify as constants the arguments of CWallet's functions:
IsLockedCoin, LockCoin and UnlockCoin.

- Diagnose unsuitable outputs in lockunspent (backports bitcoin/bitcoin
bitcoin#11087)
@bitcoin bitcoin locked as resolved and limited conversation to collaborators Sep 8, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

lockunspent returns true even for non-existent outputs

9 participants