Composite Moves + Programmatic NextPlayer

Hey guys,
I have a couple questions about possible changes to the protocol design to allow for more complex features to be made on this platform, just wanted to see what everyone thought!
For background, I’ve been working on a Monopoly game to be implemented on the StateChannels framework, and I’ve ran into a couple issues which, while technically solvable with the current design, might be more intuitive from a change to the protocol:

  1. Composite Moves, right now I have this state transition diagram representing the Monopoly game , and with the current ForceMove protocol, each player only is allowed one ‘turn’ to move, meaning that the state moves from NextPlayer to NextPlayer, with the states inbetween being calculated client side. It would be great if we could allow each player to submit multiple channel updates before handing off their ability to do so, that way we could have a more consistent development experience and also a more consistent user experience (for now since updates are only done after each turn has ended, in between states have to be ‘trusted’ from the currentPlayer)
  2. Programmatic NextPlayer, also an issue I’ve come across while implementing the Monopoly game, the current moverAddress = participants[turnNum % participants.length] scheme works well for turn based games like this, however in the case that a player in Monopoly goes bankrupt, their turn is usually skipped. In this case however, we still must have them advance the state, which opens up a potential avenue for griefing, since the player has already lost and has almost nothing to lose by stalling out the game or disconnecting completely.

My idea is to separate the allowed ‘mover’ of the channel state from the turnNumber, that way we can still have that, but instead keep a separate currentPlayer count that gets advanced whenever the player wants to relinquish their control. This would solve both issues above at the same time, as well as open up the gates for more complex turn based games where player order isn’t perfectly cyclical. Let me know if this would be possible!

Edit: I found this post Cyclical versus dynamic turn taking for applications which discusses the dynamic turn taking, I feel like the problem could be solved by having the rules for selecting the next player set in the application contract, that way the players cannot collude but we can still select a nextPlayer dynamically. Would that work?

Welcome to the forum @SirNeural and thanks for this post!

It seems to me that 1 and 2 are very closely related: you either want to update the channel without updating the mover, or update the mover without updating the channel. And the solution you are proposing is to decouple the mover from the turn number (at the protocol level) and have it defined on a per-application basis, perhaps inside validTransition. This way each application’s rules can be inspected by prospective participants and checked for opportunities for collusion.

Perhaps there is a useful distinction between “dynamic” turn taking, which @liam wrote about, and “programmatic” turn taking (as you put it), which need not be strictly cyclical, but is also static and predictable.

While I don’t yet see any fundamental problem with your idea, I think it is safe to say it would take a major rewrite of our our contracts to achieve, and it would break a few “nice” properties that we currently enjoy. For example, in the current system you do not need to inspect the appData to decide whether a state is supported. Also, state channel wallets need only store the last nParticipants states in order to protect themselves from challenges. In the case of monopoly it is possible (although unlikely) to roll 1000 doubles, requiring all players to store at least those moves to ensure they have a support proof for the latest state (which requires signatures from all players).

Another option which would work with our current implementation, would be to have your validTransition function require players to “pass” on their (forceMove) move if it is not their (monopoly) move. In this model, after rolling a double you relinquish your forceMove move and everyone else immediately relinquishes theirs, so you are now the channel mover again. This obviously requires cooperation and is vulnerable to griefing, especially if you just made a great move. You anticipated this as a solution to 2, but I just wanted to point out that it could also solve 1.

Overall I think your current solution to 1 is probably the best compromise, and something like @liam’s suggestion in the post you linked is probably the best solution to 2. That is, when a player goes bankrupt have them gracefully leave the game by agreeing (with the other, live players) to divert the money in this channel into a new channel that they do not participate in. Residual funds that the bankrupt player is due can be unilaterally withdrawn from the existing channel by that player, very much along the lines of a partial withdrawal (see the Nitro paper)*. The residual funds might be some deposit that is required to incentivise graceful exits.

I think this solution works at the protocol level, but does not have any support in our wallet just now.

*The nitro paper talks of partial withdrawal from a ledger channel, but our implementation actually has a signature scheme which means you can even do a partial withdrawal from an application channel, too.

The way I would approach 1 would be to rethink the scope of the state channel turn. It seems that currently one state channel turn corresponds to one dice roll? A different approach would be for one state channel turn to cover the entire time until the player cedes control to the next player - to include multiple dice rolls, in the case of doubles. Would that work in this case?