Looking back at the Ethereum 1x workshop 26–28.01.2019 (part 4)

This is continuation of the part 1 and part2 and part3

Problems with large (and growing) state

Failing snapshot sync

Described in part 1

Duration of snapshot sync

Described in part 1

Slower block sealing

Described in part 2

Slower processing of transactions reading from the state

Described in part 3

I mentioned data analysis on speculative execution of transactions in parallel. This will also be somewhat relevant to the next section about the Block gas limit.

What follows is the model of speculative concurrent execution I used for my analysis (there could be other models, but this should give you a rough idea of what kind of “concurrency” you can get without fancy things like static analysis, symbolic pre-execution etc.). A block of transactions is executed in two phases:

  1. Concurrent speculative phase (cache warming)
  2. Sequential precise phase (use of warmed caches)

In the concurrent speculative phase, all transactions of the block are executed concurrently against the state that existed at the beginning of the block. Their writes are isolated from each other. If all the state reads are synchronised on a barrier and performed as a batch, the number of database accesses may reduce to the maximum number of reads in one transaction. For example, if we had a block with five transactions:

Block with five transactions that contain varied number of reads (maximum 4)

Then, execution in the concurrent speculative phase may look like this:

State reads are grouped in 4 database accesses

In this example, although there 8 state reads in 5 transactions in total, if we run them concurrently, state reads could be grouped into 4 accesses to the database, because 4 is the maximum number of reads any transaction does in this block. Let’s call this “maximum” reads.

Of course, there is no guarantee that the execution of transactions in such a way would yield the same results as the sequential execution. But if most of the reads are performed from the “static” locations, then there would be a big overlap in the sets of locations accessed by the correct, sequential execution, and locations accessed by such concurrent speculative execution.

In the sequential precise phase, transactions are executed how they are supposed to be executed, one after another, but using the cache that was built up during the concurrent speculative execution. In our example, this could look like this:

All state reads except 2, can be served from the cache built in the concurrent speculative phase

In this example, most reads in this sequential phase can proceed without access to the state database, because the locations they are accessing were already accessed by the concurrent speculative phase. Only 2 locations are new, because, for example, transaction #4 uses the value obtained by the first read to calculate the locations for the next 2 reads. Let’s call these “extra” reads.

So how much overlap in read locations would we get if used this 2-phase execution model?

First two charts show the analysis for the account reads. Black line shows number of “naked” account reads per block. Red line shows number of “extra” reads, and blue line shows the sum of “maximum” reads and “extra” reads:

This chart is not every helpful, because it is overwhelmed by the “tower” of spam attacks of 2016. If we only show blocks > 4m, we can see better:

If we do the same analysis for the SLOADs, we get this. Here, blue line is total “naked” SLOADs (this is how many DB accesses we would get if we did not use 2-phase strategy), yellow line is the sum of “maximum” SLOADs, and “extra” SLOADs, and the red line is “extra” SLOADs.

It can be easily seen that SLOAD opcode presents a bigger performance burden than reading accounts:

  1. Number of maximum SLOADs per block is around 100 on average, whereas the number of account reads per block is around 20 on average
  2. Sometimes there are clusters of SLOADs with context-dependent locations (this is where the blue line is “punctured” by the red tower).
  3. The “win” of using concurrent speculative strategy for SLOAD is about 3x or 4x on average, whereas it is 8x or 9x on average for account reads.

Block gas limit increase and the State fees (formerly known as State rent) share initial steps

During the workshop, we were discussing the State Rent proposal version 2. Now that the latest State Fees proposal (version 3) is published, I can use it for concreteness.

The main concern about raising the block gas limit further now is that it would likely accelerate the state size growth, because there will potentially be more state expansion operations (non-zero value transaction or CALL to a “fresh” address, CREATE, CREATE2, SSTORE) in a block, and every block happens every 15 seconds on average. Therefore, it seems logical, that some sort of “speed bumps” needs to be applied to these operations before the block gas limit can be safely increased. In the State Fees proposals these speed bumps are changes H and J, which are rent prepayments that are mandated for all such operations:

Rent prepayment changes H and J are highlighted by brown ovals

Prepayments for contract storage operation SSTORE are a delicate matter, and some balancing is required. On one hand, we only want to charge prepayments if SSTORE expands the storage (changes value from 0 to non-0). On the other hand, we want to make storage hoarding useless by also charging prepayments even if SSTORE does not expand the storage, but changes the storage that existed previously. That is why change J requires knowing the correct number of storage items in every contract, and that is why it is in the fork 2, not fork 1.

At the workshop, we had an idea of so-called “client side” accounting, which would seem to eliminate the need for 2 hard-forks to introduce contract sizes into the Ethereum state. However, thinking about this more, I realised that the coordination required for such “client side” accounting is probably going to be more than the coordination required for a hard fork.

Having written the part 3 of this blog post, I have also realised that the increase of block gas limit has another potential performance effect. It would likely increase the number of account reads and SLOAD opcodes that are executed within one transaction and within one block. Therefore, I wonder, if the gas costs of the state read operations will have to go up as well?

Stateless contract pattern is discouraged by the current gas schedule

To appear in the part 5 or later

eWASM interpreters could be a sensible first change even though gas cost might not be practical in the beginning

To appear in the part 5 or later

Chain pruning will become more relevant as we start constraining the state growth

To appear in the part 5 or later

Ethereum protocol changes do not need to take a year to be prepared

To appear in the part 5 or later