Skip to content

no_std support for cosmwasm-std #1483

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 10 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 20 additions & 9 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -348,29 +348,40 @@ jobs:
name: Add wasm32 target
command: rustup target add wasm32-unknown-unknown && rustup target list --installed
- run:
name: Build library for native target (no features)
name: Add no_std target
command: rustup target add thumbv7em-none-eabi && rustup target list --installed
- run:
name: Build library for no_std target
working_directory: ~/project/packages/std
command: cargo build --locked --no-default-features --target thumbv7em-none-eabi
- run:
name: Build library for native target (only "std" feature)
working_directory: ~/project/packages/std
command: cargo build --locked --no-default-features --features std
- run:
name: Build library for wasm target (only "std" feature)
working_directory: ~/project/packages/std
command: cargo build --locked --no-default-features
command: cargo wasm --locked --no-default-features --features std
- run:
name: Build library for wasm target (no features)
name: Run unit tests (only "std" feature)
working_directory: ~/project/packages/std
command: cargo wasm --locked --no-default-features
command: cargo test --locked --no-default-features --features std
- run:
name: Run unit tests (no features)
name: Build library for no_std target (all features "no_std")
working_directory: ~/project/packages/std
command: cargo test --locked --no-default-features
command: cargo build --locked --no-default-features --features abort,iterator,staking,stargate,cosmwasm_1_1 --target thumbv7em-none-eabi
- run:
name: Build library for native target (all features)
working_directory: ~/project/packages/std
command: cargo build --locked --features abort,iterator,staking,stargate,cosmwasm_1_2
command: cargo build --locked --features abort,iterator,staking,stargate,std,cosmwasm_1_2
- run:
name: Build library for wasm target (all features)
working_directory: ~/project/packages/std
command: cargo wasm --locked --features abort,iterator,staking,stargate,cosmwasm_1_2
command: cargo wasm --locked --features abort,iterator,staking,stargate,std,cosmwasm_1_2
- run:
name: Run unit tests (all features)
working_directory: ~/project/packages/std
command: cargo test --locked --features abort,iterator,staking,stargate,cosmwasm_1_2
command: cargo test --locked --features abort,iterator,staking,stargate,std,cosmwasm_1_2
- save_cache:
paths:
- /usr/local/cargo/registry
Expand Down
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,8 +117,12 @@ and this project adheres to
`CanonicalAddr` ([#1463]).
- cosmwasm-std: Implement `PartialEq` between `CanonicalAddr` and
`HexBinary`/`Binary` ([#1463]).
- cosmwasm-std: Add `std` feature to support `no_std` if this feature is not
enabled ([#1483]).
- cosmwasm-std: Add `std` feature to default features ([#1483]).

[#1463]: https://github.com/CosmWasm/cosmwasm/pull/1463
[#1483]: https://github.com/CosmWasm/cosmwasm/pull/1483

### Changed

Expand Down
4 changes: 2 additions & 2 deletions Cargo.lock

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

2 changes: 1 addition & 1 deletion contracts/cyberpunk/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ backtraces = ["cosmwasm-std/backtraces", "cosmwasm-vm/backtraces"]

[dependencies]
cosmwasm-schema = { path = "../../packages/schema" }
cosmwasm-std = { path = "../../packages/std", default-features = false, features = ["abort"] }
cosmwasm-std = { path = "../../packages/std", default-features = false, features = ["abort", "std"] }
rust-argon2 = "0.8"
thiserror = "1.0.26"

Expand Down
2 changes: 1 addition & 1 deletion contracts/hackatom/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ backtraces = ["cosmwasm-std/backtraces", "cosmwasm-vm/backtraces"]

[dependencies]
cosmwasm-schema = { path = "../../packages/schema" }
cosmwasm-std = { path = "../../packages/std", default-features = false, features = ["abort"] }
cosmwasm-std = { path = "../../packages/std", default-features = false, features = ["abort", "std"] }
schemars = "0.8.3"
serde = { version = "1.0.103", default-features = false, features = ["derive"] }
sha2 = "0.10"
Expand Down
2 changes: 1 addition & 1 deletion contracts/reflect/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ backtraces = ["cosmwasm-std/backtraces", "cosmwasm-vm/backtraces"]

[dependencies]
cosmwasm-schema = { path = "../../packages/schema" }
cosmwasm-std = { path = "../../packages/std", default-features = false, features = ["staking", "stargate", "cosmwasm_1_1"] }
cosmwasm-std = { path = "../../packages/std", default-features = false, features = ["staking", "stargate", "cosmwasm_1_1", "std"] }
cosmwasm-storage = { path = "../../packages/storage", default-features = false }
schemars = "0.8.3"
serde = { version = "=1.0.103", default-features = false, features = ["derive"] }
Expand Down
2 changes: 1 addition & 1 deletion contracts/staking/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ backtraces = ["cosmwasm-std/backtraces", "cosmwasm-vm/backtraces"]

[dependencies]
cosmwasm-schema = { path = "../../packages/schema" }
cosmwasm-std = { path = "../../packages/std", default-features = false, features = ["staking"] }
cosmwasm-std = { path = "../../packages/std", default-features = false, features = ["staking", "std"] }
cosmwasm-storage = { path = "../../packages/storage", default-features = false }
schemars = "0.8.3"
serde = { version = "1.0.103", default-features = false, features = ["derive"] }
Expand Down
25 changes: 13 additions & 12 deletions packages/std/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ license = "Apache-2.0"
readme = "README.md"

[package.metadata.docs.rs]
features = ["abort", "stargate", "staking", "ibc3", "cosmwasm_1_2"]
features = ["abort", "std", "stargate", "staking", "ibc3", "cosmwasm_1_2"]

[features]
default = ["iterator", "abort"]
default = ["std", "iterator", "abort"]
abort = []
# iterator allows us to iterate over all DB items in a given range
# optional as some merkle stores (like tries) don't support this
Expand All @@ -39,22 +39,23 @@ cosmwasm_1_1 = []
# This feature makes `GovMsg::VoteWeighted` available for the contract to call, but requires
# the host blockchain to run CosmWasm `1.2.0` or higher.
cosmwasm_1_2 = ["cosmwasm_1_1"]
std = ["forward_ref", "schemars", "serde-json-wasm", "thiserror", "cosmwasm-crypto"]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see removing stuff from no_std build, but I think both serde-json-wasm is essential for it to work. Maybe a PR to make that no-std friendly (it was forked from serde-json-core which was no-std and we added stuff).

Otherwise, how would a contract actually parse data? How would cw-storage-plus work?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thiserror is a bit sad to lose also, but I guess not absolutely needed here?
Not sure how StdError will interact with other types without it.


[dependencies]
base64 = "0.13.0"
base64 = { version = "0.13.0", default-features = false, features = ["alloc"] }
cosmwasm-derive = { path = "../derive", version = "1.2.0" }
derivative = "2"
forward_ref = "1"
hex = "0.4"
schemars = "0.8.3"
sha2 = "0.10.3"
derivative = { version = "2", features = ["use_core"] }
forward_ref = { version = "1", optional = true }
hex = { version = "0.4", default-features = false, features = ["alloc"] }
schemars = { version = "0.8.3", optional = true }
sha2 = { version = "0.10.3", default-features = false }
serde = { version = "1.0.103", default-features = false, features = ["derive", "alloc"] }
serde-json-wasm = { version = "0.5.0" }
thiserror = "1.0.26"
uint = "0.9.3"
serde-json-wasm = { version = "0.5.0", optional = true }
thiserror = { version = "1.0.26", optional = true }
uint = { version = "0.9.3", default-features = false }

[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
cosmwasm-crypto = { path = "../crypto", version = "1.2.0" }
cosmwasm-crypto = { path = "../crypto", version = "1.2.0", optional = true }

[dev-dependencies]
cosmwasm-schema = { path = "../schema" }
Expand Down
23 changes: 23 additions & 0 deletions packages/std/examples/schema.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#[cfg(feature = "std")]
use {
cosmwasm_schema::{export_schema, export_schema_with_title, remove_schemas, schema_for},
cosmwasm_std::{BlockInfo, CosmosMsg, Empty, QueryRequest, Timestamp},
std::env::current_dir,
std::fs::create_dir_all,
};

#[cfg(feature = "std")]
fn main() {
let mut out_dir = current_dir().unwrap();
out_dir.push("schema");
create_dir_all(&out_dir).unwrap();
remove_schemas(&out_dir).unwrap();

export_schema(&schema_for!(BlockInfo), &out_dir);
export_schema(&schema_for!(Timestamp), &out_dir);
export_schema_with_title(&schema_for!(CosmosMsg), &out_dir, "CosmosMsg");
export_schema_with_title(&schema_for!(QueryRequest<Empty>), &out_dir, "QueryRequest");
}

#[cfg(not(feature = "std"))]
fn main() {}
28 changes: 18 additions & 10 deletions packages/std/src/addresses.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
use schemars::JsonSchema;
use alloc::borrow::Cow;
use alloc::fmt;
use alloc::string::String;
use alloc::vec::Vec;
use core::ops::Deref;
use serde::{Deserialize, Serialize};
use sha2::{
digest::{Digest, Update},
Sha256,
};
use std::borrow::Cow;
use std::fmt;
use std::ops::Deref;
use thiserror::Error;

use crate::{binary::Binary, HexBinary};

Expand All @@ -27,9 +27,8 @@ use crate::{binary::Binary, HexBinary};
/// This type is immutable. If you really need to mutate it (Really? Are you sure?), create
/// a mutable copy using `let mut mutable = Addr::to_string()` and operate on that `String`
/// instance.
#[derive(
Serialize, Deserialize, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, JsonSchema,
)]
#[cfg_attr(feature = "std", derive(schemars::JsonSchema))]
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Addr(String);

impl Addr {
Expand Down Expand Up @@ -155,7 +154,8 @@ impl<'a> From<&'a Addr> for Cow<'a, Addr> {
/// addition to that there are many unsafe ways to convert any binary data into an instance.
/// So the type shoud be treated as a marker to express the intended data type, not as
/// a validity guarantee of any sort.
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, Hash, JsonSchema)]
#[cfg_attr(feature = "std", derive(schemars::JsonSchema))]
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, Hash)]
pub struct CanonicalAddr(pub Binary);

/// Implement `CanonicalAddr == Binary`
Expand Down Expand Up @@ -276,7 +276,8 @@ impl fmt::Display for CanonicalAddr {
}
}

#[derive(Error, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "std", derive(thiserror::Error))]
#[derive(Debug, PartialEq, Eq)]
pub enum Instantiate2AddressError {
/// Checksum must be 32 bytes
InvalidChecksumLength,
Expand Down Expand Up @@ -383,9 +384,14 @@ fn hash(ty: &str, key: &[u8]) -> Vec<u8> {
mod tests {
use super::*;
use crate::HexBinary;
use alloc::string::ToString;
use alloc::vec::Vec;
use hex_literal::hex;
#[cfg(feature = "std")]
use std::collections::hash_map::DefaultHasher;
#[cfg(feature = "std")]
use std::collections::HashSet;
#[cfg(feature = "std")]
use std::hash::{Hash, Hasher};

#[test]
Expand Down Expand Up @@ -623,6 +629,7 @@ mod tests {
}

#[test]
#[cfg(feature = "std")]
fn canonical_addr_implements_hash() {
let alice1 = CanonicalAddr::from([0, 187, 61, 11, 250, 0]);
let mut hasher = DefaultHasher::new();
Expand All @@ -645,6 +652,7 @@ mod tests {

/// This requires Hash and Eq to be implemented
#[test]
#[cfg(feature = "std")]
fn canonical_addr_can_be_used_in_hash_set() {
let alice1 = CanonicalAddr::from([0, 187, 61, 11, 250, 0]);
let alice2 = CanonicalAddr::from([0, 187, 61, 11, 250, 0]);
Expand Down
6 changes: 3 additions & 3 deletions packages/std/src/assertions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
macro_rules! ensure {
($cond:expr, $e:expr) => {
if !($cond) {
return Err(std::convert::From::from($e));
return Err(core::convert::From::from($e));
}
};
}
Expand Down Expand Up @@ -68,7 +68,7 @@ macro_rules! ensure_eq {
($a:expr, $b:expr, $e:expr) => {
// Not implemented via `ensure!` because the caller would have to import both macros.
if !($a == $b) {
return Err(std::convert::From::from($e));
return Err(core::convert::From::from($e));
}
};
}
Expand Down Expand Up @@ -100,7 +100,7 @@ macro_rules! ensure_ne {
($a:expr, $b:expr, $e:expr) => {
// Not implemented via `ensure!` because the caller would have to import both macros.
if !($a != $b) {
return Err(std::convert::From::from($e));
return Err(core::convert::From::from($e));
}
};
}
Expand Down
19 changes: 13 additions & 6 deletions packages/std/src/binary.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::fmt;
use std::ops::Deref;

use schemars::JsonSchema;
use alloc::fmt;
use alloc::string::String;
use alloc::vec::Vec;
use core::ops::Deref;
use serde::{de, ser, Deserialize, Deserializer, Serialize};

use crate::errors::{StdError, StdResult};
Expand All @@ -11,8 +11,9 @@ use crate::errors::{StdError, StdResult};
///
/// This is only needed as serde-json-{core,wasm} has a horrible encoding for Vec<u8>.
/// See also <https://github.com/CosmWasm/cosmwasm/blob/main/docs/MESSAGE_TYPES.md>.
#[derive(Clone, Default, PartialEq, Eq, Hash, PartialOrd, Ord, JsonSchema)]
pub struct Binary(#[schemars(with = "String")] pub Vec<u8>);
#[cfg_attr(feature = "std", derive(schemars::JsonSchema))]
#[derive(Clone, Default, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct Binary(#[cfg_attr(feature = "std", schemars(with = "String"))] pub Vec<u8>);

impl Binary {
/// take an (untrusted) string and decode it into bytes.
Expand Down Expand Up @@ -240,8 +241,11 @@ mod tests {
use super::*;
use crate::errors::StdError;
use crate::serde::{from_slice, to_vec};
#[cfg(feature = "std")]
use std::collections::hash_map::DefaultHasher;
#[cfg(feature = "std")]
use std::collections::HashSet;
#[cfg(feature = "std")]
use std::hash::{Hash, Hasher};

#[test]
Expand Down Expand Up @@ -504,6 +508,7 @@ mod tests {
}

#[test]
#[cfg(feature = "std")]
fn binary_implements_as_ref() {
// Can use as_ref (this we already get via the Deref implementation)
let data = Binary(vec![7u8, 35, 49, 101, 0, 255]);
Expand Down Expand Up @@ -532,6 +537,7 @@ mod tests {
}

#[test]
#[cfg(feature = "std")]
fn binary_implements_hash() {
let a1 = Binary::from([0, 187, 61, 11, 250, 0]);
let mut hasher = DefaultHasher::new();
Expand All @@ -554,6 +560,7 @@ mod tests {

/// This requires Hash and Eq to be implemented
#[test]
#[cfg(feature = "std")]
fn binary_can_be_used_in_hash_set() {
let a1 = Binary::from([0, 187, 61, 11, 250, 0]);
let a2 = Binary::from([0, 187, 61, 11, 250, 0]);
Expand Down
9 changes: 6 additions & 3 deletions packages/std/src/coin.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
use schemars::JsonSchema;
use alloc::fmt;
use alloc::string::String;
use alloc::vec::Vec;
use serde::{Deserialize, Serialize};
use std::fmt;

use crate::math::Uint128;

#[derive(Serialize, Deserialize, Clone, Default, Debug, PartialEq, Eq, JsonSchema)]
#[cfg_attr(feature = "std", derive(schemars::JsonSchema))]
#[derive(Serialize, Deserialize, Clone, Default, Debug, PartialEq, Eq)]
pub struct Coin {
pub denom: String,
pub amount: Uint128,
Expand Down Expand Up @@ -86,6 +88,7 @@ pub fn has_coins(coins: &[Coin], required: &Coin) -> bool {
#[cfg(test)]
mod tests {
use super::*;
use alloc::string::ToString;

#[test]
fn coin_implements_display() {
Expand Down
4 changes: 3 additions & 1 deletion packages/std/src/deps.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use std::marker::PhantomData;
#![cfg(feature = "std")]

use core::marker::PhantomData;

use crate::query::CustomQuery;
use crate::results::Empty;
Expand Down
Loading