How to set a static field in a NEAR smart contract? - rust

I'm working on a smart contract for escrow. In it there'll be the owner who'll supposed to be set once -- during deploying a contract.
How can this be implemented in NEAR, though?
A simplified piece of code:
#[near_bindgen]
#[derive(BorshDeserialize, BorshSerialize)]
pub struct Escrow {
pub owner_id: AccountId,
pub user1_id: AccountId,
pub user2_id: AccountId,
pub amount: Balance,
}
#[near_bindgen]
impl Escrow {
#[init]
#[private]
pub fn init(&self, owner_id: AccountId) -> Self {
assert!(!env::state_exists(), "Already initialized");
self.owner_id = env::signer_account_id(); //??? instance variable ???
}
//...........
}
self.owner_id is an instance variable. Therefore, it'd be different for each new client who uses the contract, and therefore would require initialization again, and again, each time?
In the ordinary Rust code this variable would be static, const or a function. But here it has to be initialized only once and for all, and yet be identical for all the instance of Escrow.
How would this be implemented in NEAR?
Is this owner_id = env::signer_account_id(); a correct way to refer to the address who's deploying a contract?

near-sdk-rs turns the contract instance (Escrow struct) into a singleton on a blockchain, so whatever you save to self will be then stored in the key-value storage of your contract, so it is "static". init method should not take self as a parameter, it should construct the instance (return Self), and it is expected to be called only once. You initialize your contract once, and then define other methods that could update &mut self. near-sdk-rs documentation goes into details about that.

Related

How can I store variables in traits so that it can be used in other methods on trait?

I have several objects in my code that have common functionality. These objects act essentially like services where they have a life-time (controlled by start/stop) and perform work until their life-time ends. I am in the process of trying to refactor my code to reduce duplication but getting stuck.
At a high level, my objects all have the code below implemented in them.
impl SomeObject {
fn start(&self) {
// starts a new thread.
// stores the 'JoinHandle' so thread can be joined later.
}
fn do_work(&self) {
// perform work in the context of the new thread.
}
fn stop(&self) {
// interrupts the work that this object is doing.
// stops the thread.
}
}
Essentially, these objects act like "services" so in order to refactor, my first thought was that I should create a trait called "service" as shown below.
trait Service {
fn start(&self) {}
fn do_work(&self);
fn stop(&self) {}
}
Then, I can just update my objects to each implement the "Service" trait. The issue that I am having though, is that since traits are not allowed to have fields/properties, I am not sure how I can go about saving the 'JoinHandle' in the trait so that I can use it in the other methods.
Is there an idiomatic way to handle this problem in Rust?
tldr; how can I save variables in a trait so that they can be re-used in different trait methods?
Edit:
Here is the solution I settled on. Any feedback is appreciated.
extern crate log;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use std::thread::JoinHandle;
pub struct Context {
name: String,
thread_join_handle: JoinHandle<()>,
is_thread_running: Arc<AtomicBool>,
}
pub trait Service {
fn start(&self, name: String) -> Context {
log::trace!("starting service, name=[{}]", name);
let is_thread_running = Arc::new(AtomicBool::new(true));
let cloned_is_thread_running = is_thread_running.clone();
let thread_join_handle = std::thread::spawn(move || loop {
while cloned_is_thread_running.load(Ordering::SeqCst) {
Self::do_work();
}
});
log::trace!("started service, name=[{}]", name);
return Context {
name: name,
thread_join_handle: thread_join_handle,
is_thread_running: is_thread_running,
};
}
fn stop(context: Context) {
log::trace!("stopping service, name=[{}]", context.name);
context.is_thread_running.store(false, Ordering::SeqCst);
context
.thread_join_handle
.join()
.expect("joining service thread");
log::trace!("stopped service, name=[{}]", context.name);
}
fn do_work();
}
I think you just need to save your JoinHandle in the struct's state itself, then the other methods can access it as well because they all get all the struct's data passed to them already.
struct SomeObject {
join_handle: JoinHandle;
}
impl Service for SomeObject {
fn start(&mut self) {
// starts a new thread.
// stores the 'JoinHandle' so thread can be joined later.
self.join_handle = what_ever_you_wanted_to_set //Store it here like this
}
fn do_work(&self) {
// perform work in the context of the new thread.
}
fn stop(&self) {
// interrupts the work that this object is doing.
// stops the thread.
}
}
Hopefully that works for you.
Depending on how you're using the trait, you could restructure your code and make it so start returns a JoinHandle and the other functions take the join handle as input
trait Service {
fn start(&self) -> JoinHandle;
fn do_work(&self, handle: &mut JoinHandle);
fn stop(&self, handle: JoinHandle);
}
(maybe with different function arguments depending on what you need). this way you could probably cut down on duplicate code by putting all the code that handles the handles (haha) outside of the structs themselves and makes it more generic. If you want the structs the use the JoinHandle outside of this trait, I'd say it's best to just do what Equinox suggested and just make it a field.

