Skip to content

Commit

Permalink
Merge branch 'nightly' into feature/rename_address_trait
Browse files Browse the repository at this point in the history
  • Loading branch information
citizen-stig authored Aug 23, 2023
2 parents 528558b + 05c4f25 commit 3e48b3b
Show file tree
Hide file tree
Showing 24 changed files with 1,239 additions and 317 deletions.
18 changes: 18 additions & 0 deletions Cargo.lock

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

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ members = [
"module-system/module-implementations/sov-sequencer-registry",
"module-system/module-implementations/module-template",
"module-system/module-implementations/examples/sov-value-setter",
"module-system/module-implementations/examples/sov-vec-setter",
"module-system/module-implementations/examples/sov-election",
"module-system/module-implementations/integration-tests",
]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
[package]
name = "sov-vec-setter"
description = "A Sovereign SDK example module for setting/reading vectors from state"
authors = { workspace = true }
edition = { workspace = true }
homepage = { workspace = true }
license = { workspace = true }
repository = { workspace = true }
rust-version = { workspace = true }
version = { workspace = true }
readme = "README.md"
resolver = "2"
publish = false

[dev-dependencies]
sov-modules-api = { path = "../../../sov-modules-api" }
tempfile = { workspace = true }

[dependencies]
anyhow = { workspace = true }
sov-modules-api = { path = "../../../sov-modules-api", default-features = false, features = ["macros"] }
sov-state = { path = "../../../sov-state", default-features = false }
sov-rollup-interface = { path = "../../../../rollup-interface" }
schemars = { workspace = true, optional = true }
serde = { workspace = true, optional = true }
serde_json = { workspace = true, optional = true }
thiserror = { workspace = true }
borsh = { workspace = true, features = ["rc"] }
jsonrpsee = { workspace = true, features = ["macros", "client-core", "server"], optional = true }
clap = { workspace = true, optional = true }

[features]
default = ["native"]
serde = ["dep:serde", "dep:serde_json"]
native = ["serde", "sov-modules-api/native", "dep:jsonrpsee", "dep:schemars", "dep:clap"]
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# An example of a `SOV-MODULE`

It demonstrates the following concepts:

### 1. Module structure:

- `lib.rs` contains `VecSetter` module definition and `sov_modules_api::Module` trait implementation for `VecSetter`.
- `genesis.rs` contains the module initialization logic.
- `call.rs` contains methods that change module state in response to `CallMessage`.
- `query.rs` contains functions for querying the module state.

### 2. Functionality:

The `admin` (specified in the `VecSetter` genesis) can update a single `u32` value by creating `CallMessage::SetValue(new_value)` message. Anyone can query the module state by calling the `vecSetter_queryValue` endpoint.

For implementation details, please check comments in the `genesis.rs, call.rs & query.rs`.
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
use std::fmt::Debug;

use anyhow::Result;
#[cfg(feature = "native")]
use sov_modules_api::macros::CliWalletArg;
use sov_modules_api::CallResponse;
use sov_state::WorkingSet;
use thiserror::Error;

use super::VecSetter;

/// This enumeration represents the available call messages for interacting with the `sov-vec-setter` module.
#[cfg_attr(
feature = "native",
derive(serde::Serialize),
derive(serde::Deserialize),
derive(CliWalletArg),
derive(schemars::JsonSchema)
)]
#[derive(borsh::BorshDeserialize, borsh::BorshSerialize, Debug, PartialEq, Clone)]
pub enum CallMessage {
/// value to push
PushValue(u32),
/// value to set
SetValue {
/// index to set
index: usize,
/// value to set
value: u32,
},
/// values to set
SetAllValues(Vec<u32>),
/// Pop
PopValue,
}

/// Example of a custom error.
#[derive(Debug, Error)]
enum SetValueError {
#[error("Only admin can change the value")]
WrongSender,
}

