NEAR Core | Episode 02: Runtime Action and Data Receipts
Nothing is loaded from YouTube until you press play, and then without tracking cookies.
About this video
An in-depth code review of how NEAR Runtime implements cross contract calls.
Follow the latest from NEAR Protocol on,
Website: nearprotocol.com Discord: near.ai/discord Medium: near.ai/medium Twitter: near.ai/twitter GitHub: near.ai/github
#NEARCore #Blockchain #FutureIsNEAR
Transcript
8,814 wordsCaptions as YouTube publishes them, usually machine-generated, so product and people names can be misheard.
- 0:00
hey everyone thanks for joining this uh the runtime walkr session again um the topic today is going to be initialization from the Genesis uh actions and the receipts and also we're going to look at how we actually execute those callbacks and the how the promises work uh in the runtime because we've been talking last time that near provides a very friendly developer experience for the contract developers and that allows them to work with promises without thinking how it's been
- 0:31
executed behind the scenes so we're going to actually look inside this box and and see how promises translate into very specific messages that uh runtime is passing between the shards and executing so we're going to start again with some analysis of the cases that we have do you guys see my whiteboard here yes cool all right cool so again we have oops multiple shards in the r time draw them like this bunch of shards each shart has its own uh in the blockchain each sh has its own runtime
- 1:18
and let's say you have Alice uh who is trying to call Contract Bob just as a a walk through what we discussed last time so see Alis contract is trying to C Bob contract and Alice leaves on Shard a a and Bob leaves on Shard B so what's going to happen is that uh the transaction is going to arrive oops it's going to arrive uh to this sh so you're going to have a transaction arriving to sh a uh then this transaction is immediately getting
- 2:02
converted into the receipt it's actually going to be local receipt as far as remember the last time we discussed that when transaction and the and and the contract that it's calls or like the account that it's Target is on the same Shard that it just becomes local receipts and it executed immediately so been converted to the receipt it calls contact Alis and then Alis is actually going to send create um another receipt that is going to be targeting
- 2:37
contract Bob and on the next step so let's say this is block X and this is block x + one so on the next step Shard B is going to process this receipt and execute it right um yes so now let's take in the more complex scenario the more complex scenario is uh when you have a call back so let's say Ellis wants to execute contract Bob but at the same time have a call back back to Alis this can be useful for instance when you build an exchange so in in for instance if if you're working with the
- 3:20
exchange near you would call an exchange and say exchange token X for token y exchange contract will send a call to the contract X send a call to contract Y in parallel and then going to receive the call backs both from contracts X and Y and uh and try to do something like you know swap them for instance so the Callback is like a very important part of the of the of the contract building experience in here so let's say again
- 3:51
that we have Ellis contract Bob and then once contract Bob executes Ellis wants to be called back again so so it's Ellis Bob then it's getting called back again to Alis um in in in in nears DEC the way you would write it is that you would create a promise to Bob and then you would attach a call back that says call me back again when Bob is done and and the way it's going to work is in terms
- 4:27
of the receipts is again the transaction arrives to Shard a uh then local receipt is being processed then Shard a spits out the receipt that travels to Shard B and and block X plus one is getting executed but now on the next block uh Shard B needs to call back Ellis so obviously there needs to be like next step oops uh next step like this and uh this is going to be let's say block x+2 and in this block X Plus
- 5:00
to um Shard B is actually talking now to Shard a by the way Max it's a bit off screen the stuff on the right hand side okay can you can you see the the shards so the the diagram or not or is it cut through we can see uh the cut off side of the far right two squares shards okay that right try doing something about it okay how about now it's better is it better cool so uh Shard B now needs to call Shard a on the next step right because the call back is
- 5:50
happening and the way it's going to work is there's also going to be a receipt flying because you need some information you need some exchange of information between shart uh BNA but this receipt is going to be called Data receipt data is because it just tells the result that b was executed it just has some information that well B has executed maybe with certain even data because you want to have call back maybe with some data and uh that's why it's called data receip and the receip that
- 6:24
does that calls uh that calls contract B the first time it's called action receipt all right so this is pretty much uh the high level overview of like very very simple approach a very very simple scenario where you have a call back cross contract call with a call back and you have both action receipt and data receipt by the way the local receipt is also going to be action receipt now let's look at the code in those actually action and data receipts
- 6:58
to see how what they are on second let me see are there any questions I think there might be questions all right discuss later um yeah so right now you see my ID again it slower uh smaller cool there we go thanks all right so um this is action receipt let's go back to the runtime so the way I always start working with the runtime as I recommended you last time you start with the apply method which is like a
- 7:39
goto for most of the information you see the receipt here which is the central structure that I was discussing receipt has some predecessor ID which is just an information who emitted this receipt in in case of the transaction that is going to be the account that signed to the transaction that was converted to the receipt uh um if this is a receipt that was created by another contract in case like when Alex contract called Bob contract the receipt that's flying to Bob is going to have as predecessor
- 8:11
Alice even if Alice was not the one that was actually signing the original transaction receiver is the one who is receiving this receipt and this is some unique identifier that we're going to use to identify this receipt globally in in a blockchain and the this is where most of the stuff is so there re now so you can see it can be either action or data so that's what I was talking about
- 8:36
an action receip contains those actions that that we visited last time so it actually tells you what to do it can tell it tells you create account deploy contract function Call Etc the data the data receipt it doesn't have actions it only has a blob of data Maybe so uh if you if your call back does not require transference some execution result for instance Lis called contract
- 9:08
Bob but when Bob was executed when the contract Bob was executed the function the contract function did not return anything it returned like void then this is going to be null um and uh and otherwise it's going to contain some serialized execution results depending on what kind of language which you're going to use it's going to have different data in there and going to probably use different calization
- 9:34
methods so that's the difference between action receipt and data receipt the data receipt only contains execution result of of the contract when it's been used for the Callback an action receipt actually has you know the actions as I said um so here here is uh an interesting thing we now start looking into the uh the data IDs so uh the receipt has dependencies um so it has dependencies called input data IDs and it produces
- 10:12
something called Data receivers which also has some data IDs so what does it mean me go back to this drawing so in this drawing when uh the way the way we execute this callback right is by creating a receipt that waits for the data receipt to arrive so when when here when we convert transaction to the receipt and execute the receipt so the moment the receipt is executed we realize that we need to call Contract
- 10:51
Bob but at the same time we're going to wait on contract Bob to to finish execution so what we're going to create we're going to create an action receipt here but we're not going to execute it immediately we're just going to we're just going to store it in our state and then when and then we're going to identify that execute this receipt only when you receive call back from Bob so it's like a
- 11:26
dependency and then what happens is that when Bob finishes execution and it meets data receipt this data receipt here and this data receipt arrives to Shard a uh the runtime finds this action receipt that we stored for for for later in the first step it identifies this data ID of this data receipt is equal to the data ID mentioned in the Callback and it now knows that it can exec execute this stored action receipt and that's how callbacks work in a
- 12:06
runtime so in this case let again we we are not seeing part of the the red the right part of that stuff uh but during the time when you're moving this stuff uh my question would be uh the the purpose of creating of action receipts is this for for the sake of saving uh Network here S network what do yeah so why why why uh Bob contract is not able to to send an action receipt back to uh that there there are targeting the same contract of
- 12:46
Alis and so there are probably several potential designs of the runtime to that could achieve similar result so one of them is that Bob could maybe send an action receipt back to Ellis um then that means that Bob needs to know that it needs to send an action receipt so Bob contract when it executes needs to know that it needs to tell like a very specific execution to Alice and it's kind of seems to be like a very simple thing to implement when
- 13:17
you have a single course contract call when Alex calls Bob but if you have let's say you know like Ellis of course Bob and then Bob calls Carol uh and then Carol calls whatever I don't remember Danny and then Etc and then someone calls Ellis back again then as you call in this chain of contracts at each step you need to remember somehow through your receipts that at the very very end you got to
- 13:50
call Ellis so you're going to be passing this data you know around with a specific action receipt for Alis with a specific an execution re results like all through the chain and um in this case what you're doing is that you're just passing the the data ID uh which is uh kind of simpler um because it's just like an identifier rather than the whole structure that you're like tossing around the blockchain um and that's like the big uh number one difference so the number two
- 14:22
difference is that we also allow um the following scenario so Ellis can call Bob then Alis can in parallel call Carol so uh Alis would construct promise for Bob it would construct promise for Carol and then it would say when both of them execute at the same time when both and Carol execute at the same time call back Alice and in the example with the with exchange that would be quite obvious an example example right you have an
- 14:59
exchange you want to have a contract call to one token that locks it certain amount you want to have contract call to another token that locks certain amount you want to wait for both of them you don't want to be called uh twice you want to be called once when both of them already and so you need to kind of bundle them together on the runtime level say only like bother me when all this stuff is done and only then I'm going to be executing
- 15:26
something so when when you want to have something like that where you where your call back is bundled it's easier when you have uh multiple data IDs rather than you know you pass information because because then if if you say if you say for instance that Ellis needs to be called when Bob and Carol is done then neither Bob nor Carol is going to be the primary responsible contract for
- 15:50
col and Ellice so who is who is actually going to be like emitting this action receipt Bob or Carol I mean they're kind of equal in this position yeah should be neither of them and this is actually a great question because it's a segue to to multiple data IDs so in this case Alice has two dependences so Alice uh action receipt yeah Max by the way it is a Hell in the screen happening
- 16:23
at least what I see yeah I don't know maybe you need to to restart the screen sharing oh maybe just find a zoom out button a little bit oh it's like too small living lots of it is living lots of artifacts actually really from the from the movement of the stuff yeah that's unfortunate oh from the movement of the stuff but is it do you see any artifacts now yeah still seeing it damn it
- 16:59
hm what if I do this is it better better much better wow Zoom okay apparently sharing a screen creates artifacts but sharing this window does not um well I hacked Zoom great uh so Alice has um Alice is an action receipt so you're going to have this action receipt here right this one that waits for some data ID in this case let me RA it oops in this case Lis is going to be waiting for two action receipts so in this case there
- 17:44
are not two action it's two data IDs two data IDs so lsis action receipt is going to have two dependences and uh incoming dependences so it's actually good going to be waiting for these two data IDs to arrive while these other two uh action receipts that we meeting one for the Bob and one for the Carol they don't they don't have any data IDs that they depend on but they themselves emit data IDs each one
- 18:15
each of them emits one the data ID and when Lis executes the first time it emits two data uh no I mean yeah it doesn't emit any data ID when it executes the first time so uh going back to the code going back to the code that's why you see input data IDs here as a vector because action receipt can be waiting for multiple data IDs to actually arrive uh to this chart um and you also have a multiple data receivers as a vector
- 18:57
because um a single a single promise can be waited on by multiple other contracts so that's why I have a vector here um so this is a high level overview of how cross contracts calls work call calls work in runtime together with callbacks let's see do you guys any have have any questions about it I like kind of more general question um maybe I missed this from the first session but like how where are receipts stored is there like a separate like mempool like thing mhm yes so these
- 19:40
receipts that I would just talked about the um um whatever we're going to call them the special reip that are waiting they're stored in a in a queer that is implemented on top of the State uh State try that we have so our state try um it stores accounts right so it's a hierarchical structure it has accounts in it with some uh contract data under each account but it has a very special
- 20:10
separate key at the very top which is um specific uh to the uh to the to the receipts that are waiting on on to execute this spe the some accounts and they're waiting for certain data ID this they might be actually stored under each of the accounts um that's not not on the root of the triy so this is something I don't remember exactly by heart it would make sense to them to be stored under the accounts because that would allow Dynamic sharting to actually
- 20:42
work because I mean if you if you A Shard you you cut through the accounts and you want your receipts that are waiting for certain data IDs to travel together with the accounts that they're going to be actually call the contracts on okay um so let's go again into the actions just to let's go through this actions that we can actually perform on the on the with the receipts make sure that we know their content so one of them is the
- 21:15
create account account action as I said it doesn't have any information inside uh because the way you create an account in here is that your receiver of your transaction or the receiver you of your receipt is actually the account that you want to create if you if you if you if you are creating a transaction that creates an account so when you go all the way back into the receipt here then the receiver ID is the
- 21:50
account that is going to be created if the first action is create account and uh uh similar logic applies for instance to the transfer so transfer only has deposit like it doesn't say whom you transferred from and whom you transferred to because they all deducible from the predecessor uh or like signer and through the receiver the receiver is the one who's receiving the balance uh the
- 22:21
predecessor is the one who who sent it and very similar to the function call function call doesn't say doesn't say who Who you calling because it's deducible from the receiver uh it only says what's the method name the arguments how much gas um you use to do this function call and the attach balance so when you attach certain amount of balance to the function call it works exactly like transfer it's just
- 22:48
like a bundled action um these this amount of tokens is going to be deposited uh before the function executes and when function IF function fails it's going to be undone so we also have stake action we not going to touch this yet this is a complet different topic add key again it doesn't say whom you adding this key for because it's deducible and um can we see the access key struct that was in
- 23:25
there so the interesting thing about like uh design in in the near for those of you who don't know is that we have multiple access keys for each account and this access key some of them they can be um like suda they can have full permission they can do anything with this contract or this account they can delete it they can call any method on it so it's full access or it can be
- 23:48
restricted to calling only specific methods on the contract that is deployed to this account and that's what it's called a function function access key that specifies is the the method names list of method names that you can call um and even whom you can call for instance I can add access key to Alis that says that uh this access key can only call certain method on contract Bob and allowance like how much gas the whoever uses access key can use from that account to do the
- 24:25
calls and the the interesting thing here is that we have NS not per account but per access key the idea is that multiple users can use the same account but different access keys and if there was common NS for all of them they would be interfering with each other like they would be crashing transactions of each other all the time because they would have conflict in ners because we have separate nonces for
- 24:51
separate access Keys U there is no problem with that so the noun the noun are stored per access keys are not not per account and this is also like a very important thing then everything else is quite simple there's delete key delete account it's pretty straightforward um except one Nuance here that when you delete an account a near you have to specify beneficiary because like whatever tokens you have left on this account they need to go somewhere and we want to incentivize users obviously not to like
- 25:22
lose it um so especially because we have um States taken in here stat taken means that when you uh when you want to write something in the state near you you you're going to have certain amount of tokens locked on your balance it's a different model than the one ethereum uses so in ethereum when you write something into the state you burn certain fixed amount of gas and then when you delete it from the state you get reimbursed certain percentage of
- 25:52
this gas and here what you do when you write it in a state you lock certain amount of tokens on your balance like they become not liquid you won't be able to transfer them out and then while you're using the state the tokens that are locked they're kind of paying for the state maintenance through the inflation mechanism just because you you have the tokens locked and you cannot stake them you are using you missing the
- 26:17
opportunity to stake them and therefore you're not getting a return on the investment from your tokens and that's how you pay uh for for using our state certain amount of time by not being able to use your tokens and uh therefore when account is getting deleted whether you have contract on it or it's just a a raw account without anything you're going to have certain amount of tokens unlocked even if it's small account it's going to be small tiny amount of tokens unlocked when you delete just an account with
- 26:49
some access keys and we want to incentify people to just not toss this tokens away and actually move it to a different account so delete actions delete transactions in near blockchain they have beneficiary that specify who is going to be receiving the stuff uh okay so I'm going to read through the questions what if receipt with attached tokens is reverted and by the time it arrives back to the originated the account the account the account is already deleted in this case the tokens
- 27:20
are going to be burned lost there is literally nothing we can do in this uh scenario um B can correct me if I'm wrong I think they're burned yes yes they're burnt they're also burnt if if you delete account and benici ID does not exist in that case the tokens are support yeah the tricky part about beneficiary ID is you might not be able to verify upon the Del of the account that this beneficiary exists because this beneficiary might exist on a different chart and the whole point of the near blockchain is that our state is sharded not just computation so Shard a
- 27:55
doesn't know what the state on Shard B and whether there is there does exist or doesn't exist Bob uh Bob's account in there so you can lose tokens by just providing a type like a typo in a beneficiary ID beneficiary just real quick while we're on this topic this is good timing I had a solidity developer asked me this morning what our zero address is for burning um you want to is there information on that or like how we don't have a zero address yeah there's there's
- 28:25
not right now there has been talked around providing a API for uh host function for burning tokens but as of now as of now there is no certain way you can you can make sure your tokens are burn you might think that you can send tokens and um to a non-existing account and then uh delete your own account to burn the token it mostly would work the only problem is that someone can uh squat that account while you debat your account uh so in the end you instead of burning the token you
- 28:58
just sent to someone else so there is no reliable way to to so that you can be 100% sure that you can burn the token well you probably kind of can say that sending it to all zeros account not not all zeros oh God Dam it we actually can anyone can actually squat anything in know in our blockchain any we're kind of here yeah okay um so the second question is from Michael I think we can have implicit account with an invalid
- 29:31
key yes yes that could be great um implic account is a completely different topic also that we're going to cover in the future um very interesting one Michael bur asks uh does the beneficiary get State other than near tokens as well AG nft or WRA a other than new tokens as well talk about the case where an account gets deleted and it needs to send it stuff the state yeah the state is not transferred only the tokens are transferred only the token no State okay transfer on the state is is a bit too
- 30:10
too much yeah it's hard for sure because it's not clear what's valuable State and what's not so and also it's it's very large you you really don't want to think about what happens when one of the messages in your one one of the receipts just carries around you know like hundreds of megabytes of data um Mike asks I can create burn near move all keys then you can burn by sending to goodbye burn near or any other sub account to The Brick account that's
- 30:37
pretty neat it's a good idea I mean yeah that that that that I mean that kind of burns a token but not not actually burns them like they they still exist like it's a there's a slight difference between U uh tokens that are not accessible and tokens that are like actually burnt because in the total it reflects different values and this also affect the inflation in the end so there is still yeah I mean you can like kind
- 31:08
of lock or burn like like in a nominal sense that yeah but if if if you were able to delete burn near after sending it then it would have been burning but I don't think you can do it with our current constraints on what kind of sequences of actions you can execute so as as I said last time the sequences of actions uh in here there you cannot have anything like you cannot have arbitrary
- 31:34
actions because we we try to take a very conservative approach with it we say we allow almost anything but things that we have concerns with for instance when you create delete account multiple times we just prohibit for now and we figure it out in the future if actually there is a use case uh so for instance uh mic scenario will not work will it no it will actually you you can actually do it you can create a transaction that creates burn I mean uh
- 32:06
removes whatever doesn't need to remove all the keys creates sends send certain uh tokens to goodbye burn near and then delet burn near in the same transaction it might actually going to burn tokens uh all right so let's move on from the action receipts I hope I got you properly confused here but but I think we we actually reviewed almost every field in the receipts which is great except the gas price so this is going to be the topic of the refunds uh that's where it's
- 32:38
going to be useful what the guas price is and um yeah so that the other important thing here is that you can see that very frequently we specify who is the receiver of something for instance with the data receiver we're not just saying data ID and that's it we're saying data ID and the and the receiver ID and that's because of the shardan the to to to know where you need to Route
- 33:02
this information you need to know which Shard it lives on and to know which shed lives on you need to know what what what is the receiver ID because the shed in our blockchain happens according to the accounts so we like you can think of it on a high level as we literally just like mod accounts like account um identifiers so you can really easily deduce from the account ID uh on which
- 33:25
chart it leaves on and so you would know where to Route this data ID so this is something common for the code of the runtime is that very frequently in the data structures you will see receiver ID for some reason next to something and that's because we need to know where to Route this information all right so uh we have 25 minutes and I think that's enough time to look into the
- 33:51
another important method of the runtime which is apply Genesis States so the difference between apply gen State and apply is that well as the name suggests that you call it only when when you when you execute Genesis block which is just once and the apply is being called on every new block and uh the difference here is that our Genesis contains what we call State records and State records it's basically our way to describe what the state what we want the look uh the state to look
- 34:28
like when the blockchain starts um and uh we want to have certain number of the accounts for instance already exist upon the Genesis right we want near foundation account to exist in there we want accounts of our investors tools exist in there and of our employees well our employees who add it later maybe even some of our investors who add it later I'm not sure but near foundations should certainly exist in
- 34:54
there yeah actually only a few accounts exist the main Genesis cool yeah thanks for correcting B uh then we also want to have maybe this accounts to have actually some data in them and some contract deployed on them so we want to have some contract code to be deployed already on the Genesis start and the data to exist also upon the in this in this contract we also access keys to
- 35:18
exists and now there is um the interesting uh the interesting part comes in which is postpone receipts receive data and delayed receipts so uh let's start with the delay Tres U well I mean let's let's start first with the motivation why do we need anything but the but the top things uh so before we launch on the main net uh our blockchain the test net specifically one was undergoing Forks frequently because we were experimenting with the code and
- 35:50
we were um and we were just like it was easy to to do a fork upgrade rather than you know to do a proper upgrade and reability was not implemented I think back then um either and so we wanted to take whatever the state the blockchain was at a given moment of time and start with this state as that was um a Genesis so it's a proper Fork but additionally what we wanted to uh to uh to carry over are also with the
- 36:21
receipts because as I said last time we want to have a guarantee that receipts are always going to be executed so in any blockchain receipts are never lost because if if you allow receipts to be lost or not executed then you cannot have any uh contracts with any kind of guarantees built uh on across the shards on near blockchain for instance as I give an example with exchange that calls
- 36:45
one token contract and calls another token contract so suppose that we have a following scenario when your exchange first calls one token contract to lock tokens with a call back then calls another contract to lock tokens with a call back and then if they both s successfully lock you perform the the swap uh if they don't then you unlock them if you if you lose the receipts then you might lose the receipt that does the unlocking and so your tokens
- 37:15
might end up locked even maybe permanently so this is like a very simple scenario when you absolutely need a guarantee of the receips to be executed and um there is a lot of work and the complexity inside the runtime code to ensure that this actually happens and the delayed receipts here is one of the reasons why this is exists so when you want when we were doing Fork on the test net we wanted we didn't want to lose the receipts that were delayed that
- 37:44
were like in the process of being executed but we're not executed yet and therefore we would we would scoop this receipts from the delayed queue from the state and put them in the State records saying this delayed receipts you got execute them at some point you you cannot lose them um with with the with the postponed receipts there is a slight difference here that delayed re can ask you a question about the delayed receipts what's the point in keeping the delayed
- 38:15
receipts if you're restarting the blockchain from the very beginning you will not have respective contracts there deployed and stuff like that but you will I mean when when we starting we we we're taking the state when when we're doing the work of the of the blockchain yeah we're rebasing the state uh so there might be actually the you might be creating a fork right in the moment when someone was doing let's
- 38:41
say an exchange uh Swap and you don't want them to end up with lock tokens or anything like that yeah yeah got it and uh and the difference between postponed and delayed receipt is that delayed receipt was the one who was actually lived in the delayed que of the of the blockchain maybe because maybe because there was a congestion at that moment so remember last time I said the delayed receipts are actually the receips that written in the state
- 39:03
carried over uh between the blocks postpone receipts is actually the receipt that was simply in flight so it was a receipt that was emitted by the block right you remember that when we process the block and near not only we output the state as the new state as the artifact but we also put what does the next set of the receipts that we need to route between the sharts so postponed receipt is the receipt that was uh
- 39:27
created it but it didn't wasn't the part of the delayed receipt but you still need to execute it so that's the difference between postponed receipts and delayed receipt and uh the received data is also the thing that we just touched so theed data it could be situation uh for instance let's go back to our drawing one second like let's go back to this scenario with Alice and Bob one second here so it could be
- 40:01
that um like Bob has already executed and and send the data ID uh the data to to uh back to Ellis and right at this moment we decided to to Fork the test net but but Carol did not execute yet so some of the data has arrived and some of the data hasn't so we we cannot execute Alice yet but we already but we need to keep the information around that the data has arrived part of the data has arrived for Lis to be
- 40:34
executed and therefore we have this received data thing that exists um that exists in as part of our state records is that maybe we had some complex cross contract calls with callbacks and part of it was executed and part of it was not you know some of the data has arrived some of the data hasn't is it that local receipts can become delayed receipts uh yes the local receipts can become
- 41:07
delayed receipts uh let's actually go back to the code uh I think it it can if it's so contested that local reips cannot even all be executed in the same block yeah or for example yeah mhm yeah no continue see so you see like when your local receipts are executed you check on every step am I above the gust limit and if you are then instead of process and you say right I'm delaying this receipt and just like since I've been talking a lot about the
- 41:40
delayed receipts let's even take a pick into this function and you can see what literally does it just takes this receipt as this and it writes it into the state so you can see this some set function State update thing what it really does it just writes it into the state try at some place that's that's all it does and also updates uh the pointer on this um delayed receip Q by one so it doesn't do anything besides that um right let's go back to the apply
- 42:11
Genesis State and additional question Max so so so it is um it is independent of user whether the receipts that that are created within the tree of calls are are are are coming to the delayed state or not does this mean that making a receipt a delayed one is costing zero gas so so the execution gas costs are can be calculated beforehand yeah so the the putting receipt into the delayed Q incurs extra cost um that we don't have a separate fee for
- 42:56
and and uh we consider it as a part of basically the burden that validators need to carry the problem with the fees is that you need to make um to draw a line at some point like you cannot create a fee for everything in a blockchain like you cannot you cannot create a fee for sending things over the network like what is your network it's such a such a volatile thing you cannot like assign a very specific fee to it uh you cannot assign fee to I don't know
- 43:23
um uh RPC things right talking to the RPC and another thing mhm uh and and therefore therefore you need to you need to draw a line sometimes and say most of the fees especially like things that are deterministic most of them we try to have a fee for them and and also we try not to have fees for things that are unexpected of the contract developers so again we don't want contract developers to be like oh my God why does my thing certainly costs more than it than I thought it would cost why do I need to
- 43:55
why do I need to care as a developer that there is something inside the black box of the runtime happening and my receipt is being put somewhere somehow and because of that I pay extra cost and that's basically one of our criteria so when we decide where whether to make it a fee or not is that is it going to surprise the hell out of the developer and if yes then maybe it shouldn't be a separate fee yeah so that's the reason
- 44:20
why I'm asking this so if if we are attach a fee from making the the receipts at a delayed one M then this is something unexpected to the developers yeah the good thing is that the execution of the receipt is like probably orders like three orders of mud or something like that more expensive than putting it into the state just like moving this thing around yeah so the the execution of the receipt right now it's on the order of teras like whatever single digitas I
- 44:52
think um they write in something in a blob of data into the state is uh way below single digit tages like 0 point and then you have like either two one zeros before you actually like 0.02 or something like that it's quite cheap so negligible all right so uh let's look uh in here so here you see this is the this is the applyed Genesis State function right so we iterate over the state records that are stored right in the Genesis uh this
- 45:29
is the part of the Genesis that means that um as you know we use Genesis to identify the chain too so if you have two blockchains that have everything equal but different State records those are two different chains they they're part of two different networks so the state record is as important as having you know anything any other config like the block size for instance in in our blockchain it's identify it's it's a unique identifier of the of the
- 46:02
chain there is some stuff about the storage computation which we also going to skip for now this is a completely different topic um there is this stuff is convoluted and you I don't think you need to you need just a high level idea of what what the hell is postpone receipt is somewhere here it's actually going to execute them or set them to to exe to be executed later I think there is this this code is about updating validators
- 46:32
as I said last time it's also a separate topic discussing how validators are updated what what happens with the stake Etc and everything else is all about updating the um the state and discussing runtime state is also a separate topic so we covered the apply Genesis State now um let's now look at the apply method again so in the apply method as I said this is like the most important method of the
- 47:01
runtime and I think the second most important method of the runtime that you can start looking into is process receipt since most of the logic is about the receipts right transa logic about the transaction is quite simple because transaction is getting converted to the receipt almost immediately that makes basically puts most of the complexity of the runtime inside the receipt execution so processor receipt
- 47:27
it follows this very standard rust pattern of you know having a really large match against the tagam and uh what you can see here if you actually look into the data ID uh the receipt data is that you're going to see that the logic here is all about waiting for all data to arrive when when there is a call back so like a lot of the code here maybe more than half of it is all about is about the
- 47:58
case when you have a call back and you're waiting for some data to arrive and only when it arrives only then you do some execution so we're not going to deconstruct this code here you can go over it yourself I I hope you understood the high level idea of what data ID is and how the callbacks work and uh yeah so you see there is some something here called like pending data count we actually count how many data we
- 48:24
still yet to receive and once it becomes zero then we actually execute the receip um so I don't think uh we should go into any more topics today because other topics are quite large and we shouldn't start on them uh do you guys have any more questions this is this is this might be the most complex topic of the runtime by the way and the most uh Like New in terms of the mental model all the scbs and the receipts and all this data uh data flying between the sharts everything else is going to be
- 48:56
more lineer straightforward so do you have any questions on this topic well maybe not exactly on this topic so there is a problem with this system of which I thought for quite some time so we as as you said we have we have a guarantee that the receipt never gets lost and I think this is most important for Action receipts but this is on the low level but for the contract there is is a problem which can make a receipt appear
- 49:31
to get lost specifically if the execution runs out of gas then for the contract because such execution is reverted from the point of the contract this receipt is lost and the problem is that you can't really guarantee that you have enough gas for anything so there is always a risk that you execute ution will run out of gas and in ethereum it's much simpler because like the entire transaction gets reverted so it is as if
- 50:05
this transaction didn't exist but for near it is possible that multiple execution need to happen either all of them need to happen or none of them needs to happen and it is possible that one of them is completed and the second one runs out of gas y yeah so that's a f problem on the sh blockchain where you have a synchronous contracts um which is if your contracts are like your incomplete thing that can do anything H you you can try your best
- 50:39
to estimate what is the what is the amount of gas that you need to attached to it to always guarantee that it's going to be enough to execute it but you might be wrong and any kind of callback which is can also be a t in complete program can actually run out of gas so we either need need to if if you want to to allow users to make like like a foolproof mechanism uh for unlocking and
- 51:05
for the callbacks we either need to drop uh this completeness through incompleteness and we say whatever you execute as a callback is actually can be limited in gas and we can guarantee it and it's always going to work and not never going to run out of gas or we need a complet different mechanism which is lot of synchronous calls which is also what we've been discussing some research meetings so I thought I think what I
- 51:31
thought about was more like the first approach so I thought I had an idea to have some sort of event cues so the idea is that the call back adds some item to an event queue that is part of account State and so this action of adding this like promise result to an event Q is not during complete so it is possible to guarantee in advance that it will not run out of gas and then it is maybe
- 52:07
possible to invoke a regular callback as well but if that callbacks call back runs out of gas it may be possible to send a transaction to reinvoke the same call back with the information from that queue like with more gas so if that call on the one hand it is possible to have a call back which can do something like schedule further receipts for instance like more do something else but on the
- 52:38
other hand even if that call back runs out of gas it it is not lost completely like there is still a record in the state that this contract can use to redo this action if someone sends another transaction to get to give it more gas to run yeah that's one of the mechanisms I also like uh the approach that Libra has where they just special case anything that is an asset and they create the entire virtual machine around the fact that you cannot accidentally burn some
- 53:17
asset so it's like a it's like a first class citizen for them all this years 20 tokens and uh we were actually brainstorming ideas around that there are multiple at least one proposal in in the Naps we call it safe where we ex like extend our runtime with some extra host functions that will allow you to have basically the Libra functionality uh specifically for the for the asset uh for the asset manipulations so that that could also be a solution but I also like the QQ is more Universal
- 53:53
um but it's it's harder it's harder for the developers because now they have to think in terms of this Q like they need this new abstraction to deal with uh I mean we don't need to turn resarch meeting it is possible to hide the thing behind some SDK functions and instead just make it like possible to redo call back if it was it if if a previous attempt to run a call back failed then
- 54:25
it might be possible for anyone to send the transaction to pay for the gas to try to run the same exactly the same CW again so this is like simple approach it shouldn't affect SEC the security so we always had a guarantee that the call back can be invoked at any time like possibly much later and so now the difference is that if uh execution of a callback failed that anyone can attempt to re execute it exact in exactly the
- 54:59
same way but with more possibly more gas but also one so one once it finishes it removes like itself from the que so it cannot be the same in call back can it be called again yeah yeah something like that and we can even create some uh design patterns for the contracts that people can just like use as a recipe book without without really thinking too much about how to design something custom on
- 55:30
top of this C using as the key cool uh so let's wrap it up that was as I said probably the most complicate complex Topic in the in the runtime in in the ROM code and I'm happy that we have through because that will allow us to understand other things because as we're going to be reading the the the rest of the code like around the state around the fees um around the wasm execution we're going to see a
- 56:00
lot of these receipts and data IDs and all things like that and we will be able to understand what it actually means so it is was important that we covered this topic early on uh but I hope it didn't discourage you from attending more runtime bookr videos because they're going to be simpler than this one right thanks everyone thanks so much Max great thanks Max by thanks bye bye guys
- 56:27
thanks