Rust: Implement Hash/Eq

What is the simplest way to implement Hash/Eq on a struct so that two different instances with the same properties will be unequal?
Consider the following struct:
struct Person {
name: String,
}
What is the simplest way to implement Hash/Eq so that two different people are NOT equal, even if they have the same name? Is the only way to Box<> something?
You don't. Rust isn't Java. Two identical Person instances are represented in memory by the exact same sequence of bits and are, thus, indistinguishable. And Box won't even save you here: The Eq instance for Box delegates to the contained value.
The only way to compare for pointer equality in the way you're describing is with std::ptr::eq, using std::pin to ensure that the pointers don't change. But, and I cannot emphasize this enough, this is the wrong approach. You don't want this kind of equality. It doesn't make sense in Rust. If Person { name: "Joe" } and Person { name: "Joe" } are meant to be distinct objects, then your data structure is poorly designed. It's your job to add a distinguishing field. If these are backed by a database, you might use
struct Person {
primary_key: u64,
name: String,
}
Or maybe everybody has a hexadecimal employee ID.
struct Person {
employee_id: String,
name: String,
}
The point is that the data structure itself (Person in our example) encodes everything about it. Rust eschews the Java-esque notion that every object intrinsically has an identity distinct from all others, in favor of your data explicitly describing itself to the world.
As pointed out by #SilvioMayolo, value "identity" is not a thing in Rust because Rust's values are not heap-allocated by default. While you can take an address of any value, you can't use it as to represent identity the address changes every time the value is moved to a different variable, passed to a function, or inserted in a container. You can make the address stable by heap-allocating the value, but that requires an allocation when the value is created, and an extra dereference on every access.
For values that heap-allocate their content, such as Strings, you could use the address of the contents to represent identity, as shown in #Smitop's answer. But that is also not a good representation of identity because it changes any time the string re-allocates, e.g. if you append some data to it. If you never plan to grow your strings, then that option will work well. Otherwise, you must use something else.
In general, instead of using an address to represent identity, you can explicitly track the identity as part of the object. Nothing stops you from adding a field representing identity, and assigning it in the constructor:
static NEXT_ID: AtomicU64 = AtomicU64::new(0);
pub struct Person {
id: u64,
name: String,
}
impl Person {
/// Create a new unique person.
pub fn new(name: String) -> Self {
Person {
id: NEXT_ID.fetch_add(1, Ordering::Relaxed),
name,
}
}
/// Identity of a `Person`.
///
/// Two persons with the same name will still have different identities.
pub fn id(&self) -> u64 {
self.id
}
}
Then you can implement Hash and Eq to use this identity:
impl Hash for Person {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.id.hash(state);
}
}
impl Eq for Person {}
impl PartialEq for Person {
fn eq(&self, other: &Self) -> bool {
self.id == other.id
}
}
// We can't #[derive(Clone)] because that would clone the id, and we
// want to generate a new one instead.
impl Clone for Person {
fn clone(&self) -> Person {
Person::new(self.name.clone())
}
}
Playground
You can compare the String pointers instead of the actual String data. Of course, this method has issue that the Hash of a person will change every execution, but you can't really get around that since there's no extra data in a Person:
use std::{cmp, hash};
impl cmp::PartialEq for Person {
fn eq(&self, other: &Self) -> bool {
self.name.as_ptr() == other.name.as_ptr()
}
}
impl cmp::Eq for Person {}
impl hash::Hash for Person {
fn hash<H: hash::Hasher>(&self, state: &mut H) {
self.name.as_ptr().hash(state);
}
}

How can I simultaneously access data from and call a method from a struct?

