Skip to content

Conversation

Sjors
Copy link
Member

@Sjors Sjors commented Mar 2, 2020

When using fundrawtransaction and walletcreatefundedpsbt with lockUnspents, it would only lock automatically selected coins, not manually selected coins. That doesn't make much sense to me if the goal is to prevent accidentally double-spending yourself before you broadcast a transaction.

Note that when creating a transaction, manually selected coins are automatic "unlocked" (or more accurately: the lock is ignored). Earlier versions of this PR introduced an error when a locked coin is manually selected, but this idea was abandoned after some discussion. An application that uses this RPC should either rely on automatic coin selection (with lockUnspents) or handle lock concurrency itself with manual coin selection. In particular it needs to make sure to avoid/pause calls with automatic coin selection between calling lockunspent and the subsequent spending RPC.

See #7518 for historical background.

@promag
Copy link
Contributor

promag commented Mar 4, 2020

Concept ACK!

This made me think that we should fail funding if some coin is already locked?

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.

Add a release note maybe? Clients unaware of this change can have dangling utxos locked.

@Sjors Sjors force-pushed the 2020/03/rpc_coin_locks branch from 0af7e9f to ccdae9d Compare March 5, 2020 09:26
@Sjors
Copy link
Member Author

Sjors commented Mar 5, 2020

Added a release note.

This made me think that we should fail funding if some coin is already locked?

Maybe in a separate PR. I also think it's safer for users to explicitly unlock coins before using them.

@promag
Copy link
Contributor

promag commented Mar 5, 2020

I also think it's safer for users to explicitly unlock coins before using them.

The unspent locking was done to deal with concurrent clients and so a client shouldn't take the decision to unlock a coin so lightly - it might screw with a concurrent funding. This is a possible use case and for this reason the user should be able to lock all or nothing IMO.

Maybe in a separate PR

Yes sure! Well kind of, the lock-an-already-locked-coin-and-ignore behavior is added here 🤔.

@Sjors
Copy link
Member Author

Sjors commented Mar 6, 2020

the lock-an-already-locked-coin-and-ignore behavior

Not sure what you mean. This PR can potentially lock a coin that's already locked, but why is that a problem? This PR does not ignore new things.

@promag
Copy link
Contributor

promag commented Mar 6, 2020

The problem is that you might screw with a concurrent funding. When you lock a coin you should expect that it won't be used by others.

@Sjors
Copy link
Member Author

Sjors commented Mar 6, 2020

If a concurrent wallet consumer uses manual coin selection, I don't think this PR makes their problem worse; we were already ignoring any lock they had. If it uses automatic automatic coin selection then this PR has no impact.

@Sjors Sjors force-pushed the 2020/03/rpc_coin_locks branch from ccdae9d to 2ad4155 Compare March 6, 2020 15:08
@Sjors Sjors changed the title rpc: have lockUnspents also lock manually selected coins rpc: fundrawtransaction and walletcreatefundedpsbt respect locks even with manual coin selection Mar 6, 2020
@Sjors
Copy link
Member Author

Sjors commented Mar 6, 2020

After IRC discussion I changed this PR to honour locks for manually selected coins.

unspent_0 = self.nodes[1].listunspent()[0]
self.nodes[1].lockunspent(False, [unspent_0])
tx = self.nodes[1].createrawtransaction([unspent_0], { self.nodes[1].getnewaddress() : 1 })
tx = self.nodes[1].fundrawtransaction(tx)['hex']
Copy link
Contributor

Choose a reason for hiding this comment

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

Are you removing this case because it's used elsewhere?

Copy link
Member Author

Choose a reason for hiding this comment

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

The original test was for auto-unlocking a coin, which now produces an error, so I check for that.

@DrahtBot
Copy link
Contributor

DrahtBot commented Mar 6, 2020

The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

Conflicts

No conflicts as of last run.

@Sjors Sjors force-pushed the 2020/03/rpc_coin_locks branch from 2ad4155 to 991a38c Compare March 6, 2020 17:01
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.

Code review ACK 991a38c.

# fundrawtransaction can lock an input
self.nodes[1].lockunspent(True, [unspent_0])
assert_equal(len(self.nodes[1].listlockunspent()), 0)
tx = self.nodes[1].fundrawtransaction(tx,{"lockUnspents": True})['hex']
Copy link
Contributor

