String attribute set in init method always returns empty string - nearprotocol

I have the following struct with impl:
#[near_bindgen]
#[derive(Default, Serialize, Deserialize, BorshDeserialize, BorshSerialize, Debug)]
pub struct MyStruct {
owner: String
}
#[near_bindgen(init => new)]
impl MyStruct {
fn new() -> Self {
Self {
owner: "bob".to_string()
}
}
fn get_owner(&self) -> String {
return self.owner;
}
}
Then I deploy the contract using near deploy my_contract --masterAccount myAccount
If I call get_owner using near-shell: near call my_contract get_owner --accountId=myAccount It always returns "" instead of the expected "bob".
It seems like the new method might not get called on deployment.

Initializer doesn't automatically get called on deploy. deploy just deploys the code and doesn't call anything on the contract. We should probably add a new method to shell, that does deploy_and_call. But for now just call new manually.
The reason why we don't initialize automatically is that initializer might take additional arguments. You can pass an owner to new method. Here is an example how to use initializer with custom arguments and as well as how to make sure a contract can't be called without initialization:
#[near_bindgen]
#[derive(BorshDeserialize, BorshSerialize)]
pub struct FunToken {
/// AccountID -> Account details.
pub accounts: Map<AccountId, Account>,
/// Total supply of the all token.
pub total_supply: Balance,
}
impl Default for FunToken {
fn default() -> Self {
env::panic(b"Not initialized");
unreachable!();
}
}
#[near_bindgen(init => new)]
impl FunToken {
pub fn new(owner_id: AccountId, total_supply: Balance) -> Self {
let mut ft = Self { accounts: Map::new(b"a".to_vec()), total_supply };
let mut account = ft.get_account(&owner_id);
account.balance = total_supply;
ft.accounts.insert(&owner_id, &account);
ft
}
}
From here: https://github.com/nearprotocol/near-bindgen/blob/master/examples/fun-token/src/lib.rs#L52-L77
Basically it panics during Default call, so non initialized contract can't be called.

Initializer functions are usually used when you need to parametrize the initialization of the contract. If there are no parameters then just implement Default trait:
impl Default for MyStruct {
fn default() -> Self {
Self {
owner: "bob".to_string()
}
}}

Related

How to get the AccountId of the contract instantiated in the contract in Substrate ink

