Skip to content
by Unity Nodes
NEAR Protocol

[NEAR Protocol engineering interview series] Understanding gas (April 26th, 2023)

about 25:58 long

Nothing is loaded from YouTube until you press play, and then without tracking cookies.

About this video

Join NEAR's community: Website: near.org Reddit:   / nearprotocol   Discord: near.chat Medium:   / nearprotocol   Blog: near.org/blog Twitter:   / nearprotocol   GitHub: github.com/near github.com/nearprotocol Dev Docs: docs.near.org Create a wallet: wallet.near.org/create Apps on NEAR: awesomenear.com Learn to Build On NEAR: near.university Grants & Funding: near.org/grants #Blockchain #FutureisNEAR #NEAR #nearprotocol #nft #dao

Transcript

3,345 words

Captions as YouTube publishes them, usually machine-generated, so product and people names can be misheard.

  1. 0:01

    and we are recording nice so uh tell me please uh some basic terminology what gas is why we use gas and not near what does it mean to charge gas what does it mean to burn gas or in that area yes okay yes so gas is a currency you could think of that we use to pay for execution on near blockchain and the workflow is a user submits a transaction on chain um we compute what it costs to execute this transaction and we calculate this in in number of gas

  2. 0:52

    units and then there's a dynamic gas price that makes a conversion from near tokens to gas units and that Dynamic price is taken and to convert how many near tokens that will cost and then from the user we subtract the near tokens that was required to execute the transaction they want on a very fundamental level we need this uh as a way to protect ourselves so if everything is free then uh Deni of service attack would super easy anyone can just Spam

  3. 1:31

    transactions so we want some way of assuming making sure there's a fair sharing someone wants something to be executed so they should pay for something um in other blockchains often gas is directly given to the validators we don't do this so other blockchains might explain they need gas because validators needed an incentive to execute it that's not how our incentive model Works validators get

  4. 2:04

    their uh get like a fixed amount of uh rewards even if there is very little traffic so their reward doesn't depend on traffic directly we actually just burn the gas and that means you purchase gas with near tokens and those near tokens are just burned they're removed from the total and that indirectly incentivizes validators maybe because total Shing so their part of it becomes more valuable but that's like a tiny tiny effect I wouldn't say this is

  5. 2:43

    actually the incentive it's mostly about making sure it costs something when you want to execute something so that the incentives for yeah like denial of service attacks are not really possible or at least it should cost something um and I think that's like the basic economics and idea of of how we G use gas okay so we can now jump straight into the Jersey part the code of it uh what I I assume the hardest part is how we keep uh how we calculate uh

  6. 3:29

    the gas charge but there's the parts around it in runtime that may be useful I don't know can you thr something around this I don't know how is the formulated but maybe before we jump into code a couple of implementation difficulties that I can explain without code so one thing is we don't know ahead of time how much gas it will cost in all cases yes if we create a new account that's something we can pretty much know what it will cost because it's always a fixed amount of

  7. 4:07

    work when we execute a smart contract that is a tour incomplete program we literally cannot compute ahead of time how long it will take to execute we have an upper limit because we just stop the program after a certain amount of gas which technically makes it not tour incomplete but yeah really into technicalities at this point main point is like we don't know how many iterations of a loop are going

  8. 4:37

    to happen inside this um execution before we actually execute it so if you want to protect ourselves from executing too much we have to make some estimates before we we start executing um and our solution is basically we assume the worst case so we just when we start executing we assume well okay it's going to use all the gas it has and we only under this assumption we're actually going to execute in and even that doesn't quite work always so

  9. 5:15

    we have an interesting way of filling up our chunks um but the B but roughly what we're trying to achieve is within one Chunk we should only have one second of compute work workload and we try to match gas units with time it takes to execute something yeah so that's like yeah an additional step of what gas is it's it's not just money it's also time compute time oh do you know some uh back of the

  10. 5:47

    napkin estimations for gas uh to seconds of estimation uh of computing yep so one petag gas is 1 second M or most often we we kind of use Terra gas for one millisecond one millisecond is one Terra gas so okay yeah yeah at the end of the day you can use anything you want but teras seems to be most useful often think in milliseconds and 1,000 teras equals one pagas that's what we put in a junk now the feeling is a bit interesting

  11. 6:26

    here because when we start executing received we don't know how much it will take so we don't have a hard limit on 1,000 what we do is as long as we're below 1,000 teras we will always add a new receipt and once we start working on it we will always finish the receipt which means in the worst case we are at 999 and we add another one that takes 300 so we can actually go with gas up to 1, 300

  12. 6:56

    peras um but that is then not a strict limited can never go above that okay yeah maybe now we can go into code um yeah look at some places present screen let me see do you think that large enough for the recording I mean if you can make it bigger if it will not hurt I can always make it bigger it's just we can we see less and less at the time okay okay let's try this way so first of all we

  13. 7:47

    are here in the runtime runtime Source lip. RS file this is basically where our transaction runtime lives and like where the we execute transactions and receive um this apply function applies uh a list of incoming receipts to the current state and there's also a list of transactions we're not necessarily going to execute all of them we just execute as many as fit and then everyone

  14. 8:27

    deterministically has the same list that belongs into it because the gas calculation is uh it doesn't depend on any any like local time measurements it's always we do a bunch of work and then we count that piece of work in number of gas units so everyone will have the exact same counter and maybe from 100 receipts everyone will execute the exact same 32 and the remainder will be postponed to the next um it is it's delayed I should say

  15. 9:00

    delayed we have a concept of postponed and delayed receipts these are the delayed receipts what is the difference delayed receipts are those that don't have enough gas like that didn't fit the junk postpone received are those that are waiting for a data dependency okay you have like a promise chain then you have to wait for the result before it can execute it uh I think those are possible but

  16. 9:31

    maybe I'm confusing names here as well okay so for gas here we we in this apply function and we first the first interesting step in here I think is process transaction here so it's a loop through the transactions and we process them one by one each time we have apply it we will receive stees we will burn some amount of gas so let's treat this as black black box for now we process a transaction something happens with the transaction that doesn't mean we execute all the actions inside we

  17. 10:12

    actually only accept the transaction and convert it to receip so I sign a transaction that I want to execute the function call on contract B first it will go on my chart verify the signature that's what we do process transaction and then it will produce a receipt and that will be sent to contract B chart and that will execute there so that's step one and here after processing it we have a number of gas here in the outcome we

  18. 10:48

    have a number of gas burned and we use Save arithmetic to add this here so we don't have any overflows um and then increase the total gas burn counter and somewhere below here we should be checking that this is not over the limit um total gas burn see gas it's hard to read so decrease the font if you want let's see so here we have total gas burn oh well okay we've recently changed it to Total compute

  19. 11:47

    usage that makes sense and we're now checking on compute usage I think for the purpose of this conversation with this assum comput usage equals gas and not worry about the difference um but then you have a limit and here we're executing receipts until compute limit is reached up here we are still processing transactions um but the tricky bit here is I think we're yeah like at some point there's also a check for when we above 500 teras so

  20. 12:35

    half of the full space we can use for transactions and if it's above that we will stop with the transactions but I think this check is actually done outside so we what we receive here this list is already truncated to only 500 teras for the transactions for the receipts we don't have the luxury we can't truncate like the a block producer or I should say a chunk producer can decide which transactions get in and they will

  21. 13:09

    only add as many as 500 teras can fit for receipts you just have to execute what's there so these can be incoming from all other shards and you just have to accept them and you can execute as many as until the limit is reached which is 1,000 gas 1,000 teras and everything beyond that you have to delay it put it in a queue and you can easily see that there is a bit of a problem here if if we constantly have more receipts incoming and we can execute and the queue just kind of grows to Infinity

  22. 13:49

    that's roughly the congestion problem we're trying to solve at the moment so that's related but not the topic today um yeah it's like process transaction is here after having processed them we have process received and again we add G gas bur and at some point we reach the limit and we stop um like here okay yeah this Loop like this is uh closure we put here somewhere on the stack to do all of this code here it's a bit hard to read don't worry about the details the important

  23. 14:38

    part is here we Loop process received until we are above the limit and then we delay all the remaining receipts and delaying can be a bit costly because you have to write them to dis and whatnot but yeah all of this is kind of accounted for now how do we figure out these gas numbers from from this view all we see is in the outcome we have some compute usage or gas usage whichever we are more interested in um have like a gas burn

  24. 15:15

    value and let me actually jump in here we have a gas burnt counter on this execution outcome and we often has a tokens burnt well and we need both of them because depending on the gas price um the ratio between the two will be different so yeah we we always keep both of them tokens burnt will be removed from the yeah let's actually talk about that when are we removing pokon where when we

  25. 15:57

    process the receip in that stage we remove all the tokens from the user that signed the transaction and we prepay a lot of G like all the necessary gas that the transactions and all the following receipts will consume and we have to do it there because when we on the next chart then we can like we're on the wrong chart to subtract tokens from the original user if we had the model where the contract pays for gas then we could do it in every single step but because we want the user to pay for

  26. 16:39

    it uh you have to do it ahead of time and to make that possible there is a bunch of complications now so first of all you have to look at the list of actions you're going to execute and figure out how much gas each them will cost and for function calls that's difficult and that's why if we look at actions.

  27. 17:09

    RS and then we look at function call Action here well let's go to the definition this action you have to Define an amount of gas you're willing to spend um for the other action you don't need to specify it it's a fixed amount but here you have to specify it and then we purchase that amount of gas on top of the base cost and then all the following receipts just draw from this pool and as soon as this pool reaches zero the receipt will be failing uh and

  28. 17:50

    it will fail deterministically all notes at the same time with the same error um even within Vas it will fail in the exact same operation so it will have like um maybe he was able to make 10 Loop iterations and then it stopped it doesn't really matter that we're that accurate the important part is that everyone agrees that the receipt failed and when it fails there is no State change um to the to the account

  29. 18:25

    State we still burn the gas and like actually make them pay for it so that state does change but the account didn't make any changes to its own State okay so here is one more complications when we pay for this gas we don't know the gas price yet so the price is the ratio between token and gas and that could change in the future and for that reason we have a pessimistic gas price calculation that will extrapolate into the future like

  30. 19:06

    okay it could be that we're executing the received 10 blocks in the future and in every block we could have an increase of um I think 1% um and then it basically calculates what's the worst case what's the highest price that it could be and based on that potentially highest price we have to purchase the gas so if we go back to here and let me search for process transaction here

  31. 19:47

    yes this function verify and charge transaction and then that's a match so always a bit confusing to read so we have this large call uh then we have a match and the result gets in here let's actually go inside first so we have validate transaction this returns a transaction cost and the cost is a number of gas burn um gas remain and received gas price and that's what I was looking for so the pessimistic gas price used while we purchased the

  32. 20:36

    initial receipt gets written in here so let's say the normal price is one and then it decides okay but pessimistically it's 1.5 we write it in this transaction cost result and this is now inherited by all the following receipts so each receipt will know it has purchased the gas at this price and then in every step when we burn gas at the current price and the current price is lower than this pessimistic price we calculate the difference and refund the difference and at the very end whatever

  33. 21:15

    gas is left we also refund it and calculate it back to tokens using this price that was originally put in here and it's a bunch of different ref right yes so it's an every if you have a function called chain of like five calls then you will have five refunds um you you can merge like in the last receipt you will have a refund for the difference between gas prices like the actual price and

  34. 21:54

    pessimistic price and you will have some left over so this is emerged to one single receipt so but in all the other steps it's like these happen at different times and so we actually have to produce different receipts so it's a bit inefficient here um we're also there these refund receipts are also completely free uh we don't charge extra gas for it we still take it into consideration

  35. 22:23

    when we fill our chunks so that they're not it doesn't take too much time but economically it's free yes so in the last minute what I want to show is maybe we've already been here in like verifying charge transaction and then in here we've see validate transaction will return this cost so how is it computed and I'm just going to show one example and then you can kind of think about how the rest will be done so we have a bunch of

  36. 23:02

    verifi stuff and then in the end we have transaction cost this function is where the cost is or transaction is computed you have a similar one for received cost and the transaction cost has a base cost here which starts here and that's the example I want to show we look up in the config so there's a runtime fees config a parameter passed in and that can be different for each protocol version so we can change the fees

  37. 23:34

    protocol version so here we assume we get the right comp for the right protocol version and then we look up what is the fee for a new action receipt without any actions inside just an empty new receipt what's the cost then we read the send fee we also we always have two parts the send and the execution part now we the on the sending side so we only look at the send cost and then we have to say whether the sender is the receiver

  38. 24:06

    because if both sender and receiver are the same account ID then it's a local receip and at least in theory these could be cheaper in practice we have the same cost in virtually all the places so like for all purposes that it matters it's the same cost um but we have the option to make it cheaper if it's a local receipt and that just returns a gas value and that is one specific parameter

  39. 24:38

    that we're charging below here you can see at some point we have to go through each of the actions inside the trans transaction and charge for each of those and here we have like another helper function total send fees and a bunch of other stuff that I don't have time to go into but total s fees in here you will see a loop as you might expect over all actions and then for each action we look up the fee in a very similar way like we

  40. 25:14

    take this config fee and we have this parameter here and then the send fee just add all of these up and return the result so much less scary than I expected less scary or Le less scar yes okay yeah I'm happy yeah it shouldn't be that scary um but yeah the devil is in the detail when you actually have to change something yeah well that was amazing thank you thank you very much okay cool I hope it helps um yeah yeah I hope it help

  41. 25:58

    somebody else besides me it definitely helped me thank you cool