Choose a reason for hiding this comment

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

nit, add space if you happen to push again.

@instagibbs
Copy link
Member

concept ACK

Copy link
Contributor

@meshcollider meshcollider left a comment

Choose a reason for hiding this comment

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

utACK 991a38c

@Sjors
Copy link
Member Author

Sjors commented Apr 27, 2020

Rebased

@Sjors Sjors force-pushed the 2020/03/rpc_coin_locks branch from 6433bf4 to 0c5b867 Compare May 4, 2020 13:37
@Sjors Sjors force-pushed the 2020/03/rpc_coin_locks branch from 0c5b867 to 650437a Compare May 4, 2020 17:54
@Sjors Sjors force-pushed the 2020/03/rpc_coin_locks branch from 650437a to 74992fd Compare May 18, 2020 16:46
@achow101
Copy link
Member

ACK 74992fd

@Sjors Sjors requested a review from meshcollider June 12, 2020 09:06
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.

This made me think that we should fail funding if some coin is already locked?

After reading past discussions and some more careful analysis I now think this is not correct.

With the current approach, a client C1 must unlock the unspents to manually use them. But right after lockunspent true ... some other client C2 can fund/send and and take C1 unspents, and C1 will error.

So I think the "is locked" check should be used only for automatic coin selection, not for those explicitly set.

This means that:
a) the client handles concurrency elsewhere and doesn't use locked unspents
b) the client locks unspents beforehand and then use them by funding transactions with those as inputs - and also sets lockUnspents to grab the new ones
c) the user makes consecutive fundings with lockUnspents set.

In other words, we can assume that the client that funds a transaction with locked inputs is the one that locked them in the first place.

The c) case above is relevant - with the current approach it wouldn't be possible because between each funding iteration all inputs would have to be unlocked.

Lastly, the option lockUnspents when true should always lock all inputs - the caller will "own" all inputs (existing inputs whether locked or not and the new ones). This was the original change.

Sorry @Sjors for the misdirection 😞

Copy link
Member

@jonatack jonatack left a comment

Choose a reason for hiding this comment

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

Almost-ACK, review/tested, modulo I need to think about #18244 (review).

@Sjors
Copy link
Member Author

Sjors commented Jun 25, 2020

I'll await the above discussion. Will address nits if that leads to a change.

…ed coins

Previously only automatically selected coins were locked when lockUnspents is set.
It now also locks selected coins.
@Sjors Sjors force-pushed the 2020/03/rpc_coin_locks branch from 74992fd to 6d1f513 Compare August 7, 2020 12:13
@Sjors
Copy link
Member Author

Sjors commented Aug 7, 2020

Based on the above discussion I changed this PR again, it now does the following:

  1. lock all inputs for a transaction, rather than just the automatically selected ones
  2. unchanged behaviour: ignore lock on manually coins (with some tests)

I updated the description to clarify the discussion a bit.

@Sjors Sjors changed the title rpc: fundrawtransaction and walletcreatefundedpsbt respect locks even with manual coin selection rpc: fundrawtransaction and walletcreatefundedpsbt also lock manually selected coins Aug 7, 2020
@promag
Copy link
Contributor

promag commented Aug 7, 2020

Thanks @Sjors will review again.

Copy link
Contributor

@meshcollider meshcollider left a comment

Choose a reason for hiding this comment

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

Code review ACK 6d1f513

@maflcko maflcko removed the Tests label Aug 27, 2020
@Sjors Sjors requested a review from promag August 28, 2020 13:30
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.

Just want to point out that it's impossible to prevent 2 clients spend the same manually specified inputs.

One way to fix this is to make each client explicitly lock those inputs, and only proceed if the lock was granted.

@@ -2047,6 +2047,7 @@ static UniValue lockunspent(const JSONRPCRequest& request)
"Temporarily lock (unlock=false) or unlock (unlock=true) specified transaction outputs.\n"
"If no transaction outputs are specified when unlocking then all current locked transaction outputs are unlocked.\n"
"A locked transaction output will not be chosen by automatic coin selection, when spending bitcoins.\n"
"Manually selected coins are automatically unlocked.\n"
Copy link
Contributor

@promag promag Aug 29, 2020

