New Ethereum talks, every Monday. The week's conference uploads by event, in your inbox.

Loading player…

🎤 Demystifying EVM Opcodes

ETHGlobalSun, Oct 9, 2022, 12:00 AM

Join Gilbert G of Macro for a talk titled, "Demystifying EVM Opcodes." This workshop is part of ETHNewYork 2022, a three-day in person hackathon that will feature hackers, mentors, enthusiasts, sponsors and speakers who are all gathering in New York June 24-26, 2022 to talk about the future of money, finance, the web, ownership, the way software works and the way power is distributed. We're excited about a new frontier. ---------------------------------------------------- Follow us: https://twitter.com/ETHGlobal​ Check us out: https://ethglobal.co​m Email us at: hello@ethglobal.com

Transcript

foreign [Applause] [Music] welcome everyone it's good to be here uh good to see all your faces uh how many of you are a solidity developer quieter for you you that's good um if you don't develop solidity or on ethereum this might be a little uh technical but that's okay you're welcome to sit in but today I'm going to go over a topic that is usually difficult to find online um evm op codes is something that salinity Developers uh whether they know it or not to deal with every day and it's good to learn so yeah so I'm Gilbert I work at macro we have a fellowship where you can learn stuff we do audits more on that later so first these are all the things that we're going to go over we're going to learn why we want to learn ebm Loft codes we're going to learn what a virtual machine is very briefly we're going to have a animated introduction to the evm we're going to look at a slightly easier syntax and then we're going to see how opcodes directly relate to the solidity language so to start off why do we want to learn evm objects well the answer is we want to become a better solidity engineer a better solidity engineer is not just about developing but it's also about security obviously we are working with smart contracts that handle a lot of money you need to write secure code evm will help you understand how solidity Works which means you will write fewer books a lot of design decisions around solidity is based on DVM directly so if you know why those decisions are made you're going to be better off and of course all sorts of interesting design patterns and solidity are related to low-level evm opcodes so let's just move on to Virtual machines so real quick what is a virtual machine well a virtual machine is named after a physical machine physical machines are the things that actually run the hardware that runs on your computer usually it's x86 or ERM nowadays there's an apple M1 uh but the point is that the lowest level of instruction is binary for a physical machine so here we have some binary here is an example of the add op code for x86 and it happens to be the same for Arn and then we have another set of binary for the subtract opcode you may have heard that machines are all zeros and ones this is where we're talking about right now the physical machine is going to look at this binary and based on this binary it's going to do something in this case it's going to add or subtract or whatever there's lots of op codes but these are basic ones now contrast that to a virtual machine a virtual machine is software instead of hardware and virtual machines pretend to be like physical machines so virtual machines usually also have op codes so this op code for example is the op code for adding two integers together on the GBM jbm jbm pretends to be a physical machine what's the benefit of that well the benefit is that you can take code that runs on the GBM and then Oracle or whoever writes the jvm makes it work for different machines so your benefit is that you can take your code you can run it on multiple machines that's the whole point of a virtual machine and evm is no different evm is a virtual machine ethereum virtual machine that's what it stands for and the purpose is so that you can run the evm on multiple Hardwares that's good for decentralization we want to run ethereum on as many platforms as we can and the aspect of the virtual machine helps us do that so what we're going to do next is we are going to look at how the evm runs there's three parts to the evm there's the stack there's memory and there is Storage so we're gonna take a look at how that works so first we have the opcode syntax uh what you see on the slide is some binary but usually binary is too long as humans it's harder to read so we take chunks of binary every four characters of binary equals one binary one character of hex and then we put all of that together into one string so this here is a single byte one byte is eight bits or eight binary characters or two hex characters and this is generally what we do when we're working with opcodes we write it in this format even though the op code is in HEX uh written in HEX we also have the human readable name so here we have ADD we call this hex code add and anything we can pretty much use them interchangeably whenever we're discussing op codes so that's the lowest point so now on the right we have some op codes in human readable name and some op codes take some data as you will see so we're going to actually run through a bit of evm execution keep in mind that this is the lowest level that you will deal with when working with the evm when you compile solidity you get something on the right you don't get your solidity code on the ebm instead it gets compiled to up codes and then that is what actually runs on the blockchain so what we're doing here is we're going to see what is actually going on when you run a contract on the blockchain there's no solidity code so first we have a push one push one is an OP code that takes the next byte in this case three and puts it on the stack and that's the entirety of the object each op code is going to do something very simple usually so you've just learned push one there are many pushes here's another example push 2 says to push the next two bytes onto the stack so the next two bytes is just the number four but it's written to be in two bytes because we have extra zeros there's in this example there's no reason to do that you can still use a push one this is just showing you that if you had a bigger number you could uh push bigger numbers onto the stack here's another example of push one and now we're going to look at Swap two swap two will swap the top of the stack with whatever X that you're using so there's swap one swap two swap Three swap four all the way up to swap 16. and when we swap as you'll see it just takes the top and swaps it with something else so let me show you that again we have nine then we swap and then this is the state of our stack now swap only goes up to 16. which means that well not which means but yeah which means you can only reach back that far you can only reach back up to 16 spots in your stack if your stack gets too big uh that might be a problem specifically in solidity if you have too many variables you've probably seen the stack is too big uh compile time error this is why there's only 16 you can go back all right and lastly on this example we have ADD add will pop the top two out of a stack which means it's going to consume four and three and then it's going to push back the result onto the stack which is up and that's generally how the evm works if you understand this you probably do because Stacks are not hard and you're all software Developers [Music] if you want to learn more about the evm op codes a lot of them are going to be specific to ethereum so for example color is an opcode and caller pushes a value onto the stack it doesn't take any arguments and it's simply puts uh in solidity message not sender so every time you type in messages under in solidity uh the number of bytes you're adding to your contract is actually only one because caller is an OP code and that's one byte and um yeah it's pretty cool so normally I would take questions um during one of our fellowships but right now it's a talk so I'm going to move on uh each stack item is 32 bytes that's just the way it works if you have something larger than 32 bytes and you need it need it on the stack uh you get to do really complicated stuff or you can use memory so memory is another data structure that you have access to on the evm from memory it's just a really long array effectively it starts at zero and it goes as long as you want uh in practice it doesn't go as long as you want because you will eventually run out of gas but they're technically there's no restriction as to what memory address you decide to use so we're going to look at the M store op code so first we're just going to push some values like we did before and this value M store takes two arguments the first argument is where you want to store in memory so this 20 is referring to the memory adjust 20. and well this is technically 32. the second argument is the value itself so in this example we are storing the value three at memory address 0x20 so when we do that and you want to pay attention now because animation is fancy we consume those two items off the stack and then we write to memory that value that's how mstore works now if we want to actually use that value we can read from memory as well so we can M load only takes one argument instead of two that is again the memory address and when we run M load it will pop that off the stack [Music] and copy this from memory onto our stack so now after our M load we have the value that we originally stored and of course we can do this as many times as we want so in terms of memory um memory is pretty cheap but of course memory only exists for a single transaction if you want to store stuff over many transactions as you might guess you need storage so with storage it turns out that it behaves pretty much uh pretty close to the same way as memory does so we can replace these M stores and M loads with s stores and S loads and we get the same result there are some restrictions such as well I'll talk about it later that's to advance but it behaves pretty similar so you might ask why don't we just use storage instead of memory isn't it why not just always use storage well the reason is storage is extremely expensive on blockchain so a single s door can be anywhere between 2900 or 20 000 gas but memory only costs like three gas so that's the main reason we don't use storage for everything Only Store what you really need because it's very expensive that's effectively it so we have we just went over to stack we just went over memory we just went over storage um memory is like a giant array storage is like a key value database and that's all you really need to get going with the evm so what we're going to do now is we're going to learn a slightly easier syntax using a small programming language that I wrote and we're only going to look at one feature and we want to do this because it compacts the syntax so that we can learn solidity Concepts a bit easier thank you so on the left we have what we just learned we have op codes some data associated with that now what we want to write instead is this syntax so s Expressions every time you have a parenthesis the first item is going to be the op code and then the items after that are just going to be arguments to the op code and in this case if you have data you can just write the number instead of having to say push one push two or whatever and that's it that's all we're gonna learn uh for now now we're going to move on to tying this opcode knowledge to solidity itself so here's some Primitives we just talked about message.

