Okay, that makes sense! I like thinking of double spends as just invalid history, since the first spend makes the second one’s history be invalid There is one attack I would be worried about which I’m curious if you’ve considered–this is something we’ve been thinking about a lot for atomic swaps:
There is a danger that the operator includes the buyer transaction, with a valid history, but withholds the buyer transaction. Then, they create an invalid block later than the buyer transaction, and begin an exit from the invalid state. Because the buyer transaction has a valid history, it would pass the collateral exit game and return the money to the operator–but, by the time the merchant sees this and knows the buyer transaction is valid, the operator’s malicious exit from the later block may be finalized, stealing both ranges.
This is an issue for trading/DEX predicates as well, where the trading predicate does not want to specify the range it swaps with in advance because the trader is waiting for any other user to agree to the other side of the exchange.
Our solution, which can probably apply here as well, has been to completely reuse the exit game of the main plasma contract for the collateral dispute. In this model, if the merchant exits the collateral, the way for the operator to deprecate the exit is for them to exit the buyer payment on the merchant’s behalf. So, if the merchant exits the collateral, the function call which the operator makes to deprecate the merchant’s exit contains a sub-call to
finalizeExit on the buyer’s payment. This guarantees the merchant absolutely that they will either get the collateral exit, or get the buyer payment exit.
Does this make sense? I like it because it is easier to reason about safety–the only way to cancel the merchant withdrawal is to finalize the buyer payment exit. Further, it makes the predicate simpler, since it may simply call
finalizeExit instead of having its own custom logic for determining the validity of the payment.
One concern I would have is that if the payments are very small, it might not be worth the gas to play out. In that case, it may be better to use channels entirely (e.g. the plasma debit predicate).