Skip to content
by Unity Nodes
NEAR Protocol

Rust: NEAR collections, U128, build, deploy, call/view with NEAR CLI

about 23:28 long

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

About this video

We take a tour starting from a StackOverflow question and delve into a few topics. Like why we shouldn't use Rust's HashMap data structure, what NEAR Collections are available, and how to use them. We'll also cover not-great behavior that can occur when sending large numbers as parameters, and the need to use U64 or U128, which are different than u64 and u128.

StackOverflow question: https://stackoverflow.com/questions/6...

Examples: near.dev

Rust contract demonstrating U128 issues: https://github.com/mikedotexe/near-de...

The project shown in this video: https://github.com/mikedotexe/near-st...

Install NEAR CLI: https://docs.near.org/docs/developmen...

All the NEAR Collections for Rust: https://docs.rs/near-sdk/2.0.0/near_s...

If you don't have an account, go to wallet.testnet.near.org

CLI Commands: near create-account 64378144.stackoverflow.testnet --masterAccount stackoverflow.testnet near deploy --accountId 64378144.stackoverflow.testnet --wasmFile res/veggie_example.wasm --initFunction 'new' --initArgs '{}' near call 64378144.stackoverflow.testnet add_veggie_taste '{"upc": "679508051007679508", "taste": "just alright"}' --accountId 64378144.stackoverflow.testnet near view 64378144.stackoverflow.testnet get_taste '{"upc": "679508051007679508"}'

Then: (will fail) near call 64378144.stackoverflow.testnet perish_all '{}' --accountId mike.testnet

(would succeed if you had the keys) near call 64378144.stackoverflow.testnet perish_all '{}' --accountId 64378144.stackoverflow.testnet

Make minor change not affecting state, then deploy with: near deploy --accountId 64378144.stackoverflow.testnet --wasmFile res/veggie_example.wasm

Add a veggie from another account:

near call 64378144.stackoverflow.testnet add_veggie_taste '{"upc": "199508051007679508", "taste": "ono"}' --accountId mike.testnet near view 64378144.stackoverflow.testnet get_taste '{"upc": "199508051007679508"}'

I'm on Twitter at @mikedotexe

Follow the latest from NEAR Protocol on,

Website: near.org Discord: near.ai/discord Medium: near.ai/medium Twitter: near.ai/twitter GitHub: near.ai/github

Transcript

