As a part of a recent overhaul of the contract layer of the state channels stack, we have achieved a significant reduction in costs for end users of our general scaling solution for the Ethereum blockchain.

Ethereum runs on transactions, submitted by end users and causing changes of state in the Ethereum virtual machine (EVM) “world computer”. Gas is the unit of an internal currency used to meter the computational cost of processing those transactions. It must be paid for in ETH, at an exchange rate (“gas cost”) set by the user (and tunable for speed / cost tradeoff). Right now a typical gas cost is around 2 GWei. At recent exchange rates, this implies about 0.30 USD for 1M gas. The fee for a transaction is the product of the gas cost with the amount of gas consumed: this fee is an incentive for Ethereum miners to try and get the transaction included in the blockchain, since once it is ‘confirmed’ they are paid the fee. The fee is a pain point for DApp users — less so if the DApp is converted to use a state channel.

State channels reduce gas by eliminating transactions

Because the Ethereum virtual machine is replicated on a large number ( > 7500 at the time of writing) of Ethereum nodes, loosely speaking the transaction fees are symptomatic of having this large number of nodes compute and validate state transitions that may or may not be of interest to them. State channels exploit this fact to reduce the need for all of those state transitions to be validated, and therefore reduce the transaction fees that need to be paid. Since Ethereum currently runs on a Proof of Work protocol, the use of state channels can also reduce the amount of unnecessary electricity consumed by the network as a whole.

State channels are a method of taking as many transactions as possible — but not all — “off chain”. A regular DApp would submit every state update as an Ethereum transaction, incurring the gas costs and significant latency of at least one or more block confirmation periods (about 15 seconds) for each one. A state channel app (SCApp) ideally only submits two transactions, which bring about a state transition representing the net change in state agreed upon by the state channel participants. In the event of a disagreement, more transactions may be used to cause the chain to settle the dispute.

Many companies today use their own, private accounting system to reduce the need for payments to be processed by a public network: for example, consider store gift-cards, cellphone contracts or utility companies. Individual “payments” in the private system are typically quite small, are not of interest to outside parties, and are essentially IOUs signed by the participant, submitted to the company, and backed by an initial deposit. State channels operate in much the same way, only the initial funds are not in the sole custody of any one party, but held in escrow by the blockchain.

If starting from scratch, state channels require at least one transaction to set up (e.g. to escrow some ETH), and one transaction to tear down (e.g. to payout the ETH), with all other state updates (e.g. transfer a portion of that ETH between the participants) being off chain and therefore fast and free.

Residual gas costs for state channels

With our state channel network protocol Nitro, users will likely only ever need to setup a single channel once with a hub, and administer it periodically (say once a month). A hub connection can be bootstrapped to virtually setup and teardown state channels without any on chain transactions. This means that the setup and teardown costs of that single hub connection channel are less critical. They still represent a pain point for end users, however, and therefore a barrier to mainstream adoption for Ethereum: the costs need to be reduced as much as possible.

Additionally, settling state channel disputes on chain will always involve Ethereum transactions, even if in an ideal (and hopefully also in a typical) world they are never used. The possibility of having disputes settled lends strong guarantees about fair extraction of any escrowed assets, however: the gas consumed during settlement therefore remains an important consideration. If the associated costs were prohibitive, or if they outweighed the assets staked in the channel, it might mean that challenges would never be used and the security guarantees would be effectively void.

Gas consumption in state channels is influenced by a number of factors: including for example the EVM version (e.g. the latest: Istanbul), and the solidity compiler; but most of all it is influenced by the design of the smart contracts that implement the state channel adjudication and asset holding protocols: influenced, that is, by the efficiency by which those contracts compute the necessary state transitions. Efficiency in this context is determined by the original Ethereum gas fee schedule (plus subsequent changes).

Deploying the contracts to chain also consumes gas: typically a large amount since they involve storing an amount of bytecode roughly proportional to the “size” of the contract source code.

Over the past 18 months, our contracts have been evolving towards a much more gas efficient implementation.

In the early days of state channels, there was the Simple Adjudicator contract, which escrowed ETH and settled disputes for a single state channel only. As such, a new deployed instance was required for each state channel. This is very inefficient from a gas point of view, since the same code is stored on chain over and over.

The Simple Adjudicator was replaced by the the first (legacy) incarnation of the Nitro Adjudicator, which stored sufficient data on chain for managing an unlimited number of channels. This was a great improvement, since deployment costs were now only borne once and probably not by the end user. The other gas costs were still substantial, however, and equivalent to dozens of regular Ethereum transactions (each costing a minimum if 21000 = 21k gas).

The major costs in the legacy contracts were incurred due to storing a relatively large amount of data for each channel: data that specifies the assets escrowed, where they should be paid out when the channel resolves, and sufficient information to resolve a dispute. Writing to and reading from storage incur 20K and 15K gas per 32 bytes (respectively), dwarfing other costs associated with computations that remain in memory.

Hashed storage

The main trick to reducing this was to reduce all storage to a minimum: a single bytes32 storage slot. But how do we do this, when the outcome data is application specific and surely longer than 32 bytes?

The answer lies in the magic of cryptographic hash functions, which are a core primitive of blockchains. Cryptographic has functions accept variable length input, are infeasible to invert, and produce fixed length output. By storing only the keccak256 hash of the outcome data, we ensure that only one slot gets used, regardless of the application. Previously, the number of slots required would grow with the complexity of the application data.