Play Attacks and possible mitigations

In the other thread on “Replay Attacks and possible mitigations”, I introduced the following attack scenario:

Bob requests a payment from Alice, using the invoice workflow.
This means that Alice is the first to sign for the tx. She sends her signature to Bob, but Bob doesn’t complete the tx, and either becomes unresponsive or gives some excuse for why his wallet couldn’t complete the tx.

Alice cancels the tx, and the amount re-appears in her balance.

Then some years later, after Alice had to restore her wallet, one day she suddenly see her balance decrease. She has no memory of the canceled tx to Bob. But Bob did remember…

Th cause of the above attack is that currently, the wallet cancels a tx by merely forgetting about it and returning the amount to the balance.
It fails to prevent a future replay of the tx. Which is not even a replay because the original tx never hit the chain.
This problem cannot be solved by any kind of kernel uniqueness.

We can mitigate this scenario by having the wallet put an output that it signed for to be spent in a “limbo” state, to indicate that it no longer has exclusive control over its spending. Limbo outputs do not contribute to a wallet’s balance. It would normally remain in this limbo state until the tx confirms on-chain.

Now when Alice cancels the tx, the wallet should take the input(s) out of limbo state by spending them back to herself, i.e. “sweeping” them.
Only once the sweep confirms, can the amount be included in her balance again.

[1] "Replay Attacks and possible mitigations


Impossible to happen. Bob would need to know the partial ofdset of Alice to do that.

As i said in keybase two days ago and in the forum yesterday, the problem occurs if for some reasons the tx fails to broadcast.

This could happen if Bob gives a dishonest partial offset to Alice, and that Alice doesn’t check the balance before broadcasting. Fortunately our wallets do check the balance before sending tx.

This means that Bob cannot prevent Alice to send a honest transaction.

The remaining scenario where the problem could occur is if Bob or an attacker manages to make the tx not broadcast to a block, as in any blockchain probably. This is prevented by proper network propagation Implementation and mempool implementation. This should be checked in details.

Tx malleabikity is also a potential attack if wallet Implementation is not careful. Bob could make a bunch of sybil nodes that will propagate tx with new Bobs outputs (for example two outputs that sum up to the original output) instead of original Bobs outputs.

Alice wallet should never check Bobs outputs when she looks if the tx has made it to the block. She should rather look at the kernel only, and the issue is avoided.

Kernel uniquenesa prevents a class of different attacks, it has nothing to do with these problems which are perfectly fixed with good network propagation implementation, good mempool management and careful wallet implementation exactly like for Bitcoin.

He does when Alice sends back the slate with her partial signature and her partial offset.

As we discussed many time before, it is the receiver who sends its partial offset to the sender. And the opposite should not happen.

The above attack scenario has nothing to do with any of those. The tx was never completed by Bob.

  1. sender checks balance before sending.
  2. sender don’t send its partial offser to receiver

are botb trivially implementatable, and cancel your above attack scenario.

In the invoice workflow, it is Bob, the receiver, who completes and broadcasts the tx.

So another mitigation is to not allow the invoice workflow, and always make the sender the last to sign.

But in some situations, like in payjoin, or in multisig funding, both parties provide inputs to a tx, so there’s always one party that is able to complete the tx while the other isn’t, and the above attack scenario applies.

I think the attack in the case of PayJoin is also not possible too if the broadcaster of the tx is the party that gives money and that we apply the two above conditions that I mentioned. I’ll think about it and post my thoughts in the PayJoin thread.

I think this makes sense and would make for a better UX and better security. It is the recipient’s responsibility to ensure funds are obtained on chain, so if they fail to do so the sender has every right to do this. It is common for checks to be automatically cancelled if not deposited within a certain period of time.


If “mostly lock free” transactions potentially opens up flexibility in transaction building where the selection of outputs to be spent is deferred - I wonder if this potentially mitigates the “play” attack here.

Alice would sign with a chosen excess, but would not yet select outputs.
Bob could do nothing with this transaction until Alice selected outputs and build the final transaction.

I guess we always end up in a situation where one participant has the complete transaction and the other participant is at their mercy in terms of the tx being broadcast or not. And if not brodcast, then at least one output will be in “limbo”.

I wonder if there is way to guarantee both participants end up with the final transaction? Presumably not without a lot of additional complexity and communication during the tx building protocol.

Original txs -

A -> B, K1
B -> C, K2

And B -> C “fails” for some reason such that Charlie convinces Bob to sign a new replacement transaction with a new kernel but reusing the same original B output.

So Charlie has in their possession both -

B -> C, K2
B -> C, K2'