3,802 words

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

  1. 0:00

    hey folks i saw a cool stack overflow question come in recently i thought it'd be good to make a video uh this touches upon a few aspects of writing a rust smart contract on nir so here we have it the title is why can't i read this hash map in a near contract at the top it says i have a near smart contract that keeps a hashmap of veggie records my most basic accessor get veggie which looks up and returns one veggie record um is passing unit tests but

  2. 0:32

    fails in the actual like deployed contract it panics with veggie does not exist i'm just kind of glancing at this this isn't the entire contract but this shows kind of what's going on that there's going to be a veggies hash map apparently in here if you scroll down a little bit it looks like they are using near cli right here where it says near call account id and this is an environment variable for their account id and environment variable for that the

  3. 1:01

    contract name the method is git veggie which we see up here and then you pass in the parameters here so we have vid and we notice that this is a very large number um so a couple of things are going to be useful here to point out we can cover why near collections are important and why it's not usually a good idea to use hashmap and we can also talk about how to deal with passing large numbers um as parameters as we see we are trying to do here

  4. 1:32

    basic fact that like hash map is not something that we typically want to see here like i i like to think of it in the example of um basic attention token i'm a huge fan of brave and bat and that's an example of a erc20 token on ethereum that probably has like many millions of keys and values associated with it this person has a has 19 bat this person has four bat et cetera um when it comes to the blockchain hashmaps will actually

  5. 2:03

    go into this storage and load the entire data structure into memory so think about that for something like basic attention token you have millions and millions of like rows essentially if you want to say like that key values there'd be no way you could actually load that into the memory of smart contracts so we have at near near collections there are a few different ones um but these will actually have a

  6. 2:27

    different kind of data structure where you do not um bring the entire thing into memory it's much more specialized let's take a look at a simple rust contract that i made after looking at this stack overflow question i can close this for now so typically the way that it's laid out is you have your cargo tommel which is similar to like package.json but for for rust inside of a source folder you have your lib.rs

  7. 2:57

    and um a lot of our examples that we have at like near.dev we'll just have all the code in into one file the lib.rs you can definitely break it out but it kind of makes it easier for for simple examples so let's just like go through this little by little some of this is boilerplate some of this we can we can talk about a bit more so at the top here we're going to have some very basic uh imports near by and gen we're going to need to have for these data structures that we want to have stored

  8. 3:28

    on chain n is important for things like logging and figuring out you know who is actually calling this who is the signer who is the predecessor of this particular transaction um borsch is basically better than json serialization and this is like a huge improvement in terms of getting information to and from uh storage so we will also be having a macro above some of our data structures for this and then

  9. 3:59

    this is where we are doing something that's different than hash map like this um original poster is talking about we have specialized collections as i mentioned this one is called tree map uh if you're a computer science person that's an avl tree and actually this was a bounty that a community member uh took up so that that is kind of cool it's working great and then the lastly and this gets to kind of the second part of this

  10. 4:24

    stack overflow question with very large numbers and there is a way to handle that but i think we'll kind of wait a little bit for that so essentially we can skip over this a bit this is like smart contracts in the current state that they are don't really need to have um much in terms of like memory allocation so we have this wee alec thing that can basically be copy pasted and essentially all smart contracts you can kind of skip over that we're talking about veggies here for some particular reason which is cool

  11. 4:55

    so i have a kind of optional thing just for fun that's a type upc and it says almost like an alias where i'm saying like if i use this type upc then you can consider it a u128 notice already this is a lowercase u this uppercase u uh that's important so typically when building uh smart contracts in rust on near um it's going to be like a struct that you are going to be having and then you're going to have like an implementation um definitions inside of this thing that you just created so here we're saying like we are

  12. 5:32

    making this struct called pro produce and it's just got one field that is called veggies underscore taste and it is a tree map of a upc um to how tasty we find this thing obviously this is a kind of contrived example but i think this would go a long way this is i'm going to say this isn't also kind of boilerplate this is just good practice when making smart contracts to make sure that the contract initialization happens uh in the same vein i won't spend too

  13. 6:03

    much time on this but this is uh an initialization function uh inside of our implementation that's the first definition inside here this just makes sure that it hasn't already been initialized and it will set up the data structure in here actually this is a important part that i i could mention so when we have these specialized data structures like tree map and you create a new one um this looks kind of weird what the heck is like b v to vec all of that so essentially

  14. 6:36

    the way storage is gonna work uh internally is there's going to be like keys inside of there and there's going to be a prefix so that you don't mistake one key for another in this particular case we just have one field we could have multiple fields we could have a string here a second tree map you know a bunch of different items in here and to differentiate those you want to have a prefix so this if you look in the like literal

  15. 7:00

    storage which is possible doing some kind of lower level rpc calls you will see that this is actually prefixed with letter v so generally when using these data structures it's you know if you want to be super efficient and min max this then you can have this just be one letter just to make sure that the storage is taking up as little space as possible okay let's just keep going down through this so we're gonna have some

  16. 7:24

    super basic functions three functions i believe add veggie taste get taste and perish all so here we go we have add veggie taste and this is going to be um actually mutating state so we need to have mute here when we do get taste you'll notice that there is no mute because this is simply just like viewing what's what's on there um and here we have our our upc is taking in as a pram this is capital u128

  17. 7:55

    and the taste is going to be a string so won't go too much into it here except for if you're trying to add something that's already there it'll say sorry we've already got this um otherwise it'll it'll insert it you notice the end panic is kind of like you know throwing an error and execution will stop and it won't get to this point um get taste is seeing if there is already that particular upc in there and then it will log a message using n log here

  18. 8:26

    and it will actually return the uh stored taste in there as a string so as we can see this function is returning a string there is kind of like an implied return in rust same thing goes down here and then parish will basically check to make sure that this contract that we have deployed to is the same as the predecessor account id which is basically saying the person who called this contract needs to have the key to this contract um so

  19. 8:58

    you can do this different ways but this is essentially almost like a guard to make sure that not everyone can call this parish all function down here we have some some tests these are unit tests there are a couple of different kinds of tests i'll have a link here in the description about the various kinds of tests some argue that simulation tests are probably the most useful but unit tests are especially useful when it comes to making sure that all the business logic

  20. 9:28

    inside of your contract works um these do not work for like cross-contract calls but they're a great way to like test that you're you're doing things right essentially so in normal rust contract development like if you follow the official rest guide great guide it walks you through some simple examples and you'll have an entry point like a main function we don't have that in in blockchain so

  21. 9:53

    tests like this unit tests are a great way to like quickly like run tests against your code and in here this is very much boilerplate above what you just see i have one simple test and this is all inside of a repo you can get you will see that here we are creating a variable called cucumber upc and we are wrapping it so we have a capital u 128 of this very large number and we are saying that this cucumber it

  22. 10:24

    tastes so-so so we have loaded the contract and we're calling this function saying that cucumbers taste so-so and we test to make sure that it all uh worked accordingly and it passes you run this command with cargo tests no capture inside of this directory that will do what you want okay so we've covered a little bit of collections uh in terms of us using the tree map another thing to note is that there are a bunch of awesome

  23. 10:55

    other collections here um i have a link right there is a kind of different syntax if you want to load a bunch of them it's very strange to just have one field on your struct so it's likely that you'll use other ones here are some other options that you may consider along this and again like look look at the different collections and the rust crate documentation so that was about the collections and essentially i would probably go as far as to say never use hash maps um i can't think of

  24. 11:26

    a great time to to do that i i suppose if you're having some kind of like five player game and it's always gonna be each team has five players and you know it's capped out at that then maybe it's not a big deal to to load that into memory but uh it's recommended to use the the near collections that we just talked about so the second thing was this large number and it looks like this particular poster

  25. 11:51

    um answered already saying caution javascript slightly truncates integers of more than 53 bits and goes over how they ran into this so that is true and technically what this is is that json serialization does not have that in the standard i actually have another link that i will have in the description that is a quick demonstration of this in action i won't go into that much detail except for to say this is a very simple rest contract defined of small underscore u so this is as simple

  26. 12:30

    as it gets we are taking in a regular lower case u 128 and we're just saying hey log what we got i received this value super duper simple right so let's try calling that this command that i'm going to be typing out is for near cli so we're saying near view on the contract debug.mike.testnet call the method small u and then we're passing in um the parameter here we go like a kind of a large timestamp here right

  27. 13:04

    so let's do this and i received um okay looks the same that looks the same nope it is not the same actually um this has 800 this one that we gave has 700 so this is a great example of how you cannot do this you actually need to use the capital u 128 which means that as you're passing it in it needs to be as a string so if we had this number right here surrounded in double quotes

  28. 13:35

    then that can be seen as almost a string as it's getting passed from you into the blockchain from there you can convert it to an actual lowercase u128 if that makes sense this this does affect numbers that require more than 53 bits so in that case two there's a there's a note that i have here we're using u128 um there is also u64 because this is you know more than 53.

  29. 14:04

    so those are two items that were kind of problematic with with what's going on we'll use the near collections and realize that if you're passing in large numbers you're going to want to basically treat them as as strings so given that knowledge i think that this person can get unblocked here how to actually like build and deploy this we've created a build.sh shell script and it's going to do these these two things gonna be running this command cargo build and then we're gonna have this target wasn't 32 unknown unknown

  30. 14:38

    um we'll have a link to what that is um then we're saying yeah this is gonna be a release this will create a compiled wasm file in a kind of deeply nested folder and so typically we just say hey you know what just copy that and put it somewhere easier copy and put it right here so that's what we're doing with this with this build so let's just go ahead and do this the way that you get a test net account is you go to wallet.testnet.ner.org

  31. 15:11

    and i did that and lucky me stackoverflow.testnet was was available and there is a very interesting concept that i will not go into fully here this would be another great video but nir has sub accounts and so what i'm going to do now is create a sub account for this particular stack overflow question the stack overflow question um in the url is this so i'm going to say hey near create an account called 643 blah blah blah dot stackoverflow.testnet

  32. 15:44

    from the master account that i have stackoverflow.testnet so when i when i hit enter it's going to look in a directory inside of my home directory called dot near dash credentials it's going to find that indeed i have a private key to this stack overflow.testnet it's going to say yeah you are allowed to do that so i hit enter it has now created it so now i control this account um and the key for stackoverflow.testnet

  33. 16:16

    has nothing to do with this account anymore i i cannot like delete this um subaccount using the key from the master account so it's its own thing but no one else can create this account for me run the build script build.sh it has already done it very quickly and so here what is going to happen is we are going to deploy this file with a kind of a long command near deploy to the account id the one we just created where's the wasm file the wasm file is in this folder

  34. 16:54

    called res veggie example.wasm and notice how we had these initialization pieces where we want to make sure that this contract is initialized right here and then the init function right here the init function i decided to call new so we are saying well this is the first time we're deploying it so we might as well like in the same motion let's call the inet function called new and in this particular case we have no parameters so we're just going to pass

  35. 17:25

    this empty object it's talking to the rpc.testnbc and it's done if you want to click on this you can see that it is actually this is our near explorer and it will say succeeded this is kind of like ether scan so back here okay so we've deployed it now let's call this function adding a veggie taste near call because we're mutating because before it was near view sometimes near call the same account function name add veggie taste and then here we

  36. 18:11

    have two parameters uh upc notice this big number is surrounded in double quotes the taste is just all right i'm saying cucumbers just all right and then the last one here is saying we are calling this from the account well it's actually the same account in this particular case okay it's done okay let's try to get that and since this is also just a view method it's near view get taste and then you pass there's only

  37. 18:44

    one parameter that same upc and it says this veggie is pretty just all right this veggie is pretty just all right so there we have it um now in this particular case when we were adding the veggie taste we were calling from the same account but you know near is permissionless so this would be an example where we are calling uh a function from a different account so we are trying to call the perishall

  38. 19:15

    function from mic.testnet which i also own so let's just try that out and see what happens panicked blah blah blah this method must be a call by the implied contract owner um this is this error message right here where we were asserting that the current account id is the the predecessor account id i called it with mic.testnet that is not equal to the subaccount that we just created so it throws this error and it did not clear it so we can

  39. 19:48

    actually make sure of that by saying what is the taste yep we still have that stored okay but we could actually perish that by calling with the contract that we created this is a quick test here okay now if we try to go and do the same thing see how cucumbers taste says no veggie found because we've cleared it okay great so the other thing that may happen here is you are working on this you're in a hackathon or you're just you're building a real dap a real project

  40. 20:27

    and you say change this to have an exclamation point right here you can go through and you would say you know build and then you could say deploy it that that new change so you run this this time we did not have the init function flags so you can do this you can deploy to that same account and essentially overwrite it and everything will be just fine however there is something that happens when you try to have the state change then that will cause issues so if i were

  41. 21:07

    to create another one of these so if i were to have this and i can't have it be v i'm going to have it be z because it has to be a different prefix right let's try building it cool deploy it seems like everything's okay um but it's not so if i try to near view this then it's going to have a big error and if i were to scroll up a bunch and it would be kind of clunky to do on video it's basically saying that there's a state mismatch so you

  42. 21:51

    cannot be changing like the state variables like this and in that case what you would have to do is near delete and we are going to be like deleting this and giving all the leftover near that's in that account to the original stackoverflow.testnet and then you'd have to recreate it and then let's say we deploy again uh now that it's basically completely reset this time we will deploy with the init function and init args since it has not been initialized yet

  43. 22:36

    in this essentially brand new account done deploying and initializing even though there's obviously nothing in here we're going to call the same call near view this is the same one that gave us that horrible error before and it's going to say no veggie found so this is an important thing to to realize is if you're going to be having your contracts be very upgradable um that you can make changes like adding an exclamation

  44. 23:02

    mark inside of functions you can actually add new methods here too but you cannot be messing with how the state needs to be otherwise you will have to delete and recreate it so that is kind of an overkill on how you use nir and how you would solve this problem and how you would you know build deploy and make this whole thing work uh hopefully that was helpful we're looking forward to making more

  45. 23:28

    videos like this and have these as resources to give to the community so yeah thank you for watching