impl<C: sov_modules_api::Context> VecSetter<C> {
/// Pushes `value` field to the `vector`, only admin is authorized to call this method.
pub(crate) fn push_value(
&self,
new_value: u32,
context: &C,
working_set: &mut WorkingSet<C::Storage>,
) -> Result<sov_modules_api::CallResponse> {
// If admin is not then early return:
let admin = self.admin.get_or_err(working_set)?;

if &admin != context.sender() {
// Here we use a custom error type.
Err(SetValueError::WrongSender)?;
}

// This is how we push a new value to vector:
self.vector.push(&new_value, working_set);

let new_length = self.vector.len(working_set);

working_set.add_event(
"push",
&format!("value_push: {new_value:?}, new length: {new_length:?}"),
);

Ok(CallResponse::default())
}

/// Sets `value` field to the given index of `vector`, only admin is authorized to call this method.
pub(crate) fn set_value(
&self,
index: usize,
new_value: u32,
context: &C,
working_set: &mut WorkingSet<C::Storage>,
) -> Result<sov_modules_api::CallResponse> {
// If admin is not then early return:
let admin = self.admin.get_or_err(working_set)?;

if &admin != context.sender() {
// Here we use a custom error type.
Err(SetValueError::WrongSender)?;
}

// This is how we set a new value:
self.vector.set(index, &new_value, working_set)?;

working_set.add_event(
"set",
&format!("value_set: {new_value:?} for index: {index:?}"),
);

Ok(CallResponse::default())
}

/// Sets `values` completely to the `vector`, only admin is authorized to call this method.
pub(crate) fn set_all_values(
&self,
values: Vec<u32>,
context: &C,
working_set: &mut WorkingSet<C::Storage>,
) -> Result<sov_modules_api::CallResponse> {
// If admin is not then early return:
let admin = self.admin.get_or_err(working_set)?;

if &admin != context.sender() {
// Here we use a custom error type.
Err(SetValueError::WrongSender)?;
}

// This is how we set all the vector:
self.vector.set_all(values, working_set);

let new_length = self.vector.len(working_set);

working_set.add_event("set_all", &format!("new length: {new_length:?}"));

Ok(CallResponse::default())
}

/// Pops last value from the `vector`, only admin is authorized to call this method.
pub(crate) fn pop_value(
&self,
context: &C,
working_set: &mut WorkingSet<C::Storage>,
) -> Result<sov_modules_api::CallResponse> {
// If admin is not then early return:
let admin = self.admin.get_or_err(working_set)?;

if &admin != context.sender() {
// Here we use a custom error type.
Err(SetValueError::WrongSender)?;
}

// This is how we pop last value value:
let pop_value = self.vector.pop(working_set);

let new_length = self.vector.len(working_set);

working_set.add_event(
"pop",
&format!("value_pop: {pop_value:?}, new length: {new_length:?}"),
);

Ok(CallResponse::default())
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
use anyhow::Result;
use sov_state::WorkingSet;

use super::VecSetter;

impl<C: sov_modules_api::Context> VecSetter<C> {
/// Initializes module with the `admin` role.
pub(crate) fn init_module(
&self,
admin_config: &<Self as sov_modules_api::Module>::Config,
working_set: &mut WorkingSet<C::Storage>,
) -> Result<()> {
self.admin.set(&admin_config.admin, working_set);
Ok(())
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
#![deny(missing_docs)]
#![doc = include_str!("../README.md")]
mod call;
mod genesis;

#[cfg(feature = "native")]
mod query;

pub use call::CallMessage;
#[cfg(feature = "native")]
pub use query::{VecSetterRpcImpl, VecSetterRpcServer};
use sov_modules_api::{Error, ModuleInfo};
use sov_state::WorkingSet;

/// Initial configuration for sov-vec-setter module.
pub struct VecSetterConfig<C: sov_modules_api::Context> {
/// Admin of the module.
pub admin: C::Address,
}

/// A new module:
/// - Must derive `ModuleInfo`
/// - Must contain `[address]` field
/// - Can contain any number of ` #[state]` or `[module]` fields
#[cfg_attr(feature = "native", derive(sov_modules_api::ModuleCallJsonSchema))]
#[derive(ModuleInfo)]
pub struct VecSetter<C: sov_modules_api::Context> {
/// Address of the module.
#[address]
pub address: C::Address,

/// Some vector kept in the state.
#[state]
pub vector: sov_state::StateVec<u32>,

/// Holds the address of the admin user who is allowed to update the vector.
#[state]
pub admin: sov_state::StateValue<C::Address>,
}

impl<C: sov_modules_api::Context> sov_modules_api::Module for VecSetter<C> {
type Context = C;

type Config = VecSetterConfig<C>;

type CallMessage = call::CallMessage;

fn genesis(
&self,
config: &Self::Config,
working_set: &mut WorkingSet<C::Storage>,
) -> Result<(), Error> {
// The initialization logic
Ok(self.init_module(config, working_set)?)
}

fn call(
&self,
msg: Self::CallMessage,
context: &Self::Context,
working_set: &mut WorkingSet<C::Storage>,
) -> Result<sov_modules_api::CallResponse, Error> {
match msg {
call::CallMessage::PushValue(new_value) => {
Ok(self.push_value(new_value, context, working_set)?)
}
call::CallMessage::SetValue { index, value } => {
Ok(self.set_value(index, value, context, working_set)?)
}
call::CallMessage::SetAllValues(values) => {
Ok(self.set_all_values(values, context, working_set)?)
}
call::CallMessage::PopValue => Ok(self.pop_value(context, working_set)?),
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#![allow(missing_docs)]
use jsonrpsee::core::RpcResult;
use sov_modules_api::macros::rpc_gen;
use sov_state::WorkingSet;

use super::VecSetter;

/// Response returned from the vecSetter_queryVec endpoint.
#[derive(serde::Serialize, serde::Deserialize, Debug, Eq, PartialEq, Clone)]
pub struct QueryResponse {
/// Value saved in the module's state vector.
pub value: Option<u32>,
}

/// Response returned from the vecSetter_lenVec endpoint
#[derive(serde::Serialize, serde::Deserialize, Debug, Eq, PartialEq, Clone)]
pub struct LenResponse {
/// Length of the vector
pub value: usize,
}

#[rpc_gen(client, server, namespace = "vecSetter")]
impl<C: sov_modules_api::Context> VecSetter<C> {
/// Queries the state vector of the module.
#[rpc_method(name = "queryVec")]
pub fn query_vec(
&self,
index: usize,
working_set: &mut WorkingSet<C::Storage>,
) -> RpcResult<QueryResponse> {
Ok(QueryResponse {
value: self.vector.get(index, working_set),
})
}
/// Queries the length of the vector
#[rpc_method(name = "lenVec")]
pub fn len_vec(&self, working_set: &mut WorkingSet<C::Storage>) -> RpcResult<LenResponse> {
Ok(LenResponse {
value: self.vector.len(working_set),
})
}
}
Loading

0 comments on commit 3e48b3b

Please sign in to comment.