BUIP085: Double spend relaying

torusJKL

Active Member
Nov 30, 2016
497
1,156
BUIP085: Double spend relaying
Submitted on 4th February 2018 by torusJKL


Background
A double spend can happen within the time from the initial broadcast until the transaction is included in a block.
Although this is on average within 10 minutes at the point of sale we need to know that a unconfirmed transaction is as safe as possible withing seconds.

Currently double spend transactions are not relayed thus a merchant might not know that there is a high chance of him not receiving his transaction.
In order to detect double spends those transactions need to be forwarded by the nodes.


Motivation
By receiving and forwarding double spend transactions sellers learn about attempts to defraud them faster and can take appropriate steps.
This will make 0-conf transaction on Bitcoin Cash more safe and will give it broader acceptance.


Task
1) Develop a double spend relaying that is compatible with BitcoinXT's implementation (the relaying as such and the rpc call).
2) Add a double spend visualization in the wallet GUI.


Timeline
The double spend proof should be developed and to be implemented for BUCash with the aim of being ready for inclusion in the scheduled November 2018 protocol upgrade.

Caveats
The lead developer will have discretion and flexibility to modify details specified in this BUIP, while keeping within the spirit of the BUIP with the goal of advancing 0-conf tx security on Bitcoin Cash while staying compatible with the implementation used by BitcoinXT.


References
Relay and alert user to double spends (BitcoinXT merge)
 
Last edited:

solex

Moderator
Staff member
Aug 22, 2015
1,558
4,693
@torusJKL
Certainly. This is something which has been long overdue for the other clients. I recall that the code in XT was from a collaboration between Gavin and Mike.
 

Hyena

Member
Feb 27, 2017
42
60
I used XT nodes for half a year but one-by-one they all started to suffer from mysterious issues such as being unable to connect with any other nodes and even disallowing me to spend any of my own funds due to strange wallet conflitcts. For that reason I strongly suggest you to be very cautious when implementing double-spend relaying in BU nodes. I personally was not perfectly happy with the particular implementation XT had for double-spend relaying because 90% of the times it failed to notify me about real double-spends. I guess the hacker directly pushed to the mining pool which in turn did not relay double-spends, so the rest of the network only learned about it when a block containing the DS was finally mined by that pool.

That said, since it is technically impossible to distinguish between a malicious double-spend and the original TX we have an option of:
1) allowing the Scorched Earth arm-wrestling between the merchant and the double-spender where both outbid each-other's TX fees until no one gets their money and all the funds end up in TX fees via CPFP TXs.
2) try to enforce the first-seen rule and other kludges to combat double-spending of 0-conf TXs

Since the first option is vastly more radical than the second option, I will elaborate here how the first-seen rule could be reinforced. Implement a pre-mempool that stores all new 0-conf TXs that your node learns about. However, when a TX is insterted into the pre-mempool queue it will have to wait there for 10 seconds before it is allowed to enter the actual mempool. During that 10-second time it is possible that a conflicting TX is received by the same node. When that happens the node could fire the `-respendnotify` event so that the merchant could act on it. Whenever conflicting TXs enter the pre-mempool all of their 10-second timers should be reset because all of them become competitors and there could be more than one double-spend coming. It makes the most sense to allow the competitor with the greatest TX fee into the actual mempool because miners are incentivized to do exactly this whether we like it or not.

The 10-second gap is necessary so that the receiving node could relay the new TX immediately to all of its neighbours while still waiting for any potential double-spends to arrive. I would guess that within 10 seconds a TX will reach all the nodes of the network. If the double-spend arrives later than 10 seconds then the first-seen rule is naturally applied even by old nodes who don't relay double-spends. If the double-spend arrives within 10 seconds the merchant has a theoretical chance to quickly spawn a CPFP TX from the initial payment, donating all of the funds to the miners and thus making it unprofitable for the adversary to even attempt double-spending.

By implementing pre-mempool we are keeping this new double-spend relaying functionality more separate from the old and working implementation and thus there is a smaller chance for introducing new bugs and vulnerabilities. New RPCs should be added for polling the pre-mempool and getting events similar to walletnotify exclusively about the pre-mempool. In other words, the improvment should be backwards-compatible with any software using the current RPCs. Software relying solely on old RPCs would experience 10 second lag before gaining information about new payments.