The one with kernel K2' was broadcast, the original one “failed” and was never broadcast.
K2 and K2' have different excess commitments with corresponding different offsets.

So now Bob is at risk of a “replay attack” if A -> B, K1 were ever replayed.

But now Alice and Charlie can work together and “(re)play” the original failed, un-broadcast transaction - B -> C, K2

Kernel uniqueness at the consensus level will not help here.

Edit: With max_height on kernels the window for this attack succeeding would be small but it could not be prevented within the window.

1 Like

On second thought - this part is prevented in this scenario.

So you would need conflicting txs in both “halves” -

A -> B, K1
A -> B, K1'

B -> C, K2
B -> C, K2'

So no kernel ever gets “replayed”.
Which I guess is harder to pull off.

This is not a “replay” from the perspective of kernels, but a “replay” from the perspective of creating and subsequently spending B.

This is nice for the solution for the circumstance of a single functioning wallet. It doesnt address when a wallet is restored or when multiple wallet instances are used concurrently. These latter situations could be addressed by having slates expire (I though they did, but if this is a concern they maybe they dont). Expired slates would have to be enforceable, but could have a default setting and also be user configurable.

However, I see no possible way of identifying which outputs are in “limbo” during a restore or multiple wallet instances, which would put these outputs at risk of being unintentionally spent by the sender. These situations are different for standard send vs invoice tx but either way I believe it is the recipients responsibility to verify they received the funds on chain.

“Electronic transactions for all.
Without censorship or restrictions.”

Tromp accommodates with censorship with broken and unacceptable wallet tweaks.
It can be fixed extremely simply with little and simple rules extremely easy to implement to make GRIN tx uncensorable, and hence secure following the normal blockchain model.

Grin is designed for the decades to come, not just tomorrow. Grin wants to be usable by everyone — regardless of borders, culture, skills or access.

Tromp also doesn’t care about this, as he is stubborn with broken wallet tweaks.

We have everything to make grin nice with clean and simple and elegant solutions. instead this mental jerking with wallet tweaks has been going on for quite long time now. Its an attack on grin basically. How can we tolerate to make this coin with one of the worst security and user exp in the industry? Do it if you want. I would be sad that this is the final choice, and doubtful about your intentions on Grin.

Peace out

1 Like

Not only are you completely mischaracterizing the pros and cons of the mitigations, but you have to use insulting language as well.

I didn’t insult anyone. I lost sufficient time arguing against arguments that don’t make sense at all and are flawed from scratch as they stample both security and User experience while simple solutions exist.

with all due respect, at least right now, you seems more focus on finding flaws on others proposals (and this can be misinterpreted); I think people wants the read more pros of your proposal and as far I can notice, it feels like your solution transfers the responsibility to users and relies on wallet tweaks, and it’s really hard to engage with that.

1 Like

The main pro of my proposal is safeguarding the user from losing funds.
The other proposal fails to do so, as it still allows the user to cancel a tx (which was to be completed by another party) without sweeping its input(s), and then be subjected to a play attack within a limited time window.

This risk of losing funds is easily avoided though as noted below in Play Attacks and possible mitigations
The other pro of my solution is preserving tx monotonicity, as argued for in Replay Attacks and possible mitigations

What are you talking about here Tromp? Are you ignoring other people’s writings?

I explained that:

  1. Check mw transaction balance before sending coin.
  2. the receiver should never see sender’s partial offset.
  3. checking of tx confirmation on the sender side should not be made against reveiver’s outputs.

fixes all play attacks until proven otherwise.

Could you please speak technology rather than using authority argument with no technical foundation and bring to us a concrete instance of an attack with all these trivial and simple and easily auditable rules being implemented?

Maybe bitcoin should sweep as well ? (in case God knows an attacks that haven’t been found)

I’m not sure its entirely fair to categorize healthy output/transaction management at the wallet level as “wallet tweaks”.

Grin/MW transaction building is inherently interactive. We should embrace this and take advantage of this where we can. The concept of “locking” outputs (aka outputs in “limbo”) once they are known to have participated in an interactive transaction building protocol is potentially a very clean solution to this “play” problem.

With a good wallet UX this does not shift responsibility onto the user. It does put additional responsibility on the wallet implementation but interactive transaction building effectively requires this responsibility regardless.

Once an output is in “limbo” it can be spent by the associated transaction, now or in the future (unless spent by another transaction). The only way to mitigate this would be to spend by another transaction.

This is true for Bitcoin also. But in bitcoin the number of participants in possession of the (unbroadcast) transaction is reduced because transaction building is not interactive.