Outlining the structure of a generalized state channel app infrastructure.

State Channel Applications

Frequently making transactions to progress the Ethereum Virtual Machine is needlessly expensive and slow. Most applications using Ethereum today work by updating a storage variable of an on-chain contract for which users pay transaction fees and spend time waiting for block confirmations.

Naturally, this is quite slow. In order to use an application, we’re forcing users to manually submit database updates to the world’s most secure, decentralised, and trust-free…. mobile phone from 1999.

Thankfully, there’s a better way.

We can write applications that are exactly as secure by shifting some of the responsibility onto the clientside code instead of relying on Ethereum to do everything for us. Generally, we call these “Layer 2” technologies. At L4, we’ve written extensively about the different ways of doing this to help explain the idea.

Most of the “Ethereum doesn’t scale!” narrative isn’t due to the underlying blockchain being unsuitable. More accurately, it’s because it’s very difficult for developers to use layer 2 technologies like state channels. We need better developer tooling on top of ethereum, which will make it easier to write applications in an efficient way.

Counterfactual is an open-source project that is tackling this problem head on. Our goal is to make it easy for developers to build their applications using state channels on ethereum. You can read more about the goals of the project on our website, and check out the code on our github.


Why is it difficult to use state channels today?

Today, if a developer wants to write their application to be decentralized using Ethereum, they’re likely to implement each of:

  1. A public API — public or external functions on their contract
  2. Authorization logic — usually by checking msg.sender
  3. Resolution logic — to decide how funds are distributed

For the most part, this is a good level of abstraction for a developer to be thinking at when designing a decentralized application. We’ve seen thousands of developers build applications using Ethereum over the last year using this pattern, so it’s probably best to not radically change it.

Thinking about state channels from this point of view gives you far more empathy for app developers. Most of the time when trying to design a state channel application, you’ll run into all kinds of roadblocks like:

  • It’s not clear how the public API should be written since you aren’t signing Ethereum transactions anymore, you’re signing generic state objects
  • The authorization logic requires each user of the state channel to sign an object for each update and verify these signatures using ecrecover
  • The resolution logic is now more complicated by the fact that there is a built-in “challenge” or “dispute” period every time new state is submitted

And worst of all, there are zero established standards for the entire state channel protocol, making it hard for frameworks or common libraries to emerge.


What can we do to make it easier?

The most important first step to making state channel applications easier to reason about is to standardize the generic state channel functionality in a way that cleanly splits the state channel resolution logic from the application logic. It should be as easy as possible to write your application in a format that is state-channel compatible and, ideally, should feel like you’re writing regular smart contract code.

One way to accomplish this is to model an application as a state machine. The force-move game framework was an example of this and, generally, the EVM is already built upon the foundational idea of being a state machine with state updating each block based on transaction execution.

So what’s the difference between a regular smart contract and a state channel compatible smart contract? Essentially it boils down to the fact that we need a standard way to interface with the state transitions of your application regardless of the implementation of the public API. More simply put, we need an entry-point function to compute state transitions.

An Example — Tic Tac Toe

Let’s say we want to write a Tic Tac Toe application. Probably we’ll write a smart contract that has a public API with placeX and placeO functions, checking msg.sender to verify that the correct player is making their move.

An example Tic Tac Toe smart contract written in Solidity.

Modelling this game as a state machine, we can see that there would be 5 types of states and 2 kinds of valid transition types between them.

An example of a state machine for the Tic Tac Toe application. If it is X’s turn, X can take an action to win the game, end the game in a draw, or just place their piece and pass it over to O for their turn.

Coming back to the idea of a standard interface for updating the state of the application, we want to create a function that accepts some prior state of the state machine (e.g., X_TURN) and an action that can be taken to get to a new state (e.g., PLACE_X). Interestingly enough, this is the exact same pattern of some common web frameworks that exist today, such as Redux. They tend to call such a function a “reducer”. So let’s try to write the Tic Tac Toe application in this way:

A Tic Tac Toe application with a single reducer function that handles PLACE_X and PLACE_O actions instead of multiple functions called placeX and placeO. The reducer function “dispatches” the actions to helper functions.

