Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(sails): Storage trait, impls, examples #767

Draft
wants to merge 8 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions examples/demo/app/src/counter_storage/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
use sails_rs::{prelude::*, static_storage};

#[derive(Default)]
pub struct Data(pub u128);
static_storage!(Data, Data(0u128));

pub struct Service<'a> {
storage: Box<dyn Storage<Item = Data> + 'a>,
}

impl<'a> Service<'a> {
pub fn new(storage: impl Storage<Item = Data> + 'a) -> Self {
Self {
storage: Box::new(storage),
}
}

pub fn from_accessor<T: StorageAccessor<'a, Data>>(accessor: &'a T) -> Self {
Self {
storage: accessor.boxed(),
}
}
}

#[service(events = Event)]
impl Service<'_> {
pub fn bump(&mut self) {
let state = self.storage.get_mut();
state.0 = state.0.saturating_add(1);

self.notify_on(Event::Bumped).expect("unable to emit event");
}

pub fn get(&self) -> u128 {
self.storage.get().0
}
}

#[derive(Clone, Debug, Encode, TypeInfo)]
#[codec(crate = sails_rs::scale_codec)]
#[scale_info(crate = sails_rs::scale_info)]
enum Event {
Bumped,
}
21 changes: 21 additions & 0 deletions examples/demo/app/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use demo_walker as walker;
use sails_rs::{cell::RefCell, prelude::*};

mod counter;
mod counter_storage;
mod dog;
mod mammal;
mod ping;
Expand All @@ -16,6 +17,8 @@ mod value_fee;
// of using a global variable here. It is just a demonstration of how to use global variables.
static mut DOG_DATA: Option<RefCell<walker::WalkerData>> = None;
static mut REF_DATA: u8 = 42;
static STORAGE_CELL: SyncUnsafeCell<counter_storage::Data> =
SyncUnsafeCell::new(counter_storage::Data(0u128));

#[allow(static_mut_refs)]
fn dog_data() -> &'static RefCell<walker::WalkerData> {
Expand All @@ -30,6 +33,7 @@ pub struct DemoProgram {
// Counter data has the same lifetime as the program itself, i.e. it will
// live as long as the program is available on the network.
counter_data: RefCell<counter::CounterData>,
counter_storage: RefCell<counter_storage::Data>,
}

#[program]
Expand All @@ -45,6 +49,7 @@ impl DemoProgram {
}
Self {
counter_data: RefCell::new(counter::CounterData::new(Default::default())),
counter_storage: RefCell::new(counter_storage::Data(0u128)),
}
}

Expand All @@ -60,6 +65,7 @@ impl DemoProgram {
}
Ok(Self {
counter_data: RefCell::new(counter::CounterData::new(counter.unwrap_or_default())),
counter_storage: RefCell::new(counter_storage::Data(0u128)),
})
}

Expand All @@ -74,6 +80,21 @@ impl DemoProgram {
counter::CounterService::new(&self.counter_data)
}

pub fn counter_storage(&self) -> counter_storage::Service<'_> {
let data = self.counter_storage.borrow_mut();
counter_storage::Service::new(data)
// can be simplified to
//counter_storage::Service::from_accessor(&self.counter_storage)
}

pub fn counter_storage_cell(&self) -> counter_storage::Service<'_> {
counter_storage::Service::from_accessor(&STORAGE_CELL)
}

pub fn counter_storage_static(&self) -> counter_storage::Service<'_> {
counter_storage::Service::new(counter_storage::Data::storage())
}

// Exposing yet another service
pub fn dog(&self) -> dog::DogService {
dog::DogService::new(walker::WalkerService::new(dog_data()))
Expand Down
15 changes: 14 additions & 1 deletion examples/demo/app/tests/fixture/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use demo_client::{
counter::{self, events::CounterEvents},
dog::{self, events::DogEvents},
Counter, DemoFactory, Dog, References, ValueFee,
Counter, CounterStorage, CounterStorageCell, CounterStorageStatic, DemoFactory, Dog,
References, ValueFee,
};
use sails_rs::{events::Listener, gtest::calls::*, gtest::System, prelude::*};

Expand Down Expand Up @@ -45,6 +46,18 @@ impl Fixture {
counter::events::listener(self.program_space.clone())
}

pub(crate) fn counter_storage_client(&self) -> CounterStorage<GTestRemoting> {
CounterStorage::new(self.program_space.clone())
}

pub(crate) fn counter_storage_cell_client(&self) -> CounterStorageCell<GTestRemoting> {
CounterStorageCell::new(self.program_space.clone())
}

pub(crate) fn counter_storage_static_client(&self) -> CounterStorageStatic<GTestRemoting> {
CounterStorageStatic::new(self.program_space.clone())
}

pub(crate) fn dog_client(&self) -> Dog<GTestRemoting> {
Dog::new(self.program_space.clone())
}
Expand Down
44 changes: 44 additions & 0 deletions examples/demo/app/tests/gclient.rs
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,50 @@ async fn value_fee_works() {
);
}

