diff --git a/.circleci/config.yml b/.circleci/config.yml index 4fca9a1a..05bbb9f0 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -61,8 +61,23 @@ jobs: keys: - v4-cargo-cache-{{ arch }}-{{ checksum "Cargo.lock" }} - run: - name: Build all targets + name: Check all targets in std + command: cargo check --all + - run: + name: Check all target in no_std + command: cargo check --no-default-features --all + - run: + name: Build all targets in std command: cargo build --all --all-targets + - run: + name: Build all targets in no_std + command: cargo build --all --no-default-features + - run: + name: Run all tests with no-std + command: cargo test --all --no-default-features + - run: + name: Run all tests with std + command: cargo test --all - save_cache: paths: - /usr/local/cargo/registry diff --git a/rust/Cargo.lock b/rust/Cargo.lock index c4bb0faf..19e4131d 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -193,6 +193,7 @@ dependencies = [ "serde_json", "sha2", "sha3", + "sp-std", ] [[package]] @@ -540,6 +541,12 @@ dependencies = [ "opaque-debug", ] +[[package]] +name = "sp-std" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35391ea974fa5ee869cb094d5b437688fbf3d8127d64d1b9fed5822a1ed39b12" + [[package]] name = "syn" version = "0.15.44" diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 7af03938..119c0047 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -13,14 +13,28 @@ members = ["codegen"] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -prost = "0.7.0" -bytes = "1.0.1" -hex = "0.4.3" -sha2 = "0.9.3" -sha3 = "0.9.1" -ripemd160 = "0.9.1" -anyhow = "1.0.40" +prost = { version = "0.7.0", default-features = false, features = ["prost-derive"] } +bytes = { version = "1.0.1", default-features = false } +hex = { version = "0.4.3", default-features = false, features = [ "alloc" ] } +sha2 = { version = "0.9.3", default-features = false } +sha3 = { version = "0.9.1", default-features = false } +ripemd160 = { version = "0.9.1", default-features = false } +anyhow = { version = "1.0.40", default-features = false } +sp-std = {version = "3.0.0", default-features = false } [dev-dependencies] serde = { version = "1.0.125", features = ["derive"] } serde_json = "1.0.64" + +[features] +default = ["std"] +std = [ + "prost/std", + "bytes/std", + "hex/std", + "sha2/std", + "sha3/std", + "ripemd160/std", + "anyhow/std", + "sp-std/std", +] diff --git a/rust/src/api.rs b/rust/src/api.rs index b906cd0f..bbd7e15c 100644 --- a/rust/src/api.rs +++ b/rust/src/api.rs @@ -1,5 +1,7 @@ -use std::collections::HashMap; -use std::hash::BuildHasher; +use std::collections::btree_map::BTreeMap as HashMap; + +#[cfg(not(feature = "std"))] +use std::prelude::*; use crate::compress::{decompress, is_compressed}; use crate::ics23; @@ -64,11 +66,11 @@ pub fn verify_non_membership( } #[allow(clippy::ptr_arg)] -pub fn verify_batch_membership( +pub fn verify_batch_membership( proof: &ics23::CommitmentProof, spec: &ics23::ProofSpec, root: &CommitmentRoot, - items: HashMap<&[u8], &[u8], G>, + items: HashMap<&[u8], &[u8]>, ) -> bool { // ugly attempt to conditionally decompress... let mut proof = proof; @@ -204,14 +206,18 @@ pub fn tendermint_spec() -> ics23::ProofSpec { #[cfg(test)] mod tests { + extern crate std as _std; use super::*; use anyhow::{bail, ensure}; use prost::Message; use serde::Deserialize; - use std::fs::File; - use std::io::prelude::*; + #[cfg(feature = "std")] + use _std::fs::File; + #[cfg(feature = "std")] + use _std::io::prelude::*; use std::vec::Vec; + use alloc::string::String; use crate::compress::compress; use crate::helpers::Result; @@ -230,6 +236,7 @@ mod tests { pub value: Option>, } + #[cfg(feature = "std")] fn load_file(filename: &str) -> Result<(ics23::CommitmentProof, RefData)> { let mut file = File::open(filename)?; let mut contents = String::new(); @@ -252,6 +259,7 @@ mod tests { Ok((parsed, data)) } + #[cfg(feature = "std")] fn verify_test_vector(filename: &str, spec: &ics23::ProofSpec) -> Result<()> { let (proof, data) = load_file(filename)?; @@ -267,77 +275,90 @@ mod tests { } #[test] + #[cfg(feature = "std")] fn test_vector_iavl_left() -> Result<()> { let spec = iavl_spec(); verify_test_vector("../testdata/iavl/exist_left.json", &spec) } #[test] + #[cfg(feature = "std")] fn test_vector_iavl_right() -> Result<()> { let spec = iavl_spec(); verify_test_vector("../testdata/iavl/exist_right.json", &spec) } #[test] + #[cfg(feature = "std")] fn test_vector_iavl_middle() -> Result<()> { let spec = iavl_spec(); verify_test_vector("../testdata/iavl/exist_middle.json", &spec) } #[test] + #[cfg(feature = "std")] fn test_vector_iavl_left_non() -> Result<()> { let spec = iavl_spec(); verify_test_vector("../testdata/iavl/nonexist_left.json", &spec) } #[test] + #[cfg(feature = "std")] fn test_vector_iavl_right_non() -> Result<()> { let spec = iavl_spec(); verify_test_vector("../testdata/iavl/nonexist_right.json", &spec) } #[test] + #[cfg(feature = "std")] fn test_vector_iavl_middle_non() -> Result<()> { let spec = iavl_spec(); verify_test_vector("../testdata/iavl/nonexist_middle.json", &spec) } #[test] + #[cfg(feature = "std")] fn test_vector_tendermint_left() -> Result<()> { let spec = tendermint_spec(); verify_test_vector("../testdata/tendermint/exist_left.json", &spec) } #[test] + #[cfg(feature = "std")] fn test_vector_tendermint_right() -> Result<()> { let spec = tendermint_spec(); verify_test_vector("../testdata/tendermint/exist_right.json", &spec) } #[test] + #[cfg(feature = "std")] fn test_vector_tendermint_middle() -> Result<()> { let spec = tendermint_spec(); verify_test_vector("../testdata/tendermint/exist_middle.json", &spec) } #[test] + #[cfg(feature = "std")] fn test_vector_tendermint_left_non() -> Result<()> { let spec = tendermint_spec(); verify_test_vector("../testdata/tendermint/nonexist_left.json", &spec) } #[test] + #[cfg(feature = "std")] fn test_vector_tendermint_right_non() -> Result<()> { let spec = tendermint_spec(); verify_test_vector("../testdata/tendermint/nonexist_right.json", &spec) } #[test] + #[cfg(feature = "std")] fn test_vector_tendermint_middle_non() -> Result<()> { let spec = tendermint_spec(); verify_test_vector("../testdata/tendermint/nonexist_middle.json", &spec) } + #[cfg(feature = "std")] fn load_batch(files: &[&str]) -> Result<(ics23::CommitmentProof, Vec)> { let mut entries = Vec::new(); let mut data = Vec::new(); @@ -393,6 +414,7 @@ mod tests { } #[test] + #[cfg(feature = "std")] fn test_vector_iavl_batch_exist() -> Result<()> { let spec = iavl_spec(); let (proof, data) = load_batch(&[ @@ -407,6 +429,7 @@ mod tests { } #[test] + #[cfg(feature = "std")] fn compressed_iavl_batch_exist() -> Result<()> { let spec = iavl_spec(); let (proof, data) = load_batch(&[ @@ -422,6 +445,7 @@ mod tests { } #[test] + #[cfg(feature = "std")] fn test_vector_iavl_batch_nonexist() -> Result<()> { let spec = iavl_spec(); let (proof, data) = load_batch(&[ @@ -436,6 +460,7 @@ mod tests { } #[test] + #[cfg(feature = "std")] fn compressed_iavl_batch_nonexist() -> Result<()> { let spec = iavl_spec(); let (proof, data) = load_batch(&[ @@ -451,6 +476,7 @@ mod tests { } #[test] + #[cfg(feature = "std")] fn test_vector_tendermint_batch_exist() -> Result<()> { let spec = tendermint_spec(); let (proof, data) = load_batch(&[ @@ -465,6 +491,7 @@ mod tests { } #[test] + #[cfg(feature = "std")] fn test_vector_tendermint_batch_nonexist() -> Result<()> { let spec = tendermint_spec(); let (proof, data) = load_batch(&[ diff --git a/rust/src/compress.rs b/rust/src/compress.rs index 76e6836e..26e6d27d 100644 --- a/rust/src/compress.rs +++ b/rust/src/compress.rs @@ -1,6 +1,7 @@ use prost::Message; -use std::collections::HashMap; +use std::collections::btree_map::BTreeMap as HashMap; use std::vec::Vec; +use std::borrow::ToOwned; use crate::helpers::Result; use crate::ics23; @@ -86,7 +87,9 @@ pub fn compress_exist( .iter() .map(|x| { let mut buf = Vec::new(); - x.encode(&mut buf)?; + x.encode(&mut buf).map_err(|e : prost::EncodeError | { + anyhow::anyhow!(e) + })?; if let Some(&idx) = registry.get(buf.as_slice()) { return Ok(idx); diff --git a/rust/src/ics23.rs b/rust/src/ics23.rs index dd75e80b..d32a229e 100644 --- a/rust/src/ics23.rs +++ b/rust/src/ics23.rs @@ -21,13 +21,13 @@ #[derive(Clone, PartialEq, ::prost::Message)] pub struct ExistenceProof { #[prost(bytes, tag = "1")] - pub key: std::vec::Vec, + pub key: alloc::vec::Vec, #[prost(bytes, tag = "2")] - pub value: std::vec::Vec, + pub value: alloc::vec::Vec, #[prost(message, optional, tag = "3")] - pub leaf: ::std::option::Option, + pub leaf: ::core::option::Option, #[prost(message, repeated, tag = "4")] - pub path: ::std::vec::Vec, + pub path: ::alloc::vec::Vec, } /// ///NonExistenceProof takes a proof of two neighbors, one left of the desired key, @@ -37,18 +37,18 @@ pub struct ExistenceProof { pub struct NonExistenceProof { /// TODO: remove this as unnecessary??? we prove a range #[prost(bytes, tag = "1")] - pub key: std::vec::Vec, + pub key: alloc::vec::Vec, #[prost(message, optional, tag = "2")] - pub left: ::std::option::Option, + pub left: ::core::option::Option, #[prost(message, optional, tag = "3")] - pub right: ::std::option::Option, + pub right: ::core::option::Option, } /// ///CommitmentProof is either an ExistenceProof or a NonExistenceProof, or a Batch of such messages #[derive(Clone, PartialEq, ::prost::Message)] pub struct CommitmentProof { #[prost(oneof = "commitment_proof::Proof", tags = "1, 2, 3, 4")] - pub proof: ::std::option::Option, + pub proof: ::core::option::Option, } pub mod commitment_proof { #[derive(Clone, PartialEq, ::prost::Oneof)] @@ -91,7 +91,7 @@ pub struct LeafOp { /// prefix is a fixed bytes that may optionally be included at the beginning to differentiate /// a leaf node from an inner node. #[prost(bytes, tag = "5")] - pub prefix: std::vec::Vec, + pub prefix: alloc::vec::Vec, } ///* ///InnerOp represents a merkle-proof step that is not a leaf. @@ -114,9 +114,9 @@ pub struct InnerOp { #[prost(enumeration = "HashOp", tag = "1")] pub hash: i32, #[prost(bytes, tag = "2")] - pub prefix: std::vec::Vec, + pub prefix: alloc::vec::Vec, #[prost(bytes, tag = "3")] - pub suffix: std::vec::Vec, + pub suffix: alloc::vec::Vec, } ///* ///ProofSpec defines what the expected parameters are for a given proof type. @@ -134,9 +134,9 @@ pub struct ProofSpec { /// any field in the ExistenceProof must be the same as in this spec. /// except Prefix, which is just the first bytes of prefix (spec can be longer) #[prost(message, optional, tag = "1")] - pub leaf_spec: ::std::option::Option, + pub leaf_spec: ::core::option::Option, #[prost(message, optional, tag = "2")] - pub inner_spec: ::std::option::Option, + pub inner_spec: ::core::option::Option, /// max_depth (if > 0) is the maximum number of InnerOps allowed (mainly for fixed-depth tries) #[prost(int32, tag = "3")] pub max_depth: i32, @@ -159,7 +159,7 @@ pub struct InnerSpec { /// iavl tree is [0, 1] (left then right) /// merk is [0, 2, 1] (left, right, here) #[prost(int32, repeated, tag = "1")] - pub child_order: ::std::vec::Vec, + pub child_order: ::alloc::vec::Vec, #[prost(int32, tag = "2")] pub child_size: i32, #[prost(int32, tag = "3")] @@ -168,7 +168,7 @@ pub struct InnerSpec { pub max_prefix_length: i32, /// empty child is the prehash image that is used when one child is nil (eg. 20 bytes of 0) #[prost(bytes, tag = "5")] - pub empty_child: std::vec::Vec, + pub empty_child: alloc::vec::Vec, /// hash is the algorithm that must be used for each InnerOp #[prost(enumeration = "HashOp", tag = "6")] pub hash: i32, @@ -178,13 +178,13 @@ pub struct InnerSpec { #[derive(Clone, PartialEq, ::prost::Message)] pub struct BatchProof { #[prost(message, repeated, tag = "1")] - pub entries: ::std::vec::Vec, + pub entries: ::alloc::vec::Vec, } /// Use BatchEntry not CommitmentProof, to avoid recursion #[derive(Clone, PartialEq, ::prost::Message)] pub struct BatchEntry { #[prost(oneof = "batch_entry::Proof", tags = "1, 2")] - pub proof: ::std::option::Option, + pub proof: ::core::option::Option, } pub mod batch_entry { #[derive(Clone, PartialEq, ::prost::Oneof)] @@ -200,15 +200,15 @@ pub mod batch_entry { #[derive(Clone, PartialEq, ::prost::Message)] pub struct CompressedBatchProof { #[prost(message, repeated, tag = "1")] - pub entries: ::std::vec::Vec, + pub entries: ::alloc::vec::Vec, #[prost(message, repeated, tag = "2")] - pub lookup_inners: ::std::vec::Vec, + pub lookup_inners: ::alloc::vec::Vec, } /// Use BatchEntry not CommitmentProof, to avoid recursion #[derive(Clone, PartialEq, ::prost::Message)] pub struct CompressedBatchEntry { #[prost(oneof = "compressed_batch_entry::Proof", tags = "1, 2")] - pub proof: ::std::option::Option, + pub proof: ::core::option::Option, } pub mod compressed_batch_entry { #[derive(Clone, PartialEq, ::prost::Oneof)] @@ -222,24 +222,24 @@ pub mod compressed_batch_entry { #[derive(Clone, PartialEq, ::prost::Message)] pub struct CompressedExistenceProof { #[prost(bytes, tag = "1")] - pub key: std::vec::Vec, + pub key: alloc::vec::Vec, #[prost(bytes, tag = "2")] - pub value: std::vec::Vec, + pub value: alloc::vec::Vec, #[prost(message, optional, tag = "3")] - pub leaf: ::std::option::Option, + pub leaf: ::core::option::Option, /// these are indexes into the lookup_inners table in CompressedBatchProof #[prost(int32, repeated, tag = "4")] - pub path: ::std::vec::Vec, + pub path: ::alloc::vec::Vec, } #[derive(Clone, PartialEq, ::prost::Message)] pub struct CompressedNonExistenceProof { /// TODO: remove this as unnecessary??? we prove a range #[prost(bytes, tag = "1")] - pub key: std::vec::Vec, + pub key: alloc::vec::Vec, #[prost(message, optional, tag = "2")] - pub left: ::std::option::Option, + pub left: ::core::option::Option, #[prost(message, optional, tag = "3")] - pub right: ::std::option::Option, + pub right: ::core::option::Option, } #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] #[repr(i32)] diff --git a/rust/src/lib.rs b/rust/src/lib.rs index ee11e1ec..3ab9e4bd 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -1,3 +1,11 @@ +#![cfg_attr(not(feature = "std"), no_std)] +#![allow(dead_code)] +#![allow(unused_imports)] + +extern crate alloc; +extern crate core; +extern crate sp_std as std; + mod api; mod compress; mod helpers; diff --git a/rust/src/ops.rs b/rust/src/ops.rs index 40381394..28fa16c6 100644 --- a/rust/src/ops.rs +++ b/rust/src/ops.rs @@ -3,6 +3,8 @@ use ripemd160::Ripemd160; use sha2::{Digest, Sha256, Sha512, Sha512Trunc256}; use sha3::Sha3_512; use std::convert::TryInto; +use alloc::format; + use crate::helpers::{Hash, Result}; use crate::ics23::{HashOp, InnerOp, LeafOp, LengthOp}; @@ -76,6 +78,8 @@ fn proto_len(length: usize) -> Result { #[cfg(test)] mod tests { use super::*; + use std::vec::Vec; + use std::prelude::*; fn decode(input: &str) -> Vec { hex::decode(input).unwrap() diff --git a/rust/src/verify.rs b/rust/src/verify.rs index c1d6677d..2e0dbe87 100644 --- a/rust/src/verify.rs +++ b/rust/src/verify.rs @@ -6,6 +6,8 @@ use anyhow::{bail, ensure}; use crate::helpers::Result; use crate::ics23; use crate::ops::{apply_inner, apply_leaf}; +use std::vec::Vec; +use alloc::format; pub type CommitmentRoot = ::std::vec::Vec; @@ -261,7 +263,9 @@ mod tests { use super::*; use crate::api; use crate::ics23::{ExistenceProof, HashOp, InnerOp, LeafOp, LengthOp, ProofSpec}; - use std::collections::HashMap; + use std::collections::btree_map::BTreeMap as HashMap; + use std::prelude::*; + #[test] fn calculate_root_from_leaf() {