For my first project I wanted to create a terminal implementation of Monopoly. I have created a Card, Player, and App structs. Originally my plan was to create an array inside the App struct holding a list of cards which I could then randomly select and run an execute() method on, which would push a log to the logs field of the App. What I thought would be best was this:
pub struct Card {
pub group: u8,
pub name: String,
pub id: u8,
}
impl Card {
pub fn new(group: u8, name: String, id: u8) -> Card {
Card { group, name, id }
}
pub fn execute(self, app: &mut App) {
match self.id {
1 => {
app.players[app.current_player].index = 24;
app.push_log("this works".to_string(), "LOG: ".to_string());
}
_ => {}
}
}
}
pub struct Player<'a> {
pub name: &'a str,
pub money: u64,
pub index: u8,
pub piece: char,
pub properties: Vec<u8>,
pub goojf: u8, // get out of jail freeh
}
impl<'a> Player<'a> {
pub fn new(name: &'a str, piece: char) -> Player<'a> {
Player {
name,
money: 1500,
index: 0,
piece,
properties: Vec::new(),
goojf: 0,
}
}
}
pub struct App<'a> {
pub cards: [Card; 1],
pub logs: Vec<(String, String)>,
pub players: Vec<Player<'a>>,
pub current_player: usize,
}
impl<'a> App<'a> {
pub fn new() -> App<'a> {
App {
cards: [Card::new(
11,
"Take a ride on the Penn. Railroad!".to_string(),
0,
)],
logs: vec![(
String::from("You've begun a game!"),
String::from("BEGIN!:"),
)],
players: vec![Player::new("Joe", '#')],
current_player: 0,
}
}
pub fn draw_card(&mut self) {
if self.players[self.current_player].index == 2
|| self.players[self.current_player].index == 17
|| self.players[self.current_player].index == 33
{
self.cards[0].execute(self);
}
}
pub fn push_log(&mut self, message: String, status: String) {
self.logs.push((message, status));
}
}
fn main() {}
However this code throws the following error:
error[E0507]: cannot move out of `self.cards[_]` which is behind a mutable reference
--> src/main.rs:76:13
|
76 | self.cards[0].execute(self);
| ^^^^^^^^^^^^^ move occurs because `self.cards[_]` has type `Card`, which does not implement the `Copy` trait
I managed to fix this error by simply declaring the array of cards in the method itself, however, this seem to be pretty brute and not at all efficient, especially since other methods in my program depend on cards. How could I just refer to a single array of cards for all of my methods implemented in App or elsewhere?
As others have pointed out, Card::execute() needs to take &self instead of self, but then you run into the borrow checker issue, which I'll spend the rest of this answer discussing.
It may seem odd, but Rust is actually protecting you here. The borrow checker does not look into functions to see what they do, so it has no idea that Card::execute() won't do something to invalidate the referenced passed as the first argument. For example, if App::cards was a vector instead of an array, it could clear the vector.
Something that could actually practically happen here to cause undefined behavior would be if Card::execute() took a string slice from self.name and then cleared the card's name attribute through the mutable reference to app. None of these actions would be prohibited, and you'd be left with an invalid reference to a string slice. This is why the borrow checker isn't letting you make this method call, and this is exactly the kind of accident that Rust is designed to prevent.
There's a few ways around this. One option is to only pass the pieces of the App value needed to complete the task. You can borrow different parts of the same value. The problem here is that the reborrow of self overlaps with the borrow self.cards[0]. Passing each field separately isn't very ergonomic though, as in this case you'll wind up having to pass a reference to pretty much everything else on App.
It looks like the Card values don't actually contain any game state, and are used as data for the game engine. If this is the case, then the cards can live outside of App, like so:
pub struct App<'a> {
// Changed to an unowned slice.
pub cards: &'a [Card],
pub logs: Vec<(String, String)>,
pub players: Vec<Player<'a>>,
pub current_player: usize,
}
impl<'a> App<'a> {
pub fn new(cards: &'a [Card]) -> App<'a> {
App {
cards,
// ...
Then in your main() you can initialize the data and borrow it:
fn main() {
let cards: [Card; 1] = [Card::new(
11,
"Take a ride on the Penn. Railroad!".to_string(),
0,
)];
let app = App::new(&cards);
}
This solves the compilation problem. I'd suggest making other changes, as well:
App should probably be renamed GameState or something to emphasize that this struct should contain only mutable game state, and no immutable reference data.
Player's name field should probably be an owned String instead of an unowned &str, otherwise some other entity in the program will need to own a string slice for the duration of the program so that Player can borrow it.
Does a card need to be able to mutate the cards in self? If you know that execute will not need access to cards, the easiest solution is to split App into further structs so you can better limit the access of the function.
Unless there is another layer to your program that interacts with App as a singular object, requiring everything be in a single struct to perform operations will likely only constrain your code. If possible it is better to split it into its core components so you can be more selective when sharing references and avoid needing to make so many fields pub.
Here is a rough example:
pub struct GameState<'a> {
pub players: Vec<Player<'a>>,
pub current_player: usize,
}
/// You may want to look into using https://crates.io/crates/log instead to make logging easier.
pub struct Logs {
entries: Vec<(String, String)>,
}
impl Logs {
/// Use ToOwned so you can use both both &str and String
pub fn push<S: ToOwned<String>>(&mut self, message: S, status: S) {
self.entries.push((message.to_owned(), status.to_owned()));
}
}
pub struct Card {
group: u8,
name: String,
id: u8,
}
impl Card {
pub fn new(group: u8, name: String, id: u8) -> Self {
Card { group, name, id }
}
/// Use &self because there is no reason we need are required to consume the card
pub fn execute(&self, state: &mut GameState, logs: &mut Logs) {
if self.id == 1{
state.players[state.current_player].index = 24;
logs.push("this works", "LOG");
}
}
}
Also as a side note, execute consumes a card when called since it does not take a reference. Since Card does not implement Copy, that would require it be removed from cards so it can be moved.
Misc Tips and Code Review
Using IDs
It looks like you frequently use IDs to distinguish between items. However, I think your code will look cleaner and be easier to write if you used more human readable types. For example, do cards need an ID? Usually it is preferable to define your struct based on how the data is used. Last time I played monopoly, I don't remember picking up a card and referring to the card ID to determine what to do. I would instead recommend defining a Card by how it is used in the came. If I am remembering correctly, each card contains a short message telling the player what to do. Technically a card could consist of just the message, but you can instead make your code a bit cleaner by separating out the action to an enum so actions are not hard coded to the text on the card.
pub struct Card {
text: String,
action: CardAction,
}
// Note: enums which can also hold data, are more commonly referred to as
// "tagged unions" in computer science. It can be a pain to search for them if
// you don't know what they are called.
pub enum CardAction {
ProceedToGo,
GoToJail,
GainOrLoseMoney(i64),
// etc.
}
On a similar note, it looks like you are trying to be memory conscious by using the smallest type required for a given value. I would recommend against this thinking. If a value of 253u8 is equally as invalid as 324234i32, then the smaller type is not doing anything to help you. You might as well use i32/u32 or i64/u64 since most systems will have an easier time operating on these types. The same thing goes for indices and using other integer types instead of usize since choosing to use another type will only give you more work converting it to and from a usize.
Sharing Owned References
Depending on your design philosophy you might want to store a reference to a struct in multiple places. This can be done using a reference counter Rc<T>. Here are some quick examples. Note that these can not be shared between threads.
let property: Rc<Property> = Rc::new(Property::new(/* etc */));
// Holds an owned reference to the same property as property that can be accessed immutably
let ref_to_property: Rc<Property> = property.clone();
// Or if you want interior mutability you can use Rc<RefCell<T>> instead.
let mutable_property = Rc::new(RefCell::new(Property::new(/* etc */)));

How to add new properties to a NEAR Rust smart contract that already has state?

I have a Rust smart contract deployed to NEAR protocol, and now I want to update it and add properties for persistence. But the contract does already have state, and if calling the new version I get the error Cannot deserialize the contract state.
Here's the updated state struct ( where I want to add another HashMap ):
#[near_bindgen]
#[derive(Default, BorshDeserialize, BorshSerialize)]
pub struct RepositoryPermission {
permission: HashMap<String, HashMap<String, Permission>>,
invitations: HashMap<InvitationId, Invitation>, // I want to add this HashMap
}
What is the best way to add new properties for persisting?
Instead of adding the property to the original and already persisted struct, you can create a new struct
const INVITATIONS_KEY: &[u8] = b"INVITATIONS";
#[derive(Default, BorshDeserialize, BorshSerialize)]
pub struct Invitations {
invitations: HashMap<InvitationId, Invitation>
}
and create (private) methods in the contract for deserialize / serialize this in the contract:
fn load_invitations(&self) -> Invitations {
return env::storage_read(INVITATIONS_KEY)
.map(|data| Invitations::try_from_slice(&data).expect("Cannot deserialize the invitations."))
.unwrap_or_default();
}
fn save_invitations(&self, invitations: Invitations) {
env::storage_write(INVITATIONS_KEY, &invitations.try_to_vec().expect("Cannot serialize invitations."));
}

How to offer an API that stores values of different types and can return them with the original type restored?

I want to offer a safe API like below FooManager. It should be able to store arbitrary user-defined values that implement a trait Foo. It should also be able to hand them back later - not as trait object (Box<dyn Foo>) but as the original type (Box<T> where T: Foo). At least conceptually it should be possible to offer this as a safe API, by using generic handles (Handle<T>), see below.
Additional criteria:
The solution should work in stable Rust (internal usage of unsafe blocks is perfectly okay though).
I don't want to modify the trait Foo, as e.g. suggested in How to get a reference to a concrete type from a trait object?. It should work without adding a method as_any(). Reasoning: Foo shouldn't have any knowledge about the fact that it might be stored in containers and be restored to the actual type.
trait Foo {}
struct Handle<T> {
// ...
}
struct FooManager {
// ...
}
impl FooManager {
// A real-world API would complain if the value is already stored.
pub fn keep_foo<T: Foo>(&mut self, foo: Box<T>) -> Handle<T> {
// ...
}
// In a real-world API this would return an `Option`.
pub fn return_foo<T: Foo>(&mut self, handle: Handle<T>) -> Box<T> {
// ...
}
}
I came up with this (Rust Playground) but not sure if there's a better way or if it's safe even. What do you think of that approach?

Resources