Transcript from the "Diamond Pattern Storage Overview" Lesson
>> So we're finally getting to it, we're finally getting to memory. Now this is kind of the important part of the whole thing. If you don't get this part the rest becomes more difficult. So I think it's super duper neat, it's super ultra duper duper neat. So let's start with the whiteboard of course.
[00:00:17] Let's go over here. Any contract that exists, it has slots of memory. These slots of memory are 256 bits long. They start at zero, and they go all the way up to the 256 minus one of course. So there is a ton of storage slots available. In fact there are more storage slots available than there probably is atoms in the universe, right?
[00:00:44] It's just like an incredible amount that's available, but remember it's just a space that's out there. It's not obviously filled up, we wouldn't have enough material to do that. So it's just a theoretical landscape for you to be able to store data in. So now this is just, it's just so exciting.
[00:01:05] So now that we've done that, that means when you specify a contract, right? When you say contract A, and the very first slot you say U INT A, what happens to the compiled code as you reference A throughout it? Well it actually translate that to say, storage slot zero.
[00:01:27] That's all it does. That is why, when we called contract A via B, and it had variable A versus our B, the ordering was the same. Hence also my surprise that we were able to call again after setting over our own memory, it theoretically should have set over our own memory.
[00:01:49] So this is what happened right here, is that we can set slot A, so slot or slot zero. So that means long as our variables are ordered the same way, all of our contracts will be pointing to the same slots. I wanna make sure I get this stuff, okay, good.
[00:02:08] I was making sure my notes don't lead me anywhere else. All right, so let's think about something. Remember how I kept talking about, you'd understand why storage arrays can get pushed to. Well, when you do a storage array, say you do like array, it's a U INT array.
[00:02:27] What happens is it goes to the next slot down, wherever that slot is, say one. And this slot is used to store its length. And then index zero goes through a magical little formula. It goes through its slot indexed cacked along with the index into the array. So it appears somewhere magically in between this gigantic list of items.
[00:02:56] Which means it knows its length, so we can iterate it. And then it goes through a magical formula to figure out each one of its slotting. So you're thinking well wanna collide. Well once again, that space is so big that the probability of colliding is so very, very small.
[00:03:10] It's like flying through an asteroid field. I know on the movies, it's super awesome and you're dodging stuff. But in reality, you could fly through the asteroid field for your entire lifetime around our galaxy, and you'd never actually hit an asteroid. It's very boring, it's very sad, very on Han solo like.
[00:03:24] And so the exact same thing happens with mappings. Remember I said you'd understand why mappings work the way they do. I think everybody now understands exactly how they work, right? Mappings simply use their slot index, hashed in with the key that's created to point to somewhere magically inside of this big Gigantic place for each key.
[00:03:49] Therefore it doesn't know what its keys are. It doesn't know anything about it. It's just a math formula for offsetting into this gigantic slot array. Hence the reason you cannot for each. This makes perfect sense now, doesn't it? This is just like, yeah, it's kind of it's almost sad because it becomes so less magical all of a sudden.
[00:04:09] Because at first it's just like well how does it not know its own keys. Now it's like okay, it's just math, boring math doing boring math things. All right, so that's that, so let's kind of go over some examples. It will be a little bit more clear if I can kind of program the examples, and then show you the memory.
[00:04:28] So let's keep on using these things. So what I'm gonna do, is I'm gonna go like this. And let's create C and D, and I'm gonna go like this, B equals four, C equals 0x45, D equals how about a 255, why not? There we go, so now we have these numbers, and they're all stored.
[00:04:57] Well, technically you can't do that with D, D is a U INT, you can't store that big. So I should probably store something like 1F, how's that? Or even better levity five, our friend LIC Bachman taught us about levity five. We should at least use it once in this talk, so there we go.
[00:05:11] We have these values stored. So how do you think these things are aligned in slot memory? Well, I can tell you the first one is 256 bits wide, so it's probably in slot 0. But what about the rest? How should they appear? Well, what I find to be the easiest way to do things is we can play investigative journalists.
[00:05:29] So let's go in here, and let's do the following. Let's go like this, console.log, actually let's create a little async function to make it easy, async function, print storage. And we're gonna take in a contract, we're gonna take in a name, and we're gonna take in count, there we go.
[00:05:49] I'm gonna go for let I equals zero, I has to be less than count plus plus I, there we go. Then I'm gonna go console.log, name, I, and then go await, and we got to go like this, ethers provider get storage at contract address I. So I want to be able to get the storage at index I of this address.
[00:06:19] So that's all we're doing right there pretty straightforward. So now let's go here, and go await print storage of B three. So we're gonna print the first three items inside of B3. Now let's also give it the name of B, just in case we start printing A which we will.
[00:06:41] So now we have this nice little function, we can print it out. Let's see what is stored right away. So I'm gonna just simply launch this. So let's go over what we see. This may be a little unusual, the first one contains our four, right? Because it was 256 bits.
[00:06:56] What is the next one containing right here?
>> Use address?
>> No, it contains 45, 45 of course was what C was. Because C appears before the address, D appears before the address of levity five. So if we go back here and look, there it is, levity five.
[00:07:19] And if we look right here 3690, we can now jump back to this. And let's see if we can see contract A deployment of this. What is its address? 3690 there we go, we can see contract A's address still in there. So, it tightly packed these things as tight as possible into your storage slots.
[00:07:39] That's why I said, it's an unknown cost when it comes to how should I write these? Should I write it as a full UINT or should I do a U and INT? Well, U and INT has to go into its slot storage, do the offset, bring it over, shift out everything else, and go here's your U and INT.
[00:07:57] Because it could tightly pack stuff, which also means, if I simply jump in here, and take this thing, and put it right here. Notice we went from two bytes of storage or two slots of storage, into three slots of storage. Please I just split a storage slot and Twain.
[00:08:15] Here's, what is it C and D? Here's B, here's the address of A, because the address of A cannot be stored along with a UINT, because that's 256 bits. So it stores it according to ordering, and tries to tightly packet as much as possible. Now I think we're gonna have to take a break, we have a little snapping over there.
[00:08:36] Everyone take a moment, it's about to get really intense, and I'd like to really kind of finish this off. And then we're gonna do a quick diamond deploy, we're gonna call it a day