From 8712e44bd087fe8bc292b081a6a2c2f629fc88e8 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Fri, 13 Sep 2024 14:54:25 -0400 Subject: [PATCH 001/196] feat: first draft of rust interchain core --- rust/.gitignore | 16 ++++++++++++++++ rust/Cargo.toml | 17 +++++++++++++++++ rust/context/Cargo.toml | 12 ++++++++++++ rust/context/src/lib.rs | 25 +++++++++++++++++++++++++ rust/core/Cargo.toml | 19 +++++++++++++++++++ rust/core/src/lib.rs | 17 +++++++++++++++++ rust/core_macros/Cargo.toml | 14 ++++++++++++++ rust/core_macros/src/lib.rs | 33 +++++++++++++++++++++++++++++++++ rust/message_api/Cargo.toml | 11 +++++++++++ rust/message_api/src/lib.rs | 4 ++++ rust/prelude/Cargo.toml | 15 +++++++++++++++ rust/prelude/src/lib.rs | 7 +++++++ rust/schema/Cargo.toml | 11 +++++++++++ rust/schema/src/lib.rs | 6 ++++++ rust/state_objects/Cargo.toml | 11 +++++++++++ rust/state_objects/src/item.rs | 8 ++++++++ rust/state_objects/src/lib.rs | 9 +++++++++ rust/state_objects/src/map.rs | 6 ++++++ rust/state_objects/src/set.rs | 8 ++++++++ 19 files changed, 249 insertions(+) create mode 100644 rust/.gitignore create mode 100644 rust/Cargo.toml create mode 100644 rust/context/Cargo.toml create mode 100644 rust/context/src/lib.rs create mode 100644 rust/core/Cargo.toml create mode 100644 rust/core/src/lib.rs create mode 100644 rust/core_macros/Cargo.toml create mode 100644 rust/core_macros/src/lib.rs create mode 100644 rust/message_api/Cargo.toml create mode 100644 rust/message_api/src/lib.rs create mode 100644 rust/prelude/Cargo.toml create mode 100644 rust/prelude/src/lib.rs create mode 100644 rust/schema/Cargo.toml create mode 100644 rust/schema/src/lib.rs create mode 100644 rust/state_objects/Cargo.toml create mode 100644 rust/state_objects/src/item.rs create mode 100644 rust/state_objects/src/lib.rs create mode 100644 rust/state_objects/src/map.rs create mode 100644 rust/state_objects/src/set.rs diff --git a/rust/.gitignore b/rust/.gitignore new file mode 100644 index 000000000000..66a635463e74 --- /dev/null +++ b/rust/.gitignore @@ -0,0 +1,16 @@ +### Rust template +# Generated by Cargo +# will have compiled files and executables +debug/ +target/ + +# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries +# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html +Cargo.lock + +# These are backup files generated by rustfmt +**/*.rs.bk + +# MSVC Windows builds of rustc generate these, which store debugging information +*.pdb + diff --git a/rust/Cargo.toml b/rust/Cargo.toml new file mode 100644 index 000000000000..d22fec1c822f --- /dev/null +++ b/rust/Cargo.toml @@ -0,0 +1,17 @@ +[workspace] +members = [ "context", + "core", + "core_macros", "message_api", + "prelude" +, "schema", "state_objects"] +resolver = "2" + +[workspace.package] +version = "0.0.1" +repository = "https://github.com/cosmos/cosmos-sdk" +license = "Apache-2.0" + +[workspace.lints] + +[workspace.lints.rust] +missing_docs = "deny" diff --git a/rust/context/Cargo.toml b/rust/context/Cargo.toml new file mode 100644 index 000000000000..473d695ce99e --- /dev/null +++ b/rust/context/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "interchain_context" +edition = "2021" +version.workspace = true +repository.workspace = true +license.workspace = true + +[lints] +workspace = true + +[dependencies] +interchain_message_api = { path = "../message_api" } diff --git a/rust/context/src/lib.rs b/rust/context/src/lib.rs new file mode 100644 index 000000000000..c73c09bb6bd0 --- /dev/null +++ b/rust/context/src/lib.rs @@ -0,0 +1,25 @@ +//! This crate provides an encoding agnostic implementation of a Context type which wraps +//! the basic RFC 003 message passing API along with an associated router and memory +//! management functions. + +use interchain_message_api::{Address}; + +/// Context wraps a single message request (and possibly response as well) along with +/// the router callbacks necessary for making nested message calls. +pub struct Context {} + +impl Context { + /// This is the address of the account that is getting called. + /// In a receiving account, this is the account's own address. + pub fn address(&self) -> &Address { + unimplemented!() + } + + /// This is the address of the account which is making the message call. + pub fn caller(&self) -> &Address { + unimplemented!() + } +} + +/// Response is the type that should be used for message handler responses. +pub type Response = Result; \ No newline at end of file diff --git a/rust/core/Cargo.toml b/rust/core/Cargo.toml new file mode 100644 index 000000000000..2f685d208f1f --- /dev/null +++ b/rust/core/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "interchain_core" +edition = "2021" +version.workspace = true +repository.workspace = true +license.workspace = true + +[lints] +workspace = true + +[dependencies] +interchain_message_api = { path = "../message_api" } +interchain_context = { path = "../context" } +interchain_schema = { path = "../schema" } +interchain_core_macros = { path = "../core_macros" } + +[features] +default = ["core_macros"] +core_macros = [] \ No newline at end of file diff --git a/rust/core/src/lib.rs b/rust/core/src/lib.rs new file mode 100644 index 000000000000..6d3966a9edbf --- /dev/null +++ b/rust/core/src/lib.rs @@ -0,0 +1,17 @@ +//! This crate defines types and macros for constructing easy to use account and module implementations. +//! It integrates with the encoding layer but does not specify a state management framework. + +#[doc(inline)] +pub use interchain_message_api::{Address}; +#[doc(inline)] +pub use interchain_context::{Context, Response}; +#[doc(inline)] +pub use interchain_schema::{StructCodec}; + +#[cfg(feature = "core_macros")] +#[allow(unused_imports)] +#[macro_use] +extern crate interchain_core_macros; +#[cfg(feature = "core_macros")] +#[doc(inline)] +pub use interchain_core_macros::*; \ No newline at end of file diff --git a/rust/core_macros/Cargo.toml b/rust/core_macros/Cargo.toml new file mode 100644 index 000000000000..586a5e9c0680 --- /dev/null +++ b/rust/core_macros/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "interchain_core_macros" +edition = "2021" +version.workspace = true +repository.workspace = true +license.workspace = true + +[lints] +workspace = true + +[lib] +proc-macro = true + +[dependencies] diff --git a/rust/core_macros/src/lib.rs b/rust/core_macros/src/lib.rs new file mode 100644 index 000000000000..d67214074f27 --- /dev/null +++ b/rust/core_macros/src/lib.rs @@ -0,0 +1,33 @@ +//! This is a macro utility crate for interchain_core. + +use proc_macro::TokenStream; + +/// This derives an account handler. +#[proc_macro] +pub fn account_handler(item: TokenStream) -> TokenStream { + item +} + +/// This derives an module handler. +#[proc_macro] +pub fn module_handler(item: TokenStream) -> TokenStream { + item +} + +/// This publishes a trait or struct impl block or a single fn within an impl block. +#[proc_macro] +pub fn publish(item: TokenStream) -> TokenStream { + item +} + +/// This attribute macro should be attached to a trait that implements a account API. +#[proc_macro] +pub fn account_api(item: TokenStream) -> TokenStream { + item +} + +/// This attribute macro should be attached to a trait that implements a module API. +#[proc_macro] +pub fn module_api(item: TokenStream) -> TokenStream { + item +} diff --git a/rust/message_api/Cargo.toml b/rust/message_api/Cargo.toml new file mode 100644 index 000000000000..5b6af68aa36a --- /dev/null +++ b/rust/message_api/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "interchain_message_api" +edition = "2021" +version.workspace = true +repository.workspace = true +license.workspace = true + +[lints] +workspace = true + +[dependencies] diff --git a/rust/message_api/src/lib.rs b/rust/message_api/src/lib.rs new file mode 100644 index 000000000000..0e77426a7b76 --- /dev/null +++ b/rust/message_api/src/lib.rs @@ -0,0 +1,4 @@ +//! This crate provides a low-level implementation of the Cosmos SDK RFC 003 message passing API. + +/// A globally unique identifier for an account or message. +pub struct Address {} \ No newline at end of file diff --git a/rust/prelude/Cargo.toml b/rust/prelude/Cargo.toml new file mode 100644 index 000000000000..e820aae05af8 --- /dev/null +++ b/rust/prelude/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "interchain_prelude" +edition = "2021" +version.workspace = true +repository.workspace = true +license.workspace = true + +[lints] +workspace = true + +[dependencies] +interchain_core = { path = "../core" } +interchain_message_api = { path = "../message_api" } +interchain_context = { path = "../context" } +state_objects = { path = "../state_objects" } diff --git a/rust/prelude/src/lib.rs b/rust/prelude/src/lib.rs new file mode 100644 index 000000000000..42d772e4f4ee --- /dev/null +++ b/rust/prelude/src/lib.rs @@ -0,0 +1,7 @@ +//! This crate defines a single import prelude for building account and module handlers including +//! a built-in state management framework. + +#[doc(inline)] +pub use interchain_core::*; +#[doc(inline)] +pub use state_objects::*; \ No newline at end of file diff --git a/rust/schema/Cargo.toml b/rust/schema/Cargo.toml new file mode 100644 index 000000000000..c62ae5bfe39e --- /dev/null +++ b/rust/schema/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "interchain_schema" +edition = "2021" +version.workspace = true +repository.workspace = true +license.workspace = true + +[dependencies] + +[lints] +workspace = true diff --git a/rust/schema/src/lib.rs b/rust/schema/src/lib.rs new file mode 100644 index 000000000000..2808c174d9eb --- /dev/null +++ b/rust/schema/src/lib.rs @@ -0,0 +1,6 @@ +//! This crate defines the basic traits and types for schema and encoding. + +/// StructCodec is the trait that should be derived to encode and decode a struct. +pub trait StructCodec { + +} diff --git a/rust/state_objects/Cargo.toml b/rust/state_objects/Cargo.toml new file mode 100644 index 000000000000..3c22a87202fe --- /dev/null +++ b/rust/state_objects/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "state_objects" +edition = "2021" +version.workspace = true +repository.workspace = true +license.workspace = true + +[dependencies] + +[lints] +workspace = true diff --git a/rust/state_objects/src/item.rs b/rust/state_objects/src/item.rs new file mode 100644 index 000000000000..c7b67c26cf5f --- /dev/null +++ b/rust/state_objects/src/item.rs @@ -0,0 +1,8 @@ +//! The item module contains the `Item` struct, which represents a single item in storage. + +use crate::Map; + +/// A single item in storage. +pub struct Item { + map: Map<(), V> +} \ No newline at end of file diff --git a/rust/state_objects/src/lib.rs b/rust/state_objects/src/lib.rs new file mode 100644 index 000000000000..d1000e86f864 --- /dev/null +++ b/rust/state_objects/src/lib.rs @@ -0,0 +1,9 @@ +//! State objects projects a state management framework that works well with interchain_core. + +mod map; +mod set; +mod item; + +pub use map::{Map}; +pub use set::{Set}; +pub use item::{Item}; diff --git a/rust/state_objects/src/map.rs b/rust/state_objects/src/map.rs new file mode 100644 index 000000000000..8c3035201dce --- /dev/null +++ b/rust/state_objects/src/map.rs @@ -0,0 +1,6 @@ +//! The map module contains the `Map` struct, which represents a key-value map in storage. + +/// A key-value map. +pub struct Map { + _phantom: std::marker::PhantomData<(K, V)>, +} \ No newline at end of file diff --git a/rust/state_objects/src/set.rs b/rust/state_objects/src/set.rs new file mode 100644 index 000000000000..5444fdfc42dd --- /dev/null +++ b/rust/state_objects/src/set.rs @@ -0,0 +1,8 @@ +//! The set module contains the `Set` struct, which represents a set of keys in storage. + +use crate::Map; + +/// A set of keys in storage. +pub struct Set { + map: Map +} \ No newline at end of file From 03c88ffa8ee88ed49567b20e5d46490be4fe2068 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Fri, 13 Sep 2024 18:01:49 -0400 Subject: [PATCH 002/196] updates --- rust/Cargo.toml | 25 ++++++++-- rust/core/Cargo.toml | 7 +-- .../src/lib.rs => core/src/context.rs} | 8 +--- rust/core/src/events.rs | 12 +++++ rust/core/src/lib.rs | 22 +++++++-- rust/core/src/response.rs | 2 + rust/core_macros/Cargo.toml | 3 ++ rust/core_macros/src/lib.rs | 47 ++++++++++++++----- rust/examples.rs | 2 + rust/examples/bank.rs | 34 ++++++++++++++ rust/examples/counter.rs | 27 +++++++++++ rust/prelude/Cargo.toml | 1 - rust/schema/Cargo.toml | 11 ++++- rust/schema/src/lib.rs | 40 +++++++++++++++- rust/{context => schema_macros}/Cargo.toml | 9 ++-- rust/schema_macros/src/lib.rs | 8 ++++ rust/state_objects/Cargo.toml | 2 + rust/state_objects/src/item.rs | 15 +++++- 18 files changed, 236 insertions(+), 39 deletions(-) rename rust/{context/src/lib.rs => core/src/context.rs} (60%) create mode 100644 rust/core/src/events.rs create mode 100644 rust/core/src/response.rs create mode 100644 rust/examples.rs create mode 100644 rust/examples/bank.rs create mode 100644 rust/examples/counter.rs rename rust/{context => schema_macros}/Cargo.toml (64%) create mode 100644 rust/schema_macros/src/lib.rs diff --git a/rust/Cargo.toml b/rust/Cargo.toml index d22fec1c822f..471eff36a212 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -1,10 +1,12 @@ [workspace] -members = [ "context", +members = [ + "prelude", "core", - "core_macros", "message_api", - "prelude" -, "schema", "state_objects"] -resolver = "2" + "core_macros", + "message_api", + "schema", + "state_objects" +, "schema_macros"] [workspace.package] version = "0.0.1" @@ -15,3 +17,16 @@ license = "Apache-2.0" [workspace.lints.rust] missing_docs = "deny" + +# The settings below are for this root package which mainly contains examples: +[package] +name = "interchain_sdk_rust" +edition = "2021" +publish = false + +[lib] +path = "examples.rs" + +[dependencies] +interchain_prelude = { path = "prelude" } +arrayvec = "0.7.6" diff --git a/rust/core/Cargo.toml b/rust/core/Cargo.toml index 2f685d208f1f..7ef9e10fe3a1 100644 --- a/rust/core/Cargo.toml +++ b/rust/core/Cargo.toml @@ -10,10 +10,11 @@ workspace = true [dependencies] interchain_message_api = { path = "../message_api" } -interchain_context = { path = "../context" } interchain_schema = { path = "../schema" } interchain_core_macros = { path = "../core_macros" } +interchain_schema_macros = { path = "../schema_macros" } [features] -default = ["core_macros"] -core_macros = [] \ No newline at end of file +default = ["core_macros", "schema_macros"] +core_macros = [] +schema_macros = [] \ No newline at end of file diff --git a/rust/context/src/lib.rs b/rust/core/src/context.rs similarity index 60% rename from rust/context/src/lib.rs rename to rust/core/src/context.rs index c73c09bb6bd0..11edf8260ab8 100644 --- a/rust/context/src/lib.rs +++ b/rust/core/src/context.rs @@ -1,8 +1,4 @@ -//! This crate provides an encoding agnostic implementation of a Context type which wraps -//! the basic RFC 003 message passing API along with an associated router and memory -//! management functions. - -use interchain_message_api::{Address}; +use interchain_message_api::Address; /// Context wraps a single message request (and possibly response as well) along with /// the router callbacks necessary for making nested message calls. @@ -21,5 +17,3 @@ impl Context { } } -/// Response is the type that should be used for message handler responses. -pub type Response = Result; \ No newline at end of file diff --git a/rust/core/src/events.rs b/rust/core/src/events.rs new file mode 100644 index 000000000000..952afd78a23f --- /dev/null +++ b/rust/core/src/events.rs @@ -0,0 +1,12 @@ +/// An event bus that can be used to emit events. +pub struct EventBus { + _phantom: std::marker::PhantomData, +} + +impl EventBus { + /// Emits an event to the event bus. + pub fn emit(&mut self, event: U) + where + U: AsRef, + {} +} \ No newline at end of file diff --git a/rust/core/src/lib.rs b/rust/core/src/lib.rs index 6d3966a9edbf..94c9008612f2 100644 --- a/rust/core/src/lib.rs +++ b/rust/core/src/lib.rs @@ -1,12 +1,18 @@ //! This crate defines types and macros for constructing easy to use account and module implementations. //! It integrates with the encoding layer but does not specify a state management framework. +mod context; +mod response; +mod events; + +pub use context::Context; +pub use response::Response; +pub use events::EventBus; #[doc(inline)] -pub use interchain_message_api::{Address}; +pub use interchain_message_api::Address; #[doc(inline)] -pub use interchain_context::{Context, Response}; #[doc(inline)] -pub use interchain_schema::{StructCodec}; +pub use interchain_schema::StructCodec; #[cfg(feature = "core_macros")] #[allow(unused_imports)] @@ -14,4 +20,12 @@ pub use interchain_schema::{StructCodec}; extern crate interchain_core_macros; #[cfg(feature = "core_macros")] #[doc(inline)] -pub use interchain_core_macros::*; \ No newline at end of file +pub use interchain_core_macros::*; + +#[cfg(feature = "schema_macros")] +#[allow(unused_imports)] +#[macro_use] +extern crate interchain_schema_macros; +#[cfg(feature = "schema_macros")] +#[doc(inline)] +pub use interchain_schema_macros::*; diff --git a/rust/core/src/response.rs b/rust/core/src/response.rs new file mode 100644 index 000000000000..b38460ce7420 --- /dev/null +++ b/rust/core/src/response.rs @@ -0,0 +1,2 @@ +/// Response is the type that should be used for message handler responses. +pub type Response = Result; diff --git a/rust/core_macros/Cargo.toml b/rust/core_macros/Cargo.toml index 586a5e9c0680..bc78a6a11c1e 100644 --- a/rust/core_macros/Cargo.toml +++ b/rust/core_macros/Cargo.toml @@ -12,3 +12,6 @@ workspace = true proc-macro = true [dependencies] +syn = { version = "2.0.77", features = ["full"] } +quote = "1.0.37" + diff --git a/rust/core_macros/src/lib.rs b/rust/core_macros/src/lib.rs index d67214074f27..de54c4f3438e 100644 --- a/rust/core_macros/src/lib.rs +++ b/rust/core_macros/src/lib.rs @@ -1,33 +1,58 @@ //! This is a macro utility crate for interchain_core. -use proc_macro::TokenStream; +use proc_macro::{TokenStream}; +use quote::quote; +use syn::{parse_macro_input, File, Item}; /// This derives an account handler. -#[proc_macro] -pub fn account_handler(item: TokenStream) -> TokenStream { +#[proc_macro_attribute] +pub fn account_handler(_attr: TokenStream, item: TokenStream) -> TokenStream { item } /// This derives an module handler. -#[proc_macro] -pub fn module_handler(item: TokenStream) -> TokenStream { +#[proc_macro_attribute] +pub fn module_handler(_attr: TokenStream, item: TokenStream) -> TokenStream { item } /// This publishes a trait or struct impl block or a single fn within an impl block. -#[proc_macro] -pub fn publish(item: TokenStream) -> TokenStream { +#[proc_macro_attribute] +pub fn publish(_attr: TokenStream, item: TokenStream) -> TokenStream { item } /// This attribute macro should be attached to a trait that implements a account API. -#[proc_macro] -pub fn account_api(item: TokenStream) -> TokenStream { +#[proc_macro_attribute] +pub fn account_api(_attr: TokenStream, item: TokenStream) -> TokenStream { item } /// This attribute macro should be attached to a trait that implements a module API. -#[proc_macro] -pub fn module_api(item: TokenStream) -> TokenStream { +#[proc_macro_attribute] +pub fn module_api(_attr: TokenStream, item: TokenStream) -> TokenStream { + item +} + +/// This attribute bundles account and module handlers into a package root which can be +/// loaded into an application. +#[proc_macro_attribute] +pub fn package(_attr: TokenStream, item: TokenStream) -> TokenStream { + let item = parse_macro_input!(item as File); + let expanded = quote! { + #item + }; + expanded.into() +} + +/// This attribute macro should be attached to a function that is called when the account is created. +#[proc_macro_attribute] +pub fn on_create(_attr: TokenStream, item: TokenStream) -> TokenStream { + item +} + +/// This attribute macro should be attached to a function that is called when the account is migrated. +#[proc_macro_attribute] +pub fn on_migrate(_attr: TokenStream, item: TokenStream) -> TokenStream { item } diff --git a/rust/examples.rs b/rust/examples.rs new file mode 100644 index 000000000000..2439986e69d8 --- /dev/null +++ b/rust/examples.rs @@ -0,0 +1,2 @@ +//! This crate serves as a workspace crate, and this is a dummy root file that indicates +//! that the only code in this root package which is executable is in the examples/ folder. \ No newline at end of file diff --git a/rust/examples/bank.rs b/rust/examples/bank.rs new file mode 100644 index 000000000000..ac04dafae838 --- /dev/null +++ b/rust/examples/bank.rs @@ -0,0 +1,34 @@ +#[interchain_prelude::module_handler(Bank)] +pub mod bank { + use interchain_prelude::*; + + pub struct Bank { + balances: Map<(Address, String), u128>, + } + + #[derive(StructCodec)] + pub struct Coin<'a> { + pub denom: &'a str, + pub amount: u128, + } + + #[module_api] + pub trait BankAPI { + fn send(&self, ctx: &mut Context, to: Address, amount: &[Coin], evt: &mut EventBus) -> Response<()>; + } + + #[derive(StructCodec)] + pub struct EventSend<'a> { + pub from: Address, + pub to: Address, + pub coin: Coin<'a>, + } + + impl BankAPI for Bank { + fn send(&self, ctx: &mut Context, to: Address, amount: &[Coin], evt: &mut EventBus) -> Response<()> { + todo!() + } + } +} + +fn main() {} \ No newline at end of file diff --git a/rust/examples/counter.rs b/rust/examples/counter.rs new file mode 100644 index 000000000000..534025cd5859 --- /dev/null +++ b/rust/examples/counter.rs @@ -0,0 +1,27 @@ +#[interchain_prelude::account_handler] +pub mod counter { + use interchain_prelude::*; + + pub struct Counter { + value: Item + } + + #[publish] + impl Counter { + pub fn get(&self, ctx: &Context) -> Response { + self.value.get(ctx) + } + + pub fn inc(&mut self, ctx: &mut Context) -> Response<()> { + let value = self.value.get(ctx)?; + self.value.set(ctx, value + 1) + } + + pub fn dec(&mut self, ctx: &mut Context) -> Response<()> { + let value = self.value.get(ctx)?; + self.value.set(ctx, value - 1) + } + } +} + +fn main() {} diff --git a/rust/prelude/Cargo.toml b/rust/prelude/Cargo.toml index e820aae05af8..b529aa1cf583 100644 --- a/rust/prelude/Cargo.toml +++ b/rust/prelude/Cargo.toml @@ -11,5 +11,4 @@ workspace = true [dependencies] interchain_core = { path = "../core" } interchain_message_api = { path = "../message_api" } -interchain_context = { path = "../context" } state_objects = { path = "../state_objects" } diff --git a/rust/schema/Cargo.toml b/rust/schema/Cargo.toml index c62ae5bfe39e..e50fd45564a8 100644 --- a/rust/schema/Cargo.toml +++ b/rust/schema/Cargo.toml @@ -5,7 +5,14 @@ version.workspace = true repository.workspace = true license.workspace = true -[dependencies] - [lints] workspace = true + +[dependencies] +interchain_message_api = { path = "../message_api" } +interchain_schema_macros = { path = "../schema_macros" } + +[features] +default = ["address", "macros"] +address = [] +macros = [] diff --git a/rust/schema/src/lib.rs b/rust/schema/src/lib.rs index 2808c174d9eb..08c949ccffbd 100644 --- a/rust/schema/src/lib.rs +++ b/rust/schema/src/lib.rs @@ -1,6 +1,42 @@ //! This crate defines the basic traits and types for schema and encoding. /// StructCodec is the trait that should be derived to encode and decode a struct. -pub trait StructCodec { +pub trait StructCodec {} -} +/// Value is the trait that should be implemented for all types that can be encoded and decoded. +pub trait Value<'a> +where + Self: 'a, +{} +impl<'a> Value<'a> for u8 {} +impl<'a> Value<'a> for u16 {} +impl<'a> Value<'a> for u32 {} +impl<'a> Value<'a> for u64 {} +impl<'a> Value<'a> for u128 {} +impl<'a> Value<'a> for i8 {} +impl<'a> Value<'a> for i16 {} +impl<'a> Value<'a> for i32 {} +impl<'a> Value<'a> for i64 {} +impl<'a> Value<'a> for i128 {} +impl<'a> Value<'a> for bool {} +impl<'a> Value<'a> for &'a str {} +impl<'a, T: Value<'a>> Value<'a> for Option {} +impl<'a> Value<'a> for &'a [u8] {} + +#[cfg(feature = "address")] +impl<'a> Value<'a> for interchain_message_api::Address {} +#[cfg(feature = "address")] +impl<'a> Value<'a> for &'a interchain_message_api::Address {} + +#[cfg(feature = "arrayvec")] +impl<'a, T: Value<'a>, const N: usize> Value<'a> for arrayvec::ArrayVec {} +#[cfg(feature = "arrayvec")] +impl<'a, const N: usize> Value<'a> for arrayvec::ArrayString {} + +#[cfg(feature = "macros")] +#[allow(unused_imports)] +#[macro_use] +extern crate interchain_schema_macros; +#[cfg(feature = "macros")] +#[doc(inline)] +pub use interchain_schema_macros::*; diff --git a/rust/context/Cargo.toml b/rust/schema_macros/Cargo.toml similarity index 64% rename from rust/context/Cargo.toml rename to rust/schema_macros/Cargo.toml index 473d695ce99e..e0b2d36bfe8e 100644 --- a/rust/context/Cargo.toml +++ b/rust/schema_macros/Cargo.toml @@ -1,12 +1,15 @@ [package] -name = "interchain_context" +name = "interchain_schema_macros" edition = "2021" version.workspace = true repository.workspace = true license.workspace = true +[dependencies] + +[lib] +proc-macro = true + [lints] workspace = true -[dependencies] -interchain_message_api = { path = "../message_api" } diff --git a/rust/schema_macros/src/lib.rs b/rust/schema_macros/src/lib.rs new file mode 100644 index 000000000000..ca903eead1f1 --- /dev/null +++ b/rust/schema_macros/src/lib.rs @@ -0,0 +1,8 @@ +//! Macros for generating code for the schema crate. +use proc_macro::TokenStream; + +/// This derives a struct codec. +#[proc_macro_derive(StructCodec)] +pub fn derive_struct_codec(input: TokenStream) -> TokenStream { + TokenStream::new() +} \ No newline at end of file diff --git a/rust/state_objects/Cargo.toml b/rust/state_objects/Cargo.toml index 3c22a87202fe..bfec4ca1bd6a 100644 --- a/rust/state_objects/Cargo.toml +++ b/rust/state_objects/Cargo.toml @@ -6,6 +6,8 @@ repository.workspace = true license.workspace = true [dependencies] +interchain_core = { path = "../core" } +interchain_schema = { path = "../schema" } [lints] workspace = true diff --git a/rust/state_objects/src/item.rs b/rust/state_objects/src/item.rs index c7b67c26cf5f..1d99d7709288 100644 --- a/rust/state_objects/src/item.rs +++ b/rust/state_objects/src/item.rs @@ -1,8 +1,21 @@ //! The item module contains the `Item` struct, which represents a single item in storage. +use interchain_core::{Context, Response}; use crate::Map; /// A single item in storage. pub struct Item { map: Map<(), V> -} \ No newline at end of file +} + +impl Item { + /// Gets the value of the item. + pub fn get(&self, ctx: &Context) -> Response { + todo!() + } + + /// Sets the value of the item. + pub fn set(&self, ctx: &Context, value: V) -> Response<()> { + todo!() + } +} From a0767d8bb10a09bbe5195440a3b645c1902978ec Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Fri, 13 Sep 2024 19:47:54 -0400 Subject: [PATCH 003/196] WIP on types --- rust/core/src/context.rs | 12 ++++++++++++ rust/core/src/lib.rs | 1 + rust/core/src/message.rs | 6 ++++++ rust/schema/src/lib.rs | 36 ++++-------------------------------- rust/schema/src/struct.rs | 2 ++ rust/schema/src/types.rs | 25 +++++++++++++++++++++++++ rust/schema/src/value.rs | 34 ++++++++++++++++++++++++++++++++++ 7 files changed, 84 insertions(+), 32 deletions(-) create mode 100644 rust/core/src/message.rs create mode 100644 rust/schema/src/struct.rs create mode 100644 rust/schema/src/types.rs create mode 100644 rust/schema/src/value.rs diff --git a/rust/core/src/context.rs b/rust/core/src/context.rs index 11edf8260ab8..b02f494b3aee 100644 --- a/rust/core/src/context.rs +++ b/rust/core/src/context.rs @@ -1,4 +1,6 @@ use interchain_message_api::Address; +use crate::message::Message; +use crate::Response; /// Context wraps a single message request (and possibly response as well) along with /// the router callbacks necessary for making nested message calls. @@ -15,5 +17,15 @@ impl Context { pub fn caller(&self) -> &Address { unimplemented!() } + + pub fn dynamic_invoke_module>(&self, message: M) -> Response + { + unimplemented!() + } + + pub fn dynamic_invoke_account>(&self, account: &Address, message: M) -> Response + { + unimplemented!() + } } diff --git a/rust/core/src/lib.rs b/rust/core/src/lib.rs index 94c9008612f2..c672ca2c3bcc 100644 --- a/rust/core/src/lib.rs +++ b/rust/core/src/lib.rs @@ -3,6 +3,7 @@ mod context; mod response; mod events; +mod message; pub use context::Context; pub use response::Response; diff --git a/rust/core/src/message.rs b/rust/core/src/message.rs new file mode 100644 index 000000000000..b25fb65433bf --- /dev/null +++ b/rust/core/src/message.rs @@ -0,0 +1,6 @@ +use interchain_schema::StructCodec; + +pub trait Message: StructCodec { + type Response; + type Error; +} \ No newline at end of file diff --git a/rust/schema/src/lib.rs b/rust/schema/src/lib.rs index 08c949ccffbd..3392e1204c1f 100644 --- a/rust/schema/src/lib.rs +++ b/rust/schema/src/lib.rs @@ -1,37 +1,9 @@ //! This crate defines the basic traits and types for schema and encoding. +mod value; +mod types; +mod r#struct; -/// StructCodec is the trait that should be derived to encode and decode a struct. -pub trait StructCodec {} - -/// Value is the trait that should be implemented for all types that can be encoded and decoded. -pub trait Value<'a> -where - Self: 'a, -{} -impl<'a> Value<'a> for u8 {} -impl<'a> Value<'a> for u16 {} -impl<'a> Value<'a> for u32 {} -impl<'a> Value<'a> for u64 {} -impl<'a> Value<'a> for u128 {} -impl<'a> Value<'a> for i8 {} -impl<'a> Value<'a> for i16 {} -impl<'a> Value<'a> for i32 {} -impl<'a> Value<'a> for i64 {} -impl<'a> Value<'a> for i128 {} -impl<'a> Value<'a> for bool {} -impl<'a> Value<'a> for &'a str {} -impl<'a, T: Value<'a>> Value<'a> for Option {} -impl<'a> Value<'a> for &'a [u8] {} - -#[cfg(feature = "address")] -impl<'a> Value<'a> for interchain_message_api::Address {} -#[cfg(feature = "address")] -impl<'a> Value<'a> for &'a interchain_message_api::Address {} - -#[cfg(feature = "arrayvec")] -impl<'a, T: Value<'a>, const N: usize> Value<'a> for arrayvec::ArrayVec {} -#[cfg(feature = "arrayvec")] -impl<'a, const N: usize> Value<'a> for arrayvec::ArrayString {} +pub use r#struct::{StructCodec}; #[cfg(feature = "macros")] #[allow(unused_imports)] diff --git a/rust/schema/src/struct.rs b/rust/schema/src/struct.rs new file mode 100644 index 000000000000..4241c2b54c25 --- /dev/null +++ b/rust/schema/src/struct.rs @@ -0,0 +1,2 @@ +/// StructCodec is the trait that should be derived to encode and decode a struct. +pub trait StructCodec {} diff --git a/rust/schema/src/types.rs b/rust/schema/src/types.rs new file mode 100644 index 000000000000..9160dc1e8fd4 --- /dev/null +++ b/rust/schema/src/types.rs @@ -0,0 +1,25 @@ +pub trait Type: Private {} +trait Private {} + +pub struct U8T; +pub struct U16T; +pub struct U32; +pub struct U64T; +pub struct U128T; +pub struct I8T; +pub struct I16T; +pub struct I32T; +pub struct I64T; +pub struct I128T; +pub struct Bool; +pub struct StrT; +pub struct AddressT; +pub struct NullableT { + _phantom: std::marker::PhantomData, +} +pub struct ListT { + _phantom: std::marker::PhantomData, +} +pub struct StructT { + _phantom: std::marker::PhantomData, +} diff --git a/rust/schema/src/value.rs b/rust/schema/src/value.rs new file mode 100644 index 000000000000..f2453d6301bc --- /dev/null +++ b/rust/schema/src/value.rs @@ -0,0 +1,34 @@ +use crate::StructCodec; +use crate::types::*; + +/// Value is the trait that should be implemented for all types that can be encoded and decoded. +pub trait Value<'a, T: Type> +where + Self: 'a, +{} +impl<'a> Value<'a, U8T> for u8 {} +impl<'a> Value<'a, U16T> for u16 {} +impl<'a> Value<'a, U32> for u32 {} +impl<'a> Value<'a, U64T> for u64 {} +impl<'a> Value<'a, U128T> for u128 {} +impl<'a> Value<'a, I8T> for i8 {} +impl<'a> Value<'a, I16T> for i16 {} +impl<'a> Value<'a, I32T> for i32 {} +impl<'a> Value<'a, I64T> for i64 {} +impl<'a> Value<'a, I128T> for i128 {} +impl<'a> Value<'a, Bool> for bool {} +impl<'a> Value<'a, StrT> for &'a str {} +impl<'a, T: Type, V: Value<'a, T>> Value<'a, NullableT> for Option {} +impl<'a, S: StructCodec> Value<'a, StructT> for S {} +impl<'a, T: Type, V: Value<'a, T>> Value<'a, ListT> for &'a [T] {} + +#[cfg(feature = "address")] +impl<'a> Value<'a, AddressT> for interchain_message_api::Address {} +#[cfg(feature = "address")] +impl<'a> Value<'a, AddressT> for &'a interchain_message_api::Address {} + +#[cfg(feature = "arrayvec")] +impl<'a, T: Type, V: Value<'a, T>, const N: usize> Value<'a, ListT> for arrayvec::ArrayVec {} +#[cfg(feature = "arrayvec")] +impl<'a, const N: usize> Value<'a, StrT> for arrayvec::ArrayString {} + From be1761bb44a4c9c7054d5440f2f282a8d5e25443 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Fri, 13 Sep 2024 19:51:56 -0400 Subject: [PATCH 004/196] refactor prelude into root crate --- rust/Cargo.toml | 18 +++++++++++------- rust/examples.rs | 2 -- rust/examples/bank.rs | 4 ++-- rust/examples/counter.rs | 6 +++--- rust/prelude/Cargo.toml | 14 -------------- rust/prelude/src/lib.rs | 7 ------- rust/schema/src/lib.rs | 4 ++-- rust/src/lib.rs | 7 +++++++ 8 files changed, 25 insertions(+), 37 deletions(-) delete mode 100644 rust/examples.rs delete mode 100644 rust/prelude/Cargo.toml delete mode 100644 rust/prelude/src/lib.rs create mode 100644 rust/src/lib.rs diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 471eff36a212..1b6edd8661a6 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -1,6 +1,5 @@ [workspace] members = [ - "prelude", "core", "core_macros", "message_api", @@ -20,13 +19,18 @@ missing_docs = "deny" # The settings below are for this root package which mainly contains examples: [package] -name = "interchain_sdk_rust" +name = "interchain_sdk" edition = "2021" -publish = false - -[lib] -path = "examples.rs" +version.workspace = true +repository.workspace = true +license.workspace = true [dependencies] -interchain_prelude = { path = "prelude" } +interchain_core = { path = "core" } +state_objects = { path = "state_objects" } + +[dev-dependencies] arrayvec = "0.7.6" + +[lints] +workspace = true diff --git a/rust/examples.rs b/rust/examples.rs deleted file mode 100644 index 2439986e69d8..000000000000 --- a/rust/examples.rs +++ /dev/null @@ -1,2 +0,0 @@ -//! This crate serves as a workspace crate, and this is a dummy root file that indicates -//! that the only code in this root package which is executable is in the examples/ folder. \ No newline at end of file diff --git a/rust/examples/bank.rs b/rust/examples/bank.rs index ac04dafae838..05015bdc8c34 100644 --- a/rust/examples/bank.rs +++ b/rust/examples/bank.rs @@ -1,6 +1,6 @@ -#[interchain_prelude::module_handler(Bank)] +#[interchain_sdk::module_handler(Bank)] pub mod bank { - use interchain_prelude::*; + use interchain_sdk::*; pub struct Bank { balances: Map<(Address, String), u128>, diff --git a/rust/examples/counter.rs b/rust/examples/counter.rs index 534025cd5859..8d66db4c59b9 100644 --- a/rust/examples/counter.rs +++ b/rust/examples/counter.rs @@ -1,9 +1,9 @@ -#[interchain_prelude::account_handler] +#[interchain_sdk::account_handler] pub mod counter { - use interchain_prelude::*; + use interchain_sdk::*; pub struct Counter { - value: Item + value: Item, } #[publish] diff --git a/rust/prelude/Cargo.toml b/rust/prelude/Cargo.toml deleted file mode 100644 index b529aa1cf583..000000000000 --- a/rust/prelude/Cargo.toml +++ /dev/null @@ -1,14 +0,0 @@ -[package] -name = "interchain_prelude" -edition = "2021" -version.workspace = true -repository.workspace = true -license.workspace = true - -[lints] -workspace = true - -[dependencies] -interchain_core = { path = "../core" } -interchain_message_api = { path = "../message_api" } -state_objects = { path = "../state_objects" } diff --git a/rust/prelude/src/lib.rs b/rust/prelude/src/lib.rs deleted file mode 100644 index 42d772e4f4ee..000000000000 --- a/rust/prelude/src/lib.rs +++ /dev/null @@ -1,7 +0,0 @@ -//! This crate defines a single import prelude for building account and module handlers including -//! a built-in state management framework. - -#[doc(inline)] -pub use interchain_core::*; -#[doc(inline)] -pub use state_objects::*; \ No newline at end of file diff --git a/rust/schema/src/lib.rs b/rust/schema/src/lib.rs index 3392e1204c1f..a4bc95be5608 100644 --- a/rust/schema/src/lib.rs +++ b/rust/schema/src/lib.rs @@ -1,6 +1,6 @@ //! This crate defines the basic traits and types for schema and encoding. -mod value; -mod types; +// mod value; +// mod types; mod r#struct; pub use r#struct::{StructCodec}; diff --git a/rust/src/lib.rs b/rust/src/lib.rs new file mode 100644 index 000000000000..ea0460a32937 --- /dev/null +++ b/rust/src/lib.rs @@ -0,0 +1,7 @@ +//! This crate defines a single import for building account and module handlers including +//! the built-in state_objects state management framework. + +#[doc(inline)] +pub use interchain_core::*; +#[doc(inline)] +pub use state_objects::*; From 24914e820f447eaf04931cd87f430fdb8ad02336 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Fri, 13 Sep 2024 21:22:21 -0400 Subject: [PATCH 005/196] simple time lib --- rust/Cargo.toml | 2 +- rust/schema/Cargo.toml | 1 + rust/schema/src/types.rs | 2 + rust/schema/src/value.rs | 2 + rust/util/simple_time/Cargo.toml | 11 +++ rust/util/simple_time/src/lib.rs | 127 +++++++++++++++++++++++++++++++ 6 files changed, 144 insertions(+), 1 deletion(-) create mode 100644 rust/util/simple_time/Cargo.toml create mode 100644 rust/util/simple_time/src/lib.rs diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 1b6edd8661a6..63a60f84a6e7 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -5,7 +5,7 @@ members = [ "message_api", "schema", "state_objects" -, "schema_macros"] +, "schema_macros", "util/simple_time"] [workspace.package] version = "0.0.1" diff --git a/rust/schema/Cargo.toml b/rust/schema/Cargo.toml index e50fd45564a8..38e60beca440 100644 --- a/rust/schema/Cargo.toml +++ b/rust/schema/Cargo.toml @@ -11,6 +11,7 @@ workspace = true [dependencies] interchain_message_api = { path = "../message_api" } interchain_schema_macros = { path = "../schema_macros" } +simple_time = { path = "../util/simple_time" } [features] default = ["address", "macros"] diff --git a/rust/schema/src/types.rs b/rust/schema/src/types.rs index 9160dc1e8fd4..8b1651064016 100644 --- a/rust/schema/src/types.rs +++ b/rust/schema/src/types.rs @@ -14,6 +14,8 @@ pub struct I128T; pub struct Bool; pub struct StrT; pub struct AddressT; +pub struct TimeT; +pub struct DurationT; pub struct NullableT { _phantom: std::marker::PhantomData, } diff --git a/rust/schema/src/value.rs b/rust/schema/src/value.rs index f2453d6301bc..2dd1f987cb93 100644 --- a/rust/schema/src/value.rs +++ b/rust/schema/src/value.rs @@ -18,6 +18,8 @@ impl<'a> Value<'a, I64T> for i64 {} impl<'a> Value<'a, I128T> for i128 {} impl<'a> Value<'a, Bool> for bool {} impl<'a> Value<'a, StrT> for &'a str {} +impl<'a> Value<'a, TimeT> for simple_time::Time {} +impl<'a> Value<'a, DurationT> for simple_time::Duration {} impl<'a, T: Type, V: Value<'a, T>> Value<'a, NullableT> for Option {} impl<'a, S: StructCodec> Value<'a, StructT> for S {} impl<'a, T: Type, V: Value<'a, T>> Value<'a, ListT> for &'a [T] {} diff --git a/rust/util/simple_time/Cargo.toml b/rust/util/simple_time/Cargo.toml new file mode 100644 index 000000000000..e1229e437322 --- /dev/null +++ b/rust/util/simple_time/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "simple_time" +edition = "2021" +version.workspace = true +repository.workspace = true +license.workspace = true + +[dependencies] + +[lints] +workspace = true diff --git a/rust/util/simple_time/src/lib.rs b/rust/util/simple_time/src/lib.rs new file mode 100644 index 000000000000..484b3466379e --- /dev/null +++ b/rust/util/simple_time/src/lib.rs @@ -0,0 +1,127 @@ +use core::ops::{Add, Sub, Neg, AddAssign, SubAssign, Mul}; +use std::ops::MulAssign; + +/// Time is as the number of nanoseconds since the Unix epoch. +/// The default value of Time is the Unix epoch 1970-01-01 00:00:00 UTC. +/// This default may not be suitable for all applications, so +/// wrap time in an Option. +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Default)] +pub struct Time(i128); + +impl Time { + /// Constructs a time instance with nanoseconds since the Unix epoch. + pub const fn from_unix_nanos(time: i128) -> Self { + Time(time) + } + + /// Constructs a time instance with seconds since the Unix epoch. + pub const fn from_unix_secs(time: i64) -> Self { + Time(time as i128 * 1_000_000_000) + } + + pub const fn unix_nanos(&self) -> i128 { + self.0 + } + + pub const fn add(self, duration: Duration) -> Self { + Time(self.0 + duration.0) + } + + pub const fn sub(self, duration: Duration) -> Self { + Time(self.0 - duration.0) + } + + pub const fn diff(self, time: Time) -> Duration { + Duration(self.0 - time.0) + } +} + +/// Duration is a number of nanoseconds. +/// The default value of Duration is 0 nanoseconds. +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Default)] +pub struct Duration(i128); + +impl Duration { + /// Constructs a duration instance with nanoseconds. + pub const fn from_nanos(duration: i128) -> Self { + Duration(duration) + } + + /// Constructs a duration instance with seconds. + pub const fn from_secs(duration: i64) -> Self { + Duration(duration as i128 * 1_000_000_000) + } + + /// Returns the number of nanoseconds in the duration. + pub const fn nanos(&self) -> i128 { + self.0 + } + + pub const fn times(self, rhs: i128) -> Self { + Duration(self.0 * rhs) + } + + pub const SECOND: Duration = Duration(1_000_000_000); + pub const MINUTE: Duration = Duration::SECOND.times(60); + pub const HOUR: Duration = Duration::MINUTE.times(60); + pub const DAY: Duration = Duration::HOUR.times(24); + pub const WEEK: Duration = Duration::DAY.times(7); +} + +impl Add for Time { + type Output = Time; + + fn add(self, rhs: Duration) -> Self::Output { + Time(self.0 + rhs.0) + } +} + +impl AddAssign for Time { + fn add_assign(&mut self, rhs: Duration) { + self.0 += rhs.0; + } +} + +impl Sub for Time { + type Output = Time; + + fn sub(self, rhs: Duration) -> Self::Output { + Time(self.0 - rhs.0) + } +} + +impl SubAssign for Time { + fn sub_assign(&mut self, rhs: Duration) { + self.0 -= rhs.0; + } +} + +impl Sub