This adds a BIP for improve could the privacy of certain off-chain protocols like Lightning, CoinSwap or DLCs.
It has already been implemented by Sparrow wallet.
This adds a BIP for improve could the privacy of certain off-chain protocols like Lightning, CoinSwap or DLCs.
It has already been implemented by Sparrow wallet.
0@@ -0,0 +1,112 @@
1+<pre>
2+ BIP: TBD
3+ Layer: Applications
4+ Title: Anti-fee-sniping protection with nSequence in taproot transactions to improve privacy for off-chain protocols
5+ Author: Chris Belcher <belcher at riseup dot net>
6+ Status: Draft
7+ Type: Standards Track
8+ Created: 2021-06-10
9+ License: PD
5+ Author: Chris Belcher <belcher at riseup dot net>
6+ Status: Draft
7+ Type: Standards Track
8+ Created: 2021-06-10
9+ License: PD
10+ Post-History: 2021-7-10: https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2021-June/019048.html
0 Post-History: 2021-6-10: https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2021-June/019048.html
55+ transaction.version = 2
56+ # always set nlocktime if any of the transaction inputs have more
57+ # confirmations than 65535 or are not taproot inputs
58+ # otherwise choose either nlocktime or nsequence with 50% probability
59+ if any(map(lambda input: input.confirmations() > 65535
60+ || !input.is_taproot(), transaction.inputs))\
||
and !
operators. Maybe replace them or remove the mention of “python” and only say “pseudocode”?
64+ transaction.nlocktime = max(0, transaction.nlocktime
65+ - randint(0, 99))
66+ # nsequence must be set in order for nlocktime to take effect
67+ # this value also enables RBF
68+ for input in transaction.inputs:
69+ input.nsequence = 2**32 - 3
Some wallets provide an option to the user to “opt-out” of RBF. It would be good to clarify how they should handle this BIP.
Edit: Presumably, just setting to 2**32 - 2
should still work to enable locktime and “disable” rbf.
Algumas carteiras fornecem uma opção para o usuário “opt-out” da RBF. Seria bom esclarecer como eles devem lidar com esse BIP.
Editar: Presumivelmente, apenas configurar para
2**32 - 2
ainda deve funcionar para habilitar o tempo de bloqueio e “desabilitar” o rbf.
57+ # confirmations than 65535 or are not taproot inputs
58+ # otherwise choose either nlocktime or nsequence with 50% probability
59+ if any(map(lambda input: input.confirmations() > 65535
60+ || !input.is_taproot(), transaction.inputs))\
61+ || randint(2) == 0:
62+ transaction.nlocktime = blockchain.height()
Is there an intuition how much this will help in practice?
I expect smart contract implementations to use “magic numbers” for nsequence, such as 144. Or at the least use an nsequence that is biased toward such magic numbers. This will make it easier to tell them apart from “normal” transactions. I don’t have any data, but I think a tx output is (still) most likely to be spent in the block that created it (or in the few next ones that follow it). Such inputs would get marked with a small nsequence, for example 0
or 1
. Those values don’t really make sense for smart contracts, so it will be easy to tell them apart.
Maybe for small nsequence, it could make sense to also fall back to nlocktime?
Thanks so much for the reviews. I can’t believe I got the date of the mailing list post wrong.
If fixed locktimes are used then a coinswap peer in a routed coinswap can tell their own position in the route from the locktime. Randomizing locktimes can be used to avoid this, and randomized locktimes will also blend into on-chain traffic a lot better. So this BIP will certainly help the privacy of CoinSwap/Teleport, which intends to eventually use a slightly randomized locktime.
The same privacy leak applies to Lightning, and the Lightning community might also decide to implement randomized locktimes in some form. The discussion is more complicated admittedly since public channel transactions are broadcasted to everyone in the LN.
NSequence values of 1 could be used as an alternative to OP_CSV 1
which is today being discussed as a way to stop transaction pinning.
Because off-chain tech is so much more efficient in block space than on-chain tech, we can expect that the vast majority of block space will be used by on-chain tech for a long time, so it’s not a bad thing that this BIP marks on-chain transactions. The purpose of this BIP is to provide cover traffic for the rare occasion when an off-chain contract is closed with the timelock branch. This BIP aims to make that situation not immediately stand out. So I don’t think it’s worth changing anything for small nsequence values.
Thanks for the context and providing an example of why an nsequence of 1
makes sense. I guess an nsequence value of 0
doesn’t really make sense in practice? Moreover, in a (theoretical) edge case where a wallet spends untrusted unconfirmed coins, it might reduce the anti-fee-snipe guarantee. Assuming the incoming tx from another wallet didn’t have any anti-fee-snipe mechanism set, then a miner could re-mine the current block while including both the incoming tx and the one just created by the (theoretical) wallet?
Also, I am wondering if the locktime and nsequence should remain unspecified in this BIP if they don’t need to be set to achieve anti-fee-snipe? Given that smart contracts in practise will usually use either locktime or nsequence, shouldn’t this BIP recommend to set them to their “default” value if not used? (see https://github.com/chris-belcher/bips/pull/2) Otherwise it will again be easy to tell “normal” and “smart” txs apart.
0@@ -0,0 +1,116 @@
1+<pre>
2+ BIP: TBD
3+ Layer: Applications
4+ Title: Anti-fee-sniping protection with nSequence in taproot transactions to improve privacy for off-chain protocols
0@@ -0,0 +1,116 @@
1+<pre>
2+ BIP: TBD
3+ Layer: Applications
4+ Title: Anti-fee-sniping protection with nSequence in taproot transactions to improve privacy for off-chain protocols
5+ Author: Chris Belcher <belcher at riseup dot net>
6+ Status: Draft
7+ Type: Standards Track
92+
93+Thanks to craigraw for suggesting a new value for input nsequence in the absolute locktime case[7].
94+
95+== Copyright ==
96+
97+This document is placed in the public domain.
Thanks Luke!
I have dealt with your comments, edited the file name and other places to include the bip number, added an entry to the README, and squished all the commits into one.
75+ input_index = randint(len(transaction.inputs))
76+ transaction.inputs[input_index].nsequence = transaction.inputs\
77+ [input_index].confirmations()
78+ if randint(10) == 0:
79+ transaction.inputs[input_index].nsequence = max(0,
80+ transaction.inputs[input_index].nsequence - randint(0, 99))
This might again drop the nSequence below 1
. Can be fixed by
0nseq -= randint(0, nseq)
1nseq -= randint(0, nseq - 1)
Depending on whether randint is inclusive or exclusive.
0 transaction.inputs[input_index].nsequence -= randint(0, transaction.inputs[input_index].nsequence))
What do you think of max(1, transaction.inputs[input_index].nsequence - randint(0, 99))
?
i.e. Changing max(0,
into max(1,
?
The max stops the nseq going below 1. It also doesnt make assumptions about randint being exclusive or inclusive
41+
42+When wallets create transactions spending UTXOs protected by BIP341 taproot, they should set either an nLockTime value or nSequence values to discourage fee sniping, by allowing the transaction to only be mined in the next block after the tip, not the current block. This BIP suggests 50% probability for using nLockTime and 50% for nSequence. If nSequence is set it should apply to at least one of the inputs of the transaction, if it has multiple inputs. It is suggested that on-chain wallets pick an input randomly.
43+
44+Wallets should also have a second random branch which sets the nLockTime or nSequence value even further back, so that transactions that are delayed after signing for whatever reason (e.g. high-latency mix networks) have better privacy. Existing behaviour is that with a probability of 10%, choose a random number between 0 and 99, and subtract it from the current block height. See the Bitcoin Core and Electrum source codes linked in the references for an example.
45+
46+nSequence can only encode up to a max of 65535 for the block distance, see BIP68[5], so if the UTXOs being spent have more confirmations than that then the wallet should use nLockTime instead.
than that then
looks weird even if grammatically correct:
0nSequence can only encode up to 65535 for the block distance, see BIP68[5], so if the UTXOs being spent have more than 65535 confirmations, then the wallet should use nLockTime instead.
17+
18+== Motivation ==
19+
20+With taproot recently added to bitcoin, and wallet software about to implement taproot wallets, we are in a unique position to improve the privacy of off-chain protocols if we act soon.
21+
22+Taproot allows for point-time-locked contracts (PTLC) as a more private replacement for hash-time-locked contracts (HTLCs). If an off-chain contract (for example a Lightning channel) is closed using a PTLC instead of an HTLC, then the blockchain will just see a regular taproot script instead of a hash value and preimage. However, if a contract is closed using the timelock path, then the blockchain will either see a OP_CHECKSEQUENCEVERIFY opcode or a nSequence value in the transaction, neither of which are very common today, and this would mark the closing transaction as something special and unusual.
0Taproot allows for point-time-locked contracts (PTLCs) as a more private replacement for hash-time-locked contracts (HTLCs). If an off-chain contract (for example a Lightning channel) is closed using a PTLC instead of an HTLC, then the blockchain will just see a regular taproot script instead of a hash value and preimage. However, if a contract is closed using the timelock path, then the blockchain will either see a OP_CHECKSEQUENCEVERIFY opcode or a nSequence value in the transaction, neither of which are very common today, and this would mark the closing transaction as something special and unusual.
80+ transaction.inputs[input_index].nsequence - randint(0, 99))
81+</source>
82+
83+== Compatibility ==
84+
85+This BIP doesnt need any consensus changes. It can be adopted unilaterally and gradually by wallets. Although for greater privacy it would be good for software to adopt it as soon as possible. Ideally during the process of developers implementing their taproot wallets, so that when taproot starts to be used it will already include the nSequence code.
0This BIP doesn't need any consensus changes. It can be adopted unilaterally and gradually by wallets. Although for greater privacy it would be good for software to adopt it as soon as possible. Ideally during the process of developers implementing their taproot wallets, so that when taproot starts to be used it will already include the nSequence code.
19+
20+With taproot recently added to bitcoin, and wallet software about to implement taproot wallets, we are in a unique position to improve the privacy of off-chain protocols if we act soon.
21+
22+Taproot allows for point-time-locked contracts (PTLC) as a more private replacement for hash-time-locked contracts (HTLCs). If an off-chain contract (for example a Lightning channel) is closed using a PTLC instead of an HTLC, then the blockchain will just see a regular taproot script instead of a hash value and preimage. However, if a contract is closed using the timelock path, then the blockchain will either see a OP_CHECKSEQUENCEVERIFY opcode or a nSequence value in the transaction, neither of which are very common today, and this would mark the closing transaction as something special and unusual.
23+
24+This BIP proposes to improve the privacy and fungibility of off-chain protocols by having on-chain wallets like Bitcoin Core also set the nSequence field in their taproot transactions as in BIP68. This would be in place of their regular nLockTime anti-fee-sniping protection. The end result is that, if an observer of the blockchain sees a taproot spend with an nSequence value, then that could be either: a regular spend from a wallet, or an off-chain settlement transaction spent with a timelock. The two cases would be indistinguishable, and this could greatly improve the privacy and fungibility of bitcoin. The community and wallet developers should act now to implement this so that the anonymity set of nSequence transactions starts to be built up as soon as taproot itself becomes adopted by wallets.
0This BIP proposes to improve the privacy and fungibility of off-chain protocols by having on-chain wallets like Bitcoin Core also set the nSequence field in their taproot transactions as in BIP68[5]. This would be in place of their regular nLockTime anti-fee-sniping protection. The end result is that, if an observer of the blockchain sees a taproot spend with an nSequence value, then that could be either: a regular spend from a wallet, or an off-chain settlement transaction spent with a timelock. The two cases would be indistinguishable, and this could greatly improve the privacy and fungibility of bitcoin. The community and wallet developers should act now to implement this so that the anonymity set of nSequence transactions starts to be built up as soon as taproot itself becomes adopted by wallets.
59+ else:
60+ input.nsequence = 2**32 - 2
61+ # always set nlocktime if any of the transaction inputs have more
62+ # confirmations than 65535 or are not taproot inputs, or have
63+ # unconfirmed inputs
64+ # otherwise choose either nlocktime or nsequence with 50% probability
nlocktime
or 50% nlocktime
and 50% nsequence
?
41+
42+When wallets create transactions spending UTXOs protected by BIP341 taproot, they should set either an nLockTime value or nSequence values to discourage fee sniping, by allowing the transaction to only be mined in the next block after the tip, not the current block. This BIP suggests 50% probability for using nLockTime and 50% for nSequence. If nSequence is set it should apply to at least one of the inputs of the transaction, if it has multiple inputs. It is suggested that on-chain wallets pick an input randomly.
43+
44+Wallets should also have a second random branch which sets the nLockTime or nSequence value even further back, so that transactions that are delayed after signing for whatever reason (e.g. high-latency mix networks) have better privacy. Existing behaviour is that with a probability of 10%, choose a random number between 0 and 99, and subtract it from the current block height. See the Bitcoin Core and Electrum source codes linked in the references for an example.
45+
46+nSequence can only encode up to 65535 for the block distance[5] so if the UTXOs being spent have more 65535 confirmations, then the wallet should use nLockTime instead.
0nSequence can only encode up to 65535 for the block distance[5] so if the UTXOs being spent have more than 65535 confirmations, then the wallet should use nLockTime instead.
nSequence=1
values. It’s a brief retelling of the discussion between @MarcoFalke and me, which I think is worth saying in the document too.
64+ input.nsequence = 2**32 - 2
65+ # always set nlocktime if any of the transaction inputs have more
66+ # confirmations than 65535 or are not taproot inputs, or have
67+ # unconfirmed inputs
68+ # otherwise choose either nlocktime or nsequence with 50% probability
69+ if any(map(lambda input: input.confirmations() > 65535
0 if not rbf_set or any(map(lambda input: input.confirmations() > 65535
The wallet must use tx.locktime when the user asks for the bip125 opt-out sequence number
37+
38+Absolute locktimes are also still used, so we should keep using nLockTime, but also often use nSequence.
39+
40+=== Transaction pinning ===
41+
42+Transaction pinning[8] is a method for making fee bumping prohibitively expensive by abusing node protections against attacks that can waste bandwidth, CPU, and memory. This can make fee management more difficult in multipart contract protocols (such as Lightning Network or CoinSwap). One possible way of solving the problem is to include a 1-block relative timelock `1 OP_CSV` to all spend paths, making it impossible to spend the unconfirmed UTXO. Such a 1-block locktime can also be created with an nSeqeuence value of 1. Many on-chain transactions in bitcoin spend inputs that were created just one or two blocks ago, following this BIP such transactions with `nSequence=1` would also provide cover traffic for off-chain transactions which disable transaction pinning.
0Transaction pinning[8] is a method for making fee bumping prohibitively expensive by abusing node protections against attacks that can waste bandwidth, CPU, and memory. This can make fee management more difficult in multipart contract protocols (such as Lightning Network or CoinSwap). One possible way of solving the problem is to include a 1-block relative timelock `1 OP_CSV` to all spend paths, making it impossible to spend the unconfirmed UTXO. Such a 1-block locktime can also be created with an nSequence value of 1. Many on-chain transactions in bitcoin spend inputs that were created just one or two blocks ago, following this BIP such transactions with `nSequence=1` would also provide cover traffic for off-chain transactions which disable transaction pinning.
nit: typo
To improve privacy for off-chain protocols