Do we really need the post-fund-setup round?

Currently, the first 2*numParticipants turns are devoted towards channel setup in a directly or indirectly funded channel. This is hard-coded into the ForceMove rules: only the turn number is allowed to change during this channel setup phase. This is an artifact from an older version of ForceMove which didn’t support multiple signatures on the same state.

forceMove requires a supported state to launch a challenge. Therefore, the first numParticipants states form the “PreFundSetup” phase: without these states, any deposit could be locked forever, because no ForceMove functions can be called. The next numParticipants states form the “PostFundSetup” phase, where each participant only deposits after all prior participants have already deposited.

Now, a state s can be supported by having each participant sign s. Therefore, we could reduce this “PreFundSetup” phase to just one states, at turn numParticipants - 1. At this point, we might as well make the setup phase last only numparticipants + 1 turns.

I also believe that the second half of this “setup” phase is unnecessary – I need to be convinced every few months that it’s important. If I am correct, then turns 1,...,numParticipants + 1 are unnecessary during the setup phase, and the setup phase has been reduced to just state 0.

In fact, at that point, there is no special logic required for the setup phase at all. Suppose we remove the special setup logic:

  • All participants sign state 0, in whatever turn they want
  • All participants then deposit, in order. No rational participant would deposit out of order.
  • All participants wait until the channel is fully funded before signing turn i for i > 0. No rational participant would deviate from this.
  • Once the channel is fully funded, participant 1 can update the appData according to the application-specific rules.

Note that the same argument can be made about final states: it’s unnecessary to increment the turn number, and it’s also unnecessary to sign in order. Participants could simply all sign the first final state.

Summary

Therefore, the valid transition rules (excluding support checks) could be written without any conditional logic:

function validTransition(a, b) <=>
  b.turnNum == a.turnNum + 1
  b.chainId == a.chainId
  b.participants == a.participants
  b.appDefinition == a.appDefinition
  b.challengeDuration == a.challengeDuration
  app.validTransition(a, b)
  !a.isFinal

Here are my claims that make this validTransition “safe”.

  1. No rational participant would deposit before state 0 is supported.
  2. No rational participant would deposit out of order.
  3. No rational participant would move past state 0 before the channel is fully funded.
  4. No rational participant would insist on incrementing turnNum on a final state.

I agree that I’ve never really understood the need for the post-fund setup stage either.

In my code, opening a channel requires a co-signed (or fully-supported) state 0. In addition, the app is passed some initialisation data which allows it to generate appData for state 0 - which is useful if state 0 needs to be complex (eg the initial setup for a game, or in my case the RNG seeds).

I certainly prefer not having any of the setup stuff in validTransition - it seems that otherwise it’s performing two separate functions.

I also try never to think of my participants as rational! What would be the consequences of moving past state 0 before the channel was fully funded? Or reaching a supported isFinal state? Could I be malicious by not being rational?

Also - the way your code is written, should

!a.isFinal

be

(!a.isFinal) || (a.outcome == b.outcome)

?

I also claim, which wasn’t obvious in the above post, that acting rationally protects you at least as much as the current ForceMove protocol rules do. I don’t mean to assume that all participants act rationally in order to achieve safety.

Explicitly, in a skill-based game channel between [Alice, Bob, Charlie]

Under the current rules

  • Alice should not sign state 3 until the channel is fully funded
  • Once the channel is fully funded, and Alice signs 3, Bob and Charlie can do whatever they wants on turn 6.
    • This might be a clever combo take all of Alice’s funds
    • Alice has no control over this: he has to accept this risk if she wants to play this game

Without post-fund-setup

  • Bob should not sign state 1 until the channel is fully funded
  • Once the channel is fully funded, and Bob signs state 1, Charlie and Alice can do whatever they want on turns 2 and 3, which might be the same clever combo as above

It’s not trivial that the two scenarios above give exactly the same safety, but to me it seems obvious.

Actually, no! In a channel between Alice and Bob, if Alice signs state s = { turnNum: 10, outcome: O, isFinal: true }, the only currently valid transition is s' = {turnNum: 11, outcome: O, isFInal: true }. But, there’s no benefit in Bob making this transition, since the outcome is now fixed. Instead, the above rules force him to support s.

There’s no strict need to add this requirement to the ForceMove rules, but it does make the implementation simpler, and rational channels would always choose this behaviour, since:

  • participants can sign s in any order, speeding up the channel conclusion
  • conclude is now more gas-efficient, since you never call validTransition(s, s')

The round of post-fund setups is necessary to ensure you have a universally finalizable* outcome at the point when the deposit is made. This is a useful thing to have, because it gives compete certainty about how the funds will be distributed, regardless of the total deposited.

If you didn’t have the post-fund setup, you’d need to trace though the possible outcomes from the first round of the application, to decide whether it’s safe to deposit or not. You could argue that you have to trace through all the outcomes of the game anyway, to decide whether it’s safe to play or not, so why is the post-fund setup helping? You can view the post-fund setup as decoupling the funding from the game safety: for the purpose of evaluating the game, you can assume it’s fully funded, and for the purpose of evaluating whether the deposit act itself is safe, you can ignore the rules of the game.

* From the Nitro paper: a universally finalizable outcome is a an outcome that every participant is capable of finalizing on-chain, regardless of the actions of the other participants.

I don’t see why, for the purpose of evaluating whether the deposit act is safe, you can’t assume that you agree to any outcome dictated by the rules of the game. Is there a clarifying example?

I don’t believe that this is correct. Here is a counter example:

Suppose we have a game with Alice, Bob, and Charlie. In each round, Alice chooses a number, and whoever guesses closest out of Bob and Charlie wins, and Alice gets a small reward. If they fail to play, they forfeit. Bob and Charlie are both supposed to deposit 5ETH. Bob deposits, Charlie doesn’t, but Alice proceeds anyway. Now Bob has to play (or he forfeits) but he can only lose, as none of Charlie’s money is in the pot.

1 Like

Ok, this example also points out that post-fund-setup is a special case: the participants should only support their own states until the first app-phase state.

It still seems like a wallet could take advantage of multiple signatures in special cases. For example, while opening a virtual channel, it’s still safe for everyone to immediately sign state 2n-1 in the joint channel, rather than having to sign each state in order up to 2n-1.