Choose a reason for hiding this comment

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

This is incorrect, or am I missing something? I mean, all spent coins are unlocked right?

Copy link
Member Author

@Sjors Sjors Aug 30, 2020

Choose a reason for hiding this comment

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

Yes, but that's not the point. Automatically selection avoids locks, manually selection causes an unlock. This remark protects a user who assumes locked coins can't be accidentally spend by manually picking them. (it's like the difference between a Japanese toilet with shoes in front of it indicating it's occupied, and a Dutch toilets that's locked like a vault because people just pull the door open to find out)

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 "Locks on manually selected coins are ignored." would be a more intuitive description of what happens but I understand this to mean the same thing.

@Sjors
Copy link
Member Author

Sjors commented Aug 30, 2020

Client-specific locks sounds fun, but not in this PR :-)

Copy link
Contributor

@fjahr fjahr left a comment

Choose a reason for hiding this comment

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

Code review ACK 6d1f513

if (lockUnspents) {
LockCoin(txin.prevout);
}

Copy link
Contributor

Choose a reason for hiding this comment

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

mirco-nit if you retouch: empty line seems misplaced

@@ -2047,6 +2047,7 @@ static UniValue lockunspent(const JSONRPCRequest& request)
"Temporarily lock (unlock=false) or unlock (unlock=true) specified transaction outputs.\n"
"If no transaction outputs are specified when unlocking then all current locked transaction outputs are unlocked.\n"
"A locked transaction output will not be chosen by automatic coin selection, when spending bitcoins.\n"
"Manually selected coins are automatically unlocked.\n"
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 "Locks on manually selected coins are ignored." would be a more intuitive description of what happens but I understand this to mean the same thing.

@meshcollider meshcollider merged commit f98872f into bitcoin:master Aug 31, 2020
@Sjors Sjors deleted the 2020/03/rpc_coin_locks branch August 31, 2020 11:36
sidhujag pushed a commit to syscoin/syscoin that referenced this pull request Aug 31, 2020
…bt also lock manually selected coins

6d1f513 [rpc] fundrawtransaction, walletcreatefundedpsbt lock manually selected coins (Sjors Provoost)

Pull request description:

  When using `fundrawtransaction` and `walletcreatefundedpsbt` with `lockUnspents`, it would only lock automatically selected coins, not manually selected coins. That doesn't make much sense to me if the goal is to prevent accidentally double-spending yourself before you broadcast a transaction.

  Note that when  creating a transaction, manually selected coins are automatic "unlocked" (or more accurately: the lock is ignored). Earlier versions of this PR introduced an error when a locked coin is manually selected, but this idea was abandoned after some discussion. An application that uses this RPC should either rely on automatic coin selection (with `lockUnspents`) or handle lock concurrency itself with manual coin selection. In particular it needs to make sure to avoid/pause calls with automatic coin selection between calling `lockunspent` and the subsequent spending RPC.

  See bitcoin#7518 for historical background.

ACKs for top commit:
  meshcollider:
    Code review ACK 6d1f513
  fjahr:
    Code review ACK 6d1f513

Tree-SHA512: 8773c788d92f2656952e1beac147ba9956b8c5132d474e0880e4c89ff53642928b4cbfcd1cb3d17798b9284f02618a8830c93a9f7a4733e5bded96adff1d5d4d
meshcollider added a commit that referenced this pull request Sep 15, 2020
92326d8 [rpc] add send method (Sjors Provoost)
2c2a144 [rpc] add snake case aliases for transaction methods (Sjors Provoost)
1bc8d0f [rpc] walletcreatefundedpsbt: allow inputs to be null (Sjors Provoost)

