[Music]
some of the reasons we want we want to
put eof into the into uh
evm so about two years uh in the
beginning the legend has it that the two
two of the early core developers were
responsible for writing evm and they did
it over the weekend um and it wasn't
perfect but it was it was really good
and it got almost everything right I
think the only thing that they changed
before before it went public was they
added um one of the C++ client
developers who's on tpon now asked them
to add the jump dust operation in there
for jumps to signal that this is a
correct place to land and they needed
that for jit compilation for the llvm
and that's an important thing to to keep
in mind is that this is that jit
compilation is is going to be a running
theme it's going to come up with with
the Z kvms so they added that feature
and it was good enough it wasn't the
thing with the most problems that was
you know stuff like you know sinking
nodes and keeping consensus together so
they moved on from that so it it worked
but there was still um a few things that
that needed to be added early on into
the evm call code didn't work like they
thought it would so they replaced it
with delegate call um there were some
performance issues with some of the op
codes so they increased the prices on
some of them appropriately um the there
is a bit shifting math wasn't uh wasn't
exactly what they expected it to be uh
so they added some bit shifting code uh
and there are some developer experience
requests to put in things like the rever
op code so you could signal to the
system that when when a call fil failed
in an unexpected way that you could pass
data back within the stack and outside
of the stack and also some pre-compiled
for some Advanced cryptography were
added because that's just too
inefficient for the evm to
execute so one of the first big
proposals to do more than just add one
or two small things to the evm was EIP
615 that's a really low EIP number um
and it was proposing um the the Top Line
in the motivation says the design of the
evm makes near linear time compilation
to machine code difficult um the jump
dust analysis and a few other things
that were in there um a malicious person
could write a piece of evm software that
would take a really long time to compile
and provide another form of attack to
the evm so that's why uh it wasn't
really you know evm uh Justin Time
compilation really hasn't gone too far
it's because of issues like that and so
this was designed to address some of
those issues and the biggest things they
added was they provided a static jump
instead of a relative jump and they also
added um subes and the last three items
if you look look at them and squint
really hard it looks a lot like what we
have designed in eof um they have a
begin data section to say anything after
this op code is data they have an object
header that says this is evm code and
they have code validation rules that say
that everything between the beginning of
the header and the beginning of the data
has to be valid executable code if you
stand back and squint your eyes that's
some of the key features of eof so way
back in 2017 a lot of the needs for eof
were recognized so the obvious question
is well why wasn't this done at that
point in time we had all the stuff in
place to get it
done the reason is ethereum 2.0 AKA
Serenity was announced about not too
long after this this EIP was announced
and it it pro it was proposing some
major changes to the theorum itself
among those was switching to proof of
stake um and also introducing data
sharding and as part of step two uh
introducing ewm as as an alternate form
of execution and then finally step the
phase three step four was a bunch of
other improvements and you'll notice the
further down we go down the list the
more and more it changed from the
original Vision proof of stake shipped
pretty much as envisioned in Serenity um
the the data sharding became the rollup
Centric road map and the ewm was
eventually abandoned for reasons I'll
get to in the next slide but that last
Point um they didn't have the idea of
oifc built in yet and there's a big push
to aify the protocol at this
point so why was ewam abandoned why they
put a lot of effort into it Why didn't
it ship um there were a number of
reasons and one of them was just the
complexity around it um we were going to
have to keep the evm around and ewm
around and there was there was proposals
and and plans to try and get the
shifting between the two versions um to
to to cross compile evm and ewom um but
also didn't ewom does not natively
support uh the gas into it you would
have to weave the gas into it and have
validation rules relating to the gas and
there are also issues Rel reled to the
256-bit math and that really is what
caused a lot of performance problems
they the the ipsilon team went through a
summary of the performance of their ewm
prototype in Osaka and you know they had
a they came public that it wasn't as
performant as they was hoping it was
going to be um there were some things
can be done to fix it but that it wasn't
going to hit its main goal which was to
be faster than interpreted evm it was
kind of kind of a gut punch to to the
Epsilon team but they they did the right
thing and they they brought the data out
and showed what was going on with it
so looking at all these things with the
evm is probably we should probably look
and ask before we ask why eof we should
ask why not eof couldn't we just do all
these changes without doing a big change
to the evm and just do these things peac
meal so this next section we'll talk
about answer that question of why not
why couldn't we just you know just
introduce uh immediate jumps with
immediate codes why couldn't we just do
SUB routines why couldn't we just
enforce code data separation and
validate the code why do we have to do
this all at once in this big giant
change and the problem is all these
features are deeply intertwined you
really need to do them all at once
because the value comes in all of them
together at the same time not on them
individually and doing them individually
actually creates new problems so the
first thing we'll talk about is relative
jumps and relative jumps um as as I
mentioned before uh you needed to put
the jump Target into the code using
something called an immediate argument
um and the push data the push op code is
an example of things that have the the
immediate argument so if we added a new
one let's say we're going to pretend
we're going to do this e z is going to
be the new R jump instruction and we
have a two bit two byte signed field
that's going tell relative jumps and
you'll see from this that we actually
you know on average save a bite if if
the uh if the contract is over 256 bit
bytes long the problem comes with
existing code that may have this op code
in place for a number of reasons so
here's an example up here I have of of a
code that may exist um that has a couple
of push instructions one of those push
instruction
has the 5B instruction that is the the
uh the jump dust Target and then we go
into some extra data that has a bunch of
invalid op codes the ezo op code is not
allocated so the evm doesn't care the 5B
exists after the EZ FF C9 2A so if we
introduce a new ezero OP code that takes
two immediate bytes without doing
anything to this other predeployment
and hit that jump D is now going to fail
and you've done nothing to change that
contract except change the rules of the
VM and this is the sort of change in
ethereum that we frown upon and we try
our best not to do we try not to break
what has already been out there so to
add immediate op codes would break
things that exist
already and here's another piece of op
code that shows um why we really need to
get rid of relative jumps this is a
nightmare code that I learned about a
few weeks ago um you could literally
take that someone actually wanted to
make sure that they could still kind of
do any f is you can you can take some
info from the call data trim it off and
jump to a specific spot in your code
based on that call data they were using
it as a vector jump instruction but it
was just this was just mind-blowing that
people were actually I thought this was
something that you would do as a
malicious attack not that something you
to find utility in and there are people
that like to do things like this in
their code so it's this is why we need
to provide you know stronger guardrails
around some of
this um so one thing one approach that
was tried was to just version the
contracts IP 1702 was briefly in Berlin
before it was taken out and so we would
say great you were going to introduce um
e e0 with an immediate data great all
new contracts um deployed after Berlin
and later will have this Rule and all
contracts defined below won't have the
ezero op code and we'll just have these
versions and every Fork will add a new
version this was ultimately rejected
because every Fork was going to create a
new version of evm rules that would grow
and grow and grow sometimes they apply
and sometimes they don't rather than
having just two sets of rules you would
have an infinitely growing set of rules
which was going to be problematic
complexity wise so that was ultimately
taken back out of Berlin um after it was
initially brought into it um another
thing that was taken out after it was
putting in was the simple sub routines
and this also underscored another
problem that we had during the design
process of some of these up codes is we
didn't always directly interact with the
compiler developers so this was
implemented by all of the clients it was
ready to go tests were written and then
a couple of weeks before we were
scheduling test Nets someone pointed out
that solidity said we're not going to
use this this op code so solidity is not
going to use it that there was quite a
discussion on allore devs about why do
we even have this in there and
ultimately the decision was to take it
out I think it was in Istanbul and this
was taken out of
Istanbul but we did get one change in
before before the merge that is very
important and foundational for E any
contract that begins with ef um cannot
be deployed anymore so we can guarantee
you that if the deploy if the con if the
code starts with the EF bite um that
certain rules will be able to appli
within it so so as part of the Berlin uh
hard Fork that was passed in and no the
London hard one of them before the merch
is there's so many of them I keep
forgetting but um it was it was uh
enforced so that you could not Implement
code that would uh use this we could
preserve space for our for our validated
contract containers uh there was some
some uh emojis that were deployed to
kind of cause problems but where this
brings us up to is this brings us up to
the merge and the merge is kind of an
important milestone in a lot of these
evm changes because for a while and all
cordev to ensure that we were focusing
on getting proof of stake pushed through
on all the clients any and all
consideration of evm changes was was put
on pause until after the merge so during
this time ipsilon team went and they
were cooking and they they they thought
about all the things that they learned
from ewam and they came up with this
plan for for eof and they presented it
at Devcon Bogota and that brings us to
talking about little eof and big EF they
had originally designed it in multiple
pieces and the to present it to to all
the cevs say how much do we want to do
do we want to do a little bit of it do
we want to do a lot do we want to bring
in these modules and do it all together
so it was kind of a cafeteria approach
how much do we want to break as part of
this and so they were called little eof
and big eoff little eof started with the
evm object format V1 this was the
container format the foundation code
starts EF 0000001 you have a header
section you have code you have data it's
separated one of the neat things about
this that's better than EIP 615 is you
know the size of the container so you
know if you get a truncated eof
container you know you don't have all
the code and you can just reject it so
you're not accidentally missing code
that was something that uh 615 didn't
have ability to say the code ends here
the data ends here this is the whole
container um the next feature that was
added was code validation so for that
code section if the op code was not
allocated it couldn't exist and if you
had a code requiring immediate data all
of the data for that immediate had to be
present in the code or it would be
rejected an important thing about the
eof validation container format is if it
doesn't parse the code is the entire
transaction and the code is rejected the
contract cannot be put on the Chain so
similarly with code validation if code
validation fails the contract is
rejected and can't be placed on the
Chain so after code validation they
started to add new OP codes because as
part of code validation they also went
ahead and banned op codes they banned
the old Dynamic jumps and replac them
with relative jumps and again in the
relative jumps they did one more
Improvement above 615 and that they made
these relative jumps not just static
jumps 6 15 had static jumps and would
list the PC you would jump to but these
are relative giving a a two byte signed
integer to say how many oper before
after do you move to which is nice for
compilers because they can lift and
shift all the code that they
need and then we added and then for big
we added functions which is the answer
to sub routines um it allows us to
basically provide all the same
functionality with sub routines just
with multiple code sections and this is
something that account abstraction is
looking to use to provide a secondary
entry point in for a lot of their
functionality so it's a bit Superior to
subar tees in that
regard and finally stack validation this
is the most complex piece of code um and
specification that is in it and I think
it's the most important piece of code
that is in big eof what this allows us
to do is if you can evaluate your code
and you can pass all the stack
validation rules then at runtime for all
of your operands you can just ignore
stack validation you know that you will
have enough operands on the stack and
you know there will be room on the stack
and you can remove all the code that you
were doing to check to say is there
enough room in the stack do I have
enough operands do I have too few
operands the downside is it makes you do
good things with code but any modern
compiler is going to spit out code that
is completely compatible with stack
validation one minor cave yet for an
optimization we added ranges for
validations and this was useful and
requested by solidity so they could you
have one revert section rather than
having to have a revert section for each
stack height so you can come into that
reverse section with a range of op codes
and then exit the entire the entire
contract so this is a tweet that I came
across uh a few weeks ago and this was
like some something really exciting to
me uh a uh uh someone had a residency as
ainc labs and they went through and they
implemented uh eof in in a in a ZK
context with the same contracts that way
you do with Legacy and they got some
amazing numbers just by implementing
these features um you can get rid of all
the stack checks and a lot of the other
validation checks because you presume
it's valid and it reduced in an improved
performance by three times so that much
time was spent just validating stack
Heights and that that's to me I mean
when you ship a 10% Improvement that's
what I'm when I get excited and I start
shipping stuff this is like 300% this is
better than I hope for so it's already
providing real value in ZK context and
aots they get they get benefit but not
nearly as much as zk's got this is
amazing so we were ready to ship this in
Shanghai except we had one minor issue
with the solidity Constructor um but but
vitalic about a month before our
interrupt Dropped a Bomb in that he
wanted to get rid of code introspection
which was another thing um that that was
bothering him for Z for zks the ability
to take memory into code and code into
memory caused all sorts of problems with
zks and made things really difficult for
them so we wanted to remove all the code
introspection so the interrupt was
decided that we were going to take it
completely out of Shanghai and add new
features to remove code introspection
and also everyone said well while we're
breaking things let's break everything
we want to break do it one time do it
once and for all because we'll never
have to do this again right um and
hopefully we'll be able to just get
everything that we want broken and get
it fixed and do it
right so that brings us to Mega eof
where we break everything that needed to
be broken we do it once we try and
reduce the number of times we're going
to have to update the base major version
of eof the first thing we started with
is is contract creation which is a code
introspection code introspection mostly
impacts to create op codes and also to
create transaction so the the solution
that eof came up with um was that they
would put the subcontracts in as
subobjects in the container that would
be validated at a contract creation time
so when you do a create uh a create or a
create to type operation you take that
already validated code you deploy it on
the blockchain validation is done and it
never has to hit the memory so you say I
want to deploy that and there's some
some other things going in there you're
allowed to put extra data into that and
append data onto the existing data and
let it grow so you can do your
Constructor arguments
um and do things like like the um Unis
swaps pair contracts wants to have the
token numbers burnt into the code so
this allows you to do that um the next
thing was the contract creation
transaction this is a slight
modification of existing contract
Creation in that if there's any data
after the um after the eof container
it's passed in as input data so you can
provide Constructor parameters in
addition to to creating it and through
this you can create objects without you
can create contracts without having to
copy any of it to system
memory another request that came from
the um that came from that we needed to
do to to to ensure that we have uh I
forgot which slide I'm on um but one
thing we need to add to make sure that
we had code ners inspection fixed was we
need to be able to get out the data
section before the EXT code copied
everything in the container so we needed
to add new OP codes that would um that
would allow you to access just the data
section it's just your data section
right now so we get some a little bit of
code privac
uh benefits there um so you can return
only the data you want so we need to add
new OP codes for that and then after
we're done with code introspection the
next thing um was to get rid of gas
introspection uh gas introspecting and
restricting the amount of gas that you
send on to your next layer of contract
has created some problems uh with
breaking contracts when we increase and
change the gas schedule so if we don't
allow you to mess with the gas like that
then we're safe changing the gas
schedule and doing whatever changes are
necessary and the solution there is just
to get new callop codes we introduced
three new callop codes that don't um
have gas as part of their input
parameters um and also as a nice side
effect we can address a dress Bas
expansion because all the op codes in
the evm trim all addresses above uh 160
bytes so these call op codes do not so
it's safer address based expansion and
that only leaves balance is the only
open op code and that's one op code to
fix to get full address base expansion
safety if we decide we want to do that
uh the compiler teams ask for a swap and
dup instructions and the Viper team
specifically ask for an exchange
instruction which is kind of like a
super swap rather than swapping it at
position one to something deep in the
stack you take something up to 16 items
deep in the oper an stack and you swap
with something else another 16 or so uh
spaces deeper in the oper an stack so
you can switch stuff around you can save
two instructions by doing one exchange
instruction it's pretty
neat now this wasn't everything that we
wanted to put in eof in order to uh
reduce it and make it more um more
testable and reduce the attack surfaces
and risk surfaces there are about four
features that we we removed from it um
TX create is something that we might see
return um it's a way to do contract
Creations through a transaction variable
length quantities if we want to increase
the contract sizes above 64k we're
probably going to need to do some
changes to the contracts to make sure we
can access the areas don't necessarily
need it though um uh there are some
issues with ISP with the with the nft
erc's and with some some op um some
erc's that that deal with tokens like
erc20 style that that require detecting
if a contract is an eoa or not and they
do that via code size so we're looking
in ways to address that we'll probably
address that in Osaka I'm optimistic
we'll get that in there and finally
external data copy um we're going to
investigate that and figure out if it's
needed so here's a here's a diagram that
Dragon put together um that explains the
similarities similarities and
differences between eof and evm
unvalidated contracts they're more
similar than are different eof just has
a container format and different
validation rules and a few different op
codes than the evm does and when you go
into executing it it uses the same
execution Logic for evm and eof I know
I've been in all the major clients it
uses the same Loop so it's pretty
awesome and I'll just finish on this
slide um solidity said that by orders of
magnitude the eof design is what they
want for the future of the
evm right thanks
thank you thank you we have time for a
few
questions um and again you can vote to
get the question that you want pushed to
the top um and so we're going to start
with what is the motivation for not
allowing eof contracts to delegate to
Legacy code one of the op codes we
banned was self-destruct and
self-destruct deletes the code and it
deletes all of the storage and it moves
value over um we wanted to remove the
concept of code disappearing so the
reason had a band delegate code is you
could delegate call into a legacy
contract that had a self-destruct
operation and you could bring the effect
of a self-destruct into an evm OP code
um and also delegate call on alt VMS has
been an attack Vector for some of their
pre-compiled so it's just solves two
birds with one stone thank you all right
is eof the new via
IR
um it's kind of an inside baseball
question
um I don't know not not really I mean
some people don't like V but what it is
going to solve the stack to deep problem
you're going to be able to use more than
16 variables so it's better than the new
V uh since eof will have performance
benefit are there plans to decrease gas
cost when using eof um I think more
likely we would increase gas cost of
Legacy if we did that um but the
performance benefits from the gas cost
of eof are you just have fewer bite
codes you have fewer operations so
you'll see um we've we've measured this
between like 3 and 5% just by using eof
in the same contracts so you'll get
savings just by using it without having
to change the schedule amazing how far
is solidity support for eof um so the
one of the engineers from the ipsilon
team has a prototype that compiles to
the existing format of eof V1 and that's
where we got our numbers for the 3 to 5%
gas savings so um EO solidity is not
going to ship it until eof ships so it's
going to stay in a branch until it
actually is in the test Nets amazing do
you expect solidity to require a
breaking change between 0 8X and 0.9 to
add eof support um it wouldn't surprise
me uh that's a decision for solidity to
make um but that is probably the best
way to Signal um that you're going to be
using uh eof semantics other things they
might require new pragmas but I think
that's something for solidity to
answer what was the reason why solidity
didn't use sub routines in that prior
iteration and are those concerns
mitigated in eof
um I think it actually cost a few extra
bites um the way it was implemented um
it wasn't saving enough bites it was
actually costing a few more bytes and
with 24K contract size limits every
bite's precious so I think that was
their main motivation for rejecting
it why does eof not suffer from the
complexity of
versioning um it will uh 5 to 10 years
down the road um what we're doing right
now is what's taking so long is we're
taking every possible breaking change so
we don't have to do that major breaking
change in the future so what we're left
with is we're left with a codebase where
we can add the new features that we have
in a compatible way so when we add this
new feature every version of every
possible eof contract that existed
before would still be compatible in a
hypothetical eof v11 or V12 so it's
fully backwards compatible by
Design is
eof more ZK friendly um yes in two ways
uh getting rid of the code introspection
means they don't have to worry about
bite code coming off of the memory and
creating a new contract you can know
before you'd write your ZK proof what
contracts you're going to have to worry
about and the relative jumps in getting
rid of jump test analysis and being more
certain about where your jumps are going
to land is
huge and I think we have time for one
maybe two more uh will sub routines and
eof make code size analysis easier um it
can uh it depends on what the compilers
do with it and if people are trying to
obate their code it's going to provide
new creative ways to obate so it's it
goes both
ways this is this is a good one uh when
can we get rid of the evm
entirely the evm or the Legacy evm um so
the problem with the legacy evm is
there's some old contracts that we still
need to support uh getting rid of uh
sunsetting the legacy is something that
we have in mind we either need to we
don't know the answer to it we need to
be able to say we can't do it because of
reasons XYZ or we need to have a plan to
do it and that's something we're going
to be looking to in the next couple
years amazing um and the last one is a
little bit more of comment than a
question so I don't know if there's uh a
place you can direct people for uh to
read the data section of other
contracts right so the reason why we
didn't want to directly do that is we
want to give contracts the option of
saying no one can read my data if you
want to allow someone to read your data
you expose a function that you then copy
your data and send it back um but we're
going to figure out over the next couple
months if that's going to be sufficient
if there's going to cause problems so
there is a way out the question is is it
the right designed choice so I'd
encourage people who care about this to
call into our evm implementor calls and
and let us know why you feel it's
important thank you so much