ethereum-optimism / optimistic-specs

Optimistic: Bedrock, is a protocol that strives to be an extremely simple optimistic rollup that maintains 1:1 compatibility with Ethereum
MIT License
167 stars 35 forks source link

SSZ ExecutionPayload improvements/testing. #426

Open protolambda opened 2 years ago

protolambda commented 2 years ago

The l2.ExecutionPayload implements SSZ encoding/decoding manually, to avoid importing a large SSZ library that does much more than we need it to.

For reference, the existing ssz libraries out there: https://github.com/ethereum/consensus-specs/issues/2138

I maintain a Go library called ZTYP: https://github.com/protolambda/ztyp This has a codec package to implement ssz types, like in ZRNT: https://github.com/protolambda/zrnt/blob/5447d45e7e85ddff746721baaca3eced8ce67a6f/eth2/beacon/common/execution.go#L321

But it does too much, and is non-optimism code that we shouldn't mix up.

The other Go ssz library, the one that prysm uses, had bugs in the past and is built around protobufs (i.e. not compatible with our typing) and is not maintained actively enough.

So the current solution is to simply implement the SSZ code ourselves. It may be better/faster if it uses a reader pattern, although also more code + benchmarking (When using the reader pattern in ZTYP I ended up with a custom reader/writer because of the need for a scratchpad to avoid lots of allocations).

We can also do differential fuzzing between the different implementations if we want to be extra sure of the code. Note that this SSZ encoding/decoding is only used off-chain currently, for p2p. If it doesn't work the rollup still operates and can stay on the correct chain, so the risk is not that high.

ferranbt commented 2 years ago

The other Go ssz library, the one that prysm uses

Hey!

Not sure if you are talking about fastssz from which I am the maintainer. If so, I have a different point of view for some of the comments in the issue and here.

It is not protobuf specific (I wish... :smile:), the SSZ code generation works directly on Go structs and the output ends up being quite readable, this is an example with ExecutionPayload in the eth2 spec.

Regarding bugs, I am not aware there were historically any significant issues, the only thing related is that the code generation has problems with BeaconState object and Prysm ended up with an ad-hoc generation for this one. But, I would not consider that a showstopper, especially if you can easily audit the generated code.

With respect to maintenance, I try to give the library as much love as possible but I am not involved day to day in Ethereum 2 (debugging gets complicated) and code generation on top of Go code is extremely hard and has many corner cases to cover. The nice thing about generated code is that it requires little changes once it is done (forget about the endless rabbit holes optimizing and caching reflections).

Regarding optimizations, the library is hell fast (x250 faster than the legacy Prysm SSZ encoder).