14 Comments

Top notch content

Expand full comment
Apr 23, 2022Liked by noxx

Very great article, and very easy to follow along, despite how low level and in-depth the EVM opcodes are.

I just noticed a small typo:

"There we have it, after this opcode executes you’ll be taken to the location of the store(uint156) bytecode and the execution of the function will continue as normal."

Where it should be 'store(uint256)' :)

Can I also ask which tool you used to create the green screenshot of the stack? :)

Expand full comment
author

Thanks for the great answer below, the green sreenshots are made in Figma

Expand full comment

Finally had a chance to read this. Great stuff!!

Expand full comment

Still the best EVM deep dive.

Expand full comment

Where are you? I dont see your twitter account..

Expand full comment

Thank you so much for this, awesome article!!

Expand full comment

Reminds me of my college hard days. Thank you

Expand full comment

I started learning Solidity, to get into blockchain security but I had so many questions of how the code work's at a fundamental EVM level, this is the real deal. Only other thing that would have blown my mind is if you explained how each function() is a unit of energy, interacting at energy level with the EVM (but that's matrix stuff) :)

Expand full comment

Hi. This is a great article! Thank you! Anyway, can I ask why do they need to go through the trouble of `PUSH4 0x2e64cec1 -> EQ -> PUSH2 0x003b -> JUMPI` to push the `retrieve()` (`0x2e64cec1`) function when it is clearly not needed/executed (after all, it is `store(uint256)` that is being called)?

Expand full comment
Apr 23, 2022Liked by noxx

@Jin Xing Lim

That's a great question. It does not appear obvious in the first place, but here is the answer.

The reason why the `retrieve()` function selector comes first (and is compared first) is because of the way the selectors are stored in the smart contract bytecode.

Basically, the list of selectors in this "sequence of if / else opcodes" (I like to call that the 'dispatcher' or 'function dispatcher').

The order of the functions selectors depends on their "decimal value". They are listed from the "lowest" to the "highest" number.

- store(uint256) -> selector = 0x6057361d (in hex) = 1,616,328,221 (in decimal)

- retrieve() -> selector = 0x2e64cec1 (in hex) = 778,358,465 (in decimal)

(in hex) 0x2e64cec1 < 0x6057361d

(in decimal) 1,616,328,221 < 778,358,465

So in summary, because 778 millions (the decimal number representation of the retrieve()) is a lower number compared to 1,616 billion (the decimal number representation of the store(uint256) selector), the retrieve() will come first/before in the dispatcher list.

Expand full comment

@CJ42

Thank you for the great answer! Learnt something new today thanks to you!

Expand full comment

so we can be more careful with our function naming and arguments for gas optimizations? so no unneeded checks be executed for functions that are called not so often?

Expand full comment