From a851290ad2a1adecfac62cea14478eccee20008e Mon Sep 17 00:00:00 2001 From: Saeed Dadkhah Date: Wed, 12 Jun 2024 18:42:08 +0330 Subject: [PATCH 01/34] feat: add a fetch function inside the runtime host environment --- Cargo.lock | 17 +++++++-------- crates/node/gen_localnet_configs.sh | 2 ++ crates/runtime/Cargo.toml | 1 + crates/runtime/examples/fetch.rs | 32 +++++++++++++++++++++++++++++ crates/runtime/src/logic.rs | 21 +++++++++++++++++++ crates/runtime/src/logic/imports.rs | 1 + crates/sdk/src/env.rs | 10 +++++++++ crates/sdk/src/sys.rs | 3 +++ 8 files changed, 79 insertions(+), 8 deletions(-) create mode 100644 crates/runtime/examples/fetch.rs diff --git a/Cargo.lock b/Cargo.lock index 6aeac27f6..526940747 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1154,6 +1154,7 @@ dependencies = [ "serde", "serde_json", "thiserror", + "ureq", "wasmer", "wasmer-types", ] @@ -3142,7 +3143,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "socket2 0.4.10", + "socket2 0.5.6", "tokio", "tower-service", "tracing", @@ -3620,7 +3621,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19" dependencies = [ "cfg-if 1.0.0", - "windows-targets 0.48.5", + "windows-targets 0.52.4", ] [[package]] @@ -6658,9 +6659,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.22.3" +version = "0.22.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99008d7ad0bbbea527ec27bddbc0e432c5b87d8175178cee68d2eec9c4a1813c" +checksum = "bf4ef73721ac7bcd79b2b315da7779d8fc09718c6b3d2d1b2d94850eb8c18432" dependencies = [ "log", "ring 0.17.8", @@ -8262,15 +8263,15 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "ureq" -version = "2.9.6" +version = "2.9.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11f214ce18d8b2cbe84ed3aa6486ed3f5b285cf8d8fbdbce9f3f767a724adc35" +checksum = "d11a831e3c0b56e438a28308e7c810799e3c118417f342d30ecec080105395cd" dependencies = [ - "base64 0.21.7", + "base64 0.22.0", "flate2", "log", "once_cell", - "rustls 0.22.3", + "rustls 0.22.4", "rustls-pki-types", "rustls-webpki 0.102.2", "url", diff --git a/crates/node/gen_localnet_configs.sh b/crates/node/gen_localnet_configs.sh index d55a03a99..88adef1ba 100755 --- a/crates/node/gen_localnet_configs.sh +++ b/crates/node/gen_localnet_configs.sh @@ -1,3 +1,5 @@ +#!/usr/bin/env bash + set -o pipefail # Check if an argument was provided diff --git a/crates/runtime/Cargo.toml b/crates/runtime/Cargo.toml index 7f18d7b58..12c3ce7a9 100644 --- a/crates/runtime/Cargo.toml +++ b/crates/runtime/Cargo.toml @@ -13,6 +13,7 @@ owo-colors = { workspace = true, optional = true } serde = { workspace = true, features = ["derive"] } serde_json.workspace = true thiserror.workspace = true +ureq = "2.9.7" wasmer.workspace = true wasmer-types.workspace = true diff --git a/crates/runtime/examples/fetch.rs b/crates/runtime/examples/fetch.rs new file mode 100644 index 000000000..a6baa3c0a --- /dev/null +++ b/crates/runtime/examples/fetch.rs @@ -0,0 +1,32 @@ +use calimero_runtime::{logic, run, store, Constraint}; +use serde_json::json; + +fn main() -> eyre::Result<()> { + let file = include_bytes!("../../../apps/only-peers/res/only_peers.wasm"); + + let mut storage = store::InMemoryStorage::default(); + + let limits = logic::VMLimits { + max_stack_size: 200 << 10, // 200 KiB + max_memory_pages: 1 << 10, // 1 KiB + max_registers: 100, + max_register_size: (100 << 20).validate()?, // 100 MiB + max_registers_capacity: 1 << 30, // 1 GiB + max_logs: 100, + max_log_size: 16 << 10, // 16 KiB + max_events: 100, + max_event_kind_size: 100, + max_event_data_size: 16 << 10, // 16 KiB + max_storage_key_size: (1 << 20).try_into()?, // 1 MiB + max_storage_value_size: (10 << 20).try_into()?, // 10 MiB + }; + + let cx = logic::VMContext { + input: serde_json::to_vec(&json!({}))?, + }; + let get_outcome = run(file, "fetch", cx, &mut storage, &limits)?; + let returns = String::from_utf8(get_outcome.returns.unwrap().unwrap()).unwrap(); + println!("{returns}"); + + Ok(()) +} diff --git a/crates/runtime/src/logic.rs b/crates/runtime/src/logic.rs index 563b0fca5..9fd14702b 100644 --- a/crates/runtime/src/logic.rs +++ b/crates/runtime/src/logic.rs @@ -1,3 +1,4 @@ +use std::collections::HashMap; use std::num::NonZeroU64; use ouroboros::self_referencing; @@ -305,4 +306,24 @@ impl<'a> VMHostFunctions<'a> { Ok(0) } + + pub fn fetch( + &mut self, + url_ptr: u64, + url_len: u64, + headers_ptr: u64, + headers_len: u64, + out_register_id: u64, + ) -> Result<()> { + let url = self.get_string(url_ptr, url_len)?; + let headers = self.get_string(headers_ptr, headers_len)?; + let headers: HashMap = serde_json::from_str(&headers).unwrap(); + let body: String = ureq::get(&url).call().unwrap().into_string().unwrap(); + self.with_logic_mut(|logic| { + logic + .registers + .set(&logic.limits, out_register_id, body.into_bytes()) + })?; + Ok(()) + } } diff --git a/crates/runtime/src/logic/imports.rs b/crates/runtime/src/logic/imports.rs index 732b7b8bf..34e519c61 100644 --- a/crates/runtime/src/logic/imports.rs +++ b/crates/runtime/src/logic/imports.rs @@ -44,6 +44,7 @@ impl<'a> VMLogic<'a> { register_id: u64, ) -> u32; fn storage_read(key_ptr: u64, key_len: u64, register_id: u64) -> u32; + fn fetch(url_ptr: u64, url_len: u64, headers_ptr: u64, headers_len: u64, out_register_id: u64); } } } diff --git a/crates/sdk/src/env.rs b/crates/sdk/src/env.rs index 3e8a0984b..a837d454c 100644 --- a/crates/sdk/src/env.rs +++ b/crates/sdk/src/env.rs @@ -1,3 +1,5 @@ +use std::collections::HashMap; + use crate::sys; const DATA_REGISTER: sys::RegisterId = sys::RegisterId::new(sys::PtrSizedInt::MAX.as_usize() - 1); @@ -145,3 +147,11 @@ pub fn state_write(state: &T) { }; storage_write(STATE_KEY, &data); } + +pub fn fetch(url: &str, headers: HashMap) -> String { + let headers = serde_json::to_string(&headers).unwrap(); + let url = sys::Buffer::from(url); + let headers = sys::Buffer::from(headers.as_str()); + unsafe { sys::fetch(url, headers, DATA_REGISTER) } + String::from_utf8(read_register(DATA_REGISTER).unwrap_or_else(expected_register)).unwrap() +} diff --git a/crates/sdk/src/sys.rs b/crates/sdk/src/sys.rs index 6d360dac2..9c2b26fc0 100644 --- a/crates/sdk/src/sys.rs +++ b/crates/sdk/src/sys.rs @@ -4,6 +4,7 @@ mod types; pub use types::*; +#[link(wasm_import_module = "env")] extern "C" { pub fn panic(loc: Location) -> !; pub fn panic_utf8(msg: Buffer, loc: Location) -> !; @@ -18,4 +19,6 @@ extern "C" { // -- pub fn storage_read(key: Buffer, register_id: RegisterId) -> Bool; pub fn storage_write(key: Buffer, value: Buffer, register_id: RegisterId) -> Bool; + + pub fn fetch(url: Buffer, headers: Buffer, out_register_id: RegisterId); } From 052f4eda720bd1936e4daae4014b241de04e1a0f Mon Sep 17 00:00:00 2001 From: Saeed Dadkhah Date: Wed, 12 Jun 2024 19:16:59 +0330 Subject: [PATCH 02/34] Add headers --- crates/runtime/Cargo.toml | 1 + crates/runtime/src/logic.rs | 14 ++++++++++---- crates/sdk/src/env.rs | 7 +++++-- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/crates/runtime/Cargo.toml b/crates/runtime/Cargo.toml index 12c3ce7a9..728b8ae62 100644 --- a/crates/runtime/Cargo.toml +++ b/crates/runtime/Cargo.toml @@ -16,6 +16,7 @@ thiserror.workspace = true ureq = "2.9.7" wasmer.workspace = true wasmer-types.workspace = true +borsh = { workspace = true, features = ["derive"] } [[example]] name = "demo" diff --git a/crates/runtime/src/logic.rs b/crates/runtime/src/logic.rs index 9fd14702b..a5884cb30 100644 --- a/crates/runtime/src/logic.rs +++ b/crates/runtime/src/logic.rs @@ -316,13 +316,19 @@ impl<'a> VMHostFunctions<'a> { out_register_id: u64, ) -> Result<()> { let url = self.get_string(url_ptr, url_len)?; - let headers = self.get_string(headers_ptr, headers_len)?; - let headers: HashMap = serde_json::from_str(&headers).unwrap(); - let body: String = ureq::get(&url).call().unwrap().into_string().unwrap(); + let headers = self.read_guest_memory(headers_ptr, headers_len)?; + let headers: HashMap = borsh::from_slice(&headers).unwrap(); + let mut request = ureq::request("GET", &url); + + for (key, value) in headers.iter() { + request = request.set(key, value); + } + + let response = request.call().unwrap().into_string().unwrap(); self.with_logic_mut(|logic| { logic .registers - .set(&logic.limits, out_register_id, body.into_bytes()) + .set(&logic.limits, out_register_id, response.into_bytes()) })?; Ok(()) } diff --git a/crates/sdk/src/env.rs b/crates/sdk/src/env.rs index a837d454c..51a72707a 100644 --- a/crates/sdk/src/env.rs +++ b/crates/sdk/src/env.rs @@ -149,9 +149,12 @@ pub fn state_write(state: &T) { } pub fn fetch(url: &str, headers: HashMap) -> String { - let headers = serde_json::to_string(&headers).unwrap(); + let headers = match borsh::to_vec(&headers) { + Ok(data) => data, + Err(err) => panic_str(&format!("Cannot serialize headers: {:?}", err)), + }; let url = sys::Buffer::from(url); - let headers = sys::Buffer::from(headers.as_str()); + let headers = sys::Buffer::from(headers.as_slice()); unsafe { sys::fetch(url, headers, DATA_REGISTER) } String::from_utf8(read_register(DATA_REGISTER).unwrap_or_else(expected_register)).unwrap() } From ad06f976d1cba4ef046630b5c3f11cc9919446fe Mon Sep 17 00:00:00 2001 From: Saeed Dadkhah Date: Wed, 12 Jun 2024 19:22:30 +0330 Subject: [PATCH 03/34] Add method --- crates/runtime/src/logic.rs | 5 ++++- crates/runtime/src/logic/imports.rs | 2 +- crates/sdk/src/env.rs | 5 +++-- crates/sdk/src/sys.rs | 2 +- 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/crates/runtime/src/logic.rs b/crates/runtime/src/logic.rs index a5884cb30..ab61f704e 100644 --- a/crates/runtime/src/logic.rs +++ b/crates/runtime/src/logic.rs @@ -309,16 +309,19 @@ impl<'a> VMHostFunctions<'a> { pub fn fetch( &mut self, + method_ptr: u64, + method_len: u64, url_ptr: u64, url_len: u64, headers_ptr: u64, headers_len: u64, out_register_id: u64, ) -> Result<()> { + let method = self.get_string(method_ptr, method_len)?; let url = self.get_string(url_ptr, url_len)?; let headers = self.read_guest_memory(headers_ptr, headers_len)?; let headers: HashMap = borsh::from_slice(&headers).unwrap(); - let mut request = ureq::request("GET", &url); + let mut request = ureq::request(&method, &url); for (key, value) in headers.iter() { request = request.set(key, value); diff --git a/crates/runtime/src/logic/imports.rs b/crates/runtime/src/logic/imports.rs index 34e519c61..5d22d3f8f 100644 --- a/crates/runtime/src/logic/imports.rs +++ b/crates/runtime/src/logic/imports.rs @@ -44,7 +44,7 @@ impl<'a> VMLogic<'a> { register_id: u64, ) -> u32; fn storage_read(key_ptr: u64, key_len: u64, register_id: u64) -> u32; - fn fetch(url_ptr: u64, url_len: u64, headers_ptr: u64, headers_len: u64, out_register_id: u64); + fn fetch(method_ptr: u64, method_len: u64, url_ptr: u64, url_len: u64, headers_ptr: u64, headers_len: u64, out_register_id: u64); } } } diff --git a/crates/sdk/src/env.rs b/crates/sdk/src/env.rs index 51a72707a..a335b003c 100644 --- a/crates/sdk/src/env.rs +++ b/crates/sdk/src/env.rs @@ -148,13 +148,14 @@ pub fn state_write(state: &T) { storage_write(STATE_KEY, &data); } -pub fn fetch(url: &str, headers: HashMap) -> String { +pub fn fetch(method: &str, url: &str, headers: HashMap) -> String { let headers = match borsh::to_vec(&headers) { Ok(data) => data, Err(err) => panic_str(&format!("Cannot serialize headers: {:?}", err)), }; + let method = sys::Buffer::from(method); let url = sys::Buffer::from(url); let headers = sys::Buffer::from(headers.as_slice()); - unsafe { sys::fetch(url, headers, DATA_REGISTER) } + unsafe { sys::fetch(method, url, headers, DATA_REGISTER) } String::from_utf8(read_register(DATA_REGISTER).unwrap_or_else(expected_register)).unwrap() } diff --git a/crates/sdk/src/sys.rs b/crates/sdk/src/sys.rs index 9c2b26fc0..85857320b 100644 --- a/crates/sdk/src/sys.rs +++ b/crates/sdk/src/sys.rs @@ -20,5 +20,5 @@ extern "C" { pub fn storage_read(key: Buffer, register_id: RegisterId) -> Bool; pub fn storage_write(key: Buffer, value: Buffer, register_id: RegisterId) -> Bool; - pub fn fetch(url: Buffer, headers: Buffer, out_register_id: RegisterId); + pub fn fetch(method: Buffer, url: Buffer, headers: Buffer, out_register_id: RegisterId); } From 5279d24c34ec859bbfcf01b418aec55ddc97e372 Mon Sep 17 00:00:00 2001 From: Saeed Dadkhah Date: Wed, 12 Jun 2024 19:42:07 +0330 Subject: [PATCH 04/34] Add body --- Cargo.lock | 1 + crates/runtime/src/errors.rs | 2 ++ crates/runtime/src/logic.rs | 19 ++++++++++++++++++- crates/runtime/src/logic/imports.rs | 3 ++- crates/sdk/src/env.rs | 5 +++-- crates/sdk/src/sys.rs | 8 +++++++- 6 files changed, 33 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 526940747..50d78660d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1145,6 +1145,7 @@ name = "calimero-runtime" version = "0.1.0" dependencies = [ "assert-json-diff", + "borsh 1.4.0", "clap 4.5.4", "eyre", "fragile", diff --git a/crates/runtime/src/errors.rs b/crates/runtime/src/errors.rs index c8a2ba5ee..879f76c0b 100644 --- a/crates/runtime/src/errors.rs +++ b/crates/runtime/src/errors.rs @@ -86,6 +86,8 @@ pub enum HostError { EventKindSizeOverflow, #[error("event data size overflow")] EventDataSizeOverflow, + #[error("failed to fetch data from {url} with error: {error}")] + FetchError { url: String, error: String }, } #[derive(Debug, Serialize)] diff --git a/crates/runtime/src/logic.rs b/crates/runtime/src/logic.rs index ab61f704e..b67ddbacb 100644 --- a/crates/runtime/src/logic.rs +++ b/crates/runtime/src/logic.rs @@ -315,19 +315,36 @@ impl<'a> VMHostFunctions<'a> { url_len: u64, headers_ptr: u64, headers_len: u64, + body_ptr: u64, + body_len: u64, out_register_id: u64, ) -> Result<()> { let method = self.get_string(method_ptr, method_len)?; let url = self.get_string(url_ptr, url_len)?; let headers = self.read_guest_memory(headers_ptr, headers_len)?; let headers: HashMap = borsh::from_slice(&headers).unwrap(); + let body = self.read_guest_memory(body_ptr, body_len)?; let mut request = ureq::request(&method, &url); for (key, value) in headers.iter() { request = request.set(key, value); } - let response = request.call().unwrap().into_string().unwrap(); + let response = if !body.is_empty() { + request.send_bytes(&body) + } else { + request.call() + } + .map_err(|e| HostError::FetchError { + url: url.clone(), + error: e.to_string(), + })? + .into_string() + .map_err(|e| HostError::FetchError { + url, + error: e.to_string(), + })?; + self.with_logic_mut(|logic| { logic .registers diff --git a/crates/runtime/src/logic/imports.rs b/crates/runtime/src/logic/imports.rs index 5d22d3f8f..874706b30 100644 --- a/crates/runtime/src/logic/imports.rs +++ b/crates/runtime/src/logic/imports.rs @@ -44,7 +44,8 @@ impl<'a> VMLogic<'a> { register_id: u64, ) -> u32; fn storage_read(key_ptr: u64, key_len: u64, register_id: u64) -> u32; - fn fetch(method_ptr: u64, method_len: u64, url_ptr: u64, url_len: u64, headers_ptr: u64, headers_len: u64, out_register_id: u64); + fn fetch(method_ptr: u64, method_len: u64, url_ptr: u64, url_len: u64, headers_ptr: u64, + headers_len: u64, body_ptr: u64, body_len: u64, out_register_id: u64); } } } diff --git a/crates/sdk/src/env.rs b/crates/sdk/src/env.rs index a335b003c..1661f0cf5 100644 --- a/crates/sdk/src/env.rs +++ b/crates/sdk/src/env.rs @@ -148,7 +148,7 @@ pub fn state_write(state: &T) { storage_write(STATE_KEY, &data); } -pub fn fetch(method: &str, url: &str, headers: HashMap) -> String { +pub fn fetch(method: &str, url: &str, headers: HashMap, body: Vec) -> String { let headers = match borsh::to_vec(&headers) { Ok(data) => data, Err(err) => panic_str(&format!("Cannot serialize headers: {:?}", err)), @@ -156,6 +156,7 @@ pub fn fetch(method: &str, url: &str, headers: HashMap) -> Strin let method = sys::Buffer::from(method); let url = sys::Buffer::from(url); let headers = sys::Buffer::from(headers.as_slice()); - unsafe { sys::fetch(method, url, headers, DATA_REGISTER) } + let body = sys::Buffer::from(body.as_slice()); + unsafe { sys::fetch(method, url, headers, body, DATA_REGISTER) } String::from_utf8(read_register(DATA_REGISTER).unwrap_or_else(expected_register)).unwrap() } diff --git a/crates/sdk/src/sys.rs b/crates/sdk/src/sys.rs index 85857320b..b35764e49 100644 --- a/crates/sdk/src/sys.rs +++ b/crates/sdk/src/sys.rs @@ -20,5 +20,11 @@ extern "C" { pub fn storage_read(key: Buffer, register_id: RegisterId) -> Bool; pub fn storage_write(key: Buffer, value: Buffer, register_id: RegisterId) -> Bool; - pub fn fetch(method: Buffer, url: Buffer, headers: Buffer, out_register_id: RegisterId); + pub fn fetch( + method: Buffer, + url: Buffer, + headers: Buffer, + body: Buffer, + out_register_id: RegisterId, + ); } From 16b37aee715de120ebfe2e8569e82f75f94abf56 Mon Sep 17 00:00:00 2001 From: Saeed Dadkhah Date: Thu, 13 Jun 2024 17:48:52 +0330 Subject: [PATCH 05/34] feat: Add app-side library for NEAR --- Cargo.lock | 14 ++++++++-- Cargo.toml | 1 + apps/only-peers/Cargo.toml | 1 + crates/near-sdk/Cargo.toml | 13 +++++++++ crates/near-sdk/src/jsonrpc.rs | 49 ++++++++++++++++++++++++++++++++++ crates/near-sdk/src/lib.rs | 46 +++++++++++++++++++++++++++++++ 6 files changed, 122 insertions(+), 2 deletions(-) create mode 100644 crates/near-sdk/Cargo.toml create mode 100644 crates/near-sdk/src/jsonrpc.rs create mode 100644 crates/near-sdk/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 50d78660d..c7562ed91 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3587,7 +3587,7 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" name = "leaderboard" version = "0.1.0" dependencies = [ - "near-sdk", + "near-sdk 5.1.0", "near-workspaces", "serde_json", "tokio", @@ -4997,6 +4997,15 @@ dependencies = [ "tokio", ] +[[package]] +name = "near-sdk" +version = "0.1.0" +dependencies = [ + "calimero-sdk", + "serde", + "serde_json", +] + [[package]] name = "near-sdk" version = "5.1.0" @@ -5356,6 +5365,7 @@ name = "only-peers" version = "0.1.0" dependencies = [ "calimero-sdk", + "near-sdk 0.1.0", ] [[package]] @@ -5522,7 +5532,7 @@ name = "package-manager" version = "0.1.0" dependencies = [ "hex", - "near-sdk", + "near-sdk 5.1.0", "near-workspaces", "semver", "serde_json", diff --git a/Cargo.toml b/Cargo.toml index 97451cd5d..fe0198155 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,6 +15,7 @@ members = [ "./crates/primitives", "./crates/runtime", "./crates/sdk", + "./crates/near-sdk", "./crates/sdk/macros", "./crates/server", "./crates/server-primitives", diff --git a/apps/only-peers/Cargo.toml b/apps/only-peers/Cargo.toml index cc3360bac..757ff2783 100644 --- a/apps/only-peers/Cargo.toml +++ b/apps/only-peers/Cargo.toml @@ -11,3 +11,4 @@ crate-type = ["cdylib"] [dependencies] calimero-sdk = { path = "../../crates/sdk" } +near-sdk = { path = "../../crates/near-sdk" } diff --git a/crates/near-sdk/Cargo.toml b/crates/near-sdk/Cargo.toml new file mode 100644 index 000000000..c08b06cba --- /dev/null +++ b/crates/near-sdk/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "near-sdk" +version = "0.1.0" +authors.workspace = true +edition.workspace = true +repository.workspace = true +license.workspace = true + +[dependencies] +serde = { workspace = true, features = ["derive"] } +serde_json.workspace = true +calimero-sdk = { path = "../sdk" } + diff --git a/crates/near-sdk/src/jsonrpc.rs b/crates/near-sdk/src/jsonrpc.rs new file mode 100644 index 000000000..1f9f03dcc --- /dev/null +++ b/crates/near-sdk/src/jsonrpc.rs @@ -0,0 +1,49 @@ +use calimero_sdk::env::internal::fetch; +use serde::de::DeserializeOwned; +use serde::Deserialize; +use std::collections::HashMap; + +pub struct Client { + url: String, +} + +impl Client { + pub fn new(url: String) -> Self { + Self { url } + } + + pub fn call( + &self, + method: &str, + params: serde_json::Value, + ) -> Response { + let headers = HashMap::from([("Content-Type".to_string(), "application/json".to_string())]); + + let body = serde_json::to_vec(&serde_json::json!({ + "jsonrpc": "2.0", + "id": "1", + "method": method, + "params": params, + })) + .unwrap(); + + let response = unsafe { fetch("POST", &self.url, headers, body) }; + serde_json::from_str(&response).unwrap() + } +} + +#[derive(Debug, Clone, Deserialize)] +pub struct Response { + pub result: Option, + pub error: Option>, + pub id: String, + + pub jsonrpc: Option, +} + +#[derive(Debug, Clone, Deserialize)] +pub struct RpcError { + pub code: i32, + pub message: String, + pub data: Option, +} diff --git a/crates/near-sdk/src/lib.rs b/crates/near-sdk/src/lib.rs new file mode 100644 index 000000000..dcd06d27d --- /dev/null +++ b/crates/near-sdk/src/lib.rs @@ -0,0 +1,46 @@ +use jsonrpc::Response; +use serde::Deserialize; + +mod jsonrpc; + +pub struct NearSdk { + jsonrpc_client: jsonrpc::Client, +} + +#[derive(Debug, Clone, Deserialize)] +pub struct BalanceResponse { + pub amount: String, +} + +impl NearSdk { + pub fn testnet() -> Self { + Self { + jsonrpc_client: jsonrpc::Client::new("https://rpc.testnet.near.org/".to_string()), + } + } + + pub fn mainnet() -> Self { + Self { + jsonrpc_client: jsonrpc::Client::new("https://rpc.mainnet.near.org/".to_string()), + } + } + + pub fn get_balance(&self, account_id: &str) -> BalanceResponse { + let response: Response = self.jsonrpc_client.call( + "query", + serde_json::json!({ + "request_type": "view_account", + "finality": "final", + "account_id": account_id, + }), + ); + + if let Some(response) = response.result { + response + } else if let Some(error) = response.error { + panic!("Error: {:?}", error.message); + } else { + panic!("Error: no response or error field in response"); + } + } +} From 7bef965253d6053ecfeb6e8b0e5c68b9f0482ffc Mon Sep 17 00:00:00 2001 From: Saeed Dadkhah Date: Tue, 18 Jun 2024 14:51:21 +0330 Subject: [PATCH 06/34] code review fixes --- Cargo.lock | 23 ++++--- Cargo.toml | 2 +- apps/only-peers/Cargo.toml | 1 - crates/near-sdk/src/jsonrpc.rs | 49 -------------- crates/near-sdk/src/lib.rs | 46 ------------- crates/runtime/Cargo.toml | 1 - crates/{near-sdk => sdk/libs/near}/Cargo.toml | 4 +- crates/sdk/libs/near/src/jsonrpc.rs | 66 +++++++++++++++++++ crates/sdk/libs/near/src/lib.rs | 43 ++++++++++++ crates/sdk/src/env.rs | 15 ----- 10 files changed, 123 insertions(+), 127 deletions(-) delete mode 100644 crates/near-sdk/src/jsonrpc.rs delete mode 100644 crates/near-sdk/src/lib.rs rename crates/{near-sdk => sdk/libs/near}/Cargo.toml (78%) create mode 100644 crates/sdk/libs/near/src/jsonrpc.rs create mode 100644 crates/sdk/libs/near/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index c7562ed91..27094a7cc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1182,6 +1182,15 @@ dependencies = [ "thiserror", ] +[[package]] +name = "calimero-sdk-near" +version = "0.1.0" +dependencies = [ + "calimero-sdk", + "serde", + "serde_json", +] + [[package]] name = "calimero-server" version = "0.1.0" @@ -3587,7 +3596,7 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" name = "leaderboard" version = "0.1.0" dependencies = [ - "near-sdk 5.1.0", + "near-sdk", "near-workspaces", "serde_json", "tokio", @@ -4997,15 +5006,6 @@ dependencies = [ "tokio", ] -[[package]] -name = "near-sdk" -version = "0.1.0" -dependencies = [ - "calimero-sdk", - "serde", - "serde_json", -] - [[package]] name = "near-sdk" version = "5.1.0" @@ -5365,7 +5365,6 @@ name = "only-peers" version = "0.1.0" dependencies = [ "calimero-sdk", - "near-sdk 0.1.0", ] [[package]] @@ -5532,7 +5531,7 @@ name = "package-manager" version = "0.1.0" dependencies = [ "hex", - "near-sdk 5.1.0", + "near-sdk", "near-workspaces", "semver", "serde_json", diff --git a/Cargo.toml b/Cargo.toml index b66c67627..f113e5396 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,7 +15,7 @@ members = [ "./crates/primitives", "./crates/runtime", "./crates/sdk", - "./crates/near-sdk", + "./crates/sdk/libs/near", "./crates/sdk/macros", "./crates/server", "./crates/server-primitives", diff --git a/apps/only-peers/Cargo.toml b/apps/only-peers/Cargo.toml index 757ff2783..cc3360bac 100644 --- a/apps/only-peers/Cargo.toml +++ b/apps/only-peers/Cargo.toml @@ -11,4 +11,3 @@ crate-type = ["cdylib"] [dependencies] calimero-sdk = { path = "../../crates/sdk" } -near-sdk = { path = "../../crates/near-sdk" } diff --git a/crates/near-sdk/src/jsonrpc.rs b/crates/near-sdk/src/jsonrpc.rs deleted file mode 100644 index 1f9f03dcc..000000000 --- a/crates/near-sdk/src/jsonrpc.rs +++ /dev/null @@ -1,49 +0,0 @@ -use calimero_sdk::env::internal::fetch; -use serde::de::DeserializeOwned; -use serde::Deserialize; -use std::collections::HashMap; - -pub struct Client { - url: String, -} - -impl Client { - pub fn new(url: String) -> Self { - Self { url } - } - - pub fn call( - &self, - method: &str, - params: serde_json::Value, - ) -> Response { - let headers = HashMap::from([("Content-Type".to_string(), "application/json".to_string())]); - - let body = serde_json::to_vec(&serde_json::json!({ - "jsonrpc": "2.0", - "id": "1", - "method": method, - "params": params, - })) - .unwrap(); - - let response = unsafe { fetch("POST", &self.url, headers, body) }; - serde_json::from_str(&response).unwrap() - } -} - -#[derive(Debug, Clone, Deserialize)] -pub struct Response { - pub result: Option, - pub error: Option>, - pub id: String, - - pub jsonrpc: Option, -} - -#[derive(Debug, Clone, Deserialize)] -pub struct RpcError { - pub code: i32, - pub message: String, - pub data: Option, -} diff --git a/crates/near-sdk/src/lib.rs b/crates/near-sdk/src/lib.rs deleted file mode 100644 index dcd06d27d..000000000 --- a/crates/near-sdk/src/lib.rs +++ /dev/null @@ -1,46 +0,0 @@ -use jsonrpc::Response; -use serde::Deserialize; - -mod jsonrpc; - -pub struct NearSdk { - jsonrpc_client: jsonrpc::Client, -} - -#[derive(Debug, Clone, Deserialize)] -pub struct BalanceResponse { - pub amount: String, -} - -impl NearSdk { - pub fn testnet() -> Self { - Self { - jsonrpc_client: jsonrpc::Client::new("https://rpc.testnet.near.org/".to_string()), - } - } - - pub fn mainnet() -> Self { - Self { - jsonrpc_client: jsonrpc::Client::new("https://rpc.mainnet.near.org/".to_string()), - } - } - - pub fn get_balance(&self, account_id: &str) -> BalanceResponse { - let response: Response = self.jsonrpc_client.call( - "query", - serde_json::json!({ - "request_type": "view_account", - "finality": "final", - "account_id": account_id, - }), - ); - - if let Some(response) = response.result { - response - } else if let Some(error) = response.error { - panic!("Error: {:?}", error.message); - } else { - panic!("Error: no response or error field in response"); - } - } -} diff --git a/crates/runtime/Cargo.toml b/crates/runtime/Cargo.toml index eadaec2a9..586435a42 100644 --- a/crates/runtime/Cargo.toml +++ b/crates/runtime/Cargo.toml @@ -17,7 +17,6 @@ thiserror.workspace = true ureq.workspace = true wasmer.workspace = true wasmer-types.workspace = true -borsh = { workspace = true, features = ["derive"] } [[example]] name = "demo" diff --git a/crates/near-sdk/Cargo.toml b/crates/sdk/libs/near/Cargo.toml similarity index 78% rename from crates/near-sdk/Cargo.toml rename to crates/sdk/libs/near/Cargo.toml index c08b06cba..59cf5038d 100644 --- a/crates/near-sdk/Cargo.toml +++ b/crates/sdk/libs/near/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "near-sdk" +name = "calimero-sdk-near" version = "0.1.0" authors.workspace = true edition.workspace = true @@ -9,5 +9,5 @@ license.workspace = true [dependencies] serde = { workspace = true, features = ["derive"] } serde_json.workspace = true -calimero-sdk = { path = "../sdk" } +calimero-sdk = { path = "../../" } diff --git a/crates/sdk/libs/near/src/jsonrpc.rs b/crates/sdk/libs/near/src/jsonrpc.rs new file mode 100644 index 000000000..0e73deb4f --- /dev/null +++ b/crates/sdk/libs/near/src/jsonrpc.rs @@ -0,0 +1,66 @@ +use calimero_sdk::env; +use serde::de::DeserializeOwned; +use serde::{Deserialize, Serialize}; + +pub(crate) struct Client { + url: String, +} + +impl Client { + pub fn new(url: String) -> Self { + Self { url } + } + + pub fn call( + &self, + method: &str, + params: serde_json::Value, + ) -> Result, String> { + let headers = [("Content-Type", "application/json")]; + + let body = serde_json::to_vec(&serde_json::json!({ + "jsonrpc": "2.0", + "id": "1", + "method": method, + "params": params, + })) + .map_err(|err| format!("Cannot serialize request: {:?}", err))?; + + let response = unsafe { env::ext::fetch(&self.url, "POST", &headers, &body) }?; + serde_json::from_slice(&response).unwrap() + } +} + +#[derive(Serialize, Deserialize)] +#[serde(remote = "Result")] +pub enum ResultAlt { + #[serde(rename = "result")] + Ok(T), + #[serde(rename = "error")] + Err(E), +} + +impl From> for Result { + fn from(result: ResultAlt) -> Self { + match result { + ResultAlt::Ok(value) => Ok(value), + ResultAlt::Err(err) => Err(err), + } + } +} + +#[derive(Debug, Clone, Deserialize)] +pub struct Response { + pub jsonrpc: Option, + pub id: String, + + #[serde(with = "ResultAlt")] + pub data: Result>, +} + +#[derive(Debug, Clone, Deserialize)] +pub struct RpcError { + pub code: i32, + pub message: String, + pub data: Option, +} diff --git a/crates/sdk/libs/near/src/lib.rs b/crates/sdk/libs/near/src/lib.rs new file mode 100644 index 000000000..10192a702 --- /dev/null +++ b/crates/sdk/libs/near/src/lib.rs @@ -0,0 +1,43 @@ +use jsonrpc::Response; +use serde::Deserialize; + +mod jsonrpc; + +pub struct NearSdk { + client: jsonrpc::Client, +} + +#[derive(Debug, Clone, Deserialize)] +pub struct BalanceResponse { + pub amount: String, +} + +impl NearSdk { + pub fn testnet() -> Self { + Self { + client: jsonrpc::Client::new("https://rpc.testnet.near.org/".to_string()), + } + } + + pub fn mainnet() -> Self { + Self { + client: jsonrpc::Client::new("https://rpc.mainnet.near.org/".to_string()), + } + } + + pub fn get_balance(&self, account_id: &str) -> Result { + let response: Response = self.client.call( + "query", + serde_json::json!({ + "request_type": "view_account", + "finality": "final", + "account_id": account_id, + }), + )?; + + match response.data { + Ok(r) => Ok(r), + Err(e) => Err(e.message), + } + } +} diff --git a/crates/sdk/src/env.rs b/crates/sdk/src/env.rs index ec312438a..9cb0465a1 100644 --- a/crates/sdk/src/env.rs +++ b/crates/sdk/src/env.rs @@ -1,5 +1,3 @@ -use std::collections::HashMap; - use crate::sys; #[doc(hidden)] @@ -157,16 +155,3 @@ pub fn state_write(state: &T) { }; storage_write(STATE_KEY, &data); } - -pub fn fetch(method: &str, url: &str, headers: HashMap, body: Vec) -> String { - let headers = match borsh::to_vec(&headers) { - Ok(data) => data, - Err(err) => panic_str(&format!("Cannot serialize headers: {:?}", err)), - }; - let method = sys::Buffer::from(method); - let url = sys::Buffer::from(url); - let headers = sys::Buffer::from(headers.as_slice()); - let body = sys::Buffer::from(body.as_slice()); - unsafe { sys::fetch(method, url, headers, body, DATA_REGISTER) } - String::from_utf8(read_register(DATA_REGISTER).unwrap_or_else(expected_register)).unwrap() -} From a63bc2b4b03c7a019b2517ca979d48905cca0c83 Mon Sep 17 00:00:00 2001 From: Saeed Dadkhah Date: Tue, 18 Jun 2024 15:09:30 +0330 Subject: [PATCH 07/34] Fix serde deserializer --- Cargo.lock | 1 + crates/primitives/src/common.rs | 20 ++++++++++++++++++++ crates/sdk/libs/near/Cargo.toml | 1 + crates/sdk/libs/near/src/jsonrpc.rs | 20 +------------------- 4 files changed, 23 insertions(+), 19 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 27094a7cc..6492e0bdc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1186,6 +1186,7 @@ dependencies = [ name = "calimero-sdk-near" version = "0.1.0" dependencies = [ + "calimero-primitives", "calimero-sdk", "serde", "serde_json", diff --git a/crates/primitives/src/common.rs b/crates/primitives/src/common.rs index 0f1182e32..cf8b83007 100644 --- a/crates/primitives/src/common.rs +++ b/crates/primitives/src/common.rs @@ -1,3 +1,23 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize)] +#[serde(remote = "Result")] +pub enum ResultAlt { + #[serde(rename = "result")] + Ok(T), + #[serde(rename = "error")] + Err(E), +} + +impl From> for Result { + fn from(result: ResultAlt) -> Self { + match result { + ResultAlt::Ok(value) => Ok(value), + ResultAlt::Err(err) => Err(err), + } + } +} + pub const fn bool_true() -> bool { true } diff --git a/crates/sdk/libs/near/Cargo.toml b/crates/sdk/libs/near/Cargo.toml index 59cf5038d..c705b756c 100644 --- a/crates/sdk/libs/near/Cargo.toml +++ b/crates/sdk/libs/near/Cargo.toml @@ -10,4 +10,5 @@ license.workspace = true serde = { workspace = true, features = ["derive"] } serde_json.workspace = true calimero-sdk = { path = "../../" } +calimero-primitives = { path = "../../../primitives" } diff --git a/crates/sdk/libs/near/src/jsonrpc.rs b/crates/sdk/libs/near/src/jsonrpc.rs index 0e73deb4f..5f74270fb 100644 --- a/crates/sdk/libs/near/src/jsonrpc.rs +++ b/crates/sdk/libs/near/src/jsonrpc.rs @@ -31,30 +31,12 @@ impl Client { } } -#[derive(Serialize, Deserialize)] -#[serde(remote = "Result")] -pub enum ResultAlt { - #[serde(rename = "result")] - Ok(T), - #[serde(rename = "error")] - Err(E), -} - -impl From> for Result { - fn from(result: ResultAlt) -> Self { - match result { - ResultAlt::Ok(value) => Ok(value), - ResultAlt::Err(err) => Err(err), - } - } -} - #[derive(Debug, Clone, Deserialize)] pub struct Response { pub jsonrpc: Option, pub id: String, - #[serde(with = "ResultAlt")] + #[serde(with = "calimero_primitives::common::ResultAlt")] pub data: Result>, } From 854b6fea740b193dbb1e419c3143bc588e10ad9a Mon Sep 17 00:00:00 2001 From: Saeed Dadkhah Date: Tue, 18 Jun 2024 15:49:59 +0330 Subject: [PATCH 08/34] Remove unwrap --- crates/sdk/libs/near/src/jsonrpc.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/crates/sdk/libs/near/src/jsonrpc.rs b/crates/sdk/libs/near/src/jsonrpc.rs index 5f74270fb..056dc1a3a 100644 --- a/crates/sdk/libs/near/src/jsonrpc.rs +++ b/crates/sdk/libs/near/src/jsonrpc.rs @@ -1,6 +1,6 @@ use calimero_sdk::env; use serde::de::DeserializeOwned; -use serde::{Deserialize, Serialize}; +use serde::Deserialize; pub(crate) struct Client { url: String, @@ -27,7 +27,8 @@ impl Client { .map_err(|err| format!("Cannot serialize request: {:?}", err))?; let response = unsafe { env::ext::fetch(&self.url, "POST", &headers, &body) }?; - serde_json::from_slice(&response).unwrap() + serde_json::from_slice(&response) + .map_err(|err| format!("Cannot deserialize response: {:?}", err))? } } From 3d387423b57db99ba77bc28e251b7dd3bd3dec1b Mon Sep 17 00:00:00 2001 From: Saeed Dadkhah Date: Tue, 18 Jun 2024 19:12:35 +0330 Subject: [PATCH 09/34] Add methods --- crates/primitives/src/common.rs | 20 ------------------- crates/runtime/src/logic.rs | 1 - crates/sdk/libs/near/Cargo.toml | 1 - crates/sdk/libs/near/src/jsonrpc.rs | 26 ++++++++++++++++++++---- crates/sdk/libs/near/src/lib.rs | 31 +++++++++++++++++++---------- crates/sdk/libs/near/src/views.rs | 15 ++++++++++++++ 6 files changed, 58 insertions(+), 36 deletions(-) create mode 100644 crates/sdk/libs/near/src/views.rs diff --git a/crates/primitives/src/common.rs b/crates/primitives/src/common.rs index cf8b83007..0f1182e32 100644 --- a/crates/primitives/src/common.rs +++ b/crates/primitives/src/common.rs @@ -1,23 +1,3 @@ -use serde::{Deserialize, Serialize}; - -#[derive(Serialize, Deserialize)] -#[serde(remote = "Result")] -pub enum ResultAlt { - #[serde(rename = "result")] - Ok(T), - #[serde(rename = "error")] - Err(E), -} - -impl From> for Result { - fn from(result: ResultAlt) -> Self { - match result { - ResultAlt::Ok(value) => Ok(value), - ResultAlt::Err(err) => Err(err), - } - } -} - pub const fn bool_true() -> bool { true } diff --git a/crates/runtime/src/logic.rs b/crates/runtime/src/logic.rs index ac8681fea..ecb1a4fa4 100644 --- a/crates/runtime/src/logic.rs +++ b/crates/runtime/src/logic.rs @@ -1,4 +1,3 @@ -use std::collections::HashMap; use std::num::NonZeroU64; use ouroboros::self_referencing; diff --git a/crates/sdk/libs/near/Cargo.toml b/crates/sdk/libs/near/Cargo.toml index c705b756c..59cf5038d 100644 --- a/crates/sdk/libs/near/Cargo.toml +++ b/crates/sdk/libs/near/Cargo.toml @@ -10,5 +10,4 @@ license.workspace = true serde = { workspace = true, features = ["derive"] } serde_json.workspace = true calimero-sdk = { path = "../../" } -calimero-primitives = { path = "../../../primitives" } diff --git a/crates/sdk/libs/near/src/jsonrpc.rs b/crates/sdk/libs/near/src/jsonrpc.rs index 056dc1a3a..89750635c 100644 --- a/crates/sdk/libs/near/src/jsonrpc.rs +++ b/crates/sdk/libs/near/src/jsonrpc.rs @@ -1,6 +1,24 @@ use calimero_sdk::env; use serde::de::DeserializeOwned; -use serde::Deserialize; +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize)] +#[serde(remote = "Result")] +pub enum ResultAlt { + #[serde(rename = "result")] + Ok(T), + #[serde(rename = "error")] + Err(E), +} + +impl From> for Result { + fn from(result: ResultAlt) -> Self { + match result { + ResultAlt::Ok(value) => Ok(value), + ResultAlt::Err(err) => Err(err), + } + } +} pub(crate) struct Client { url: String, @@ -27,8 +45,8 @@ impl Client { .map_err(|err| format!("Cannot serialize request: {:?}", err))?; let response = unsafe { env::ext::fetch(&self.url, "POST", &headers, &body) }?; - serde_json::from_slice(&response) - .map_err(|err| format!("Cannot deserialize response: {:?}", err))? + let response = String::from_utf8(response).map_err(|e| e.to_string())?; + serde_json::from_str::>(&response).map_err(|e| e.to_string()) } } @@ -37,7 +55,7 @@ pub struct Response { pub jsonrpc: Option, pub id: String, - #[serde(with = "calimero_primitives::common::ResultAlt")] + #[serde(with = "ResultAlt", flatten)] pub data: Result>, } diff --git a/crates/sdk/libs/near/src/lib.rs b/crates/sdk/libs/near/src/lib.rs index 10192a702..6fa88d208 100644 --- a/crates/sdk/libs/near/src/lib.rs +++ b/crates/sdk/libs/near/src/lib.rs @@ -1,18 +1,13 @@ use jsonrpc::Response; -use serde::Deserialize; mod jsonrpc; +pub mod views; -pub struct NearSdk { +pub struct Client { client: jsonrpc::Client, } -#[derive(Debug, Clone, Deserialize)] -pub struct BalanceResponse { - pub amount: String, -} - -impl NearSdk { +impl Client { pub fn testnet() -> Self { Self { client: jsonrpc::Client::new("https://rpc.testnet.near.org/".to_string()), @@ -25,8 +20,8 @@ impl NearSdk { } } - pub fn get_balance(&self, account_id: &str) -> Result { - let response: Response = self.client.call( + pub fn view_account(&self, account_id: &str) -> Result { + let response: Response = self.client.call( "query", serde_json::json!({ "request_type": "view_account", @@ -40,4 +35,20 @@ impl NearSdk { Err(e) => Err(e.message), } } + + pub fn view_code(&self, account_id: &str) -> Result { + let response: Response = self.client.call( + "query", + serde_json::json!({ + "request_type": "view_code", + "finality": "final", + "account_id": account_id, + }), + )?; + + match response.data { + Ok(r) => Ok(r), + Err(e) => Err(e.message), + } + } } diff --git a/crates/sdk/libs/near/src/views.rs b/crates/sdk/libs/near/src/views.rs new file mode 100644 index 000000000..9ded6cf39 --- /dev/null +++ b/crates/sdk/libs/near/src/views.rs @@ -0,0 +1,15 @@ +#[derive(serde::Deserialize, Debug, Clone)] +pub struct AccountView { + pub amount: String, + pub locked: String, + pub code_hash: String, + pub storage_usage: String, + pub storage_paid_at: String, +} + +#[derive(serde::Deserialize, Debug, Clone)] +pub struct ContractCodeView { + #[serde(rename = "code_base64")] + pub code: String, + pub hash: String, +} From 96e6c6aa150365ce31831ad3d3591b03c069a6e9 Mon Sep 17 00:00:00 2001 From: Saeed Dadkhah Date: Wed, 19 Jun 2024 14:04:49 +0330 Subject: [PATCH 10/34] Move AltResult to primitives. --- Cargo.toml | 1 + crates/primitives/Cargo.toml | 2 +- crates/primitives/src/common.rs | 20 ++++++++++++++++++++ crates/primitives/src/events.rs | 2 +- crates/primitives/src/identity.rs | 2 +- crates/sdk/libs/near/Cargo.toml | 1 + crates/sdk/libs/near/src/jsonrpc.rs | 22 ++-------------------- 7 files changed, 27 insertions(+), 23 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 162280136..5acd8b2e2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -48,6 +48,7 @@ futures-util = "0.3.30" hex = "0.4.3" libp2p = "0.53.2" libp2p-stream = "0.1.0-alpha.1" +libp2p-identity = "0.2.9" multiaddr = "0.18.1" multibase = "0.9.1" near-jsonrpc-client = "0.8.0" diff --git a/crates/primitives/Cargo.toml b/crates/primitives/Cargo.toml index 85449581f..853969ada 100644 --- a/crates/primitives/Cargo.toml +++ b/crates/primitives/Cargo.toml @@ -9,7 +9,7 @@ license.workspace = true [dependencies] bs58.workspace = true ed25519-dalek.workspace = true -libp2p = { workspace = true, features = ["serde"] } +libp2p-identity = {workspace=true, features = ["peerid", "serde"]} semver = { workspace = true, features = ["serde"] } serde = { workspace = true, features = ["derive"] } serde_json.workspace = true diff --git a/crates/primitives/src/common.rs b/crates/primitives/src/common.rs index 0f1182e32..91a6e7f2d 100644 --- a/crates/primitives/src/common.rs +++ b/crates/primitives/src/common.rs @@ -1,3 +1,23 @@ +use serde::{Deserialize, Serialize}; + pub const fn bool_true() -> bool { true } + +#[derive(Serialize, Deserialize)] +#[serde(remote = "Result")] +pub enum ResultAlt { + #[serde(rename = "result")] + Ok(T), + #[serde(rename = "error")] + Err(E), +} + +impl From> for Result { + fn from(result: ResultAlt) -> Self { + match result { + ResultAlt::Ok(value) => Ok(value), + ResultAlt::Err(err) => Err(err), + } + } +} diff --git a/crates/primitives/src/events.rs b/crates/primitives/src/events.rs index beedc7495..7159ee04b 100644 --- a/crates/primitives/src/events.rs +++ b/crates/primitives/src/events.rs @@ -34,7 +34,7 @@ pub struct ExecutedTransactionPayload { #[derive(Clone, Serialize, Deserialize, Debug)] #[serde(rename_all = "camelCase")] pub struct PeerJoinedPayload { - pub peer_id: libp2p::PeerId, + pub peer_id: libp2p_identity::PeerId, } #[derive(Clone, Serialize, Deserialize, Debug)] diff --git a/crates/primitives/src/identity.rs b/crates/primitives/src/identity.rs index 2d2aa5e9f..5ad948fd9 100644 --- a/crates/primitives/src/identity.rs +++ b/crates/primitives/src/identity.rs @@ -124,7 +124,7 @@ pub mod serde_signing_key { pub mod serde_identity { use std::fmt; - use libp2p::identity::Keypair; + use libp2p_identity::Keypair; use serde::de::{self, MapAccess}; use serde::ser::{self, SerializeMap}; use serde::{Deserializer, Serializer}; diff --git a/crates/sdk/libs/near/Cargo.toml b/crates/sdk/libs/near/Cargo.toml index 59cf5038d..c705b756c 100644 --- a/crates/sdk/libs/near/Cargo.toml +++ b/crates/sdk/libs/near/Cargo.toml @@ -10,4 +10,5 @@ license.workspace = true serde = { workspace = true, features = ["derive"] } serde_json.workspace = true calimero-sdk = { path = "../../" } +calimero-primitives = { path = "../../../primitives" } diff --git a/crates/sdk/libs/near/src/jsonrpc.rs b/crates/sdk/libs/near/src/jsonrpc.rs index 89750635c..cf78340de 100644 --- a/crates/sdk/libs/near/src/jsonrpc.rs +++ b/crates/sdk/libs/near/src/jsonrpc.rs @@ -1,24 +1,6 @@ use calimero_sdk::env; use serde::de::DeserializeOwned; -use serde::{Deserialize, Serialize}; - -#[derive(Serialize, Deserialize)] -#[serde(remote = "Result")] -pub enum ResultAlt { - #[serde(rename = "result")] - Ok(T), - #[serde(rename = "error")] - Err(E), -} - -impl From> for Result { - fn from(result: ResultAlt) -> Self { - match result { - ResultAlt::Ok(value) => Ok(value), - ResultAlt::Err(err) => Err(err), - } - } -} +use serde::Deserialize; pub(crate) struct Client { url: String, @@ -55,7 +37,7 @@ pub struct Response { pub jsonrpc: Option, pub id: String, - #[serde(with = "ResultAlt", flatten)] + #[serde(with = "calimero_primitives::common::ResultAlt", flatten)] pub data: Result>, } From 6bd911dc9a375a0c44eb1c63cba55eaa129c1cca Mon Sep 17 00:00:00 2001 From: Saeed Dadkhah Date: Wed, 19 Jun 2024 14:15:53 +0330 Subject: [PATCH 11/34] Make id incremental --- crates/sdk/libs/near/src/jsonrpc.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/crates/sdk/libs/near/src/jsonrpc.rs b/crates/sdk/libs/near/src/jsonrpc.rs index cf78340de..c4cfc1089 100644 --- a/crates/sdk/libs/near/src/jsonrpc.rs +++ b/crates/sdk/libs/near/src/jsonrpc.rs @@ -4,11 +4,15 @@ use serde::Deserialize; pub(crate) struct Client { url: String, + id: std::cell::RefCell, } impl Client { pub fn new(url: String) -> Self { - Self { url } + Self { + url, + id: std::cell::RefCell::new(0), + } } pub fn call( @@ -18,9 +22,10 @@ impl Client { ) -> Result, String> { let headers = [("Content-Type", "application/json")]; + *self.id.borrow_mut() += 1; let body = serde_json::to_vec(&serde_json::json!({ "jsonrpc": "2.0", - "id": "1", + "id": self.id.borrow().to_string(), "method": method, "params": params, })) From 222ae8d8de70e1bdb455e7906eda9831e9904b73 Mon Sep 17 00:00:00 2001 From: Saeed Dadkhah Date: Wed, 19 Jun 2024 16:14:45 +0330 Subject: [PATCH 12/34] Make view account more restricted. --- crates/sdk/libs/near/src/jsonrpc.rs | 4 +-- crates/sdk/libs/near/src/lib.rs | 39 ++++++++++++++++++++--------- crates/sdk/libs/near/src/query.rs | 26 +++++++++++++++++++ crates/sdk/libs/near/src/types.rs | 11 ++++++++ crates/sdk/libs/near/src/views.rs | 13 ++++++++-- 5 files changed, 77 insertions(+), 16 deletions(-) create mode 100644 crates/sdk/libs/near/src/query.rs create mode 100644 crates/sdk/libs/near/src/types.rs diff --git a/crates/sdk/libs/near/src/jsonrpc.rs b/crates/sdk/libs/near/src/jsonrpc.rs index c4cfc1089..dfbe3d22b 100644 --- a/crates/sdk/libs/near/src/jsonrpc.rs +++ b/crates/sdk/libs/near/src/jsonrpc.rs @@ -32,8 +32,8 @@ impl Client { .map_err(|err| format!("Cannot serialize request: {:?}", err))?; let response = unsafe { env::ext::fetch(&self.url, "POST", &headers, &body) }?; - let response = String::from_utf8(response).map_err(|e| e.to_string())?; - serde_json::from_str::>(&response).map_err(|e| e.to_string()) + serde_json::from_slice::>(&response) + .map_err(|e| format!("Failed to parse response: {}", e.to_string(),)) } } diff --git a/crates/sdk/libs/near/src/lib.rs b/crates/sdk/libs/near/src/lib.rs index 6fa88d208..eee4008c0 100644 --- a/crates/sdk/libs/near/src/lib.rs +++ b/crates/sdk/libs/near/src/lib.rs @@ -1,6 +1,11 @@ use jsonrpc::Response; +use query::{QueryResponseKind, RpcQueryRequest}; +use types::BlockId; +use views::QueryRequest; mod jsonrpc; +pub mod query; +pub mod types; pub mod views; pub struct Client { @@ -20,19 +25,29 @@ impl Client { } } - pub fn view_account(&self, account_id: &str) -> Result { - let response: Response = self.client.call( - "query", - serde_json::json!({ - "request_type": "view_account", - "finality": "final", - "account_id": account_id, - }), - )?; + pub fn view_account( + &self, + account_id: &str, + block_id: BlockId, + ) -> Result { + let request = RpcQueryRequest { + block_id, + request: QueryRequest::ViewAccount { + account_id: account_id.to_string(), + }, + }; + let response: Response = self + .client + .call("query", serde_json::to_value(&request).unwrap())?; match response.data { - Ok(r) => Ok(r), - Err(e) => Err(e.message), + Ok(r) => { + if let QueryResponseKind::ViewAccount(va) = r.kind { + return Ok(va); + } + return Err("Unexpected response returned.".to_string()); + } + Err(e) => Err(format!("Error: {}, Code: {}", e.message, e.code,)), } } @@ -48,7 +63,7 @@ impl Client { match response.data { Ok(r) => Ok(r), - Err(e) => Err(e.message), + Err(e) => Err(format!("Error: {}, Code: {}", e.message, e.code,)), } } } diff --git a/crates/sdk/libs/near/src/query.rs b/crates/sdk/libs/near/src/query.rs new file mode 100644 index 000000000..7668e45a1 --- /dev/null +++ b/crates/sdk/libs/near/src/query.rs @@ -0,0 +1,26 @@ +use crate::{ + types::{BlockHash, BlockHeight, BlockId}, + views::{AccountView, ContractCodeView, QueryRequest}, +}; + +#[derive(serde::Serialize, Debug)] +pub struct RpcQueryRequest { + pub block_id: BlockId, + #[serde(flatten)] + pub request: QueryRequest, +} + +#[derive(serde::Deserialize, Debug)] +pub struct RpcQueryResponse { + #[serde(flatten)] + pub kind: QueryResponseKind, + pub block_height: BlockHeight, + pub block_hash: BlockHash, +} + +#[derive(serde::Deserialize, Debug)] +#[serde(untagged)] +pub enum QueryResponseKind { + ViewAccount(AccountView), + ViewCode(ContractCodeView), +} diff --git a/crates/sdk/libs/near/src/types.rs b/crates/sdk/libs/near/src/types.rs new file mode 100644 index 000000000..87c84c5b0 --- /dev/null +++ b/crates/sdk/libs/near/src/types.rs @@ -0,0 +1,11 @@ +pub type BlockHeight = u64; +pub type BlockHash = String; +pub type AccountId = String; +pub type StorageUsage = u64; + +#[derive(Debug, Clone, serde::Serialize)] +#[serde(untagged)] +pub enum BlockId { + Height(BlockHeight), + Hash(BlockHash), +} diff --git a/crates/sdk/libs/near/src/views.rs b/crates/sdk/libs/near/src/views.rs index 9ded6cf39..f571e4be7 100644 --- a/crates/sdk/libs/near/src/views.rs +++ b/crates/sdk/libs/near/src/views.rs @@ -1,10 +1,19 @@ +use crate::types::{AccountId, BlockHeight, StorageUsage}; + +#[derive(serde::Serialize, Debug)] +#[serde(tag = "request_type", rename_all = "snake_case")] +pub enum QueryRequest { + ViewAccount { account_id: AccountId }, + ViewCode { account_id: AccountId }, +} + #[derive(serde::Deserialize, Debug, Clone)] pub struct AccountView { pub amount: String, pub locked: String, pub code_hash: String, - pub storage_usage: String, - pub storage_paid_at: String, + pub storage_usage: StorageUsage, + pub storage_paid_at: BlockHeight, } #[derive(serde::Deserialize, Debug, Clone)] From 792de5926cdb5dace80f5c300ce8487eb1ef19e1 Mon Sep 17 00:00:00 2001 From: Saeed Dadkhah Date: Wed, 19 Jun 2024 16:17:02 +0330 Subject: [PATCH 13/34] Fix code style --- crates/primitives/Cargo.toml | 2 +- crates/sdk/libs/near/Cargo.toml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/crates/primitives/Cargo.toml b/crates/primitives/Cargo.toml index 853969ada..1afb1ab86 100644 --- a/crates/primitives/Cargo.toml +++ b/crates/primitives/Cargo.toml @@ -9,7 +9,7 @@ license.workspace = true [dependencies] bs58.workspace = true ed25519-dalek.workspace = true -libp2p-identity = {workspace=true, features = ["peerid", "serde"]} +libp2p-identity = {workspace = true, features = ["peerid", "serde"]} semver = { workspace = true, features = ["serde"] } serde = { workspace = true, features = ["derive"] } serde_json.workspace = true diff --git a/crates/sdk/libs/near/Cargo.toml b/crates/sdk/libs/near/Cargo.toml index c705b756c..f1260ce4b 100644 --- a/crates/sdk/libs/near/Cargo.toml +++ b/crates/sdk/libs/near/Cargo.toml @@ -9,6 +9,7 @@ license.workspace = true [dependencies] serde = { workspace = true, features = ["derive"] } serde_json.workspace = true + calimero-sdk = { path = "../../" } calimero-primitives = { path = "../../../primitives" } From 4ed7b775166dabe3465c24acbe366b19c55721b0 Mon Sep 17 00:00:00 2001 From: Saeed Dadkhah Date: Thu, 20 Jun 2024 11:50:16 +0330 Subject: [PATCH 14/34] Add more query functions --- Cargo.toml | 1 + crates/sdk/libs/near/Cargo.toml | 1 + crates/sdk/libs/near/src/jsonrpc.rs | 27 +++++--- crates/sdk/libs/near/src/lib.rs | 95 ++++++++++++++++++++++++----- crates/sdk/libs/near/src/query.rs | 7 ++- crates/sdk/libs/near/src/types.rs | 14 +++++ crates/sdk/libs/near/src/views.rs | 75 +++++++++++++++++++++-- 7 files changed, 192 insertions(+), 28 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 5acd8b2e2..6c466d82b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -70,6 +70,7 @@ sha3 = "0.10.8" semver = "1.0.22" serde = "1.0.196" serde_json = "1.0.113" +serde_with = "3.8.1" syn = "2.0" thiserror = "1.0.56" tokio = "1.35.1" diff --git a/crates/sdk/libs/near/Cargo.toml b/crates/sdk/libs/near/Cargo.toml index f1260ce4b..91bb0ed13 100644 --- a/crates/sdk/libs/near/Cargo.toml +++ b/crates/sdk/libs/near/Cargo.toml @@ -9,6 +9,7 @@ license.workspace = true [dependencies] serde = { workspace = true, features = ["derive"] } serde_json.workspace = true +serde_with = {workspace = true, features = ["base64"]} calimero-sdk = { path = "../../" } calimero-primitives = { path = "../../../primitives" } diff --git a/crates/sdk/libs/near/src/jsonrpc.rs b/crates/sdk/libs/near/src/jsonrpc.rs index dfbe3d22b..bc2f80f11 100644 --- a/crates/sdk/libs/near/src/jsonrpc.rs +++ b/crates/sdk/libs/near/src/jsonrpc.rs @@ -1,6 +1,6 @@ use calimero_sdk::env; use serde::de::DeserializeOwned; -use serde::Deserialize; +use serde::{Deserialize, Serialize}; pub(crate) struct Client { url: String, @@ -15,20 +15,20 @@ impl Client { } } - pub fn call( + pub fn call( &self, method: &str, - params: serde_json::Value, + params: P, ) -> Result, String> { let headers = [("Content-Type", "application/json")]; *self.id.borrow_mut() += 1; - let body = serde_json::to_vec(&serde_json::json!({ - "jsonrpc": "2.0", - "id": self.id.borrow().to_string(), - "method": method, - "params": params, - })) + let body = serde_json::to_vec(&Request { + jsonrpc: "2.0", + id: self.id.borrow().to_string(), + method: method.to_string(), + params, + }) .map_err(|err| format!("Cannot serialize request: {:?}", err))?; let response = unsafe { env::ext::fetch(&self.url, "POST", &headers, &body) }?; @@ -37,6 +37,15 @@ impl Client { } } +#[derive(Debug, Clone, Serialize)] +pub struct Request { + pub jsonrpc: &'static str, + pub id: String, + pub method: String, + + pub params: P, +} + #[derive(Debug, Clone, Deserialize)] pub struct Response { pub jsonrpc: Option, diff --git a/crates/sdk/libs/near/src/lib.rs b/crates/sdk/libs/near/src/lib.rs index eee4008c0..ff0e6b348 100644 --- a/crates/sdk/libs/near/src/lib.rs +++ b/crates/sdk/libs/near/src/lib.rs @@ -1,6 +1,6 @@ use jsonrpc::Response; use query::{QueryResponseKind, RpcQueryRequest}; -use types::BlockId; +use types::{BlockId, StoreKey}; use views::QueryRequest; mod jsonrpc; @@ -36,9 +36,8 @@ impl Client { account_id: account_id.to_string(), }, }; - let response: Response = self - .client - .call("query", serde_json::to_value(&request).unwrap())?; + let response: Response = + self.client.call("query", request)?; match response.data { Ok(r) => { @@ -51,18 +50,86 @@ impl Client { } } - pub fn view_code(&self, account_id: &str) -> Result { - let response: Response = self.client.call( - "query", - serde_json::json!({ - "request_type": "view_code", - "finality": "final", - "account_id": account_id, - }), - )?; + pub fn view_code( + &self, + account_id: &str, + block_id: BlockId, + ) -> Result { + let request = RpcQueryRequest { + block_id, + request: QueryRequest::ViewCode { + account_id: account_id.to_string(), + }, + }; + + let response: Response = + self.client.call("query", request)?; match response.data { - Ok(r) => Ok(r), + Ok(r) => { + if let QueryResponseKind::ViewCode(vc) = r.kind { + return Ok(vc); + } + return Err("Unexpected response returned.".to_string()); + } + Err(e) => Err(format!("Error: {}, Code: {}", e.message, e.code,)), + } + } + + pub fn view_state( + &self, + account_id: &str, + prefix: StoreKey, + include_proof: bool, + block_id: BlockId, + ) -> Result { + let request = RpcQueryRequest { + block_id, + request: QueryRequest::ViewState { + account_id: account_id.to_string(), + prefix, + include_proof, + }, + }; + + let response: Response = + self.client.call("query", request)?; + + match response.data { + Ok(r) => { + if let QueryResponseKind::ViewState(vs) = r.kind { + return Ok(vs); + } + return Err("Unexpected response returned.".to_string()); + } + Err(e) => Err(format!("Error: {}, Code: {}", e.message, e.code,)), + } + } + + pub fn view_access_key( + &self, + account_id: &str, + public_key: &str, + block_id: BlockId, + ) -> Result { + let request = RpcQueryRequest { + block_id, + request: QueryRequest::ViewAccessKey { + account_id: account_id.to_string(), + public_key: public_key.to_string(), + }, + }; + + let response: Response = + self.client.call("query", request)?; + + match response.data { + Ok(r) => { + if let QueryResponseKind::ViewState(vs) = r.kind { + return Ok(vs); + } + return Err("Unexpected response returned.".to_string()); + } Err(e) => Err(format!("Error: {}, Code: {}", e.message, e.code,)), } } diff --git a/crates/sdk/libs/near/src/query.rs b/crates/sdk/libs/near/src/query.rs index 7668e45a1..36f9dc4d5 100644 --- a/crates/sdk/libs/near/src/query.rs +++ b/crates/sdk/libs/near/src/query.rs @@ -1,6 +1,8 @@ use crate::{ types::{BlockHash, BlockHeight, BlockId}, - views::{AccountView, ContractCodeView, QueryRequest}, + views::{ + AccessKeyList, AccessKeyView, AccountView, ContractCodeView, QueryRequest, ViewStateResult, + }, }; #[derive(serde::Serialize, Debug)] @@ -23,4 +25,7 @@ pub struct RpcQueryResponse { pub enum QueryResponseKind { ViewAccount(AccountView), ViewCode(ContractCodeView), + ViewState(ViewStateResult), + AccessKey(AccessKeyView), + AccessKeyList(AccessKeyList), } diff --git a/crates/sdk/libs/near/src/types.rs b/crates/sdk/libs/near/src/types.rs index 87c84c5b0..e48a25994 100644 --- a/crates/sdk/libs/near/src/types.rs +++ b/crates/sdk/libs/near/src/types.rs @@ -1,7 +1,11 @@ +use serde_with::base64::Base64; +use serde_with::serde_as; + pub type BlockHeight = u64; pub type BlockHash = String; pub type AccountId = String; pub type StorageUsage = u64; +pub type Nonce = u64; #[derive(Debug, Clone, serde::Serialize)] #[serde(untagged)] @@ -9,3 +13,13 @@ pub enum BlockId { Height(BlockHeight), Hash(BlockHash), } + +#[serde_as] +#[derive(serde::Deserialize, Clone, Debug)] +#[serde(transparent)] +pub struct StoreValue(#[serde_as(as = "Base64")] pub Vec); + +#[serde_as] +#[derive(serde::Serialize, serde::Deserialize, Clone, Debug)] +#[serde(transparent)] +pub struct StoreKey(#[serde_as(as = "Base64")] pub Vec); diff --git a/crates/sdk/libs/near/src/views.rs b/crates/sdk/libs/near/src/views.rs index f571e4be7..a51d360fa 100644 --- a/crates/sdk/libs/near/src/views.rs +++ b/crates/sdk/libs/near/src/views.rs @@ -1,10 +1,33 @@ -use crate::types::{AccountId, BlockHeight, StorageUsage}; +use std::sync::Arc; + +use serde_with::base64::Base64; +use serde_with::serde_as; + +use crate::types::{AccountId, BlockHeight, Nonce, StorageUsage, StoreKey, StoreValue}; #[derive(serde::Serialize, Debug)] #[serde(tag = "request_type", rename_all = "snake_case")] pub enum QueryRequest { - ViewAccount { account_id: AccountId }, - ViewCode { account_id: AccountId }, + ViewAccount { + account_id: AccountId, + }, + ViewCode { + account_id: AccountId, + }, + ViewState { + account_id: AccountId, + #[serde(rename = "prefix_base64")] + prefix: StoreKey, + #[serde(default)] + include_proof: bool, + }, + ViewAccessKey { + account_id: AccountId, + public_key: String, + }, + ViewAccessKeyList { + account_id: AccountId, + }, } #[derive(serde::Deserialize, Debug, Clone)] @@ -16,9 +39,53 @@ pub struct AccountView { pub storage_paid_at: BlockHeight, } +#[serde_as] #[derive(serde::Deserialize, Debug, Clone)] pub struct ContractCodeView { #[serde(rename = "code_base64")] - pub code: String, + #[serde_as(as = "Base64")] + pub code: Vec, pub hash: String, } + +#[derive(serde::Deserialize, Debug, Clone)] +pub struct StateItem { + pub key: StoreKey, + pub value: StoreValue, +} + +#[serde_as] +#[derive(serde::Deserialize, Debug, Clone)] +pub struct ViewStateResult { + pub values: Vec, + #[serde_as(as = "Vec")] + #[serde(default, skip_serializing_if = "Vec::is_empty")] + pub proof: Vec>, +} + +#[derive(Debug, Clone, serde::Deserialize)] +pub struct AccessKeyView { + pub nonce: Nonce, + pub permission: AccessKeyPermissionView, +} + +#[derive(Debug, Clone, serde::Deserialize)] +pub enum AccessKeyPermissionView { + FunctionCall { + allowance: Option, + receiver_id: String, + method_names: Vec, + }, + FullAccess, +} + +#[derive(serde::Deserialize, Debug, Clone)] +pub struct AccessKeyList { + pub keys: Vec, +} + +#[derive(serde::Deserialize, Debug, Clone)] +pub struct AccessKeyInfoView { + pub public_key: String, + pub access_key: AccessKeyView, +} From b13f56f3063d94f7226b7ddff9b3e640eaf60aa5 Mon Sep 17 00:00:00 2001 From: Saeed Dadkhah Date: Fri, 21 Jun 2024 11:01:36 +0330 Subject: [PATCH 15/34] add function call. --- crates/sdk/libs/near/src/lib.rs | 32 ++++++++++++++++++++++++++++++- crates/sdk/libs/near/src/query.rs | 4 +++- crates/sdk/libs/near/src/types.rs | 5 +++++ crates/sdk/libs/near/src/views.rs | 16 +++++++++++++++- 4 files changed, 54 insertions(+), 3 deletions(-) diff --git a/crates/sdk/libs/near/src/lib.rs b/crates/sdk/libs/near/src/lib.rs index ff0e6b348..742ccb262 100644 --- a/crates/sdk/libs/near/src/lib.rs +++ b/crates/sdk/libs/near/src/lib.rs @@ -1,6 +1,6 @@ use jsonrpc::Response; use query::{QueryResponseKind, RpcQueryRequest}; -use types::{BlockId, StoreKey}; +use types::{BlockId, FunctionArgs, StoreKey}; use views::QueryRequest; mod jsonrpc; @@ -133,4 +133,34 @@ impl Client { Err(e) => Err(format!("Error: {}, Code: {}", e.message, e.code,)), } } + + pub fn call_function( + &self, + account_id: &str, + method_name: &str, + args: FunctionArgs, + block_id: BlockId, + ) -> Result { + let request = RpcQueryRequest { + block_id, + request: QueryRequest::CallFunction { + account_id: account_id.to_string(), + method_name: method_name.to_string(), + args, + }, + }; + + let response: Response = + self.client.call("query", request)?; + + match response.data { + Ok(r) => { + if let QueryResponseKind::CallResult(cr) = r.kind { + return Ok(cr); + } + return Err("Unexpected response returned.".to_string()); + } + Err(e) => Err(format!("Error: {}, Code: {}", e.message, e.code,)), + } + } } diff --git a/crates/sdk/libs/near/src/query.rs b/crates/sdk/libs/near/src/query.rs index 36f9dc4d5..215f9d0b1 100644 --- a/crates/sdk/libs/near/src/query.rs +++ b/crates/sdk/libs/near/src/query.rs @@ -1,7 +1,8 @@ use crate::{ types::{BlockHash, BlockHeight, BlockId}, views::{ - AccessKeyList, AccessKeyView, AccountView, ContractCodeView, QueryRequest, ViewStateResult, + AccessKeyList, AccessKeyView, AccountView, CallResult, ContractCodeView, QueryRequest, + ViewStateResult, }, }; @@ -28,4 +29,5 @@ pub enum QueryResponseKind { ViewState(ViewStateResult), AccessKey(AccessKeyView), AccessKeyList(AccessKeyList), + CallResult(CallResult), } diff --git a/crates/sdk/libs/near/src/types.rs b/crates/sdk/libs/near/src/types.rs index e48a25994..9c9fe67bc 100644 --- a/crates/sdk/libs/near/src/types.rs +++ b/crates/sdk/libs/near/src/types.rs @@ -23,3 +23,8 @@ pub struct StoreValue(#[serde_as(as = "Base64")] pub Vec); #[derive(serde::Serialize, serde::Deserialize, Clone, Debug)] #[serde(transparent)] pub struct StoreKey(#[serde_as(as = "Base64")] pub Vec); + +#[serde_as] +#[derive(serde::Serialize, Clone, Debug)] +#[serde(transparent)] +pub struct FunctionArgs(#[serde_as(as = "Base64")] Vec); diff --git a/crates/sdk/libs/near/src/views.rs b/crates/sdk/libs/near/src/views.rs index a51d360fa..b7acd5451 100644 --- a/crates/sdk/libs/near/src/views.rs +++ b/crates/sdk/libs/near/src/views.rs @@ -3,7 +3,9 @@ use std::sync::Arc; use serde_with::base64::Base64; use serde_with::serde_as; -use crate::types::{AccountId, BlockHeight, Nonce, StorageUsage, StoreKey, StoreValue}; +use crate::types::{ + AccountId, BlockHeight, FunctionArgs, Nonce, StorageUsage, StoreKey, StoreValue, +}; #[derive(serde::Serialize, Debug)] #[serde(tag = "request_type", rename_all = "snake_case")] @@ -28,6 +30,12 @@ pub enum QueryRequest { ViewAccessKeyList { account_id: AccountId, }, + CallFunction { + account_id: AccountId, + method_name: String, + #[serde(rename = "args_base64")] + args: FunctionArgs, + }, } #[derive(serde::Deserialize, Debug, Clone)] @@ -89,3 +97,9 @@ pub struct AccessKeyInfoView { pub public_key: String, pub access_key: AccessKeyView, } + +#[derive(serde::Deserialize, Debug, Clone)] +pub struct CallResult { + pub result: Vec, + pub logs: Vec, +} From 93d3144bcabec11d5478750776c177822b1effba Mon Sep 17 00:00:00 2001 From: Saeed Dadkhah Date: Fri, 21 Jun 2024 11:04:51 +0330 Subject: [PATCH 16/34] change comment --- crates/runtime/src/logic.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/crates/runtime/src/logic.rs b/crates/runtime/src/logic.rs index ecb1a4fa4..657e6f8f8 100644 --- a/crates/runtime/src/logic.rs +++ b/crates/runtime/src/logic.rs @@ -321,7 +321,9 @@ impl<'a> VMHostFunctions<'a> { let url = self.get_string(url_ptr, url_len)?; let method = self.get_string(method_ptr, method_len)?; let headers = self.read_guest_memory(headers_ptr, headers_len)?; - let headers: Vec<(String, String)> = borsh::from_slice(&headers).unwrap(); // safety: headers are coming from an inner source. Safe to deserialize. + + // safety: It's not possible to call `fetch` directly by apps. So headers is generated by our code. Safe to deserialize. + let headers: Vec<(String, String)> = borsh::from_slice(&headers).unwrap(); let body = self.read_guest_memory(body_ptr, body_len)?; let mut request = ureq::request(&method, &url); From 9f9cf2d8af9ea99f0bec4228649331111e9c68ea Mon Sep 17 00:00:00 2001 From: Saeed Dadkhah Date: Fri, 21 Jun 2024 11:31:19 +0330 Subject: [PATCH 17/34] Update style --- Cargo.lock | 22 ++++++++++++---------- apps/only-peers/Cargo.toml | 1 + apps/only-peers/src/lib.rs | 11 +++++++++++ crates/primitives/Cargo.toml | 2 +- crates/runtime/examples/fetch.rs | 2 +- 5 files changed, 26 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8a84d3b10..eccb71d00 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1139,7 +1139,7 @@ dependencies = [ "bs58 0.5.1", "ed25519-dalek", "hex", - "libp2p", + "libp2p-identity", "semver", "serde", "serde_json", @@ -1196,6 +1196,7 @@ dependencies = [ "calimero-sdk", "serde", "serde_json", + "serde_with", ] [[package]] @@ -3883,9 +3884,9 @@ dependencies = [ [[package]] name = "libp2p-identity" -version = "0.2.8" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "999ec70441b2fb35355076726a6bc466c932e9bdc66f6a11c6c0aa17c7ab9be0" +checksum = "55cca1eb2bc1fd29f099f3daaab7effd01e1a54b7c577d0ed082521034d912e8" dependencies = [ "asn1_der", "bs58 0.5.1", @@ -5388,6 +5389,7 @@ name = "only-peers" version = "0.1.0" dependencies = [ "calimero-sdk", + "calimero-sdk-near", ] [[package]] @@ -7036,11 +7038,11 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.7.0" +version = "3.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee80b0e361bbf88fd2f6e242ccd19cfda072cb0faa6ae694ecee08199938569a" +checksum = "0ad483d2ab0149d5a5ebcd9972a3852711e0153d863bf5a5d0391d28883c4a20" dependencies = [ - "base64 0.21.7", + "base64 0.22.0", "chrono", "hex", "indexmap 1.9.3", @@ -7054,9 +7056,9 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.7.0" +version = "3.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6561dc161a9224638a31d876ccdfefbc1df91d3f3a8342eddb35f055d48c7655" +checksum = "65569b702f41443e8bc8bbb1c5779bd0450bbe723b56198980e80ec45780bce2" dependencies = [ "darling", "proc-macro2", @@ -9157,9 +9159,9 @@ dependencies = [ [[package]] name = "zeroize" -version = "1.7.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" dependencies = [ "zeroize_derive", ] diff --git a/apps/only-peers/Cargo.toml b/apps/only-peers/Cargo.toml index cc3360bac..c6ea8b840 100644 --- a/apps/only-peers/Cargo.toml +++ b/apps/only-peers/Cargo.toml @@ -11,3 +11,4 @@ crate-type = ["cdylib"] [dependencies] calimero-sdk = { path = "../../crates/sdk" } +calimero-sdk-near = { path = "../../crates/sdk/libs/near" } diff --git a/apps/only-peers/src/lib.rs b/apps/only-peers/src/lib.rs index 7375f5c6c..c8958a397 100644 --- a/apps/only-peers/src/lib.rs +++ b/apps/only-peers/src/lib.rs @@ -43,6 +43,17 @@ pub enum Event<'a> { #[app::logic] impl OnlyPeers { + pub fn foo(&mut self) -> String { + let client = calimero_sdk_near::Client::testnet(); + match client.view_account( + "nearkat.testnet", + calimero_sdk_near::types::BlockId::Height(166710735), + ) { + Ok(r) => format!("{}", r.amount), + Err(e) => e, + } + } + pub fn post(&self, id: usize) -> Option<&Post> { env::log(&format!("Getting post with id: {:?}", id)); diff --git a/crates/primitives/Cargo.toml b/crates/primitives/Cargo.toml index 1afb1ab86..3157d63eb 100644 --- a/crates/primitives/Cargo.toml +++ b/crates/primitives/Cargo.toml @@ -9,7 +9,7 @@ license.workspace = true [dependencies] bs58.workspace = true ed25519-dalek.workspace = true -libp2p-identity = {workspace = true, features = ["peerid", "serde"]} +libp2p-identity = { workspace = true, features = ["peerid", "serde"] } semver = { workspace = true, features = ["serde"] } serde = { workspace = true, features = ["derive"] } serde_json.workspace = true diff --git a/crates/runtime/examples/fetch.rs b/crates/runtime/examples/fetch.rs index a6baa3c0a..e3044a03c 100644 --- a/crates/runtime/examples/fetch.rs +++ b/crates/runtime/examples/fetch.rs @@ -24,7 +24,7 @@ fn main() -> eyre::Result<()> { let cx = logic::VMContext { input: serde_json::to_vec(&json!({}))?, }; - let get_outcome = run(file, "fetch", cx, &mut storage, &limits)?; + let get_outcome = run(file, "foo", cx, &mut storage, &limits)?; let returns = String::from_utf8(get_outcome.returns.unwrap().unwrap()).unwrap(); println!("{returns}"); From a587f3246f91664d4873e211436d020778ebe40e Mon Sep 17 00:00:00 2001 From: Saeed Dadkhah Date: Fri, 21 Jun 2024 16:10:13 +0330 Subject: [PATCH 18/34] fix code style --- crates/sdk/libs/near/Cargo.toml | 3 +-- crates/sdk/libs/near/src/query.rs | 10 ++++------ 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/crates/sdk/libs/near/Cargo.toml b/crates/sdk/libs/near/Cargo.toml index 91bb0ed13..96513d17a 100644 --- a/crates/sdk/libs/near/Cargo.toml +++ b/crates/sdk/libs/near/Cargo.toml @@ -12,5 +12,4 @@ serde_json.workspace = true serde_with = {workspace = true, features = ["base64"]} calimero-sdk = { path = "../../" } -calimero-primitives = { path = "../../../primitives" } - +calimero-primitives = { path = "../../../primitives" } \ No newline at end of file diff --git a/crates/sdk/libs/near/src/query.rs b/crates/sdk/libs/near/src/query.rs index 215f9d0b1..6d383ba74 100644 --- a/crates/sdk/libs/near/src/query.rs +++ b/crates/sdk/libs/near/src/query.rs @@ -1,9 +1,7 @@ -use crate::{ - types::{BlockHash, BlockHeight, BlockId}, - views::{ - AccessKeyList, AccessKeyView, AccountView, CallResult, ContractCodeView, QueryRequest, - ViewStateResult, - }, +use crate::types::{BlockHash, BlockHeight, BlockId}; +use crate::views::{ + AccessKeyList, AccessKeyView, AccountView, CallResult, ContractCodeView, QueryRequest, + ViewStateResult, }; #[derive(serde::Serialize, Debug)] From 034a9eb9d4fe1199b852f4466dab8eea40d7360e Mon Sep 17 00:00:00 2001 From: Saeed Dadkhah Date: Mon, 24 Jun 2024 09:01:22 +0330 Subject: [PATCH 19/34] update cargo.lock --- Cargo.lock | 7 ------- 1 file changed, 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b57ee8196..0af7940ae 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -767,9 +767,6 @@ name = "bytes" version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" -dependencies = [ - "serde", -] [[package]] name = "bytesize" @@ -3272,7 +3269,6 @@ dependencies = [ "quick-protobuf", "rand 0.8.5", "rw-stream-sink", - "serde", "smallvec", "thiserror", "tracing", @@ -3344,7 +3340,6 @@ dependencies = [ "quick-protobuf-codec 0.3.1", "rand 0.8.5", "regex", - "serde", "sha2", "smallvec", "tracing", @@ -3414,7 +3409,6 @@ dependencies = [ "quick-protobuf", "quick-protobuf-codec 0.3.1", "rand 0.8.5", - "serde", "sha2", "smallvec", "thiserror", @@ -3995,7 +3989,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "076d548d76a0e2a0d4ab471d0b1c36c577786dfc4471242035d97a12a735c492" dependencies = [ "core2", - "serde", "unsigned-varint 0.7.2", ] From cd4b7d212e4f372f7b4298cffa8e57b54f7875d4 Mon Sep 17 00:00:00 2001 From: Saeed Dadkhah Date: Mon, 24 Jun 2024 10:23:09 +0330 Subject: [PATCH 20/34] Code review fixes --- Cargo.lock | 1 + Cargo.toml | 1 + crates/sdk/libs/near/Cargo.toml | 1 + crates/sdk/libs/near/src/jsonrpc.rs | 12 ++++++------ crates/sdk/libs/near/src/types.rs | 4 ++-- crates/sdk/libs/near/src/views.rs | 4 ++-- 6 files changed, 13 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0af7940ae..d470cee6d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -965,6 +965,7 @@ version = "0.1.0" dependencies = [ "calimero-primitives", "calimero-sdk", + "near-account-id", "serde", "serde_json", "serde_with", diff --git a/Cargo.toml b/Cargo.toml index bd24e0d6b..9fba2acb5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -53,6 +53,7 @@ multiaddr = "0.18.1" near-jsonrpc-client = "0.8.0" near-jsonrpc-primitives = "0.20.0" near-primitives = "0.20.0" +near-account-id = "1.0.0" near-sdk = "5.0.0" near-workspaces = "0.10.0" ouroboros = "0.18.3" diff --git a/crates/sdk/libs/near/Cargo.toml b/crates/sdk/libs/near/Cargo.toml index 96513d17a..fce2ba1b1 100644 --- a/crates/sdk/libs/near/Cargo.toml +++ b/crates/sdk/libs/near/Cargo.toml @@ -7,6 +7,7 @@ repository.workspace = true license.workspace = true [dependencies] +near-account-id = { workspace = true } serde = { workspace = true, features = ["derive"] } serde_json.workspace = true serde_with = {workspace = true, features = ["base64"]} diff --git a/crates/sdk/libs/near/src/jsonrpc.rs b/crates/sdk/libs/near/src/jsonrpc.rs index bc2f80f11..3803be50e 100644 --- a/crates/sdk/libs/near/src/jsonrpc.rs +++ b/crates/sdk/libs/near/src/jsonrpc.rs @@ -25,8 +25,8 @@ impl Client { *self.id.borrow_mut() += 1; let body = serde_json::to_vec(&Request { jsonrpc: "2.0", - id: self.id.borrow().to_string(), - method: method.to_string(), + id: &*self.id.borrow().to_string(), + method, params, }) .map_err(|err| format!("Cannot serialize request: {:?}", err))?; @@ -38,10 +38,10 @@ impl Client { } #[derive(Debug, Clone, Serialize)] -pub struct Request { - pub jsonrpc: &'static str, - pub id: String, - pub method: String, +struct Request<'a, P: Serialize> { + pub jsonrpc: &'a str, + pub id: &'a str, + pub method: &'a str, pub params: P, } diff --git a/crates/sdk/libs/near/src/types.rs b/crates/sdk/libs/near/src/types.rs index 9c9fe67bc..72d6dcc77 100644 --- a/crates/sdk/libs/near/src/types.rs +++ b/crates/sdk/libs/near/src/types.rs @@ -2,8 +2,8 @@ use serde_with::base64::Base64; use serde_with::serde_as; pub type BlockHeight = u64; -pub type BlockHash = String; -pub type AccountId = String; +pub type BlockHash = calimero_primitives::hash::Hash; +pub type AccountId = near_account_id::AccountId; pub type StorageUsage = u64; pub type Nonce = u64; diff --git a/crates/sdk/libs/near/src/views.rs b/crates/sdk/libs/near/src/views.rs index b7acd5451..01ac54612 100644 --- a/crates/sdk/libs/near/src/views.rs +++ b/crates/sdk/libs/near/src/views.rs @@ -32,7 +32,7 @@ pub enum QueryRequest { }, CallFunction { account_id: AccountId, - method_name: String, + method_name: Box, #[serde(rename = "args_base64")] args: FunctionArgs, }, @@ -52,7 +52,7 @@ pub struct AccountView { pub struct ContractCodeView { #[serde(rename = "code_base64")] #[serde_as(as = "Base64")] - pub code: Vec, + pub code: Box<[u8]>, pub hash: String, } From c16ac269486f3fb773d78b6e373332566f1b6734 Mon Sep 17 00:00:00 2001 From: Saeed Dadkhah Date: Mon, 24 Jun 2024 11:12:31 +0330 Subject: [PATCH 21/34] Add error type for rpc calls. --- Cargo.lock | 1 + crates/sdk/libs/near/Cargo.toml | 1 + crates/sdk/libs/near/src/error.rs | 10 ++++++++++ crates/sdk/libs/near/src/jsonrpc.rs | 13 +++++++------ crates/sdk/libs/near/src/lib.rs | 1 + crates/sdk/libs/near/src/types.rs | 1 + crates/sdk/libs/near/src/views.rs | 28 +++++++++++++++++----------- 7 files changed, 38 insertions(+), 17 deletions(-) create mode 100644 crates/sdk/libs/near/src/error.rs diff --git a/Cargo.lock b/Cargo.lock index d470cee6d..bfc6d5e52 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -969,6 +969,7 @@ dependencies = [ "serde", "serde_json", "serde_with", + "thiserror", ] [[package]] diff --git a/crates/sdk/libs/near/Cargo.toml b/crates/sdk/libs/near/Cargo.toml index fce2ba1b1..56dda73a5 100644 --- a/crates/sdk/libs/near/Cargo.toml +++ b/crates/sdk/libs/near/Cargo.toml @@ -11,6 +11,7 @@ near-account-id = { workspace = true } serde = { workspace = true, features = ["derive"] } serde_json.workspace = true serde_with = {workspace = true, features = ["base64"]} +thiserror.workspace = true calimero-sdk = { path = "../../" } calimero-primitives = { path = "../../../primitives" } \ No newline at end of file diff --git a/crates/sdk/libs/near/src/error.rs b/crates/sdk/libs/near/src/error.rs new file mode 100644 index 000000000..041d0588d --- /dev/null +++ b/crates/sdk/libs/near/src/error.rs @@ -0,0 +1,10 @@ +use thiserror::Error; + +#[derive(Debug, Error)] +pub enum NearLibError { + #[error(transparent)] + JsonError(#[from] serde_json::Error), + + #[error("Failed to fetch: {0}")] + FetchError(String), +} diff --git a/crates/sdk/libs/near/src/jsonrpc.rs b/crates/sdk/libs/near/src/jsonrpc.rs index 3803be50e..954f6906e 100644 --- a/crates/sdk/libs/near/src/jsonrpc.rs +++ b/crates/sdk/libs/near/src/jsonrpc.rs @@ -2,6 +2,8 @@ use calimero_sdk::env; use serde::de::DeserializeOwned; use serde::{Deserialize, Serialize}; +use crate::error::NearLibError; + pub(crate) struct Client { url: String, id: std::cell::RefCell, @@ -19,7 +21,7 @@ impl Client { &self, method: &str, params: P, - ) -> Result, String> { + ) -> Result, NearLibError> { let headers = [("Content-Type", "application/json")]; *self.id.borrow_mut() += 1; @@ -28,12 +30,11 @@ impl Client { id: &*self.id.borrow().to_string(), method, params, - }) - .map_err(|err| format!("Cannot serialize request: {:?}", err))?; + })?; - let response = unsafe { env::ext::fetch(&self.url, "POST", &headers, &body) }?; - serde_json::from_slice::>(&response) - .map_err(|e| format!("Failed to parse response: {}", e.to_string(),)) + let response = unsafe { env::ext::fetch(&self.url, "POST", &headers, &body) } + .map_err(NearLibError::FetchError)?; + Ok(serde_json::from_slice::>(&response)?) } } diff --git a/crates/sdk/libs/near/src/lib.rs b/crates/sdk/libs/near/src/lib.rs index 742ccb262..9a4b288b2 100644 --- a/crates/sdk/libs/near/src/lib.rs +++ b/crates/sdk/libs/near/src/lib.rs @@ -3,6 +3,7 @@ use query::{QueryResponseKind, RpcQueryRequest}; use types::{BlockId, FunctionArgs, StoreKey}; use views::QueryRequest; +pub mod error; mod jsonrpc; pub mod query; pub mod types; diff --git a/crates/sdk/libs/near/src/types.rs b/crates/sdk/libs/near/src/types.rs index 72d6dcc77..990a50abc 100644 --- a/crates/sdk/libs/near/src/types.rs +++ b/crates/sdk/libs/near/src/types.rs @@ -6,6 +6,7 @@ pub type BlockHash = calimero_primitives::hash::Hash; pub type AccountId = near_account_id::AccountId; pub type StorageUsage = u64; pub type Nonce = u64; +pub type Balance = u128; #[derive(Debug, Clone, serde::Serialize)] #[serde(untagged)] diff --git a/crates/sdk/libs/near/src/views.rs b/crates/sdk/libs/near/src/views.rs index 01ac54612..194cdb90b 100644 --- a/crates/sdk/libs/near/src/views.rs +++ b/crates/sdk/libs/near/src/views.rs @@ -1,10 +1,11 @@ +use serde_with::DisplayFromStr; use std::sync::Arc; use serde_with::base64::Base64; use serde_with::serde_as; use crate::types::{ - AccountId, BlockHeight, FunctionArgs, Nonce, StorageUsage, StoreKey, StoreValue, + AccountId, Balance, BlockHeight, FunctionArgs, Nonce, StorageUsage, StoreKey, StoreValue, }; #[derive(serde::Serialize, Debug)] @@ -38,11 +39,14 @@ pub enum QueryRequest { }, } +#[serde_as] #[derive(serde::Deserialize, Debug, Clone)] pub struct AccountView { - pub amount: String, - pub locked: String, - pub code_hash: String, + #[serde_as(as = "DisplayFromStr")] + pub amount: Balance, + #[serde_as(as = "DisplayFromStr")] + pub locked: Balance, + pub code_hash: calimero_primitives::hash::Hash, pub storage_usage: StorageUsage, pub storage_paid_at: BlockHeight, } @@ -53,7 +57,7 @@ pub struct ContractCodeView { #[serde(rename = "code_base64")] #[serde_as(as = "Base64")] pub code: Box<[u8]>, - pub hash: String, + pub hash: Box, } #[derive(serde::Deserialize, Debug, Clone)] @@ -77,12 +81,14 @@ pub struct AccessKeyView { pub permission: AccessKeyPermissionView, } +#[serde_as] #[derive(Debug, Clone, serde::Deserialize)] pub enum AccessKeyPermissionView { FunctionCall { - allowance: Option, - receiver_id: String, - method_names: Vec, + #[serde_as(as = "Option")] + allowance: Option, + receiver_id: Box, + method_names: Box<[Box]>, }, FullAccess, } @@ -94,12 +100,12 @@ pub struct AccessKeyList { #[derive(serde::Deserialize, Debug, Clone)] pub struct AccessKeyInfoView { - pub public_key: String, + pub public_key: Box, pub access_key: AccessKeyView, } #[derive(serde::Deserialize, Debug, Clone)] pub struct CallResult { - pub result: Vec, - pub logs: Vec, + pub result: Box<[u8]>, + pub logs: Box<[Box]>, } From 3901d33f54feea31039873d381c81d3903cb22c7 Mon Sep 17 00:00:00 2001 From: Saeed Dadkhah Date: Mon, 24 Jun 2024 13:01:52 +0330 Subject: [PATCH 22/34] Change the design --- crates/sdk/libs/near/src/error.rs | 3 + crates/sdk/libs/near/src/lib.rs | 153 +++--------------------------- crates/sdk/libs/near/src/query.rs | 15 +++ 3 files changed, 31 insertions(+), 140 deletions(-) diff --git a/crates/sdk/libs/near/src/error.rs b/crates/sdk/libs/near/src/error.rs index 041d0588d..294eded51 100644 --- a/crates/sdk/libs/near/src/error.rs +++ b/crates/sdk/libs/near/src/error.rs @@ -5,6 +5,9 @@ pub enum NearLibError { #[error(transparent)] JsonError(#[from] serde_json::Error), + #[error(transparent)] + IoError(#[from] std::io::Error), + #[error("Failed to fetch: {0}")] FetchError(String), } diff --git a/crates/sdk/libs/near/src/lib.rs b/crates/sdk/libs/near/src/lib.rs index 9a4b288b2..913b2320b 100644 --- a/crates/sdk/libs/near/src/lib.rs +++ b/crates/sdk/libs/near/src/lib.rs @@ -1,7 +1,5 @@ +use error::NearLibError; use jsonrpc::Response; -use query::{QueryResponseKind, RpcQueryRequest}; -use types::{BlockId, FunctionArgs, StoreKey}; -use views::QueryRequest; pub mod error; mod jsonrpc; @@ -13,6 +11,13 @@ pub struct Client { client: jsonrpc::Client, } +pub trait RpcMethod { + type Response: serde::de::DeserializeOwned; + + fn method_name(&self) -> &str; + fn params(&self) -> Result; +} + impl Client { pub fn testnet() -> Self { Self { @@ -26,142 +31,10 @@ impl Client { } } - pub fn view_account( - &self, - account_id: &str, - block_id: BlockId, - ) -> Result { - let request = RpcQueryRequest { - block_id, - request: QueryRequest::ViewAccount { - account_id: account_id.to_string(), - }, - }; - let response: Response = - self.client.call("query", request)?; - - match response.data { - Ok(r) => { - if let QueryResponseKind::ViewAccount(va) = r.kind { - return Ok(va); - } - return Err("Unexpected response returned.".to_string()); - } - Err(e) => Err(format!("Error: {}, Code: {}", e.message, e.code,)), - } - } - - pub fn view_code( - &self, - account_id: &str, - block_id: BlockId, - ) -> Result { - let request = RpcQueryRequest { - block_id, - request: QueryRequest::ViewCode { - account_id: account_id.to_string(), - }, - }; - - let response: Response = - self.client.call("query", request)?; - - match response.data { - Ok(r) => { - if let QueryResponseKind::ViewCode(vc) = r.kind { - return Ok(vc); - } - return Err("Unexpected response returned.".to_string()); - } - Err(e) => Err(format!("Error: {}, Code: {}", e.message, e.code,)), - } - } - - pub fn view_state( - &self, - account_id: &str, - prefix: StoreKey, - include_proof: bool, - block_id: BlockId, - ) -> Result { - let request = RpcQueryRequest { - block_id, - request: QueryRequest::ViewState { - account_id: account_id.to_string(), - prefix, - include_proof, - }, - }; - - let response: Response = - self.client.call("query", request)?; - - match response.data { - Ok(r) => { - if let QueryResponseKind::ViewState(vs) = r.kind { - return Ok(vs); - } - return Err("Unexpected response returned.".to_string()); - } - Err(e) => Err(format!("Error: {}, Code: {}", e.message, e.code,)), - } - } - - pub fn view_access_key( - &self, - account_id: &str, - public_key: &str, - block_id: BlockId, - ) -> Result { - let request = RpcQueryRequest { - block_id, - request: QueryRequest::ViewAccessKey { - account_id: account_id.to_string(), - public_key: public_key.to_string(), - }, - }; - - let response: Response = - self.client.call("query", request)?; - - match response.data { - Ok(r) => { - if let QueryResponseKind::ViewState(vs) = r.kind { - return Ok(vs); - } - return Err("Unexpected response returned.".to_string()); - } - Err(e) => Err(format!("Error: {}, Code: {}", e.message, e.code,)), - } - } - - pub fn call_function( - &self, - account_id: &str, - method_name: &str, - args: FunctionArgs, - block_id: BlockId, - ) -> Result { - let request = RpcQueryRequest { - block_id, - request: QueryRequest::CallFunction { - account_id: account_id.to_string(), - method_name: method_name.to_string(), - args, - }, - }; - - let response: Response = - self.client.call("query", request)?; - - match response.data { - Ok(r) => { - if let QueryResponseKind::CallResult(cr) = r.kind { - return Ok(cr); - } - return Err("Unexpected response returned.".to_string()); - } - Err(e) => Err(format!("Error: {}, Code: {}", e.message, e.code,)), - } + pub fn call(&self, method: M) -> Result, NearLibError> + where + M: RpcMethod, + { + self.client.call(method.method_name(), &method.params()?) } } diff --git a/crates/sdk/libs/near/src/query.rs b/crates/sdk/libs/near/src/query.rs index 6d383ba74..44ff4bbb8 100644 --- a/crates/sdk/libs/near/src/query.rs +++ b/crates/sdk/libs/near/src/query.rs @@ -1,8 +1,11 @@ +use serde_json::json; + use crate::types::{BlockHash, BlockHeight, BlockId}; use crate::views::{ AccessKeyList, AccessKeyView, AccountView, CallResult, ContractCodeView, QueryRequest, ViewStateResult, }; +use crate::RpcMethod; #[derive(serde::Serialize, Debug)] pub struct RpcQueryRequest { @@ -29,3 +32,15 @@ pub enum QueryResponseKind { AccessKeyList(AccessKeyList), CallResult(CallResult), } + +impl RpcMethod for RpcQueryRequest { + type Response = RpcQueryResponse; + + fn method_name(&self) -> &str { + "query" + } + + fn params(&self) -> Result { + Ok(json!(self)) + } +} From 17c0563a7b1965462d807d3952c938926e85bd38 Mon Sep 17 00:00:00 2001 From: Saeed Dadkhah Date: Mon, 24 Jun 2024 13:28:06 +0330 Subject: [PATCH 23/34] minor changes --- apps/only-peers/src/lib.rs | 11 ----------- crates/sdk/libs/near/Cargo.toml | 2 +- 2 files changed, 1 insertion(+), 12 deletions(-) diff --git a/apps/only-peers/src/lib.rs b/apps/only-peers/src/lib.rs index c8958a397..7375f5c6c 100644 --- a/apps/only-peers/src/lib.rs +++ b/apps/only-peers/src/lib.rs @@ -43,17 +43,6 @@ pub enum Event<'a> { #[app::logic] impl OnlyPeers { - pub fn foo(&mut self) -> String { - let client = calimero_sdk_near::Client::testnet(); - match client.view_account( - "nearkat.testnet", - calimero_sdk_near::types::BlockId::Height(166710735), - ) { - Ok(r) => format!("{}", r.amount), - Err(e) => e, - } - } - pub fn post(&self, id: usize) -> Option<&Post> { env::log(&format!("Getting post with id: {:?}", id)); diff --git a/crates/sdk/libs/near/Cargo.toml b/crates/sdk/libs/near/Cargo.toml index 56dda73a5..1a8c8db74 100644 --- a/crates/sdk/libs/near/Cargo.toml +++ b/crates/sdk/libs/near/Cargo.toml @@ -7,7 +7,7 @@ repository.workspace = true license.workspace = true [dependencies] -near-account-id = { workspace = true } +near-account-id = { workspace = true, features = ["serde"]} serde = { workspace = true, features = ["derive"] } serde_json.workspace = true serde_with = {workspace = true, features = ["base64"]} From 4455f4b07ec2967ddc7e03a3535b804190e23935 Mon Sep 17 00:00:00 2001 From: Saeed Dadkhah Date: Mon, 24 Jun 2024 13:29:28 +0330 Subject: [PATCH 24/34] unwanted change --- crates/runtime/examples/fetch.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/runtime/examples/fetch.rs b/crates/runtime/examples/fetch.rs index e3044a03c..a6baa3c0a 100644 --- a/crates/runtime/examples/fetch.rs +++ b/crates/runtime/examples/fetch.rs @@ -24,7 +24,7 @@ fn main() -> eyre::Result<()> { let cx = logic::VMContext { input: serde_json::to_vec(&json!({}))?, }; - let get_outcome = run(file, "foo", cx, &mut storage, &limits)?; + let get_outcome = run(file, "fetch", cx, &mut storage, &limits)?; let returns = String::from_utf8(get_outcome.returns.unwrap().unwrap()).unwrap(); println!("{returns}"); From 364fc0d91df927cda5886f1f8c5def8adf13c010 Mon Sep 17 00:00:00 2001 From: Saeed Dadkhah Date: Mon, 24 Jun 2024 13:43:47 +0330 Subject: [PATCH 25/34] remove useless code --- crates/runtime/src/errors.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/crates/runtime/src/errors.rs b/crates/runtime/src/errors.rs index 879f76c0b..c8a2ba5ee 100644 --- a/crates/runtime/src/errors.rs +++ b/crates/runtime/src/errors.rs @@ -86,8 +86,6 @@ pub enum HostError { EventKindSizeOverflow, #[error("event data size overflow")] EventDataSizeOverflow, - #[error("failed to fetch data from {url} with error: {error}")] - FetchError { url: String, error: String }, } #[derive(Debug, Serialize)] From 38d146f95332f739e303342937c05d54ab6f00f2 Mon Sep 17 00:00:00 2001 From: Saeed Dadkhah Date: Mon, 24 Jun 2024 16:11:38 +0330 Subject: [PATCH 26/34] tiny fixes --- Cargo.toml | 2 +- crates/sdk/libs/near/src/jsonrpc.rs | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 9fba2acb5..3e8ba57c7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -50,10 +50,10 @@ libp2p-stream = "0.1.0-alpha.1" libp2p-identity = "0.2.9" multiaddr = "0.18.1" # multibase = "0.9.1" +near-account-id = "1.0.0" near-jsonrpc-client = "0.8.0" near-jsonrpc-primitives = "0.20.0" near-primitives = "0.20.0" -near-account-id = "1.0.0" near-sdk = "5.0.0" near-workspaces = "0.10.0" ouroboros = "0.18.3" diff --git a/crates/sdk/libs/near/src/jsonrpc.rs b/crates/sdk/libs/near/src/jsonrpc.rs index 954f6906e..0f80f4364 100644 --- a/crates/sdk/libs/near/src/jsonrpc.rs +++ b/crates/sdk/libs/near/src/jsonrpc.rs @@ -27,7 +27,7 @@ impl Client { *self.id.borrow_mut() += 1; let body = serde_json::to_vec(&Request { jsonrpc: "2.0", - id: &*self.id.borrow().to_string(), + id: *self.id.borrow(), method, params, })?; @@ -40,11 +40,11 @@ impl Client { #[derive(Debug, Clone, Serialize)] struct Request<'a, P: Serialize> { - pub jsonrpc: &'a str, - pub id: &'a str, - pub method: &'a str, + jsonrpc: &'a str, + id: u64, + method: &'a str, - pub params: P, + params: P, } #[derive(Debug, Clone, Deserialize)] From 93070fdce4add070ea761698a4a42f5db25a6be6 Mon Sep 17 00:00:00 2001 From: Saeed Dadkhah Date: Mon, 24 Jun 2024 16:14:47 +0330 Subject: [PATCH 27/34] rename error. --- crates/sdk/libs/near/src/error.rs | 2 +- crates/sdk/libs/near/src/jsonrpc.rs | 6 +++--- crates/sdk/libs/near/src/lib.rs | 10 +++++----- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/crates/sdk/libs/near/src/error.rs b/crates/sdk/libs/near/src/error.rs index 294eded51..396c95b8d 100644 --- a/crates/sdk/libs/near/src/error.rs +++ b/crates/sdk/libs/near/src/error.rs @@ -1,7 +1,7 @@ use thiserror::Error; #[derive(Debug, Error)] -pub enum NearLibError { +pub enum Error { #[error(transparent)] JsonError(#[from] serde_json::Error), diff --git a/crates/sdk/libs/near/src/jsonrpc.rs b/crates/sdk/libs/near/src/jsonrpc.rs index 0f80f4364..153acfb9c 100644 --- a/crates/sdk/libs/near/src/jsonrpc.rs +++ b/crates/sdk/libs/near/src/jsonrpc.rs @@ -2,7 +2,7 @@ use calimero_sdk::env; use serde::de::DeserializeOwned; use serde::{Deserialize, Serialize}; -use crate::error::NearLibError; +use crate::Error; pub(crate) struct Client { url: String, @@ -21,7 +21,7 @@ impl Client { &self, method: &str, params: P, - ) -> Result, NearLibError> { + ) -> Result, Error> { let headers = [("Content-Type", "application/json")]; *self.id.borrow_mut() += 1; @@ -33,7 +33,7 @@ impl Client { })?; let response = unsafe { env::ext::fetch(&self.url, "POST", &headers, &body) } - .map_err(NearLibError::FetchError)?; + .map_err(Error::FetchError)?; Ok(serde_json::from_slice::>(&response)?) } } diff --git a/crates/sdk/libs/near/src/lib.rs b/crates/sdk/libs/near/src/lib.rs index 913b2320b..41d698a57 100644 --- a/crates/sdk/libs/near/src/lib.rs +++ b/crates/sdk/libs/near/src/lib.rs @@ -1,12 +1,12 @@ -use error::NearLibError; -use jsonrpc::Response; - -pub mod error; +mod error; mod jsonrpc; pub mod query; pub mod types; pub mod views; +pub use error::Error; +use jsonrpc::Response; + pub struct Client { client: jsonrpc::Client, } @@ -31,7 +31,7 @@ impl Client { } } - pub fn call(&self, method: M) -> Result, NearLibError> + pub fn call(&self, method: M) -> Result, Error> where M: RpcMethod, { From 961cf9f02493288706de87d65026ae57a4abc7cb Mon Sep 17 00:00:00 2001 From: Saeed Dadkhah Date: Mon, 24 Jun 2024 17:47:57 +0330 Subject: [PATCH 28/34] Merge client and jsonrpcclient --- crates/sdk/libs/near/src/error.rs | 7 +++- crates/sdk/libs/near/src/jsonrpc.rs | 36 +++++++++++------ crates/sdk/libs/near/src/lib.rs | 28 +------------ crates/sdk/libs/near/src/query.rs | 61 ++++++++++++++++++++++++++++- crates/sdk/libs/near/src/types.rs | 29 +++++++++++++- 5 files changed, 119 insertions(+), 42 deletions(-) diff --git a/crates/sdk/libs/near/src/error.rs b/crates/sdk/libs/near/src/error.rs index 396c95b8d..879deef31 100644 --- a/crates/sdk/libs/near/src/error.rs +++ b/crates/sdk/libs/near/src/error.rs @@ -1,7 +1,9 @@ use thiserror::Error; +use crate::jsonrpc::RpcError; + #[derive(Debug, Error)] -pub enum Error { +pub enum Error { #[error(transparent)] JsonError(#[from] serde_json::Error), @@ -10,4 +12,7 @@ pub enum Error { #[error("Failed to fetch: {0}")] FetchError(String), + + #[error(transparent)] + ServerError(#[from] RpcError), } diff --git a/crates/sdk/libs/near/src/jsonrpc.rs b/crates/sdk/libs/near/src/jsonrpc.rs index 153acfb9c..3c5ffda16 100644 --- a/crates/sdk/libs/near/src/jsonrpc.rs +++ b/crates/sdk/libs/near/src/jsonrpc.rs @@ -2,46 +2,56 @@ use calimero_sdk::env; use serde::de::DeserializeOwned; use serde::{Deserialize, Serialize}; -use crate::Error; +use crate::{Error, RpcMethod}; -pub(crate) struct Client { +pub struct Client { url: String, id: std::cell::RefCell, } impl Client { - pub fn new(url: String) -> Self { + pub fn testnet() -> Self { + Self::new("https://rpc.testnet.near.org/".to_string()) + } + + pub fn mainnet() -> Self { + Self::new("https://rpc.mainnet.near.org/".to_string()) + } + + fn new(url: String) -> Self { Self { url, id: std::cell::RefCell::new(0), } } - pub fn call( - &self, - method: &str, - params: P, - ) -> Result, Error> { + pub fn call(&self, method: M) -> Result>> + where + M: RpcMethod, + { let headers = [("Content-Type", "application/json")]; *self.id.borrow_mut() += 1; let body = serde_json::to_vec(&Request { jsonrpc: "2.0", - id: *self.id.borrow(), - method, - params, + id: &*self.id.borrow().to_string(), + method: method.method_name(), + params: method.params()?, })?; let response = unsafe { env::ext::fetch(&self.url, "POST", &headers, &body) } .map_err(Error::FetchError)?; - Ok(serde_json::from_slice::>(&response)?) + + serde_json::from_slice::>>(&response)? + .data + .map_err(|e| Error::ServerError(e)) } } #[derive(Debug, Clone, Serialize)] struct Request<'a, P: Serialize> { jsonrpc: &'a str, - id: u64, + id: &'a str, method: &'a str, params: P, diff --git a/crates/sdk/libs/near/src/lib.rs b/crates/sdk/libs/near/src/lib.rs index 41d698a57..464fa6df6 100644 --- a/crates/sdk/libs/near/src/lib.rs +++ b/crates/sdk/libs/near/src/lib.rs @@ -5,36 +5,12 @@ pub mod types; pub mod views; pub use error::Error; -use jsonrpc::Response; - -pub struct Client { - client: jsonrpc::Client, -} +pub use jsonrpc::Client; pub trait RpcMethod { type Response: serde::de::DeserializeOwned; + type Error: serde::de::DeserializeOwned; fn method_name(&self) -> &str; fn params(&self) -> Result; } - -impl Client { - pub fn testnet() -> Self { - Self { - client: jsonrpc::Client::new("https://rpc.testnet.near.org/".to_string()), - } - } - - pub fn mainnet() -> Self { - Self { - client: jsonrpc::Client::new("https://rpc.mainnet.near.org/".to_string()), - } - } - - pub fn call(&self, method: M) -> Result, Error> - where - M: RpcMethod, - { - self.client.call(method.method_name(), &method.params()?) - } -} diff --git a/crates/sdk/libs/near/src/query.rs b/crates/sdk/libs/near/src/query.rs index 44ff4bbb8..dd2b5a27b 100644 --- a/crates/sdk/libs/near/src/query.rs +++ b/crates/sdk/libs/near/src/query.rs @@ -1,12 +1,70 @@ use serde_json::json; -use crate::types::{BlockHash, BlockHeight, BlockId}; +use crate::types::{AccountId, BlockHash, BlockHeight, BlockId, BlockReference, ShardId}; use crate::views::{ AccessKeyList, AccessKeyView, AccountView, CallResult, ContractCodeView, QueryRequest, ViewStateResult, }; use crate::RpcMethod; +#[derive(thiserror::Error, Debug, serde::Serialize, serde::Deserialize)] +#[serde(tag = "name", content = "info", rename_all = "SCREAMING_SNAKE_CASE")] +pub enum RpcQueryError { + #[error("There are no fully synchronized blocks on the node yet")] + NoSyncedBlocks, + #[error("The node does not track the shard ID {requested_shard_id}")] + UnavailableShard { requested_shard_id: ShardId }, + #[error( + "The data for block #{block_height} is garbage collected on this node, use an archival node to fetch historical data" + )] + GarbageCollectedBlock { + block_height: BlockHeight, + block_hash: calimero_primitives::hash::Hash, + }, + #[error("Block either has never been observed on the node or has been garbage collected: {block_reference:?}")] + UnknownBlock { block_reference: BlockReference }, + #[error("Account ID {requested_account_id} is invalid")] + InvalidAccount { + requested_account_id: AccountId, + block_height: BlockHeight, + block_hash: calimero_primitives::hash::Hash, + }, + #[error("account {requested_account_id} does not exist while viewing")] + UnknownAccount { + requested_account_id: AccountId, + block_height: BlockHeight, + block_hash: calimero_primitives::hash::Hash, + }, + #[error( + "Contract code for contract ID #{contract_account_id} has never been observed on the node" + )] + NoContractCode { + contract_account_id: AccountId, + block_height: BlockHeight, + block_hash: calimero_primitives::hash::Hash, + }, + #[error("State of contract {contract_account_id} is too large to be viewed")] + TooLargeContractState { + contract_account_id: AccountId, + block_height: BlockHeight, + block_hash: calimero_primitives::hash::Hash, + }, + #[error("Access key for public key {public_key} has never been observed on the node")] + UnknownAccessKey { + public_key: String, + block_height: BlockHeight, + block_hash: calimero_primitives::hash::Hash, + }, + #[error("Function call returned an error: {vm_error}")] + ContractExecutionError { + vm_error: String, + block_height: BlockHeight, + block_hash: calimero_primitives::hash::Hash, + }, + #[error("The node reached its limits. Try again later. More details: {error_message}")] + InternalError { error_message: String }, +} + #[derive(serde::Serialize, Debug)] pub struct RpcQueryRequest { pub block_id: BlockId, @@ -35,6 +93,7 @@ pub enum QueryResponseKind { impl RpcMethod for RpcQueryRequest { type Response = RpcQueryResponse; + type Error = RpcQueryError; fn method_name(&self) -> &str { "query" diff --git a/crates/sdk/libs/near/src/types.rs b/crates/sdk/libs/near/src/types.rs index 990a50abc..0277b5837 100644 --- a/crates/sdk/libs/near/src/types.rs +++ b/crates/sdk/libs/near/src/types.rs @@ -7,14 +7,41 @@ pub type AccountId = near_account_id::AccountId; pub type StorageUsage = u64; pub type Nonce = u64; pub type Balance = u128; +pub type ShardId = u64; -#[derive(Debug, Clone, serde::Serialize)] +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] #[serde(untagged)] pub enum BlockId { Height(BlockHeight), Hash(BlockHash), } +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +#[serde(rename_all = "snake_case")] +pub enum BlockReference { + BlockId(BlockId), + Finality(Finality), + SyncCheckpoint(SyncCheckpoint), +} + +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +#[serde(rename_all = "snake_case")] +pub enum SyncCheckpoint { + Genesis, + EarliestAvailable, +} + +#[derive(serde::Serialize, serde::Deserialize, Default, Clone, Debug)] +pub enum Finality { + #[serde(rename = "optimistic")] + None, + #[serde(rename = "near-final")] + DoomSlug, + #[serde(rename = "final")] + #[default] + Final, +} + #[serde_as] #[derive(serde::Deserialize, Clone, Debug)] #[serde(transparent)] From 8ffddab60733f9b07882fd9019cc4aa89850d4bf Mon Sep 17 00:00:00 2001 From: Saeed Dadkhah Date: Mon, 24 Jun 2024 17:50:07 +0330 Subject: [PATCH 29/34] make id a number. --- crates/sdk/libs/near/src/jsonrpc.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/sdk/libs/near/src/jsonrpc.rs b/crates/sdk/libs/near/src/jsonrpc.rs index 3c5ffda16..baa7fca69 100644 --- a/crates/sdk/libs/near/src/jsonrpc.rs +++ b/crates/sdk/libs/near/src/jsonrpc.rs @@ -34,7 +34,7 @@ impl Client { *self.id.borrow_mut() += 1; let body = serde_json::to_vec(&Request { jsonrpc: "2.0", - id: &*self.id.borrow().to_string(), + id: *self.id.borrow(), method: method.method_name(), params: method.params()?, })?; @@ -51,7 +51,7 @@ impl Client { #[derive(Debug, Clone, Serialize)] struct Request<'a, P: Serialize> { jsonrpc: &'a str, - id: &'a str, + id: u64, method: &'a str, params: P, @@ -60,7 +60,7 @@ struct Request<'a, P: Serialize> { #[derive(Debug, Clone, Deserialize)] pub struct Response { pub jsonrpc: Option, - pub id: String, + pub id: u64, #[serde(with = "calimero_primitives::common::ResultAlt", flatten)] pub data: Result>, From aa2cfa2c9e4a41e4a763c3240cf759376b94f760 Mon Sep 17 00:00:00 2001 From: Saeed Dadkhah Date: Mon, 24 Jun 2024 18:18:19 +0330 Subject: [PATCH 30/34] fix error --- crates/sdk/libs/near/src/jsonrpc.rs | 6 +-- crates/sdk/libs/near/src/query.rs | 62 +---------------------------- crates/sdk/libs/near/src/types.rs | 27 ------------- 3 files changed, 5 insertions(+), 90 deletions(-) diff --git a/crates/sdk/libs/near/src/jsonrpc.rs b/crates/sdk/libs/near/src/jsonrpc.rs index baa7fca69..e2a97f995 100644 --- a/crates/sdk/libs/near/src/jsonrpc.rs +++ b/crates/sdk/libs/near/src/jsonrpc.rs @@ -25,7 +25,7 @@ impl Client { } } - pub fn call(&self, method: M) -> Result>> + pub fn call(&self, method: M) -> Result> where M: RpcMethod, { @@ -42,9 +42,9 @@ impl Client { let response = unsafe { env::ext::fetch(&self.url, "POST", &headers, &body) } .map_err(Error::FetchError)?; - serde_json::from_slice::>>(&response)? + serde_json::from_slice::>(&response)? .data - .map_err(|e| Error::ServerError(e)) + .map_err(Error::ServerError) } } diff --git a/crates/sdk/libs/near/src/query.rs b/crates/sdk/libs/near/src/query.rs index dd2b5a27b..da561db5f 100644 --- a/crates/sdk/libs/near/src/query.rs +++ b/crates/sdk/libs/near/src/query.rs @@ -1,70 +1,12 @@ use serde_json::json; -use crate::types::{AccountId, BlockHash, BlockHeight, BlockId, BlockReference, ShardId}; +use crate::types::{BlockHash, BlockHeight, BlockId}; use crate::views::{ AccessKeyList, AccessKeyView, AccountView, CallResult, ContractCodeView, QueryRequest, ViewStateResult, }; use crate::RpcMethod; -#[derive(thiserror::Error, Debug, serde::Serialize, serde::Deserialize)] -#[serde(tag = "name", content = "info", rename_all = "SCREAMING_SNAKE_CASE")] -pub enum RpcQueryError { - #[error("There are no fully synchronized blocks on the node yet")] - NoSyncedBlocks, - #[error("The node does not track the shard ID {requested_shard_id}")] - UnavailableShard { requested_shard_id: ShardId }, - #[error( - "The data for block #{block_height} is garbage collected on this node, use an archival node to fetch historical data" - )] - GarbageCollectedBlock { - block_height: BlockHeight, - block_hash: calimero_primitives::hash::Hash, - }, - #[error("Block either has never been observed on the node or has been garbage collected: {block_reference:?}")] - UnknownBlock { block_reference: BlockReference }, - #[error("Account ID {requested_account_id} is invalid")] - InvalidAccount { - requested_account_id: AccountId, - block_height: BlockHeight, - block_hash: calimero_primitives::hash::Hash, - }, - #[error("account {requested_account_id} does not exist while viewing")] - UnknownAccount { - requested_account_id: AccountId, - block_height: BlockHeight, - block_hash: calimero_primitives::hash::Hash, - }, - #[error( - "Contract code for contract ID #{contract_account_id} has never been observed on the node" - )] - NoContractCode { - contract_account_id: AccountId, - block_height: BlockHeight, - block_hash: calimero_primitives::hash::Hash, - }, - #[error("State of contract {contract_account_id} is too large to be viewed")] - TooLargeContractState { - contract_account_id: AccountId, - block_height: BlockHeight, - block_hash: calimero_primitives::hash::Hash, - }, - #[error("Access key for public key {public_key} has never been observed on the node")] - UnknownAccessKey { - public_key: String, - block_height: BlockHeight, - block_hash: calimero_primitives::hash::Hash, - }, - #[error("Function call returned an error: {vm_error}")] - ContractExecutionError { - vm_error: String, - block_height: BlockHeight, - block_hash: calimero_primitives::hash::Hash, - }, - #[error("The node reached its limits. Try again later. More details: {error_message}")] - InternalError { error_message: String }, -} - #[derive(serde::Serialize, Debug)] pub struct RpcQueryRequest { pub block_id: BlockId, @@ -93,7 +35,7 @@ pub enum QueryResponseKind { impl RpcMethod for RpcQueryRequest { type Response = RpcQueryResponse; - type Error = RpcQueryError; + type Error = String; fn method_name(&self) -> &str { "query" diff --git a/crates/sdk/libs/near/src/types.rs b/crates/sdk/libs/near/src/types.rs index 0277b5837..73353cd0f 100644 --- a/crates/sdk/libs/near/src/types.rs +++ b/crates/sdk/libs/near/src/types.rs @@ -7,7 +7,6 @@ pub type AccountId = near_account_id::AccountId; pub type StorageUsage = u64; pub type Nonce = u64; pub type Balance = u128; -pub type ShardId = u64; #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] #[serde(untagged)] @@ -16,32 +15,6 @@ pub enum BlockId { Hash(BlockHash), } -#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] -#[serde(rename_all = "snake_case")] -pub enum BlockReference { - BlockId(BlockId), - Finality(Finality), - SyncCheckpoint(SyncCheckpoint), -} - -#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] -#[serde(rename_all = "snake_case")] -pub enum SyncCheckpoint { - Genesis, - EarliestAvailable, -} - -#[derive(serde::Serialize, serde::Deserialize, Default, Clone, Debug)] -pub enum Finality { - #[serde(rename = "optimistic")] - None, - #[serde(rename = "near-final")] - DoomSlug, - #[serde(rename = "final")] - #[default] - Final, -} - #[serde_as] #[derive(serde::Deserialize, Clone, Debug)] #[serde(transparent)] From 1b4474e9c6d5fcd5329fadc9ce7b7bf3f9f752f0 Mon Sep 17 00:00:00 2001 From: Saeed Dadkhah Date: Wed, 26 Jun 2024 14:56:28 +0330 Subject: [PATCH 31/34] Add more error types. --- crates/sdk/libs/near/src/error.rs | 35 ++++++++++++--- crates/sdk/libs/near/src/jsonrpc.rs | 12 ++---- crates/sdk/libs/near/src/lib.rs | 2 +- crates/sdk/libs/near/src/query.rs | 66 +++++++++++++++++++++++++++-- crates/sdk/libs/near/src/types.rs | 33 +++++++++++++-- crates/sdk/libs/near/src/views.rs | 6 +-- 6 files changed, 127 insertions(+), 27 deletions(-) diff --git a/crates/sdk/libs/near/src/error.rs b/crates/sdk/libs/near/src/error.rs index 879deef31..bd4834102 100644 --- a/crates/sdk/libs/near/src/error.rs +++ b/crates/sdk/libs/near/src/error.rs @@ -1,18 +1,39 @@ +use serde_json::Value; use thiserror::Error; -use crate::jsonrpc::RpcError; - #[derive(Debug, Error)] pub enum Error { #[error(transparent)] JsonError(#[from] serde_json::Error), - #[error(transparent)] - IoError(#[from] std::io::Error), - #[error("Failed to fetch: {0}")] FetchError(String), - #[error(transparent)] - ServerError(#[from] RpcError), + #[error("Server error {0}")] + ServerError(RpcError), +} + +#[derive(Debug, serde::Deserialize, Clone, PartialEq)] +#[serde(tag = "name", content = "cause", rename_all = "SCREAMING_SNAKE_CASE")] +pub enum RpcErrorKind { + RequestValidationError(RpcRequestValidationErrorKind), + HandlerError(R), + InternalError(Value), +} + +#[derive(Debug, serde::Serialize, serde::Deserialize, Clone, PartialEq)] +#[serde(tag = "name", content = "info", rename_all = "SCREAMING_SNAKE_CASE")] +pub enum RpcRequestValidationErrorKind { + MethodNotFound { method_name: String }, + ParseError { error_message: String }, +} + +#[derive(Debug, serde::Deserialize, Clone, PartialEq)] +#[serde(deny_unknown_fields)] +pub struct RpcError { + #[serde(flatten)] + pub error_struct: Option>, + pub code: i64, + pub message: String, + pub data: Option, } diff --git a/crates/sdk/libs/near/src/jsonrpc.rs b/crates/sdk/libs/near/src/jsonrpc.rs index e2a97f995..be9935cc6 100644 --- a/crates/sdk/libs/near/src/jsonrpc.rs +++ b/crates/sdk/libs/near/src/jsonrpc.rs @@ -2,6 +2,7 @@ use calimero_sdk::env; use serde::de::DeserializeOwned; use serde::{Deserialize, Serialize}; +use crate::error::RpcError; use crate::{Error, RpcMethod}; pub struct Client { @@ -36,13 +37,13 @@ impl Client { jsonrpc: "2.0", id: *self.id.borrow(), method: method.method_name(), - params: method.params()?, + params: method.params(), })?; let response = unsafe { env::ext::fetch(&self.url, "POST", &headers, &body) } .map_err(Error::FetchError)?; - serde_json::from_slice::>(&response)? + serde_json::from_slice::>(&response)? .data .map_err(Error::ServerError) } @@ -65,10 +66,3 @@ pub struct Response { #[serde(with = "calimero_primitives::common::ResultAlt", flatten)] pub data: Result>, } - -#[derive(Debug, Clone, Deserialize)] -pub struct RpcError { - pub code: i32, - pub message: String, - pub data: Option, -} diff --git a/crates/sdk/libs/near/src/lib.rs b/crates/sdk/libs/near/src/lib.rs index 464fa6df6..2d38277da 100644 --- a/crates/sdk/libs/near/src/lib.rs +++ b/crates/sdk/libs/near/src/lib.rs @@ -12,5 +12,5 @@ pub trait RpcMethod { type Error: serde::de::DeserializeOwned; fn method_name(&self) -> &str; - fn params(&self) -> Result; + fn params(&self) -> serde_json::Value; } diff --git a/crates/sdk/libs/near/src/query.rs b/crates/sdk/libs/near/src/query.rs index da561db5f..9724b2c73 100644 --- a/crates/sdk/libs/near/src/query.rs +++ b/crates/sdk/libs/near/src/query.rs @@ -1,6 +1,6 @@ use serde_json::json; -use crate::types::{BlockHash, BlockHeight, BlockId}; +use crate::types::{AccountId, BlockHash, BlockHeight, BlockId, BlockReference, ShardId}; use crate::views::{ AccessKeyList, AccessKeyView, AccountView, CallResult, ContractCodeView, QueryRequest, ViewStateResult, @@ -35,13 +35,71 @@ pub enum QueryResponseKind { impl RpcMethod for RpcQueryRequest { type Response = RpcQueryResponse; - type Error = String; + type Error = RpcQueryError; fn method_name(&self) -> &str { "query" } - fn params(&self) -> Result { - Ok(json!(self)) + fn params(&self) -> serde_json::Value { + json!(self) } } + +#[derive(thiserror::Error, Debug, serde::Serialize, serde::Deserialize)] +#[serde(tag = "name", content = "info", rename_all = "SCREAMING_SNAKE_CASE")] +pub enum RpcQueryError { + #[error("There are no fully synchronized blocks on the node yet")] + NoSyncedBlocks, + #[error("The node does not track the shard ID {requested_shard_id}")] + UnavailableShard { requested_shard_id: ShardId }, + #[error( + "The data for block #{block_height} is garbage collected on this node, use an archival node to fetch historical data" + )] + GarbageCollectedBlock { + block_height: BlockHeight, + block_hash: calimero_primitives::hash::Hash, + }, + #[error("Block either has never been observed on the node or has been garbage collected: {block_reference:?}")] + UnknownBlock { block_reference: BlockReference }, + #[error("Account ID {requested_account_id} is invalid")] + InvalidAccount { + requested_account_id: AccountId, + block_height: BlockHeight, + block_hash: calimero_primitives::hash::Hash, + }, + #[error("account {requested_account_id} does not exist while viewing")] + UnknownAccount { + requested_account_id: AccountId, + block_height: BlockHeight, + block_hash: calimero_primitives::hash::Hash, + }, + #[error( + "Contract code for contract ID #{contract_account_id} has never been observed on the node" + )] + NoContractCode { + contract_account_id: AccountId, + block_height: BlockHeight, + block_hash: calimero_primitives::hash::Hash, + }, + #[error("State of contract {contract_account_id} is too large to be viewed")] + TooLargeContractState { + contract_account_id: AccountId, + block_height: BlockHeight, + block_hash: calimero_primitives::hash::Hash, + }, + #[error("Access key for public key {public_key} has never been observed on the node")] + UnknownAccessKey { + public_key: String, + block_height: BlockHeight, + block_hash: calimero_primitives::hash::Hash, + }, + #[error("Function call returned an error: {vm_error}")] + ContractExecutionError { + vm_error: String, + block_height: BlockHeight, + block_hash: calimero_primitives::hash::Hash, + }, + #[error("The node reached its limits. Try again later. More details: {error_message}")] + InternalError { error_message: String }, +} diff --git a/crates/sdk/libs/near/src/types.rs b/crates/sdk/libs/near/src/types.rs index 73353cd0f..f6af2cb05 100644 --- a/crates/sdk/libs/near/src/types.rs +++ b/crates/sdk/libs/near/src/types.rs @@ -7,6 +7,7 @@ pub type AccountId = near_account_id::AccountId; pub type StorageUsage = u64; pub type Nonce = u64; pub type Balance = u128; +pub type ShardId = u64; #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] #[serde(untagged)] @@ -18,14 +19,40 @@ pub enum BlockId { #[serde_as] #[derive(serde::Deserialize, Clone, Debug)] #[serde(transparent)] -pub struct StoreValue(#[serde_as(as = "Base64")] pub Vec); +pub struct StoreValue(#[serde_as(as = "Base64")] pub Box<[u8]>); #[serde_as] #[derive(serde::Serialize, serde::Deserialize, Clone, Debug)] #[serde(transparent)] -pub struct StoreKey(#[serde_as(as = "Base64")] pub Vec); +pub struct StoreKey(#[serde_as(as = "Base64")] pub Box<[u8]>); #[serde_as] #[derive(serde::Serialize, Clone, Debug)] #[serde(transparent)] -pub struct FunctionArgs(#[serde_as(as = "Base64")] Vec); +pub struct FunctionArgs(#[serde_as(as = "Base64")] Box<[u8]>); + +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +#[serde(rename_all = "snake_case")] +pub enum BlockReference { + BlockId(BlockId), + Finality(Finality), + SyncCheckpoint(SyncCheckpoint), +} + +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +#[serde(rename_all = "snake_case")] +pub enum SyncCheckpoint { + Genesis, + EarliestAvailable, +} + +#[derive(serde::Serialize, serde::Deserialize, Default, Clone, Debug)] +pub enum Finality { + #[serde(rename = "optimistic")] + None, + #[serde(rename = "near-final")] + DoomSlug, + #[serde(rename = "final")] + #[default] + Final, +} diff --git a/crates/sdk/libs/near/src/views.rs b/crates/sdk/libs/near/src/views.rs index 194cdb90b..4f2a184a8 100644 --- a/crates/sdk/libs/near/src/views.rs +++ b/crates/sdk/libs/near/src/views.rs @@ -26,7 +26,7 @@ pub enum QueryRequest { }, ViewAccessKey { account_id: AccountId, - public_key: String, + public_key: Box, }, ViewAccessKeyList { account_id: AccountId, @@ -69,7 +69,7 @@ pub struct StateItem { #[serde_as] #[derive(serde::Deserialize, Debug, Clone)] pub struct ViewStateResult { - pub values: Vec, + pub values: Box<[StateItem]>, #[serde_as(as = "Vec")] #[serde(default, skip_serializing_if = "Vec::is_empty")] pub proof: Vec>, @@ -95,7 +95,7 @@ pub enum AccessKeyPermissionView { #[derive(serde::Deserialize, Debug, Clone)] pub struct AccessKeyList { - pub keys: Vec, + pub keys: Box<[AccessKeyInfoView]>, } #[derive(serde::Deserialize, Debug, Clone)] From fd718f7fdcd4f18be6484dc667aad1a9cf5fe0b5 Mon Sep 17 00:00:00 2001 From: Saeed Dadkhah Date: Wed, 26 Jun 2024 15:54:07 +0330 Subject: [PATCH 32/34] move code to better mods --- crates/sdk/libs/near/src/lib.rs | 2 ++ crates/sdk/libs/near/src/query.rs | 6 ++--- crates/sdk/libs/near/src/types.rs | 44 ------------------------------ crates/sdk/libs/near/src/views.rs | 45 ++++++++++++++++++++++++++++--- 4 files changed, 47 insertions(+), 50 deletions(-) diff --git a/crates/sdk/libs/near/src/lib.rs b/crates/sdk/libs/near/src/lib.rs index 2d38277da..ebeab9562 100644 --- a/crates/sdk/libs/near/src/lib.rs +++ b/crates/sdk/libs/near/src/lib.rs @@ -6,6 +6,8 @@ pub mod views; pub use error::Error; pub use jsonrpc::Client; +pub use query::*; +pub use types::*; pub trait RpcMethod { type Response: serde::de::DeserializeOwned; diff --git a/crates/sdk/libs/near/src/query.rs b/crates/sdk/libs/near/src/query.rs index 9724b2c73..08123e9a4 100644 --- a/crates/sdk/libs/near/src/query.rs +++ b/crates/sdk/libs/near/src/query.rs @@ -1,9 +1,9 @@ use serde_json::json; -use crate::types::{AccountId, BlockHash, BlockHeight, BlockId, BlockReference, ShardId}; +use crate::types::{AccountId, BlockHash, BlockHeight, BlockId, ShardId}; use crate::views::{ - AccessKeyList, AccessKeyView, AccountView, CallResult, ContractCodeView, QueryRequest, - ViewStateResult, + AccessKeyList, AccessKeyView, AccountView, BlockReference, CallResult, ContractCodeView, + QueryRequest, ViewStateResult, }; use crate::RpcMethod; diff --git a/crates/sdk/libs/near/src/types.rs b/crates/sdk/libs/near/src/types.rs index f6af2cb05..78dfa2b4d 100644 --- a/crates/sdk/libs/near/src/types.rs +++ b/crates/sdk/libs/near/src/types.rs @@ -1,6 +1,3 @@ -use serde_with::base64::Base64; -use serde_with::serde_as; - pub type BlockHeight = u64; pub type BlockHash = calimero_primitives::hash::Hash; pub type AccountId = near_account_id::AccountId; @@ -15,44 +12,3 @@ pub enum BlockId { Height(BlockHeight), Hash(BlockHash), } - -#[serde_as] -#[derive(serde::Deserialize, Clone, Debug)] -#[serde(transparent)] -pub struct StoreValue(#[serde_as(as = "Base64")] pub Box<[u8]>); - -#[serde_as] -#[derive(serde::Serialize, serde::Deserialize, Clone, Debug)] -#[serde(transparent)] -pub struct StoreKey(#[serde_as(as = "Base64")] pub Box<[u8]>); - -#[serde_as] -#[derive(serde::Serialize, Clone, Debug)] -#[serde(transparent)] -pub struct FunctionArgs(#[serde_as(as = "Base64")] Box<[u8]>); - -#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] -#[serde(rename_all = "snake_case")] -pub enum BlockReference { - BlockId(BlockId), - Finality(Finality), - SyncCheckpoint(SyncCheckpoint), -} - -#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] -#[serde(rename_all = "snake_case")] -pub enum SyncCheckpoint { - Genesis, - EarliestAvailable, -} - -#[derive(serde::Serialize, serde::Deserialize, Default, Clone, Debug)] -pub enum Finality { - #[serde(rename = "optimistic")] - None, - #[serde(rename = "near-final")] - DoomSlug, - #[serde(rename = "final")] - #[default] - Final, -} diff --git a/crates/sdk/libs/near/src/views.rs b/crates/sdk/libs/near/src/views.rs index 4f2a184a8..60ccd938b 100644 --- a/crates/sdk/libs/near/src/views.rs +++ b/crates/sdk/libs/near/src/views.rs @@ -4,9 +4,7 @@ use std::sync::Arc; use serde_with::base64::Base64; use serde_with::serde_as; -use crate::types::{ - AccountId, Balance, BlockHeight, FunctionArgs, Nonce, StorageUsage, StoreKey, StoreValue, -}; +use crate::types::{AccountId, Balance, BlockHeight, BlockId, Nonce, StorageUsage}; #[derive(serde::Serialize, Debug)] #[serde(tag = "request_type", rename_all = "snake_case")] @@ -109,3 +107,44 @@ pub struct CallResult { pub result: Box<[u8]>, pub logs: Box<[Box]>, } + +#[serde_as] +#[derive(serde::Deserialize, Clone, Debug)] +#[serde(transparent)] +pub struct StoreValue(#[serde_as(as = "Base64")] pub Box<[u8]>); + +#[serde_as] +#[derive(serde::Serialize, serde::Deserialize, Clone, Debug)] +#[serde(transparent)] +pub struct StoreKey(#[serde_as(as = "Base64")] pub Box<[u8]>); + +#[serde_as] +#[derive(serde::Serialize, Clone, Debug)] +#[serde(transparent)] +pub struct FunctionArgs(#[serde_as(as = "Base64")] Box<[u8]>); + +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +#[serde(rename_all = "snake_case")] +pub enum BlockReference { + BlockId(BlockId), + Finality(Finality), + SyncCheckpoint(SyncCheckpoint), +} + +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +#[serde(rename_all = "snake_case")] +pub enum SyncCheckpoint { + Genesis, + EarliestAvailable, +} + +#[derive(serde::Serialize, serde::Deserialize, Default, Clone, Debug)] +pub enum Finality { + #[serde(rename = "optimistic")] + None, + #[serde(rename = "near-final")] + DoomSlug, + #[serde(rename = "final")] + #[default] + Final, +} From 5559c99a03b7d33f5a216b43bfa20c71d5b3442a Mon Sep 17 00:00:00 2001 From: Saeed Dadkhah Date: Wed, 26 Jun 2024 20:33:44 +0330 Subject: [PATCH 33/34] Update crates/runtime/src/logic.rs Co-authored-by: Xabi Losada --- crates/runtime/src/logic.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/crates/runtime/src/logic.rs b/crates/runtime/src/logic.rs index 657e6f8f8..5ffe6052f 100644 --- a/crates/runtime/src/logic.rs +++ b/crates/runtime/src/logic.rs @@ -322,7 +322,9 @@ impl<'a> VMHostFunctions<'a> { let method = self.get_string(method_ptr, method_len)?; let headers = self.read_guest_memory(headers_ptr, headers_len)?; - // safety: It's not possible to call `fetch` directly by apps. So headers is generated by our code. Safe to deserialize. +// Safety: The `fetch` function cannot be directly called by applications. +// Therefore, the headers are generated exclusively by our code, ensuring +// that it is safe to deserialize them. let headers: Vec<(String, String)> = borsh::from_slice(&headers).unwrap(); let body = self.read_guest_memory(body_ptr, body_len)?; let mut request = ureq::request(&method, &url); From 885a36fe991f22a2de476cd4b8901c46e818d75a Mon Sep 17 00:00:00 2001 From: Saeed Dadkhah Date: Wed, 26 Jun 2024 21:09:03 +0330 Subject: [PATCH 34/34] Add an example for near library --- Cargo.lock | 9 ++++++++- Cargo.toml | 1 + apps/gen-ext/Cargo.toml | 14 ++++++++++++++ apps/gen-ext/build.sh | 18 ++++++++++++++++++ apps/gen-ext/src/lib.rs | 27 +++++++++++++++++++++++++++ apps/only-peers/Cargo.toml | 1 - crates/runtime/examples/fetch.rs | 9 ++++++--- crates/sdk/libs/near/src/error.rs | 2 +- crates/sdk/libs/near/src/views.rs | 4 ++-- 9 files changed, 77 insertions(+), 8 deletions(-) create mode 100644 apps/gen-ext/Cargo.toml create mode 100755 apps/gen-ext/build.sh create mode 100644 apps/gen-ext/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 1dc353528..95940c774 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2341,6 +2341,14 @@ dependencies = [ "byteorder", ] +[[package]] +name = "gen-ext" +version = "0.1.0" +dependencies = [ + "calimero-sdk", + "calimero-sdk-near", +] + [[package]] name = "generic-array" version = "0.14.7" @@ -4667,7 +4675,6 @@ name = "only-peers" version = "0.1.0" dependencies = [ "calimero-sdk", - "calimero-sdk-near", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 3e8ba57c7..b69e9aab8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,6 +24,7 @@ members = [ "./apps/kv-store", "./apps/only-peers", + "./apps/gen-ext", "./contracts/package-manager", ] diff --git a/apps/gen-ext/Cargo.toml b/apps/gen-ext/Cargo.toml new file mode 100644 index 000000000..a29fe22be --- /dev/null +++ b/apps/gen-ext/Cargo.toml @@ -0,0 +1,14 @@ +[package] +authors.workspace = true +edition.workspace = true +license.workspace = true +name = "gen-ext" +repository.workspace = true +version = "0.1.0" + +[lib] +crate-type = ["cdylib"] + +[dependencies] +calimero-sdk = {path = "../../crates/sdk"} +calimero-sdk-near = { path = "../../crates/sdk/libs/near" } diff --git a/apps/gen-ext/build.sh b/apps/gen-ext/build.sh new file mode 100755 index 000000000..8a9e420d8 --- /dev/null +++ b/apps/gen-ext/build.sh @@ -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/gen_ext.wasm ./res/ + +if command -v wasm-opt > /dev/null; then + wasm-opt -Oz ./res/gen_ext.wasm -o ./res/gen_ext.wasm +fi diff --git a/apps/gen-ext/src/lib.rs b/apps/gen-ext/src/lib.rs new file mode 100644 index 000000000..0ae5c8766 --- /dev/null +++ b/apps/gen-ext/src/lib.rs @@ -0,0 +1,27 @@ +use calimero_sdk::app; +use calimero_sdk::borsh::{BorshDeserialize, BorshSerialize}; +use calimero_sdk_near::query::RpcQueryRequest; +use calimero_sdk_near::views::QueryRequest; +use calimero_sdk_near::Client; + +#[app::state] +#[derive(Default, BorshSerialize, BorshDeserialize)] +#[borsh(crate = "calimero_sdk::borsh")] +struct GenExt; + +#[app::logic] +impl GenExt { + pub fn view_account(&mut self, account_id: &str, block_height: u64) -> String { + let client = Client::testnet(); + let request = RpcQueryRequest { + block_id: calimero_sdk_near::BlockId::Height(block_height), + request: QueryRequest::ViewAccount { + account_id: account_id.parse().unwrap(), + }, + }; + match client.call(request) { + Ok(r) => format!("{:?}", r), + Err(e) => format!("{:?}", e), + } + } +} diff --git a/apps/only-peers/Cargo.toml b/apps/only-peers/Cargo.toml index c6ea8b840..cc3360bac 100644 --- a/apps/only-peers/Cargo.toml +++ b/apps/only-peers/Cargo.toml @@ -11,4 +11,3 @@ crate-type = ["cdylib"] [dependencies] calimero-sdk = { path = "../../crates/sdk" } -calimero-sdk-near = { path = "../../crates/sdk/libs/near" } diff --git a/crates/runtime/examples/fetch.rs b/crates/runtime/examples/fetch.rs index a6baa3c0a..fe625cdc6 100644 --- a/crates/runtime/examples/fetch.rs +++ b/crates/runtime/examples/fetch.rs @@ -2,7 +2,7 @@ use calimero_runtime::{logic, run, store, Constraint}; use serde_json::json; fn main() -> eyre::Result<()> { - let file = include_bytes!("../../../apps/only-peers/res/only_peers.wasm"); + let file = include_bytes!("../../../apps/gen-ext/res/gen_ext.wasm"); let mut storage = store::InMemoryStorage::default(); @@ -22,9 +22,12 @@ fn main() -> eyre::Result<()> { }; let cx = logic::VMContext { - input: serde_json::to_vec(&json!({}))?, + input: serde_json::to_vec(&json!({ + "block_height": 167345193, + "account_id": "nearkat.testnet", + }))?, }; - let get_outcome = run(file, "fetch", cx, &mut storage, &limits)?; + let get_outcome = run(file, "view_account", cx, &mut storage, &limits)?; let returns = String::from_utf8(get_outcome.returns.unwrap().unwrap()).unwrap(); println!("{returns}"); diff --git a/crates/sdk/libs/near/src/error.rs b/crates/sdk/libs/near/src/error.rs index bd4834102..6de9a0b9b 100644 --- a/crates/sdk/libs/near/src/error.rs +++ b/crates/sdk/libs/near/src/error.rs @@ -9,7 +9,7 @@ pub enum Error { #[error("Failed to fetch: {0}")] FetchError(String), - #[error("Server error {0}")] + #[error("Server error: {0}")] ServerError(RpcError), } diff --git a/crates/sdk/libs/near/src/views.rs b/crates/sdk/libs/near/src/views.rs index 60ccd938b..b6620d647 100644 --- a/crates/sdk/libs/near/src/views.rs +++ b/crates/sdk/libs/near/src/views.rs @@ -68,9 +68,9 @@ pub struct StateItem { #[derive(serde::Deserialize, Debug, Clone)] pub struct ViewStateResult { pub values: Box<[StateItem]>, - #[serde_as(as = "Vec")] + #[serde_as(as = "Box<[Base64]>")] #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub proof: Vec>, + pub proof: Box<[Arc<[u8]>]>, } #[derive(Debug, Clone, serde::Deserialize)]