State Channels on Ethereum with Counterfactual by Liam Horne (Devcon4)
Devcon 4 · 11 Dec 2018 · 22:39
Liam Horne discusses state channels on Ethereum through the Counterfactual framework at Devcon4, covering how counterfactual instantiation lets two parties transact off-chain while retaining the ability to enforce outcomes on-chain if needed. The talk addresses how this approach lowers the cost of opening a state channel.
Speakers
Topics
From Devcon 4, hosted by Ethereum Foundation.
Transcript
Right. So, I'm going to be talking about counterfactual. Um it's an open source initiative to make secure off-chain applications easy to build in Ethereum. So, you just saw two talks about building a payment channel network and about building like a production application specific state channel uh casino game kind of application. We want to try and make those types of things as easy as possible to build for the developers to build it. So, uh Jeremy, for example, from FunFair is our target uh kind of developer that we want to like help make their life easier and the whole FunFair team in front of me. Um so, first of all, who am I? My name is Liam Horne. I'm the co-founder or one of the co-founders of L4. Um we're a company that tries to do a lot in this industry um basically promoting kind of the web 3 vision.
Uh we help build this project. We help build Eth Global and a handful of other initiatives. But, I'm also an engineer on the counterfactual project. The distinction for which has not yet been so clear, but I'm going to try to articulate in this talk. So, what am I talking about? I'm going to go through uh go through four things. Basically, what are generalized state channels? You just saw use cases of payment channels and you saw use case of uh what I'm going to kind of show is an application specific state channel. I want to show what generalized state channels are, kind of a a layer two solution for the uh that uses this technique in general for blockchain transactions. What counterfactual the project is and explain how we've approached engineering uh a framework for this stuff uh and then how you can, too.
So, basics basic agenda. Background, generalized state channels, engineering, and uh counterfactual. So, uh let's jump in. Uh initially, when I kind of first came into this space, uh I asked the question of like, "Why is it not the case that this stuff is being used by everyday people yet?" Uh and the answer I got was basically that scalability is important and and this was about a year and a half ago. And there were a handful of problems that needed to be worked on. Uh you know, including sharding uh and and one of them was state channels. And I basically was was "Why is it not the case that anyone's really tackling this? Not necessarily as an app-specific technique you can do to make your app go faster, but as a general tech a general uh solution for scaling on Ethereum. Why is
it not the case that anyone that wants to build an application can take advantage of this technique to make their application just by default be really fast. Um I stumbled upon this post uh got introduced to the guy that wrote it, Jeff Coleman, um and realized a lot of the ideas were there for how you could build state channels into a layer two kind of scaling technique, but not a lot of the implementation had been there yet and kind of wondered why. Um after a lots of like thought and uh and research, we basically realized that, you know, this is an opportunity to try and build something great. Um and so what we did is we tackle it very much with the mindset of like I mentioned, how do you build a layer two uh scalability solution using this technique? Generalized enough to allow for arbitrary applications with
maximum off-chain interactions without necessarily having to build it as a one-off uh kind of implementation technique for your particular application. So, we started off by writing this paper, um which is basically the uh the formal uh version of the the post that Jeff had put on. It goes into ton of depth of how you can do this, what are the security models you need to be thinking about, what are the general parameters that you want to be aiming for, how can you maximally have uh off-chain interactions using state channels for any application. A very abstract kind of notion, but one that if you can get right, enables uh an enormously powerful technique to be used and I'll show you how it's uh how it's useful.
So, that's a long paper, uh but it basically summarizes into some very simple uh a very simple idea. And so, I'm going to go through it very very briefly. So, you already know what payment channels are, but I'm just to set up, you you're pretty familiar with this technique. You have a blockchain, you put some money into a channel, A balance, B balance, you wait some time, off-chain Alice and Bob move uh basically over some communication protocol, They update some uh balances between them. You know, going from version zero all the way up to to end basically. And then whenever they're done, they go back to the chain. They put that latest state on and the balances get paid out. We're familiar with that here. Um and so that's a payment channel. So what's an app
specific state channel? What what's FunFair doing? It's a very similar um but what they're doing is that they have arbitrary state. They have different state per application whether it's roulette or blackjack or whatever they might be playing. And they have this added thing on the chain which is they have the application logic to handle uh disputes essentially uh or cases where someone's deviating from the protocol and they need to figure out who won the game actually. That's how they get the the probable fairness. So it's very similar to a payment channel. So that's what you can do with application state but what what's the what is the generalized state channel?
Um and as I mentioned you have the application logic. But what is the generalized state channel? In a generalized state channel you have the same setup. Blockchain, contract, you put some uh deposit in there and again ETH, ERC-20, whatever it is you want to be using off chain. But you do this interesting thing. As time goes on, you actually create for yourself, you kind of sign transactions that purport to allocating some subset of that state, a sub deposit, into what we can call an off chain application. And you do this in very much the same way in the application specific state channel. But this because you can push it down to the application agnostic to what's on chain, you can do it multiple times.
So the key benefit is that you can now install and update and uninstall applications, arbitrary applications, that you would say, you know, a roulette game, uh tic-tac-toe, uh you know, blackjack payment channel, whatever you want, uh in the same on chain state channel. In this with the same single contract on chain you can do multiple applications. That's the the key insight of generalized state channels. It's very cool. If you do it this way, then it becomes less of a quick technique for one app, it becomes a generalized scalability solution. It's very powerful. And then disputes actually or deviations from the protocol are very similar to the application specific case. You just take one of the one of those states um whichever one is the one that's being um that you need to kind of
uh ensure the fairness of and adjudicate on chain, you put that on chain. But the key idea is that off chain you're installing and uninstalling applications uh with zero fees, uh no on-chain transactions, and and that's great. So, two FAQs that I always get asked. One, how do you ensure all the sub deposits add up? Isn't this really complicated? Um yes, it's complicated and that's what warrants um as Jeremy rightly put uh mentioned, a protocol to be defined. Uh you need a protocol uh for participants of a state channel to speak to each other to say, "How do you install application? How do we uninstall it? What are we What are we saying to to each other? What are the specific commitments?" And that gets a little bit complicated, so you need a well-specified protocol, which I will
get into. Uh and the second thing is, and it's been a bit of misinterpretation if you've seen the paper, is this notion, "Don't you need to deploy the contract every time and isn't this absurdly expensive?" Uh the answer is no, very similar to Jeremy in in practice. Of course, you deploy a contract on chain that it has the rules uh that define the game ahead of time, but that's a one-time thing for application. We have introduced in the paper a notion of this term that's called counterfactual instantiation, which maybe you've heard, which allows you to do this off chain, but it's a useful technique uh for performance and upgradeability, but it's not necessarily a must-have. So, it's very very performant in much the same way as an app-specific state channel might be.
So, great. So, very quickly, what is counterfactual? And what are we doing about all this? Why why is this something we're talking about? Uh basically, the most important thing is that we are an open-source project. Our goal uh our vision is that these types of applications, like I've mentioned, should be as easy as possible to build. In the future, it should be the case that a developer goes to a like a hackathon and says, "I want to write an application and I want it to be really fast." And they should be able to build a great user experience in 36 hours. It should be as simple as possible for that to be the case. And so, our vision is to get to that. Uh mission, in terms of what the project's goals are, is to build that framework. We want to make it be as easy as possible for this entire
community to benefit from this technique that I just described. And so, we're not a company. We're not any particular uh business with any kind of business model behind this. We're an open source project trying our best to give something to the community. And so, that's that's that's the key takeaway of the project. So, what is encompassed within that? It's three core pieces of infrastructure um that basically needed to be uh implemented and need to be available for people to build uh using this technique. Um and they are a minimalist contracts layer. The absolute most bare-bones, simple to read, simple to deploy, uh small lines of code set of contracts that need to be there, on top of which you can design a protocol that does kind of what I
described. A protocol for state channels. Um you need something that defines how you install applications, how you want to install them, how you update them. Uh and an application library. Something that allows developers to interface using this protocol. So, you can think very similarly, this kind of looks like the web 3 stack uh in the sense that you have the underlying blockchain, you have the protocol that you're following of Ethereum, and you have an application library like web 3. We're trying to emulate a similar developer experience for layer 2. So, let's dive into some of the details of of of how we've approached it and what it looks like. Um first of all, the on-chain library uh the actual contracts layer consists of uh a very basic on-chain library for conditional transactions. Uh you may have heard the term conditional payments
or immediate transfers. Basically, the idea here is that uh you put is the uh the most minimal component for unanimous consent as possible on the chain, a multi-signature wallet uh that achieves N of N consensus. Um and then what we have in addition to that is very basic way to use that multi-signature wallet to sign conditional transactions. And using kind of the best in class research from a lot of the people that you're going to hear, I think, after me and and have already spoken about how you can adjudicate a state channel uh in a very uh optimal kind of way. And so we've taken a lot of the best research from all those things and built uh a simple component to enable this to to be uh to to work on chain. And we we've already released all of this.
Um the great thing is it's built to support all of this stuff. Unidirectional payment channels, bidirectional payment channels, N-party, hub and spoke, plasma, ERC-20, 20, 721, you name it. The main idea is that we're not assuming any particular type of transaction besides the most primitive unit of transaction on Ethereum to value data. That's all that we're assuming, which means as time goes on this framework is agnostic to protocol updates. As long as you don't change the idea of a transaction on Ethereum, the protocol uh will still run, and we can we can uh incrementally improve this protocol as Ethereum develops over time without necessarily having to have massive upgrades per EIP, for example.
Uh what we've done separately to the uh the generic on-chain components, we've created a very basic state machine-based library, and and you can see again like from FunFair's presentation this is kind of what they've landed on too in terms of what's the optimal way of describing applications. Uh state, action, new state. This is the type of uh way in which we're assuming someone can design their application. Uh and we support this out of the box. And we've also added very three very simple methods to enable your blockchain application to kind of benefit uh from from basically be uh easy to define using this framework. So, our resolver, something that can take your state, and uh the pre-commitment, the
sub-deposit pre-commitment that you've made, and figure out what transactions need to be made. Uh a is terminal clause, something that says is this game over? Uh, and I'll I'll show you how all these are relevant in a second. And kind of a turn taking mechanism which can define is it a valid update or not? Key point here, four very simple uh, functions that you can implement for arbitrary applications. If you implement them, the frame framework supports out of the box. So, very simple high-level example, uh, a bidirectional payment channel for example. Basically here, it's the most basic possible state machine. Uh, you have one state and people can just update the version of where you're at with that. In this case, it's uh, end
party state channel and in this case there's two in the array. All you do is update it. Most basic case. So, what if you want to jump in like more complicated for which there's all kinds of different separate bespoke applications like unidirectional payment channel? Well, we just write a state machine looks like this. You start in an open state, send in about and as a as a bit of context, a unidirectional payment channel is one of the kind where only one payments can only be sent in one direction. So, A and B, A can send to B, B can't send to A. And the idea is that B is the recipient and if they want to just leave, they can instantly leave.
So, how can you define that? You can define a machine where uh, in the open state, the sender can send and that's a valid action. And uh, you can get to the point where you are done in a terminal state which is what I would represent with this orange ring where if you are the receiver and you call the close action, you can instantly exit. So, you define your state machine in this way and you get all of the properties of unidirectional payment channels without having to implement anything different from the generalized framework. Tic-tac-toe, a bit more complicated but it's the same general idea, right? You define what is your state machine?
Is it X's turn? Is it O's turn? X can place an X and he can win or X can place an X and it can be a draw. You get the idea. And again, you're defining your state in this very simple way. So, in designing that framework, uh in addition to making it very generic and possible to build all kinds of state channel applications using it, we've also spent a significant amount of time in the engineering side to make this as easy as possible for developers to build on top of. And you can see this in kind of the implementation details of some example applications. So, I'll show you a very quick snippets of some code from a counter application. One where basically you have a counter, you can increment it, you can decrement it. The basic kind of uh example app.
And basically it it looks just like this. It's a stateless contract. And there's three slides here I'll go through. This is a stateless contract. Uh you just define what is the structure of your state. Uh and uh kind of like Jeremy mentioned, uh it's as as simple as this. Uh we actually actually had a we actually have a hacky solution to get around the necessity for abi.decode in the code base right now, but when it comes out that'll be great, too. Um and you just define your state as a struct. And you define the actions that you can use to modify it. And again, this function signature allows you to mimic what a state machine does.
Um you have a simple function, apply action like I mentioned. You take the state, you take the action, you decide what to do about it. Uh it's a very simple control flow. Um and then there's your very basic implementation. So, this is literally the entire contract for a very basic counter app. So, the great thing about this, uh again as Jeremy rightly mentioned, is that uh state machines encompass arbitrary things that you can run on the EVM um that are basically pure and content functions. There's an aspect of time dimension here, which I think probably one of the future speakers will talk about that add some complexity. But for things that you can run that are EVM um based uh this encompasses everything, which is
great. And so, that's the minimalist contracts layer. On top of that, we've had to devise a protocol for this whole generalized state channel concept. Um and without going into too much detail, we've essentially done that. This is basically a generic software for the clients can run and it has all possible messages you can receive using channels and it's designed to be as portable as possible. So this is not like a full node software that we've developed. This is just a basic very very basic implementation of a protocol that says, you know, the different types of messages that someone can send to another to use their on chain state deposit to install applications and install applications and so on and so forth. And it's it's a very practical.
We've we've tried to make it be the case that there's no unnecessary network overhead. It's it's A sends to B, they get a response back for all of the protocols in the entire construction and so it's practical and can be deployed today. If you want to look at the specifications of the protocol, we have a whole specs doc on the website on GitHub and you can you can dive into there. This is kind of the beginnings of what we hope will become a very good standard for what is the best thing you can get for state channels on Ethereum and eventually it would be nice if if if we can build on top of this common standard and hopefully a lot of the research can end up here. That's our goal at least.
So finally an application library and this is basically the thing I mentioned analogous to web 3. It's an application library that developer pulls into their to their app. They simply interact not with their wallet in a way that is kind of through the web 3 interface but with kind of this counterfactual interface or this layer 2 interface. You do things like update state to your wallet and the wallet with the implementation of the protocol figures out how to interact with its counterparts. And again, this is a little bit of abstract but it's it's it's this entire full stack suite that proves that the the use case is possible. And all of this has been designed in mind to be as easy as possible for a developer and like I mentioned earlier, we we
actually run hackathons and so we we we We an amounts of time with developers trying to understand what is it that will kind of get people caught up. Uh so why? Why is it that we're doing any of these things and and what are the kind of values that uh are lining us for this? As mentioned earlier, kind of factors open source project is multiple contributors and then I'll get into who they are. But we think this is just plain old open source. Um we we we really just want to be able to work with the Ethereum ecosystem, the people that are here, and people that are at Devcon, and try to just take a lot of the great research that we've talked about over the years and that have, you know, ETH research posted about make it concrete, arrive at standards, arrive at things that we can agree are
kind of best in class research, and build on top of that. Uh there's no one necessary ego and no one necessary um lock-in. It's just a matter of how do we build open standards that are helpful for everybody. Um and we want to do that as just plain old open source. Uh we don't think there's any necessity for a business or or token. We think that this is just plain old open source. Uh and developer focused. Mentioned this a handful of times and you can see through the like way that we've designed this, this is meant to be something as easy as possible for developers to use. Um and we want to drive for compatibility. We want to make it be the case that Ethereum can have kind of the best in class state channels protocol uh before any other chain and that we can
do this uh basically together and be interoperable with each other's software. Uh great. So who who is involved in this? I mentioned it's an open source project. Uh I do want to give kudos to a bunch of people. This is right now mostly been a collaboration between L4 and and and Prototypal. Uh handful of people from each of the teams and a bunch of independent contributors. Um we've recently even added on a whole bunch in the past uh few weeks that are uh just ramping up now. All sharing the same general vision of like let's take all these ideas, have a common place that we can write them down, and and and make something that people can use.
So really thanks to everyone that's uh contributed over the year. Um and we're also working with some of the best. We've uh over the past year we spent a bunch of time with a lot of great people in this space. Uh uh MetaMask we've been recently spending a ton of time with trying to figure out practically how are we going to get this implemented in web wallets today. Um, Celer Network, we spent a ton of time with Mo especially looking at the actual underlying research of how you build generalized state channels. Uh, we're hoping we can arrive at common interfaces uh, over the next little while. Uh, PISA, which has done a phenomenal job and they're speaking later about how to do really optimal watchtowers with state channels. Uh, we're also going to try and fold that in.
Uh, and Magmo as well, a phenomenal kind of uh, state channels uh, engineering team uh, with through which a lot of the state channel uh, state machine based designs uh, have been kind of inspired by. So, uh, yeah, if you want to get involved, uh, we have a bunch of code on GitHub. We just released a whole bunch recently as well. The whole everything I just mentioned is a full implementations of and then we have running. Um, we don't have a big uh, demo environment yet. That's one of our major kind of next goal, but we do have it running locally and you can test it out. Um, and we're actively developing this uh, very fast-paced. If you want to chat with us, we're available all the time. You can go to our chat group uh, counterfactual.com/chat.
Uh, we're very friendly. We really just uh, we want to like uh, try to help out the community as much as possible. So, you know, come in whatever you want to talk about. And uh, if you want to just learn more about the the product in general, check it out counterfactual.com. And uh, yeah, that's it. Thanks so much. I do have a minute 20 seconds left. So, if there is a question I can take one. Uh, or or I can kind of awkwardly walk off stage. Yeah?
Hey, let me give you my mic. Uh, what's the like 30-second different explanation between a state channel and a plasma chain? Is it Yeah, I had that in the I had that in the slides. Um, there's a really First of all, there's a really great talk uh, by the guy who just gave you the microphone, Josh Stark, yesterday called Making Sense of Layer 2, which gives like the 30-second uh basic uh difference. The way I like to describe it is that uh from a technical standpoint with state channels, a fixed group of people put state into an on-chain contract, and then they agree unanimously off-chain, and then at some point they all go back off uh take all that state put it back
on the chain or they or they stay off-chain. With Plasma and it's all off-chain the whole time. With Plasma, a bunch of people put state into a contract, and there's two types of people. There's an operator, and then there's the users. And the operator periodically puts a Merkle proof on the chain that lets the users have finality. So, every time the Merkle proof is put on chain, that is the notion of this is now the final state. So, there's this periodic checkpointing kind of mechanism. So, the main difference is that state channels it's instant finality all of the time. Plasma, you have a bit of a delay cuz there's a checkpoint. Um and then technically they're implemented differently, but they're both very useful scalability solutions. I recommend watching Josh's talk though.
Great. All right, thanks.