 Hey everyone, I'm Sina. This is going to be a workshop. So I will be working with the terminal I will show you some code and show you how to use gas Like guess tracing feature. That's why we specifically needed my laptop So yeah, sorry for for having to wait Also, yeah, because I will be showing code It would be great if you guys could come forward if you want to see what's happening because I imagine the phones will be small. So yeah, I'm gonna give you a bit of time to come forward and While you're doing that I want to talk a bit Something a bit personal So I come from Iran. I don't know if you heard but there's some stuff happening there I just wanted to give a quick shot out to the people Who are going to the streets there. They're protesting for their civil liberties for freedom of speech So yeah, there's been three weeks of protests now internet has been disconnected And it all started when the girl on the left who is 22 years old was in custody because of showing a bit of hair and She somehow happened to die in custody and this outraged people who went on the streets and During these protests Close to 200 people have died among them Nika who was 16 years old and By like when running away from the police She also died so Yeah, just want to give a quick shout out to them. They're risking their lives Asking for the rights and for for freedom But this is a technical topic and I don't want to waste your time anymore. So let's get straight to it So what is tracing? What would you need tracing? I? Just want to show you an example of This is if there's can you everybody knows if there's can right and the internal transaction section of if there's can is basically A trace of that transaction it shows you what happened within that transaction Every call that happened there who called who and and so on and this was This was actually probably not from a guess note But I'm guessing from open the three more air gun But we have a very we have a similar feature to this and this is not the only use case There's many of them just to name a few like I Just just before coming here. I was talking to somebody who's developing a ZK EVM who are also heavily dependent on the tracing feature of gas I've seen talks about from MEV searchers who are using the tracing features and many more Yeah, this is also another tab in the ethos scan The details where it shows you the state like the state difference We also have as we will see later. This is also something that you can get from get So before we get to in actually we get into tracing You know that you can use gas to execute a call on top of a given state So you probably know it's called you give it a sort of parameters Like as if it would be as if you want to send a transaction to the network But this is actually not sent to the network. It's just executed locally and you see the result It's a simulation I actually have to give me a bit of time because I had to restart my laptop and I lost all my setup I will have to bring up the terminal because I wanted to show you how this actually goes So, yeah, I have a I have a girly note on my machine that is kind of sync to To the network Okay. Yeah, is it behind me? Maybe I move it here. All right, so Let's do a call But I have them all stored in a file so I don't have to type it out because Anyway, I'm you I'm losing too much on time on this so I'm just gonna go I already lost a lot of time And you all know how it's called goes. Okay, let's let's move on to the next one I'm just gonna explain to you. So basically this is the I'm sending I'm sending like I'm simulating a call to the wrapped east Contract on girly to get the balance of of an account of account zero, right? This will only give you the result like in this case the result is Zero like it shouldn't be I have to figure this out like I think I have the wrong address here Like this address the zero address should have some balance But anyway, what I what I wanted to show is that when you when you do a east call You only get the execution result what is returned from the contract back But this is oftentimes not enough information. We want usually what more information we want to see what happened inside the transaction, right and that you can do by Doing the same thing but using a debug method trace call Which will simulate the call for you And trace it at the same time. I would give you more information. So if I were to run this now Think this is the mainnet contract. I was using I Was going to present with mainnet node, but then I found out the Wi-Fi here is not so good So I can SSH to my server Here we can already see that there is a lot more information as It basically shows you all the steps that happen during the execution of this transaction And yeah, there is going to be a lot of steps I'm not going to go to show you all of them, but basically you you will see okay, like what is the first opcode? What is the Programming counter at that point which opcode was executed. How much gas do we have at this point? Like what is the storage at this point and so on so it will give you almost the full information that the EVM has When it runs through the transaction You can ask questions. Sure The stack is before the instruction. Yeah, so all of these information are from before we execute the opcode Here I showed you in this example. I showed you like tracing a Call of my own craft like basically I said, okay, I want to like do from to input and so on but of course gas supports Tracing existing transactions the one that were already mined on the chain So historical transactions so to say that those you can do via these endpoints you have debug trace transaction that Traces a historical transaction you just give it a Tx hash You can also do it at the block level you can trace a block by using twice blocked by number or hash Or you can do even a whole range of blocks by using trace chain But trace chain mind you is a bit different. It's not a simple like It's not using the simple JSON RPC request You have to it's a bit based on the subscription API. So you have to use web circuit for it So the usage of it is a bit different. I'm not going to show you here but Yeah, it's cool for when you need to run over a range of blocks what what we saw and in the previous trace was the default tracer it's Basically the opcode tracer like it shows you every step, but sometimes you need Information at a different Abstraction level like for example as we saw in the ether scan screenshot you want to see What calls happen or like you want to get different information and get has a bunch of built-in tracers that you can just call them by name and And get the information you want so here like in this section. I want to show you It's three of them the first one being the one that we saw I'm just gonna like here in this table You will see all the information that you will get from the opcode tracer Which is yeah, I'm gonna give you a second if you want to see what's in there But yeah, basically you get the opcode information all the gas related information like how much this Upcode cost to execute or will cost to execute How much gas there's left the the whole memory snapshots? Of that transaction the the stack Return data of the last call like when a call finishes in the next step you will get the return data for it Storages for the storage slots for the contract depth of the execution refund and if there was any error But please note that if you want to use This tracer there are some things to note as I said Memory stack storage and return data that these are dynamic values, and they can grow large especially memory you have to watch out for memory because Mainnet transactions these days are very heavy So like if you have memory enabled It can kill the node basically Like yeah, somebody for one of our users reported that they try to trace a block with on a server with 64 gigabytes of memory and It crashed basically But because of this That the tracer accepts options to disable all these features So all of the ones that you will see in this list They can be disabled some of them are enabled by default some are not but they're all like you can toggle all of them Also, if you if you really need to trace You need a memory let's say and Jason RPC is not sufficient for it and you control the node then there's an endpoint standard trace block to file which will trace a block and Save it on a file alongside the node that you can Yeah, you can easily access so it's not a lucky Jason obviously because the next one is the call tracer This is arguably one of the more like most interesting tracers It will basically give you all the call information like all the internal calls that happened during the execution I'm gonna show you in in the previous example like like Basically when we call wrapped ether balance of What information we will get in return So you can see That Like balance off is a simple call. It's not gonna call anything else and there's there's one call It shows you who is the sender? Who's the recipient? Who's the contract? What is it call or is it create? Was there any value transfer and what was the call data? What was the input? But yeah, this is a more like Boring example we can I hope these transaction hashes are okay. I Feel like the file wasn't saved Yeah, okay, it works So I'm just gonna run it so show you guys so here I'm trying like I'm not doing trace call But I'm using historical transaction. That was mined on girly. So I'm using trace transaction endpoint This is the transaction hash and here like as an option. You can specify You can specify what which tracer you want to use So if you don't provide anything then it will default to the opcode tracer but you can say I want to use the call tracer as we did here and You will get a bunch of information Yeah, so this is this is gonna be the main call and notice that we can already see like this call Error like there it's reverted. We can also see from since recently we can see the revert reason Which is system time out outdated. This is the solidity revert error that was returned In the input output and then here from here. We have the nest that calls so basically the the the Main contract did some called another one That we can see here. We should which also reverted and like up there. You can see like there is There's more nest that calls that it's not being displayed here, but you can you can get that information also So, yeah called tracer you would use when you need information about the internal calls It also since recently it accepts a nifty option So I'm gonna provide here Okay, you can you can basically configure the tracers you can say like I want only top call This is this is useful if you need only the top call information like only if you want to know Okay, why did this transaction revert then I don't need to see all the nested call information I just get the top call and I checked the revert reason and I know okay. There was a time outdated or something This one is the pre-state tracer It has two modes of execution by default when you just you just say I want to like trace this with the pre-state tracer then it will give you all the Accounts that are needed to execute the call or the transaction You can think of it something similar to access lists or witnesses So if you somehow need to simulate a transaction and don't Store the whole state you can get the state via the pre-state tracer And then you can execute your transaction locally and In the second mode You can see all the state as state modifications that happened during during the transaction Basically, you can say you can see okay the balance of this account increased to such value the the source slots changed such and such if if we were to see it in See it live It's this one So here I'm I Need to change the address I'm gonna execute the same wrapped ether balance of call and pass the To see the pre-states and yeah as you can see like the zero address has like shows the balance of the zero address This is the the contract itself has a balance the code Nonsense and like the oldest source slots that were needed to execute these transactions These are not all the storage slots of this contract, but only those that were required here and Let's say you wanted to see the the diff You just pass a parameter diff mode and Yeah, basically we can see like the biggest change here is that the nonce so you have like a pre and post state and You have to compare them so you can see here like we have the zero address The nonce is omitted because it's zero so nonce was zero and now it's one. So this is the only The only change that happened in the state during this transaction But of course if we were to run it with a more complicated transaction you would see Yeah, you see like there's gonna be much more stuff. This is Yeah, and this is what parts of the state that changed during this particular transaction like here We had also balance updates Yeah, nonce and balance both changed and balance of zero account change and Yeah, here we have like The format works as follows Basically whenever Something is created. Let's say a contract is created. It will not show up in the pre object It will only show in the post object and Whenever something is deleted it will only Show up in the pre object but not in the post object So by comparing these two objects you can you can see How the how the state was modified So now I want to talk a bit about how gas stores state because it is very relevant When you're doing tracing like if you've been been tracing you've probably saw this error required historical state unavailable Specifically when you want to trace a historical transaction one that was mined Now now why is this? so first of all How do we prepare the state? for Simulating a transaction or rerunning a transaction. It's basically like you have to We have to find okay the transaction in block n so we need We will fetch the state for block n minus one the post state of block n minus one And start executing all of the transactions within the target block until we reach the transaction that we want At this point we have the transaction. We have the state The pre state basically for our transaction and we can we can execute it But what happens if the state for this block and minus one is not available in the database? That basically that's hint. That's what when you get this error So what so now comes the question the state for which blocks are actually persisted Let's Get the archive node out of the picture because it's the easiest so for archive node you have all the states Next one is full sync By full sync I specifically mean that you start executing all of the blocks from Genesis up until the head here It's worth to note that always Guess stores the latest 128 blocks The state for them in memory So you always have like while your node is thinking you always have the state for the last 128 blocks Now anything beyond that Is stored only like it's persisted to this only periodically And that is roughly every two hours So every two hours the state for a block will be persisted to disk and Because we think from Genesis that means we have the state of a block Roughly every two hours from Genesis on until the more recent ones and the difference between full sync and snap sync is that In snap sync you won't actually start you won't actually execute the transaction you won't actually execute the blocks from the beginning but from some pivot point so let's say here is the point when you Start like you fetch the state from the from the network and you start executing transactions So that's why we only have the checkpoints from this point on and like so We basically we cannot execute any transaction that That happened before we we did the snap sync So it's important to know like based on your use case Which think mode you should go for and now we can complete the picture again So how do we prepare the state for for executing a transaction? We fetch the state of the parent block from the database If it's not available, what do we do? Guess we'll go back in the blocks for for a number of blocks and checks if it has a state available for any of them in on disk and if so then it will Basically re-execute all of those blocks and prepare the state for your transaction. So here you can see in the error We have we have the error and we have some more information like reexec equals 128. This means that guess tried the hundred when 128 blocks Backwards to find some state on this that it could use to to go forward, but it didn't find any and this is a This is a This is a parameter that you can give so basically when when you do trace transaction You can provide this re-exec parameter and say okay. I'm willing to go back 2000 or 2 million blocks to find a state that I can use to To execute this this transaction But of course the more you're willing to go the more you go back the longer it's going to take because All of those blocks have to be re-executed to to compute the state We have a there's a there's a method that you can use to see States for which blocks are actually stored on disk and that's debug gets accessible state So let's say like I want to see I Want to see Like five five thousand blocks behind the head. Do I have any any state there? Computing no state found so I don't have anything between the last five thousand and four thousand blocks Okay, I can try again or I can enlarge in this the search parameters It's probably also gonna say no. Oh, actually no it found it. So here it says that I Have there's this block that I have the state for So I know that Yeah, so I know that I have the state for like eight thousand blocks ago basically So, yeah, this is this is the nifty method for finding Which which States you have on your disk and then when when you when you know this then you can set the re-exec parameter accordingly and sometimes There is a range of blocks that you care about a lot like you you need a lot so You want to store the whole state for that what you can do is basically stop gas at this parameter GC mode archive and And run for as long as you need and then stop it again and take it off because When this flag is there then get will store Every state like the state for every block on disk We went over the Some of the tracers that are that come as like in in stock gas But that's not your only option you can also You can you can write a custom tracer like you can basically get like there's some hooks that that you can use to collect the relevant information for your use case and only that you don't have to rely on the Tracers that we provide and Here I want to show you an example I I During dev connect in Amsterdam. I I met this guy who Was an MEV searcher and he was telling me that he found the tracing feature of gas extremely useful and then later on I saw his talk and He was talking about this so Apparently there's there are some poisonous tokens out there or they used to be at some points that direct basically searchers like the automatic bots and One of one of those tokens kind of looks like this. This is I think this is a simple one It's not a real real one, but basically it just checks to see if you are in a development environment then it Does the the actual transfer of value? But once you So let's say you simulate that In on heart hat and you see like yeah, I got some money But when you run it on mainnet then you actually don't get that money again. You'll probably lose some so that's that that's the gist of the token and Like he he wrote a like the most of the simple tracer that can detect this I'm gonna show you that This is how Custom JavaScript tracer looks like It's a it's a very simple one you have a Few methods that you can implement in a JavaScript object and You will pass this object to get When you when you invoke the API in this case We implement the step method which is run for every step of the execution and We implement also the result function, which is executed once at the end of the transaction so basically we want to that the idea of of the detection algorithm is that Token transfer shouldn't use any of the Following up codes coin based number difficulty origin. These are all block metadata, right? Why when you're doing it yours to any transfer, why would you need any of these op codes? So This is like a very simple detection thing so what what I'm doing is basically like I have a global variable called fishy and As I'm going through the opcode as I'm going the steps. I check that if any of these op codes appear then I'm gonna Say, okay, there's more coming out of this. I don't want to do this trait So I just have that variable to true and return it and now like here is my I You can't see that but basically the result is true. So what so I I run that tracer over a contract and The result was true, but Let's let's dive. This is this is probably the most interesting part of the There's a few things here, right? So I'm I'm simulating I'm simulating a call From and to to an address But note that this address is actually not Is empty there's not like there's no contract deployed on girly for this address So I'm going to introduce to you and a very nifty feature and that's called state overrides right Basically when when you when you simulate a call using is dot call or debug the trace dot call You can give a bunch of state modifications to guess like temporary and you say, okay Apply these state overrides temporarily for simulating this transaction So here what I did was I I have the bytecode of of the contract the poison is token. This is a bytecode and Here I say okay state overrides in this address. Please put this contract code So this contract code will not be deployed anywhere, but only when I'm simulating this transaction It will be as if this address has this code So this is very useful like if you're simulating stuff and and that the tracer object I'm passing also separately here. So what happens is basically yeah, there's a call to transfer to this contract and My custom tracer detects like says that it's a it's a fishy call because it uses the coinbase upgrade now the the JavaScript tracer is Is what most of people know about But it's not the only option for writing a custom tracer Since a while ago. We also have another option Namely you can write your tracers in go This is especially relevant if performance is is a concern to you The the go JavaScript Overhead is a lot. So when when you want to do tracing over a long range of blocks and It just takes a long time, but now you can actually write your tracers in go And it's pretty simple how it works I have I have one here that I'm gonna like walk through a bit But I just want to show you how you can first I want to show you how you can write one So basically you write your tracer You add this this is a very important part This is how it how guests will know that there's a tracer here to be found and you drop this file in a directory in guess so We have this directory is tracers native you simply have to drop your go file here Do the registration and you're good to go and of course your your strike has to adhere to an interface and This is the interface that you will see so the methods are capture start This is at the at the beginning of of the execution you have capture state which is Run for every every step of execution you have enter We didn't see this before Enter is basically a hook that is that is called Every time we enter a new call frame So when there's a call or it creates we enter a new call frame this This one is called Exit is when we leave the the call frame and you have fault and and the result so so the result is when Basically what you return and what the tracer will return when you call the method Yeah, it's a bit tight time was but I'm just gonna give a short overview so What this tracer does is that it will tell me the method signature for all of the All of the functions that were called so as you as you probably know Solidity functions like when you hash their signatures the four bytes That's how you actually invoke them at the EVM level, right? So like when you when you and I want to just collect The this this four bytes basically like the signature of the methods that were called so This is the gist of the logic I Check that we're we're entering a new call frame I check that is this it has to be a call or A delegate call or static call some kind of call. Otherwise just return. That's not important Also, we don't want to collect pre-compiled information. So they're also return if in otherwise Take the four first four bytes of the call data and this will be my signature and This is these are stored in some objects here Yeah, I don't have more time to go through this. So that's how you write a go tracer And I want to quickly mention What's coming next on this front? So you saw the trace call method. I'm planning to work on the trace multicoll This is when you will have a list of call objects They will be executed sequentially maintaining the intermediate state as they go to the next call and The other thing is the trace namespace or as other people refer to it as parity tracing so these are the things on the roadmap that have been Worked on right now and on the last seconds. That was a that was it basically Thank you guys Hi, most of these will probably be available in the docs, but Does trace to file exist for transactions only rather than just blocks? No, it's I think what we have is only for blocks now. Got it Is re-exec re-exec available via json rpc? Yeah So I didn't show it but basically when you do trace transaction in the same object that you provide the tracer name Use you specify re-exec got it and Does get accessible state return only the highest block number that has state or all? It will return like in the range that you specify it will return the first state that it finds the first so the So if you want to get all of them then you have to iterate you have to narrow your range as you go and So if I did Genesis to now if you need Genesis to now Then it will give you the first one like let's say it's block 10 and then you do another call from block 10 until now and so on hey quick question on the the state diff tracer so Does it provide it kind of you know if there are multiple state changes in a transaction like at at the call level Do you provide all of those state changes or is it just from the beginning to the end of the transaction? What is the state diff? I may have missed this. Oh, it's yeah It's only from like basically throughout the whole transaction. Okay, not you mean for a call level. Yes I you want the site if for yeah, no, no It's all for a whole Translation, but this is something a custom tracer, but yeah, you can you can definitely do that. Yeah Yeah, yeah, you can just check the code for the pre straight tracer. It's in the same directory that I showed Yeah, I don't think it will be very hard to do. Yeah, but thanks so much Thank you