sender a little while ago and um all of these that you see here that you write have uh Native op codes I didn't list all of them here but um this is enough to give you an idea message not sender is the color op code message.value is the call Value op code and so on so all of these solidity Concepts have a dedicated op code tied to them that's pretty easy next let's look at payable payable is a solidity feature um you may have noticed that if you want to get paid from a function you need to write the payable keyword this is not an evm uh related concept this is a solidity related concept solidity has decided to block your functions from receiving ether if you don't put the payable keyword so here is some op codes that are a rough equivalent of non-payable functions First We Take the call Value and we see if it's equal to zero and if it's not equal to zero then we jump to some location in the byte code that reverts this hashtag syntax here this is called a label in trim it's not evm this is trim and a label is just a position in your bytecode so it's an easier way to jump to a specific spot nearby code without having to count bytes and manually type the number but yeah this is what happens for every function you don't have payable we have this um code generated here so by implication it turns out if you write payable on your function you're actually reducing the code size of your contract fun fact here's some more stuff storage variables so storage variables are compiled by use not by definition so you can Define as many stores variables as you want so and it does not add to your contract by code the reason for this is because storage is a key value database you don't have to initialize your keys you just use them if you try to read a key that you've never used before that's just going to be zero it's not going to throw an error that's why you it's start at zero because of that fact that's how the evm works now Source variables are index spaced so here we are setting something equal to Y we are setting something equal to Z if you look at the first arguments to each s store we have one and two the reason for that is because solidity takes your variables and applies indices to them so Y is considered um ox1 and uh Z is ox2 same thing for reading reading takes an S load if you want to read y that's going to be an S load 0x1 uh Y is the second storage in your the second variable in your contract so that's why it's one instead of zero or any other number so these are all index based now because they're index based um sometimes that doesn't matter sometimes it does your variable names certainly do not matter you can name your variables whatever you want and it will still work because so the ending the byte code that you end up with do not have variable names in them now this does matter when you start introducing contract upgradeability when you have contract upgradability you do not want to reorder your variables because when you reorder your variables then all of the code changes according to those variables so again this use this doesn't matter if you're just writing a playing contract but it does matter if you're writing an upgradable contract so do not reorder your variables all right let's look at another interesting concept we have uh compact storage so in salinity if you have multiple variables next to each other that are less than 256 bits which is 32 bytes which is the word size for evm then solidity will compact them compact them means that it will store both of them in the same storage slot and that has some benefits so over here we are using X and Y and this first part is loading X we have an SLO zero zero is in the first storage slot so we slot zero but we don't just s load it because this storage slot which is 32 bytes now has two variables in it not just one it has both X and Y so what we do is we bit mask it this value here is how you do bitmasking if you don't know what bitmasking is you can check it out later it's a pretty fun concept and not difficult to learn but effectively we are uh whitelisting bits uh out of this 32 bytes of data so the first byte we are considering considering to be X the second one is very similar we are fit masking the second byte from the right but we can't just do that we also have to shift it so that it becomes its actual value otherwise it's going to be bigger than intended and this opcode just takes the top two and adds it together that's pretty simple so this is a somewhat Advanced composite but as you can see it's it's not that hard now the benefit to doing compact storage at all is because whenever you do an S load the first sload that you do for a given slot is going to be 2100 gas and then every other s load on that same slot is going to be only 100 guests so if you have two variables in the same slot you're not paying 2100 gas for both of them which is great so that's why solidity decides to do that it saves you gas without much effort all right we have just a few left uh an if statement if statements are a little bit more advanced but still not difficult so this first line of uh trim we have over here we are seeing if x is equal to three so we s load zero for X then we'd use the EQ op code to compare it to three and jump I will jump if the top value of the stack is not zero so if they're equal then it's going to be a one otherwise it'll be a zero and if it is a one then we jump to the then label which will um revert now the way reverts work and also the way returns work is that you have to store your message in memory and then tell the evm where it lives in memory so that's kind of what we're doing here I'm omitting some stuff because it's not that important basically we store a string into memory and then we revert using that string that's the then case if we go to the else case that's just incrementing by seven that's straightforward we do an SLO Nestor and so on one interesting thing to note is that down here we have another s Loop so as of this moment solidity 0.x 0.8 uh solidity does not optimize s loads so every time you reference a variable in solidity you are doing another s load so if you really want to avoid extra s loads you need to store it in a local variable first and then reference that all right now we're getting uh slightly more advanced um every time you call a function from another contract you're using the call op code or the static call or the delegate call but the point here is that you're using a op code to make that function call and it requires a bunch of stuff don't worry about that what I want you to focus on is that this is an external call external calls on the evm are very different from internal calls in fact the evm does not have a concept of internal calls that is a solidity specific thing so let's look at internal costs and compare internal function calls on the evm it's just jumping to a specific spot in your by code and then jumping back so here in this pseudo code we have we push we push a specific address in our by code then we jump to the internal code and then we expect it to jump back so in bar Dash FN we do our stuff and at the end we jump because we expect the return address to be on the stack so we jump and just jump back that'll probably take a bit of studying but that's okay last thing I want to go over is this one so same idea except now we have a parameter so you can see the code now has a parameter and really all that means is that we are pushing that parameter on the stack first before we jump and then down here uh we assume that parameter is on the stack and this code is doing that by S loading X and then adding adding takes two arguments so it expects another argument to be there which is the parameter but that's about it um again during an actual Fellowship I would be very happy to take questions if you want to learn more about that we have the link here Fellowship is for senior Engineers we learn Advanced things like the evm and security and common contract patterns and things you need to do to make sure that those things are secure we also do audits at macro right now I'm doing uh lots of audits not at the same time because that would be bad but if you need an audit we also have that and if you want to learn more about opcodes um this link is my favorite link there's there's lots of links but this one's great because it actually explains a lot of gas costs for each shotgun but yeah that's it any questions yes so you describe yes the question was is Viper also compiled to evm by code and the answer is yes solidity is not the only language that you can use and the reason is because we have that virtual machine so you could if you wanted to like I did write your own language and have that compiled to evm by code and it will run on the Chain just like anything else good question all right if you all have more questions I'll be here for the next 15 minutes um we also have our other co-founder David and Keyshawn over here so and Tim so we have we have a whole group here so yeah happy to meet you all and Happy to take more questions thanks

Automatic transcript — names and jargon may be misspelled.