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

fix: state sync #969

Open
wants to merge 15 commits into
base: master
Choose a base branch
from
55 changes: 12 additions & 43 deletions apps/kv-store/src/__private.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use calimero_sdk::borsh::{from_slice, to_vec};
use calimero_sdk::borsh::from_slice;
use calimero_sdk::{app, env};
use calimero_storage::collections::unordered_map::{Entry, UnorderedMap};
use calimero_storage::entities::Data;
use calimero_storage::address::Id;
use calimero_storage::integration::Comparison;
use calimero_storage::interface::{Action, Interface, StorageError};
use calimero_storage::sync::{self, SyncArtifact};
Expand All @@ -16,66 +15,36 @@ impl KvStore {
let artifact =
from_slice::<SyncArtifact>(&args).map_err(StorageError::DeserializationError)?;

let this = Interface::root::<Self>()?;

match artifact {
SyncArtifact::Actions(actions) => {
for action in actions {
let _ignored = match action {
Action::Add { type_id, .. } | Action::Update { type_id, .. } => {
match type_id {
1 => Interface::apply_action::<KvStore>(action)?,
254 => Interface::apply_action::<Entry<String, String>>(action)?,
255 => {
Interface::apply_action::<UnorderedMap<String, String>>(action)?
}
_ => return Err(StorageError::UnknownType(type_id)),
}
}
Action::Delete { .. } => {
todo!("how are we supposed to identify the entity to delete???????")
Action::Compare { id } => {
sync::push_comparison(Comparison {
data: Interface::find_by_id_raw(id)?,
comparison_data: Interface::generate_comparison_data(Some(id))?,
});
}
Action::Compare { .. } => {
todo!("how are we supposed to compare when `Comparison` needs `type_id`???????")
Action::Add { .. } | Action::Update { .. } | Action::Delete { .. } => {
Interface::apply_action(action)?;
}
};
}

if let Some(this) = this {
return Interface::commit_root(this);
}
}
SyncArtifact::Comparisons(comparisons) => {
if comparisons.is_empty() {
sync::push_comparison(Comparison {
type_id: <Self as Data>::type_id(),
data: this
.as_ref()
.map(to_vec)
.transpose()
.map_err(StorageError::SerializationError)?,
comparison_data: Interface::generate_comparison_data(this.as_ref())?,
data: Interface::find_by_id_raw(Id::root())?,
comparison_data: Interface::generate_comparison_data(None)?,
});
}

for Comparison {
type_id,
data,
comparison_data,
} in comparisons
{
match type_id {
1 => Interface::compare_affective::<KvStore>(data, comparison_data)?,
254 => Interface::compare_affective::<Entry<String, String>>(
data,
comparison_data,
)?,
255 => Interface::compare_affective::<UnorderedMap<String, String>>(
data,
comparison_data,
)?,
_ => return Err(StorageError::UnknownType(type_id)),
};
Interface::compare_affective(data, comparison_data)?;
}
}
}
Expand Down
18 changes: 8 additions & 10 deletions apps/kv-store/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,18 @@

use std::collections::BTreeMap;

use calimero_sdk::borsh::{BorshDeserialize, BorshSerialize};
use calimero_sdk::types::Error;
use calimero_sdk::{app, env};
use calimero_storage::collections::UnorderedMap;
use calimero_storage::entities::Element;
use calimero_storage::AtomicUnit;

mod __private;

#[app::state(emits = for<'a> Event<'a>)]
#[derive(AtomicUnit, Clone, Debug, PartialEq, PartialOrd)]
#[root]
#[type_id(1)]
#[derive(Clone, Debug, PartialEq, PartialOrd, BorshSerialize, BorshDeserialize)]
#[borsh(crate = "calimero_sdk::borsh")]
pub struct KvStore {
items: UnorderedMap<String, String>,
#[storage]
storage: Element,
}

#[app::event]
Expand All @@ -33,8 +29,7 @@ impl KvStore {
#[app::init]
pub fn init() -> KvStore {
KvStore {
items: UnorderedMap::new().unwrap(),
storage: Element::root(),
items: UnorderedMap::new(),
}
}

Expand Down Expand Up @@ -93,7 +88,10 @@ impl KvStore {

app::emit!(Event::Removed { key });

self.items.remove(key).map_err(Into::into)
self.items
.remove(key)
.map(|v| v.is_some())
.map_err(Into::into)
}

pub fn clear(&mut self) -> Result<(), Error> {
Expand Down
56 changes: 32 additions & 24 deletions crates/sdk/macros/src/logic/method.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use proc_macro2::TokenStream;
use quote::{quote, ToTokens};
use quote::{quote, quote_spanned, ToTokens};
use syn::spanned::Spanned;
use syn::{Error as SynError, GenericParam, Ident, ImplItemFn, Path, ReturnType, Visibility};

use crate::errors::{Errors, ParseError};
Expand Down Expand Up @@ -61,12 +62,14 @@ impl ToTokens for PublicLogicMethod<'_> {

let input_lifetime = if self.has_refs {
let lifetime = lifetimes::input();
quote! { <#lifetime> }
quote_spanned! { name.span()=>
<#lifetime>
}
} else {
quote! {}
};

quote! {
quote_spanned! {name.span()=>
#[derive(::calimero_sdk::serde::Deserialize)]
#[serde(crate = "::calimero_sdk::serde")]
struct #input_ident #input_lifetime {
Expand Down Expand Up @@ -94,38 +97,41 @@ impl ToTokens for PublicLogicMethod<'_> {
let (def, mut call) = match &self.self_type {
Some(type_) => (
{
let mutability = match type_ {
SelfType::Mutable(_) => Some(quote! {mut}),
SelfType::Owned(_) | SelfType::Immutable(_) => None,
let (mutability, ty) = match type_ {
SelfType::Mutable(ty) => (Some(quote! {mut}), ty),
SelfType::Owned(ty) | SelfType::Immutable(ty) => (None, ty),
};
quote! {
let Some(#mutability app) = ::calimero_storage::interface::Interface::root::<#self_>().ok().flatten()
quote_spanned! {ty.span()=>
let Some(#mutability app) = ::calimero_storage::collections::Root::<#self_>::fetch()
else {
::calimero_sdk::env::panic_str("Failed to find or read app state")
};
}
},
quote! { app.#name(#(#arg_idents),*); },
quote_spanned! {name.span()=>
app.#name(#(#arg_idents),*)
},
),
None => (
if init_method {
quote! {
if let Some(mut app) = ::calimero_storage::interface::Interface::root::<#self_>().ok().flatten() {
quote_spanned! {name.span()=>
if ::calimero_storage::collections::Root::<#self_>::fetch().is_some() {
::calimero_sdk::env::panic_str("Cannot initialize over already existing state.")
};

let mut app: #self_ =
let app =
}
} else {
quote! {}
},
quote! { <#self_>::#name(#(#arg_idents),*); },
quote_spanned! {name.span()=>
<#self_>::#name(#(#arg_idents),*)
},
),
};

if let (Some(_), false) = (&self.ret, init_method) {
//only when it's not init
call = quote! {
if let (Some(ret), false) = (&self.ret, init_method) {
call = quote_spanned! {ret.ty.span()=>
let output = #call;
let output = {
#[expect(unused_imports)]
Expand All @@ -140,22 +146,24 @@ impl ToTokens for PublicLogicMethod<'_> {
),
}
};
::calimero_sdk::env::value_return(&output);
};
::calimero_sdk::env::value_return(&output)
}
}

let state_finalizer = match (&self.self_type, init_method) {
(Some(SelfType::Mutable(_)), _) | (_, true) => quote! {
if let Err(_) = ::calimero_storage::interface::Interface::commit_root(app) {
::calimero_sdk::env::panic_str("Failed to commit app state")
}
app.commit();
},
_ => quote! {},
};

// todo! when generics are present, strip them
let init_impl = if init_method {
quote! {
call = quote_spanned! {name.span()=>
::calimero_storage::collections::Root::new(|| #call)
};

quote_spanned! {name.span()=>
impl ::calimero_sdk::state::AppStateInit for #self_ {
type Return = #ret;
}
Expand All @@ -164,7 +172,7 @@ impl ToTokens for PublicLogicMethod<'_> {
quote! {}
};

quote! {
quote_spanned! {name.span()=>
#[cfg(target_arch = "wasm32")]
#[no_mangle]
pub extern "C" fn #name() {
Expand All @@ -176,7 +184,7 @@ impl ToTokens for PublicLogicMethod<'_> {

#def

#call
#call;

#state_finalizer
}
Expand Down
Loading
Loading