The pre-mempool is useful because it would also provide an opt-in solution for the TX malleability problem. Zero-fee TXs are held in the pre-mempool for 10 seconds to allow a CPFP TX arrive right after the zero-fee parent TX. The child TX pays for the parent and for itself. Without the child the parent cannot be confirmed because it has a fee of zero, thus the parent TX cannot be malleated. A small consensus rule is needed though so that zero-fee TXs would be illegal if they are not paid for within the same block. In other words, all blocks containing a zero fee TX without a CPFP TX should be rejected by all nodes. As a result, we will have double-spend notifications and opt-in fix for TX malleability implemented within the same patch.
 
  • Like
Reactions: AdrianX

Tom Zander

Active Member
Jun 2, 2016
208
455
The feature would be awesome to have, yes.

The implementation in XT may not be the best as it essentially forwards both full transactions across the network. This is bad for SPV wallets as transactions may potentially be huge. It is also bad for the state of the network as it makes the 'first seen' concept harder to properly implement.

Amaury and I wrote a different solution some time ago which would be really easy to do on top of BCH, double-spend proofs. It essentially takes the idea that the only thing you need to relay is the fact that in two separate places the exact same input was signed. Thats only a small part of the transaction. I'm not going to explain the details here, as people will know where to find the documentation, but I do hope you guys can look into that solution in the short term future.
 

torusJKL

Active Member
Nov 30, 2016
497
1,156
@Tom Zander thanks for your input.
Unfortunately I don't know where to look for the mentioned documentation. Could you link it here?


Whenever conflicting TXs enter the pre-mempool all of their 10-second timers should be reset because all of them become competitors and there could be more than one double-spend coming.
What if I will send a new double spend every few seconds. Would that mean that my transaction will never go into the mempool?
This could give an attacker allot of time to mine it privately with a colluding miner even if that miner has only a little hashrate.
 

Hyena

Member
Feb 27, 2017
42
60
@torusJKL no such attack is not possible because the pre-mempool entrant is immediately relayed to all other nodes. If the attacker keeps sending a double-spend in every 10 seconds and the merchant has an updated node then the merchant would learn about those double-spends via RPC. If the merchant has old node then of course the first-seen rule is applied and the merchant is vulnerable.

However, your comment indeed raised some questions in my proposed design. I'm not exactly sure whether a more bullet-proof version of it can be devised but I just figured that the 10 second gap is not needed for the TX malleability fix. The TX malleability fix can be achieved by simply relaying the CPFP TX before the parent TX. The CPFP TX would be handled as an orphan until the zero-fee parent arrives.

As for the pre-mempool, perhaps a better route would be to reject further double-spends after 10 seconds have passed since receiving the first TX. Then after 10 seconds the one which would make the miners most money is allowed in the mempool. This way the 10 second gap will only eliminate the problem where the payment and its double-spend are broadcast concurrently and there's a small chance that a mining pool receives the double-spend but the rest of the network receives the fraudulent payment.
 

Hyena

Member
Feb 27, 2017
42
60
We could also start a mempoolexplorer project as a centralized service in the spirit of blockexplorer. It would have an API but it would be oriented on presenting the current mempool in real time. everyone would be free to push 0-conf TXs to that public mempool. It can do all sorts of things, for example prioritizing TXs from the mempool and compiling the most profitable block for the miners to mine. The merchants could then simply subscribe to that service and use its API to check for double-spends. By default the explorer gets its data from the network of course, but mining pools could directly push TXs to it. In return, miners get the most profitable candidate set for the next block. Finding the most profitable set of unconfirmed TXs is not a trivial problem due to CPFP TXs, it is not just simple ordering based on TX fee per byte. This solution is cool because it is completely separate from the production network and thus it carries zero regression risks.
 

theZerg

Moderator
Staff member
Aug 28, 2015
1,012
2,327
@Tom Zander Please do link your documentation and reference code here! I would be much happier with what your solution sounds like compared to a solution that relays the double spend transaction.
 
  • Like
Reactions: Norway and torusJKL

Tom Zander