#[tokio::test]
#[ignore = "requires run gear node on GEAR_PATH"]
async fn counter_storage_static_works() {
// Arrange

let (remoting, demo_code_id, gas_limit, ..) = spin_up_node_with_demo_code().await;

let demo_factory = demo_client::DemoFactory::new(remoting.clone());

// Use generated client code for activating Demo program
// using the `new` constructor and the `send_recv` method
let demo_program_id = demo_factory
.new(Some(42), None)
.with_gas_limit(gas_limit)
.send_recv(demo_code_id, "123")
.await
.unwrap();

let mut counter_client = demo_client::CounterStorageStatic::new(remoting.clone());

// Act

// Use generated client code for calling Counter service
// using the `send_recv` method
counter_client
.bump()
.with_gas_limit(gas_limit)
.send_recv(demo_program_id)
.await
.unwrap();

counter_client
.bump()
.with_gas_limit(gas_limit)
.send_recv(demo_program_id)
.await
.unwrap();

let result = counter_client.get().recv(demo_program_id).await.unwrap();

// Asert
assert_eq!(result, 2);
}

async fn spin_up_node_with_demo_code() -> (GClientRemoting, CodeId, GasUnit, GearApi) {
let gear_path = option_env!("GEAR_PATH");
if gear_path.is_none() {
Expand Down
108 changes: 108 additions & 0 deletions examples/demo/app/tests/gtest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -522,3 +522,111 @@ async fn value_fee_works() {
&& initial_balance - balance < 10_100_000_000_000
);
}

#[tokio::test]
async fn counter_storage_works() {
// Arrange
let fixture = Fixture::new();

let demo_factory = fixture.demo_factory();

// Use generated client code for activating Demo program
// using the `new` constructor and the `send_recv` method
let demo_program_id = demo_factory
.new(Some(42), None)
.send_recv(fixture.demo_code_id(), "123")
.await
.unwrap();

let mut counter_client = fixture.counter_storage_client();

// Act
counter_client
.bump()
.send_recv(demo_program_id)
.await
.unwrap();

counter_client
.bump()
.send_recv(demo_program_id)
.await
.unwrap();

let result = counter_client.get().recv(demo_program_id).await.unwrap();

// Asert
assert_eq!(result, 2);
}

#[tokio::test]
async fn counter_storage_cell_works() {
// Arrange
let fixture = Fixture::new();

let demo_factory = fixture.demo_factory();

// Use generated client code for activating Demo program
// using the `new` constructor and the `send_recv` method
let demo_program_id = demo_factory
.new(Some(42), None)
.send_recv(fixture.demo_code_id(), "123")
.await
.unwrap();

let mut counter_client = fixture.counter_storage_cell_client();

// Act
counter_client
.bump()
.send_recv(demo_program_id)
.await
.unwrap();

counter_client
.bump()
.send_recv(demo_program_id)
.await
.unwrap();

let result = counter_client.get().recv(demo_program_id).await.unwrap();

// Asert
assert_eq!(result, 2);
}

#[tokio::test]
async fn counter_storage_static_works() {
// Arrange
let fixture = Fixture::new();

let demo_factory = fixture.demo_factory();

// Use generated client code for activating Demo program
// using the `new` constructor and the `send_recv` method
let demo_program_id = demo_factory
.new(Some(42), None)
.send_recv(fixture.demo_code_id(), "123")
.await
.unwrap();

let mut counter_client = fixture.counter_storage_static_client();

// Act
counter_client
.bump()
.send_recv(demo_program_id)
.await
.unwrap();

counter_client
.bump()
.send_recv(demo_program_id)
.await
.unwrap();

let result = counter_client.get().recv(demo_program_id).await.unwrap();

// Asert
assert_eq!(result, 2);
}
27 changes: 27 additions & 0 deletions examples/demo/client/demo.idl
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,33 @@ service Counter {
}
};

service CounterStorage {
Bump : () -> null;
query Get : () -> u128;

events {
Bumped;
}
};

service CounterStorageCell {
Bump : () -> null;
query Get : () -> u128;

events {
Bumped;
}
};

service CounterStorageStatic {
Bump : () -> null;
query Get : () -> u128;

events {
Bumped;
}
};

service Dog {
MakeSound : () -> str;
Walk : (dx: i32, dy: i32) -> null;
Expand Down
1 change: 1 addition & 0 deletions rs/src/gstd/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use core::cell::OnceCell;
pub mod calls;
pub mod events;
pub mod services;
pub mod storage;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is it in gstd?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

or it's like everything to be used in programs?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, all the stuff for the program under gstd


// TODO: To be renamed into SysCalls or something similar
pub trait ExecContext {
Expand Down
Loading
Loading