A Tour of Web 3: Ethereum & Smart Contracts with Solidity Generating Random Numbers
Transcript from the "Generating Random Numbers" Lesson
>> All right, there we go, beautiful. So we're gonna move on and let's do the next part of this. All right, so this is where things are gonna get a little bit rowdy, okay? So hero should be stored on chain. Yep, we totally have that we have our address to uns right there.
[00:00:13] We should have five stats strength, health, intellect, magic and dexterity. For the sake of this I'm gonna take this, I'm gonna paste it. And I'm gonna switch out around dexterity cuz normally when I've done this in practice, I've always had dexterity right there just so I don't actually screw myself up.
[00:00:33] It just really just take me a moment longer to make sure I've done everything correct. So we're gonna have those right there. And then let's go look at more of our requirements really quickly. The stats need to be randomly generated. So I'm about to hit a very sensitive topic.
[00:00:46] And I think you've created a NFT or have some experience with it. Is a very sensitive topic in the NFT world, which is random number generation. Now for the sake of ours, I'm gonna use a very simple random generation function. I even put it in here because I forget how to do this function.
[00:01:02] But I'm just gonna simply copy it off the website and do this. All this does is it takes in the block difficulty plus the timestamp. Does something called an encode pact which just tightly encodes it into a set of bytes, and then pass it to something called Kecak 256 which generates out 32 byte random number.
[00:01:21] It's a mapping it's kind of like Sha 256. It takes in some input and makes a reliable hash one direction. You can't go both ways you just go one way. And so what we get out of this is we get a random affectively number somewhere between 0 and 2 to the 256 or practically infinity, right?
[00:01:40] That number is effectively infinity and so we have a random number. Now why this isn't something you would ever use in a real NFT is because miners control various information. So what is the block difficulty? That is something that's provided by the mining pool, by the people running the setups.
[00:01:58] What about the timestamp? Any of this could technically be potentially manipulated to get exactly what they want. They could calculate out if I provide them this difficulty with this amount of information or I do any of these items. I will then be able to get out the mint of the perfect most rarity, therefore I win.
[00:02:16] And so there's this thing called chain link VRF verifiably random function that actually has a chain that's dedicated only to generating random functions. It works almost the same way as this, except for you make a request. You get an ID back. You stored the ID plus the person who's currently calling the function.
[00:02:33] Maybe in three minutes later, you'll get an a sync callback with the ID that was given back to you plus a random number that's 256 bits long. And then you can kind of rehydrate and keep on going with your minting process using a random number that was not generated on your chain.
[00:02:51] For the sake of this, we don't need to go that complex. We're just doing something here. So I'm gonna do a very simple random number. I just wanted to mention that cuz I know if I didn't mention that, I'd get flamed by some set of people. Because it's just important to guarantee if you're gonna build these type of loot box type games that you're providing true randomness and no individual can take advantage of the system.
[00:03:12] There we go. Awesome. We now have a random number generator. Fantastic. So our stats of course are on a scale of 1 to 18 we the randomly pick a stat and then generate their amplitude according to the following rules. Staff one goes 18, next one 17, next one 16.
[00:03:29] If you've done advent of code, we're pretty much doing an advent of code problem now at this point. So I'm gonna jump over to the whiteboard and let's solve it first on the Whiteboard. Now remember, it is important to remember that everything cost money. So we have to be careful about what we do when it comes to how much processing.
[00:03:49] So I'm gonna do this. Let's say we could put our five stat classes in here, strength, health, dexterity, intellect, there we go and magic into an array. I could say the length is five, right? And then what I could do is I could generate a random number, take a modulo of my length, and I'd get somewhere between 0 to 4.
[00:04:13] Correct, everyone's familiar with modulo? If for those that aren't, it's the remainder after a division. So, if you divide by 5, the potential remainders are somewhere between 0 and 4. So after doing that, we can then get that index that'll be a random index so we can grab a random stat.
[00:04:29] From there, we can do 13 plus my current length, which is 5to begin with. And then we can modulo that by the random number, right? There we go. We get our modulo random number. Then we're gonna add 1,so we at least have 1 up to 18. There we go.
[00:04:47] And then after the loop is done, we need to make sure we don't randomly reselect that start again. So let's say we randomly selected health. First we admired how straight and beautiful that line is. Then, we're gonna take health, and we're gonna replace it by the length minus 1 item.
[00:05:03] So our algorithm could take m and just write it to here. And so now health has gone from our length and we adjust our length to become 4. So now we have strength, magic, dexterity and intellect remaining to be randomly selected cuz we've already generated out our health item.
[00:05:22] And then of course length now is reduced by 1, so length is 4. So next time we do this, we only have a value between 1 and 17 that is generated. We do it again. We do it again. We do it again. We don't ever touch the length of the array.
[00:05:33] We don't do any sort of expensive operations. We simply are just condensing what we're looking at until we get done. So some of the tricks of working on the blockchain is making sure you're always hyper efficient as you possibly can be about your operations. This is about as efficient as I could make it.
[00:05:50] Without doing something like trading efficiency for storage costs. Storage is pretty expensive. So maybe there's a way I could do some sort of, storage array, that works out, but no, often you're reading and writing from storage. That's super expensive. So we don't wanna do that. So I couldn't come up with the good way other than this.
[00:06:09] So this is kind of my algorithm. I'm sure someone else could come up with better one. One more. My goodness, look at that. I want to make so much NFT money. All right, so let's go back and let's create that algorithm, all right? So this is where things are gonna get a bit tricky and we're gonna have to take a break shortly.
[00:06:24] So I'm gonna put in a bunch of really weird numbers. And then I'm gonna explain why I did those really weird numbers shortly. So first let's create a unt array. And we're gonna call it stats. And this thing is gonna be a new unt array of length 5.
[00:06:40] Then we're gonna go stats, 0 equals 2. Now this is you're probably thinking okay, I don't get what's happening why a 2? Don't worry I'll show you here in a second. Then I'm gonna record a macro because remember that hold them course I told you to take. I'm gonna copy paste this increment that by one increment this one by 5 be done with my macro bam, bam, bam.
[00:07:03] My goodness. Look at how beautiful that was. But I want you to put in these numbers, this is really strange but it's gonna make perfect sense shortly. So it's gonna be 2 increment by 5 one at a time from here on out. Someone did ask in the chat, how is the address number converted to a unt?
[00:07:27] I will explain that here later on when I talk about storage. That's the next section after this. I'll talk all about kind of how mappings work, you'll understand why they don't contain keys. I'll talk about why dynamic arrays exist on storage, and why we can increment or push and pop to a storage array, when we can't do that with one of these static arrays or fixed arrays.
[00:07:49] It will make more sense here shortly. All right, so assuming everyone got this beautiful piece of code. And let's do one more thing, let's go length equals 5, beautiful. And then let's go unt hero equals class and cast that to unt. \now, remember class is a value of 0, 1 or 2 which is gonna be healer or mage healer or barbarian respectively.
[00:08:18] So there we go we've created our hero, this is looking really good, right? Now we need to do that so fun little algorithm. Where we're gonna select each stat, slowly close the window to where we've selected every stat and we've generated every single value of 1 to 18, 1 to 17, 1 to 16,1 to 15 and go through it.
[00:08:36] So now, I'm gonna do my personal favorite loop a do while loop. While length is greater than 0. Now let's see aren't do while is beautiful just makes me warm on the inside. All right so there we go. So now the first step is to randomly select an index with into this funky stat array.
[00:08:55] So I'm gonna go unt position equals of course generate random modulo length, there we go. We now have some random position picked within our stats array. Next, we're gonna need to generate a random value between 1 and whatever position or whatever stat count we're currently doing. So I'm gonna go, value equals generate random, right?
[00:09:22] Modulo by 13 plus the length. Now that obviously first round creates 18, which means I'm generating something between 0 to 17 and then add 1, there we go. Now round 1, that's one day,18 round to 1 to 17 and so forth. So now I need to store this somewhere.
[00:09:40] I will explain this operation, I just realized it's so much easier to do this and then explain it, then simply try to explain it and then do it. So I'm gonna like this hero bitwise or it. I'm gonna take the value, and I'm gonna shift it over by the stats position.
[00:10:00] I know this is probably a fairly weird looking statement. If you've never seen this before, you're like, Well, I got a couple W's couple T's and a few F's that I have to give to you. And I'm going like okay, hold on. Don't worry, you're gonna understand this shortly.
[00:10:14] So now that we've done that, I'm gonna take the length, I'm gonna decrement it by 1. And then of course, I'm gonna do that little fancy shifting method where I don't have to adjust the array. I just simply adjust the length associated with it by doing this stats.position equals stats.length, right?
[00:10:33] It's been adjusted by 1 so loop 1, it becomes four. Then I move the fourth element into the position that I picked. And I'd do it again and again and again and again. And so this is a way to get around it. I don't need to swap the variables because once we've selected it, we do not need it again.
[00:10:50] So I simply just overwrite it with the last element. Now lastly, we have to do one last thing. We have to go addresses to heroes, message shop sender.push hero. There we go. We have now created or we've now inserted the hero we've created into the addresses to heroes.