With this in place, we now have a way to compute state updates that can be made to an application with a single common interface — the reduce interface. This is very useful when thinking about the types of attacks against which a state channel must be secured.

But what does the state channel contract need to do?

Naturally, the state channel object should use the application logic to determine if a transition is valid. The core state channel functionality can exist in a generic contract which handles the various attack scenarios that are possible but delegate to the application for the specific transition rules of its state machine.

The StateChannel can use the App Logic as a means of determining valid transitions but handle the authorization and resolution logic itself based on information provided to it by the app logic.

There are two major scenarios that need to be handled. If we use the common example of Alice and Bob exchanging messages with each other, then we can frame them as:

  1. What if Bob submits outdated state?
    The contract has to be able to implement a timeout period such that Alice has time to submit newer state than what Bob submits. If the state that Bob submits is provably old, then Bob should be punished.
  2. What if Bob stops responding?
    The contract has to give Alice the ability to submit the latest signed state she has received from Bob in order to get her money out (after the timeout period elapses). In some situations, it might be possible for Alice to “make a move” that progresses the app’s state machine, and so she must be able to use the application’s reducer in that case.

To accomplish this, the contract needs to expose a basic API. Note that this is essentially the API for dealing with dispute cases. It’s the set of function calls that users of a state channel could use to ensure the off-chain state updates they’re signing have significance.

Roughly this API covers:

  • Creating a dispute.
    One party submitting the latest signed copy of the state and optionally taking an action on the app that will logically progress the state to the next state.
  • Progressing a dispute.
    One party responding to the dispute from another party by taking an action on the state that has been submitted.
  • Cancelling a dispute.
    Both parties agreeing to cancel the dispute and resume off-chain normally.

Where are the funds stored?

This is where many of the features described in our paper become useful. We put the funds in a generic multisignature wallet and use it as the primary contract that makes commitments for distributing those funds based on the outcome of the state channel.

The set of contracts required for a simple application that uses state channels without using counterfactual instantiation, but just using regular contract references.

This gives us many useful perks. One of the nicest is the ability to take advantage of the technique of counterfactual instantiation, also described in detail in the paper. When we add that to the mix, we can keep the state channel contract and the application logic contract off-chain.

The same setup as above, but this time the state channel contract and app logic contract are counterfactual — they only ever need to be deployed on-chain in the case of a dispute.

After we set this up, we get yet another immensely powerful feature: zero on-chain transactions for installing and uninstalling applications.

When we use counterfactual, adding and removing applications is free and instant.

Effectively, since we can make an unlimited number of calls from the multisignature wallet for conditional transfers, these commitments can be made for any number of applications.

Next steps

In future posts, talks, and discussions we’ll outline our vision for the software that will live on top of the contracts layer. State channels, to be usable in production, are going to require a significant amount of coordination from the entire ecosystem. Some of the specific areas we’re currently working on and look forward to further collaborating with others on are:

  • Standardizing research terminology, sharing insights, and following through on other fascinating research problems in state channels and layer 2 scaling.
  • Integrating generalized state channel patterns into existing state channel systems and applications based on off-chain paradigms.
  • Working with web3 frameworks to make off-chain concerns well-known for the future development of their developer APIs.
  • Working with wallet providers to help provide clear protocol specifications and standards around how state channels can exist in their domain.

How can I learn more and contribute?

As a good place to start, we encourage you to check out our contracts code on GitHub which contains a reference implementation for the technique.

We will continue working with great teams and individuals interested in the future of decentralized application development going forward, and would love to invite others to collaborate with us.

This is only the start of the journey. To see the vision of a fully generalized state channels network that is accessible for all users of the technology, we need to do much more.

State channels will become the protocol for peer-to-peer value transfer. They will need to be standardized for use in every type of client, in wallets, and across blockchains.

If you’re interested in working with us on this vision of the future, reach out at hello@counterfactual.com or join us on GitHub. :)

Like what you read? Give Liam Horne a round of applause.

From a quick cheer to a standing ovation, clap to show how much you enjoyed this story.