Active Member
Jun 2, 2016
208
455
I don't think it ever got fully coded or documented.

So, a double-spend transaction has one unique feature. Two different transactions share the same input. That is; a prev-txid and an 'n'.

To communicate this we can send around the net a simple package with this info.

1) tx-id/n (utxo) being double-spend
2) txid of first seen tx.
3) txid of double-spending tx.

Anyone can then trust us that this is a double spend. But trust isn't that great an idea. Proof is better.
So the simple solution for this is if we append also the relevant signature for each transaction. In Bitcoin each input gets its own signature and as such we have two signatures that should be signed by the same private key (as defined by the output they try to double-spend).
We then also send;
4) the pubkey that matches the privatekey
5) the information needed to create a signature-hash for each of the inputs.

The number 5 is something that was trivial in FlexTrans as the sighash was based on the txid of the entire transaction as well as things like the 'amount'. Making that part work for current transactions is going to be the challange.

Anyway, as soon as the receiver has the information to make the sighash of each of the two inputs, they can check the signature using (4) and compare it to the one included in the proof.

This is the most compact way to propagate a double-spend proof. (and triple etc).
 

Tom Zander

Active Member
Jun 2, 2016
208
455
I just finished watching the talk from Tom Harding in Japan and in reply to @Peter R he answered that a double-spend-proof would not work because you need the entire transaction in order to validate the proof.

This is outdated information, it used to be the case in BTC, but we changed the way that the sighash is created in Bitcoin Cash. It now has become possible to only send a part of the transaction and on the other side we can indeed validate the signature without the entire transaction.

If you look at the code (for instance in flowee) you see that in Cash we switched to having a hash being build up of a lot of separate elements, 3 of which are hashes of the rest of the transaction. So you can just send the hashes that represent the rest of the transaction instead of the entire transaction.
 

Tom Zander

Active Member
Jun 2, 2016
208
455
Yeah, Adrian-x has a point. This is why Tom Harding is wrong and XT is dangerous. The cure is worse than the disease.

The solution is double-spend proofs, which I explained above. They do not send the actual transactions and there is no propagation of the second transaction (nor the first). Just a cryptographically signed notifcation so merchants know they should be wary.
 

torusJKL

Active Member
Nov 30, 2016
497
1,156
@Tom Zander made good arguments against the tx relaying.
But because the idea of this BUIP was to go along with BitcoinXT and be compatible I will not change it.

Instead I have created the BUIP088 and the BU members will be able to decide by voting which solution is the better in their view.
 
Last edited:

sickpig

Active Member
Aug 28, 2015
926
2,541
Yeah, Adrian-x has a point. This is why Tom Harding is wrong and XT is dangerous. The cure is worse than the disease.
(cc @dgenr8 and dagur)

Care to explain why?

AFAICT the worst case scenario is that a double spend will be included in the next block rather than the legitimate txn.

if the XT signaling mechanism will be wildly deployed and hence used by merchants to detect double spends I don't see how the merchant would be defrauded even in the worst case scenario. He would have just to wait a few sec to see if the alert kicks in and then avoid to give the good to the fraudsters in case of positive signal.

This won't cause any split chain as long as we are not introducing new consensus rules that impose to the miner to reject blocks that contains an alleged double spend txn.

The solution is double-spend proofs, which I explained above. They do not send the actual transactions and there is no propagation of the second transaction (nor the first). Just a cryptographically signed notifcation so merchants know they should be wary.
That said I guess that if we have compact proof that could be used instead of relying the double spend txn, this will be even better and could be easily introduced in the code XT as deployed and also proposed for BU inclusion. See https://github.com/BitcoinUnlimited/BitcoinUnlimited/pull/1018#issuecomment-377808701 for more details.

One last slightly related topic: BitPay, in the process of deploying BIP70 (payment protocol) for all online txns it managed it introduce a change to the protocol so that the buyer have to wait for "200 OK" when sending the `payment` message to the merchant, before broadcasting the bitcoin payment. if 200 is not returned, the payment will be aborted.

I wonder if we could go even further and make the merchant the one who's going to broadcast the txn to the network and not the buyer. My gut feeling is telling me in that way merchant would have a lot more control on the process and the buyer who want to double spend will have harder time to get away with it.