Skip to content

Commit

Permalink
app example
Browse files Browse the repository at this point in the history
  • Loading branch information
danwilliams committed Oct 9, 2024
1 parent 88e44a6 commit ee27859
Show file tree
Hide file tree
Showing 8 changed files with 452 additions and 0 deletions.
10 changes: 10 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ members = [
"./apps/kv-store",
"./apps/only-peers",
"./apps/gen-ext",
"./apps/merkle-crdt",

"./contracts/context-config",
"./contracts/registry",
Expand Down
15 changes: 15 additions & 0 deletions apps/merkle-crdt/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
[package]
name = "merkle-crdt"
version = "0.1.0"
authors.workspace = true
edition.workspace = true
repository.workspace = true
license.workspace = true

[lib]
crate-type = ["cdylib"]

[dependencies]
calimero-sdk = { path = "../../crates/sdk" }
calimero-storage = { path = "../../crates/storage" }
calimero-storage-macros = { path = "../../crates/storage-macros" }
18 changes: 18 additions & 0 deletions apps/merkle-crdt/build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#!/bin/bash
set -e

cd "$(dirname $0)"

TARGET="${CARGO_TARGET_DIR:-../../target}"

rustup target add wasm32-unknown-unknown

cargo build --target wasm32-unknown-unknown --profile app-release

mkdir -p res

cp $TARGET/wasm32-unknown-unknown/app-release/merkle_crdt.wasm ./res/

if command -v wasm-opt > /dev/null; then
wasm-opt -Oz ./res/merkle_crdt.wasm -o ./res/merkle_crdt.wasm
fi
161 changes: 161 additions & 0 deletions apps/merkle-crdt/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
use calimero_sdk::app;
use calimero_sdk::borsh::to_vec;
use calimero_storage::address::{Id, Path};
use calimero_storage::entities::{Data, Element};
use calimero_storage::integration::Comparison;
use calimero_storage::interface::StorageError::ActionNotAllowed;
use calimero_storage::interface::{Action, Interface, StorageError};
use calimero_storage_macros::{AtomicUnit, Collection};

#[app::state(emits = for<'a> Event<'a>)]
#[derive(AtomicUnit, Clone, Debug, PartialEq, PartialOrd)]
#[root]
#[type_id(11)]
pub struct Library {
#[collection]
books: Books,
#[storage]
storage: Element,
}

#[derive(Collection, Clone, Debug, Eq, PartialEq, PartialOrd)]
#[children(Book)]
pub struct Books;

#[derive(AtomicUnit, Clone, Debug, PartialEq, PartialOrd)]
#[type_id(12)]
pub struct Book {
authors: Vec<String>,
isbn: String,
publisher: String,
year: u16,
rating: f32,
#[collection]
reviews: Reviews,
#[collection]
pages: Pages,
#[storage]
storage: Element,
}

#[derive(Collection, Clone, Debug, Eq, PartialEq, PartialOrd)]
#[children(Page)]
pub struct Pages;

#[derive(AtomicUnit, Clone, Debug, Eq, PartialEq, PartialOrd)]
#[type_id(13)]
pub struct Page {
content: String,
number: u16,
title: String,
#[collection]
paragraphs: Paragraphs,
#[storage]
storage: Element,
}

#[derive(Collection, Clone, Debug, Eq, PartialEq, PartialOrd)]
#[children(Paragraph)]
pub struct Paragraphs;

#[derive(AtomicUnit, Clone, Debug, Eq, PartialEq, PartialOrd)]
#[type_id(14)]
pub struct Paragraph {
content: String,
#[storage]
storage: Element,
}

#[derive(Collection, Clone, Debug, Eq, PartialEq, PartialOrd)]
#[children(Review)]
pub struct Reviews;

#[derive(AtomicUnit, Clone, Debug, Eq, PartialEq, PartialOrd)]
#[type_id(15)]
pub struct Review {
author: String,
content: String,
rating: u8,
#[storage]
storage: Element,
}

#[app::event]
pub enum Event<'a> {
Inserted { key: &'a str, value: &'a str },
Updated { key: &'a str, value: &'a str },
Removed { key: &'a str },
Cleared,
}

#[app::logic]
impl Library {
#[app::init]
pub fn init() -> Library {
Library {
books: Books {},
storage: Element::new(&Path::new("::library").unwrap()),
}
}

pub fn apply_action(&self, action: Action) -> Result<Option<Id>, StorageError> {
match action {
Action::Add { type_id, .. } | Action::Update { type_id, .. } => {
// TODO: This is long-hand - it will be put inside an enum and generated
// TODO: with a macro
match type_id {
11 => Interface::apply_action::<Library>(action),
12 => Interface::apply_action::<Book>(action),
13 => Interface::apply_action::<Page>(action),
14 => Interface::apply_action::<Paragraph>(action),
15 => Interface::apply_action::<Review>(action),
_ => Err(StorageError::UnknownType(type_id)),
}
}
Action::Delete { .. } => Interface::apply_action::<Library>(action),
Action::Compare { .. } => Err(ActionNotAllowed("Compare".to_owned())),
}
}

pub fn compare_trees(
&self,
comparison: Comparison,
) -> Result<(Vec<Action>, Vec<Action>), StorageError> {
fn instantiate<D: Data>(data: &[u8]) -> Result<D, StorageError> {
D::try_from_slice(data).map_err(StorageError::DeserializationError)
}
let Comparison {
type_id,
data,
comparison_data,
} = comparison;
match type_id {
11 => Interface::compare_trees(&instantiate::<Library>(&data)?, &comparison_data),
12 => Interface::compare_trees(&instantiate::<Book>(&data)?, &comparison_data),
13 => Interface::compare_trees(&instantiate::<Page>(&data)?, &comparison_data),
14 => Interface::compare_trees(&instantiate::<Paragraph>(&data)?, &comparison_data),
15 => Interface::compare_trees(&instantiate::<Review>(&data)?, &comparison_data),
_ => Err(StorageError::UnknownType(type_id)),
}
}

pub fn generate_comparison_data(&self, id: Id) -> Result<Comparison, StorageError> {
fn generate_for<D: Data>(id: Id) -> Result<Comparison, StorageError> {
let data = Interface::find_by_id::<D>(id)?.ok_or(StorageError::NotFound(id))?;
Ok(Comparison {
type_id: D::type_id(),
data: to_vec(&data).map_err(StorageError::SerializationError)?,
comparison_data: Interface::generate_comparison_data(&data)?,
})
}
let type_id = Interface::type_of(id)?;
match type_id {
11 => generate_for::<Library>(id),
12 => generate_for::<Book>(id),
13 => generate_for::<Page>(id),
14 => generate_for::<Paragraph>(id),
15 => generate_for::<Review>(id),
_ => Err(StorageError::UnknownType(type_id)),
}
}
}
1 change: 1 addition & 0 deletions crates/runtime/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ license.workspace = true
[dependencies]
borsh = { workspace = true, features = ["derive"] }
fragile.workspace = true
hex.workspace = true
ouroboros.workspace = true
owo-colors = { workspace = true, optional = true }
rand.workspace = true
Expand Down
Loading

0 comments on commit ee27859

Please sign in to comment.