I want to instantiate another contract inside a contract and get the AccountId of that contract.
Can anyone tell me how to do that?
Instantiate SampleContract2 in the add_contract function of SampleContract1.
I want to get the AccountId of the instantiated SampleContract2, manage it in a list, and use the AccountId later to be able to access SmapleContract2.
In the future, I would like to increase the types of contracts, so I would like to use AccountId, which can be used for general purposes, instead of the SmapleContract2 type for the list.
Why does "sample_contract_2.env().account_id()" return the address of SampleContract1?
-- snip --
#[ink(storage)]
pub struct SampleContract1 {
next_id:u128,
account_id_list:Mapping<u128, AccountId>
}
-- snip --
impl SampleContract1 {
#[ink(constructor)]
pub fn new() -> Self {
Self {
account_id_list: Mapping::default(),
next_id:0,
}
}
#[ink(message)]
pub fn add_contract(&mut self ) -> Result<()> {
let sample_contract_2 = SampleContract2::new();
let contract_address = sample_contract_2.env().account_id(); <- ###### Address of SampleContract1 is obtained.
self.token_list.insert(&self.next_id, &contract_address );
self.next_id = self.next_id + 1;
Ok(())
}
Thank you.

How do you pass and handle arguments to a `ChainExtension`?

I have an ink! contract which calls a extension method fetch_random().
// runtime/src/lib.rs
pub struct FetchRandomExtension;
impl ChainExtension<Runtime> for FetchRandomExtension {
fn call<E: Ext>(
func_id: u32,
env: Environment<E, InitState>,
) -> Result<RetVal, DispatchError>
where
<E::T as SysConfig>::AccountId:
UncheckedFrom<<E::T as SysConfig>::Hash> + AsRef<[u8]>,
{
match func_id {
1101 => {
let mut env = env.buf_in_buf_out();
let random_seed = crate::RandomnessCollectiveFlip::random_seed().0;
let random_slice = random_seed.encode();
env.write(&random_slice, false, None).map_err(|_| {
DispatchError::Other("ChainExtension failed to call random")
})?;
}
_ => {
return Err(DispatchError::Other("Unimplemented func_id"))
}
}
Ok(RetVal::Converging(0))
}
fn enabled() -> bool {
true
}
}
// contract/lib.rs
let new_random = self.env().extension().fetch_random()?;
How can can I write the extension handler to receive arguments such as let new_random = self.env().extension().fetch_random(1, "hello", true)?;?
You can have a complete example on GitHub here.
Here's the working code:
#![cfg_attr(not(feature = "std"), no_std)]
use ink_env::Environment;
use ink_lang as ink;
/// This is an example of how ink! contract should
/// call substrate runtime `RandomnessCollectiveFlip::random_seed`.
/// Define the operations to interact with the substrate runtime
#[ink::chain_extension]
pub trait FetchRandom {
type ErrorCode = RandomReadErr;
/// Note: this gives the operation a corresponding `func_id` (1101 in this
case),
/// and the chain-side chain extension will get the `func_id` to do further operations.
#[ink(extension = 1101, returns_result = false)]
fn fetch_random() -> [u8; 32];
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, scale::Encode, scale::Decode)]
#[cfg_attr(feature = "std", derive(scale_info::TypeInfo))]
pub enum RandomReadErr {
FailGetRandomSource,
}
impl ink_env::chain_extension::FromStatusCode for RandomReadErr {
fn from_status_code(status_code: u32) -> Result<(), Self> {
match status_code {
0 => Ok(()),
1 => Err(Self::FailGetRandomSource),
_ => panic!("encountered unknown status code"),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "std", derive(scale_info::TypeInfo))]
pub enum CustomEnvironment {}
impl Environment for CustomEnvironment {
const MAX_EVENT_TOPICS: usize =
<ink_env::DefaultEnvironment as Environment>::MAX_EVENT_TOPICS;
type AccountId = <ink_env::DefaultEnvironment as Environment>::AccountId;
type Balance = <ink_env::DefaultEnvironment as Environment>::Balance;
type Hash = <ink_env::DefaultEnvironment as Environment>::Hash;
type BlockNumber = <ink_env::DefaultEnvironment as Environment>::BlockNumber;
type Timestamp = <ink_env::DefaultEnvironment as Environment>::Timestamp;
type RentFraction = <ink_env::DefaultEnvironment as Environment>::RentFraction;
type ChainExtension = FetchRandom;
}
#[ink::contract(env = crate::CustomEnvironment)]
mod rand_extension {
use super::RandomReadErr;
/// Defines the storage of your contract.
/// Here we store the random seed fetched from the chain
#[ink(storage)]
pub struct RandExtension {
/// Stores a single `bool` value on the storage.
value: [u8; 32],
}
#[ink(event)]
pub struct RandomUpdated {
#[ink(topic)]
new: [u8; 32],
}
impl RandExtension {
/// Constructor that initializes the `bool` value to the given `init_value`.
#[ink(constructor)]
pub fn new(init_value: [u8; 32]) -> Self {
Self { value: init_value }
}
/// Constructor that initializes the `bool` value to `false`.
///
/// Constructors can delegate to other constructors.
#[ink(constructor)]
pub fn default() -> Self {
Self::new(Default::default())
}
/// update the value from runtime random source
#[ink(message)]
pub fn update(&mut self) -> Result<(), RandomReadErr> {
// Get the on-chain random seed
let new_random = self.env().extension().fetch_random()?;
self.value = new_random;
// emit the RandomUpdated event when the random seed
// is successfully fetched.
self.env().emit_event(RandomUpdated { new: new_random });
Ok(())
}
/// Simply returns the current value.
#[ink(message)]
pub fn get(&self) -> [u8; 32] {
self.value
}
}
/// Unit tests in Rust are normally defined within such a `#[cfg(test)]`
#[cfg(test)]
mod tests {
/// Imports all the definitions from the outer scope so we can use them here.
use super::*;
use ink_lang as ink;
/// We test if the default constructor does its job.
#[ink::test]
fn default_works() {
let rand_extension = RandExtension::default();
assert_eq!(rand_extension.get(), [0; 32]);
}
}
}
You should be able to access the arguments through one of the functions on the <'a, 'b, E: Ext, S: state::BufIn> Environment<'a, 'b, E, S> implementation of Environment, e.g. read, read_as, read_as_unbounded. Please see the Environment struct for more information on this.
The rand-extension example you've cited here has also been updated to demonstrate passing an argument to the chain extension in the runtime. See that example here. You should be able to follow that example and implement the changes.

Initialize data structure's field in Rust with another data structure

I have recently started to program in Rust and would like now to create a structure, which fields I would like to assign using other structures. In the code base, which I am working with, there is the following example:
pub struct StType1 {
f1: String,
f2: bool,
f3: usize,
}
pub struct StType2 {
// ...
field1: StType1,
// ...
}
impl StType2 {
// ...
pub fn build(mut self) {
// ...
let st = StType3 {
field1: self.field1,
};
// ...
}
pub fn field1(&self) -> &StType1 {
&self.field1
}
}
struct StType3 {
field1: StType1,
// ...
}
StType1 is the type of the field, which is contained in both structures StType2 and StType3. StType2 while running build() function creates StType3 and they should have the same value of field1.
In this code there is no move and seems no copy in this assignment field1: self.field1;. Why? What happens then?
I am asking because when I try to create a similar to StType3 - ObjType - structure outside this file:
let object1 = StType2::new(...);
let object2 = ObjType {
field1: object1.field1().clone(),
}
within my functions, I get a reference to StType1 after clone(), not an object, and when I am doing this:
let object1 = StType2::new(...);
let object2 = ObjType {
field1: *object1.field1().clone(),
}
I get an error Can't move:
move occurs because value has type
StType1, which does
not implement the Copy trait
I solve it by adding to the StType1 #[derive(Clone)]. But it worked before with StType2 without #[derive(Clone)]. Why should I add it now? Why there was no move happenning (or no clone required) for field1 when this StType3 was created inside StType2 and the field1 was initialized?
In this code there is no move and seems no copy in this assignment field1: self.field1. Why? What happens then?
This is incorrect – there is a move here, because Rust moves by default.
And this is possible because in the declaration above:
pub fn build(mut self) {
there is no & before the self, and so this build method takes self by-move.
In contrast, the method below:
pub fn field1(&self) -> &StType1 {
&self.field1
}
takes &self, i.e. a reference, and returns &StType1, another reference. So to get a StType1 to construct your object, you need to make it owned by calling .clone(). But that will only work if StType1 implements Clone, which is why you had to add #[derive(Clone)] to it.
Alternatively, you can change the field1() method to take self by-move as well:
pub fn field1(self) -> StType1 {
self.field1
}
The disadvantage of this approach is that since it consumes self, i.e. the entire struct, you won't be able to access any of the other fields after it's called.

I want to keep a reference inside an HashMap but I'm not able to specify correctly the lifetime

I'm using ws-rs to build a chat app. I need to keep associations between a Sender and a Username but I'm having issues in referencing the Sender in my HashMap.
I'm 99.99% sure that Handler keeps the ownership of Sender.
I had solved this problem cloning every time the sender passing it to another thread, together with the username, via a mspc::channel but I wanna try to use smart pointers and reference.
Here is a Minimal, Reproducible Example:
use std::collections::HashMap;
use std::sync::Arc;
use std::thread;
trait Factory {
fn connection_made(&mut self, _: Sender) -> MHandler;
}
trait Handler {
fn on_open(&mut self) -> ();
}
struct MFactory<'a> {
connections: Arc<HashMap<String, &'a Sender>>,
}
struct MHandler<'a> {
sender: Sender,
connections: Arc<HashMap<String, &'a Sender>>,
}
struct Sender{}
fn main() {
let mut connections: Arc<HashMap<String, &Sender>> = Arc::new(HashMap::new());
// Server thread
let server = thread::Builder::new()
.name(format!("server"))
.spawn(|| {
let mFactory = MFactory {
connections: connections.clone(),
};
let mHandler = mFactory.connection_made(Sender{});
mHandler.on_open();
})
.unwrap();
}
impl Factory for MFactory<'_> {
fn connection_made(&mut self, s: Sender) -> MHandler {
MHandler {
sender: s,
connections: self.connections.clone(),
}
}
}
impl Handler for MHandler<'_> {
fn on_open(&mut self) -> () {
self.connections.insert(format!("Alan"), &self.sender);
}
}
Playground.
Ps: I'm aware that Arc doesn't guarantee mutual exclusion so I have to wrap my HasMap in a Mutex. I've decided to ignore it for the moment.
What you're trying to do is unsafe. You're keeping in a map that lives for the duration of your program references to a structure that is owned by another object inside a thread. So the map outlives the the objects it stores references to, which Rust prevents.
Following on my comment, this code compiles (I've removed the factory for clarity):
use std::collections::HashMap;
use std::sync::{Arc,Mutex};
use std::thread;
use std::ptr::NonNull;
struct MHandler {
sender: Sender,
}
struct Sender{}
struct Wrapper(NonNull<Sender>);
unsafe impl std::marker::Send for Wrapper { }
fn main() {
let connections: Arc<Mutex<HashMap<String, Wrapper>>> = Arc::new(Mutex::new(HashMap::new()));
// Server thread
let server = thread::Builder::new()
.name(format!("server"))
.spawn(move || {
let mut handler = MHandler {
sender: Sender{},
};
let w = Wrapper(NonNull::new(&mut handler.sender as *mut Sender).unwrap());
Arc::clone(&connections).lock().unwrap().insert(format!("Alan"), w);
})
.unwrap();
}
This is using raw pointers (https://doc.rust-lang.org/book/ch19-01-unsafe-rust.html#dereferencing-a-raw-pointer) and NonNull to be able to implement Send (see https://github.com/rust-lang/rust/issues/21709 and https://play.rust-lang.org/?gist=1ce2532a0eefc60695663c26faddebe1&version=stable)
Not sure this helps you.

Replace a struct member with a new value that uses the previous value

I have a struct which owns a boxed value of some trait type. The struct itself also implements the same trait. I would like to replace the value with a new instance of the same struct, which wraps it.
The following code, which does not compile, should make it more clear what I am trying to do:
trait T {}
struct S {
t: Box<dyn T>,
}
impl T for S {}
impl S {
fn new(t: Box<dyn T>) -> Self {
Self { t }
}
fn wrap_t(&mut self) {
self.t = Box::new(Self::new(self.t))
}
}
This fails:
error[E0507]: cannot move out of borrowed content
--> src/lib.rs:14:37
|
14 | self.t = Box::new(Self::new(self.t))
| ^^^^ cannot move out of borrowed content
Implementing wrap_t like this does compile:
use std::mem;
fn wrap_t(&mut self) {
unsafe {
let old_t = mem::replace(&mut self.t, mem::uninitialized());
let new_t = Box::new(Self::new(old_t));
let uninit = mem::replace(&mut self.t, new_t);
mem::forget(uninit);
}
}
I wonder if there is a safe way to do this.
The only unsafe function you are using is mem::uninitialized. You need something to pass to mem::replace, but implementing Default won't work because default() returns Self, which prevents it from being object-safe. Similarly, you can't implement Clone to duplicate the old value, since clone() also returns Self.
You can just implement a dummy type for the purpose though:
struct Dummy;
impl T for Dummy {}
fn wrap_t(&mut self) {
let old_t = mem::replace(&mut self.t, Box::new(Dummy));
let new_t = Box::new(Self::new(old_t));
mem::replace(&mut self.t, new_t);
}
You also won't need the mem::forget here now either (I'm assuming that was there to prevent undefined behaviour when the uninitialised memory was dropped).
As an alternative to Clone, you can roll your own own, which clones to a Box<dyn T>, avoiding having a Self in the method signature, so the trait stays object safe:
trait T: Debug {
fn clone_in_box(&self) -> Box<dyn T>;
}
impl T for S {
fn clone_in_box(&self) -> Box<dyn T> {
Box::new(S {
t: self.t.clone_in_box(),
})
}
}
fn wrap_t(&mut self) {
let cloned = self.clone_in_box();
let old_t = mem::replace(&mut self.t, cloned);
let new_t = Box::new(Self::new(old_t));
mem::replace(&mut self.t, new_t);
}
There is also an alternative design, which is much simpler to understand when reading the code. That is just to consume self and return a new object:
fn wrap_t(self) -> Self {
Self::new(Box::new(Self::new(self.t)))
}
And instead of this:
s.wrap_t();
You would do:
s = s.wrap_t();

Resources