Pull request description:

  `walletcreatefundedpsbt` has some interesting features that `sendtoaddress` and `sendmany` don't have:
  * manual coin selection
  * outputting a PSBT (it was controversial to add this, see #18201)
  * create a transaction without adding to wallet (which leads to broadcasting, unless `-walletbroadcast=0`)

  At the same time `walletcreatefundedpsbt` can't broadcast a transaction, which is inconvenient for simple use cases.

  This PR introduces a new `send` RPC method which creates a PSBT, signs it if possible and adds it to the wallet by default. If it can't sign all inputs, it outputs a PSBT. If `add_to_wallet` is set to `false` it will return the transaction in both PSBT and hex format.

  Because it uses a PSBT internally, it will much easier to add hardware wallet support to this method (see #16546).

  For `bitcoin-cli` users, it tries to keep the simplest use case easy to use:

  ```sh
  bitcoin-cli -regtest send '{"ADDRESS": 0.1}' 1 sat/b
  ```

  This paves the way for deprecating `sendtoaddress` and `sendmany` though there's no rush. The only missing feature compared to these older methods is adding labels to a destination address.

  Depends on:
  - [x] #16377 (`[rpc] don't automatically append inputs in walletcreatefundedpsbt`)
  - [x] #11413 (`[wallet] [rpc] sendtoaddress/sendmany: Add explicit feerate option`)
  - [x] #18244 (`[rpc] have lockUnspents also lock manually selected coins`)

ACKs for top commit:
  meshcollider:
    Light re-utACK 92326d8
  achow101:
    ACK 92326d8 Reviewed code and test, ran tests.
  kallewoof:
    utACK 92326d8

Tree-SHA512: 7552ef1b193d4c06e381c44932fdb0d54f64383e4c7d6b988f49d059c7d4bba45ce6aa7813e03df86360ad9dad6f3010eb76ee7da480551742d5fd98c2251c0f
sidhujag pushed a commit to syscoin/syscoin that referenced this pull request Sep 15, 2020
92326d8 [rpc] add send method (Sjors Provoost)
2c2a144 [rpc] add snake case aliases for transaction methods (Sjors Provoost)
1bc8d0f [rpc] walletcreatefundedpsbt: allow inputs to be null (Sjors Provoost)

Pull request description:

  `walletcreatefundedpsbt` has some interesting features that `sendtoaddress` and `sendmany` don't have:
  * manual coin selection
  * outputting a PSBT (it was controversial to add this, see bitcoin#18201)
  * create a transaction without adding to wallet (which leads to broadcasting, unless `-walletbroadcast=0`)

  At the same time `walletcreatefundedpsbt` can't broadcast a transaction, which is inconvenient for simple use cases.

  This PR introduces a new `send` RPC method which creates a PSBT, signs it if possible and adds it to the wallet by default. If it can't sign all inputs, it outputs a PSBT. If `add_to_wallet` is set to `false` it will return the transaction in both PSBT and hex format.

  Because it uses a PSBT internally, it will much easier to add hardware wallet support to this method (see bitcoin#16546).

  For `bitcoin-cli` users, it tries to keep the simplest use case easy to use:

  ```sh
  bitcoin-cli -regtest send '{"ADDRESS": 0.1}' 1 sat/b
  ```

  This paves the way for deprecating `sendtoaddress` and `sendmany` though there's no rush. The only missing feature compared to these older methods is adding labels to a destination address.

  Depends on:
  - [x] bitcoin#16377 (`[rpc] don't automatically append inputs in walletcreatefundedpsbt`)
  - [x] bitcoin#11413 (`[wallet] [rpc] sendtoaddress/sendmany: Add explicit feerate option`)
  - [x] bitcoin#18244 (`[rpc] have lockUnspents also lock manually selected coins`)

ACKs for top commit:
  meshcollider:
    Light re-utACK 92326d8
  achow101:
    ACK 92326d8 Reviewed code and test, ran tests.
  kallewoof:
    utACK 92326d8

Tree-SHA512: 7552ef1b193d4c06e381c44932fdb0d54f64383e4c7d6b988f49d059c7d4bba45ce6aa7813e03df86360ad9dad6f3010eb76ee7da480551742d5fd98c2251c0f
deadalnix pushed a commit to Bitcoin-ABC/bitcoin-abc that referenced this pull request Sep 19, 2021
…ed coins

Summary:
Previously only automatically selected coins were locked when lockUnspents is set.
It now also locks selected coins.

This is a backport of [[bitcoin/bitcoin#18244 | core#18244]]

Test Plan: `ninja all check-all`

Reviewers: #bitcoin_abc, Fabien

Reviewed By: #bitcoin_abc, Fabien

Differential Revision: https://reviews.bitcoinabc.org/D10144
@bitcoin bitcoin locked as resolved and limited conversation to collaborators Feb 15, 2022
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.

9 participants