diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fbb3f7e4c..17dc69b37 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -72,6 +72,8 @@ jobs: args: --target wasm32-unknown-unknown -p fuel-asm --features typescript --crate-type=cdylib - command: check args: --target wasm32-unknown-unknown -p fuel-types --features serde --no-default-features + - command: check + args: --target wasm32-unknown-unknown -p fuel-vm --features alloc --no-default-features - command: bench args: --workspace --no-run - command: make @@ -95,7 +97,7 @@ jobs: - uses: dtolnay/rust-toolchain@master with: toolchain: ${{ env.RUST_VERSION }} - targets: "thumbv6m-none-eabi,wasm32-unknown-unknown" + targets: "thumbv6m-none-eabi,riscv32imac-unknown-none-elf,wasm32-unknown-unknown" components: "clippy" - name: Install Cargo Make uses: davidB/rust-cargo-make@v1 diff --git a/CHANGELOG.md b/CHANGELOG.md index 5c9eb51df..366ed0b7f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +#### Breaking + +- [#578](https://github.com/FuelLabs/fuel-vm/pull/578): Support `no_std` environments for `fuel-crypto`, falling back to a pure-Rust crypto implementation. +- [#582](https://github.com/FuelLabs/fuel-vm/pull/582): Make `fuel-vm` and `fuel-tx` crates compatible with `no_std` + `alloc`. This includes reworking all error handling that used `std::io::Error`, replacing some `std::collection::{HashMap, HashSet}` with `hashbrown::{HashMap, HashSet}` and many changes to feature-gating of APIs. ### Added - [#586](https://github.com/FuelLabs/fuel-vm/pull/586): Added `default_asset` method to the `ContractIdExt` trait implementation, to mirror the `default` method on AssetId in the Sway std lib. @@ -20,7 +24,6 @@ and this project adheres to [Semantic Versioning](http://semver.org/). These opcodes charged inadequately low costs in comparison to the amount of work. This change should make all transactions that used these opcodes much more expensive than before. - [#533](https://github.com/FuelLabs/fuel-vm/pull/533): Use custom serialization for fuel-types to allow no_std compilation. -- [#578](https://github.com/FuelLabs/fuel-vm/pull/578): Support `no_std` environments for `fuel-crypto`, falling back to a pure-Rust crypto implementation. ## [Version 0.36.1] diff --git a/ci_checks.sh b/ci_checks.sh index 8388f9a41..28fd76beb 100755 --- a/ci_checks.sh +++ b/ci_checks.sh @@ -26,6 +26,7 @@ cargo check --target thumbv6m-none-eabi -p fuel-asm -p fuel-storage -p fuel-merk cargo check --target wasm32-unknown-unknown -p fuel-crypto --no-default-features && cargo check --target wasm32-unknown-unknown -p fuel-types --features serde --no-default-features && cargo check --target wasm32-unknown-unknown -p fuel-tx --features serde --no-default-features && +cargo check --target wasm32-unknown-unknown -p fuel-vm --features alloc --no-default-features && cargo rustc --target wasm32-unknown-unknown -p fuel-types --features typescript --crate-type=cdylib && cargo rustc --target wasm32-unknown-unknown -p fuel-asm --features typescript --crate-type=cdylib && cargo make check && diff --git a/fuel-asm/Cargo.toml b/fuel-asm/Cargo.toml index 4f41c4021..bbce2ba88 100644 --- a/fuel-asm/Cargo.toml +++ b/fuel-asm/Cargo.toml @@ -27,7 +27,8 @@ rstest = "0.16" [features] default = ["std"] typescript = ["wasm-bindgen", "wee_alloc"] -std = ["serde?/default", "fuel-types/std"] +std = ["alloc", "serde?/default", "fuel-types/std"] +alloc = ["fuel-asm/alloc"] serde = ["dep:serde"] # docs.rs-specific configuration diff --git a/fuel-asm/src/encoding_tests.rs b/fuel-asm/src/encoding_tests.rs index 01bd7c731..ae0b3bc9b 100644 --- a/fuel-asm/src/encoding_tests.rs +++ b/fuel-asm/src/encoding_tests.rs @@ -5,6 +5,7 @@ use fuel_asm as _; use strum::IntoEnumIterator; #[test] +#[cfg(test)] fn opcode() { // values picked to test edge cases let r = RegId::new_checked(0x2d).unwrap(); diff --git a/fuel-asm/src/lib.rs b/fuel-asm/src/lib.rs index eecdda888..d912e37dc 100644 --- a/fuel-asm/src/lib.rs +++ b/fuel-asm/src/lib.rs @@ -8,11 +8,14 @@ #![deny(unsafe_code)] #![deny(unused_crate_dependencies)] +#[cfg(feature = "alloc")] +extern crate alloc; + #[cfg(feature = "wee_alloc")] use wee_alloc as _; -#[cfg(all(no_std, feature = "wee_alloc"))] // Use `wee_alloc` as the global allocator. +#[cfg(all(no_std, feature = "wee_alloc"))] #[global_allocator] static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT; @@ -877,15 +880,15 @@ where // Collect instructions into bytes or halfwords -#[cfg(feature = "std")] -impl core::iter::FromIterator for Vec { +#[cfg(feature = "alloc")] +impl core::iter::FromIterator for alloc::vec::Vec { fn from_iter>(iter: I) -> Self { iter.into_iter().flat_map(Instruction::to_bytes).collect() } } -#[cfg(feature = "std")] -impl core::iter::FromIterator for Vec { +#[cfg(feature = "alloc")] +impl core::iter::FromIterator for alloc::vec::Vec { fn from_iter>(iter: I) -> Self { iter.into_iter().map(u32::from).collect() } diff --git a/fuel-asm/src/panic_reason.rs b/fuel-asm/src/panic_reason.rs index db00f9278..37763fd8b 100644 --- a/fuel-asm/src/panic_reason.rs +++ b/fuel-asm/src/panic_reason.rs @@ -120,22 +120,6 @@ impl fmt::Display for PanicReason { } } -#[cfg(feature = "std")] -impl std::error::Error for PanicReason { - fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { - None - } -} - -#[cfg(feature = "std")] -impl From for std::io::Error { - fn from(reason: PanicReason) -> Self { - use std::io; - - io::Error::new(io::ErrorKind::Other, reason) - } -} - impl From for PanicReason { fn from(_: core::array::TryFromSliceError) -> Self { Self::MemoryOverflow diff --git a/fuel-crypto/src/lib.rs b/fuel-crypto/src/lib.rs index d9bad6a5e..fef28e025 100644 --- a/fuel-crypto/src/lib.rs +++ b/fuel-crypto/src/lib.rs @@ -9,8 +9,8 @@ #![deny(unsafe_code)] #![deny(unused_crate_dependencies)] -#[cfg(test)] // Satisfy unused_crate_dependencies lint for self-dependency enabling test features +#[cfg(test)] use fuel_crypto as _; /// Required export for using mnemonic keygen on [`SecretKey::new_from_mnemonic`] diff --git a/fuel-crypto/src/secp256/backend/r1/p256.rs b/fuel-crypto/src/secp256/backend/r1/p256.rs index cb0cc177a..bb9a6aab3 100644 --- a/fuel-crypto/src/secp256/backend/r1/p256.rs +++ b/fuel-crypto/src/secp256/backend/r1/p256.rs @@ -57,6 +57,7 @@ pub fn sign_prehashed( /// Convert the public key point to its uncompressed non-prefixed representation, /// i.e. 32 bytes of x coordinate and 32 bytes of y coordinate. +#[cfg(feature = "test-helpers")] pub fn encode_pubkey(key: VerifyingKey) -> [u8; 64] { let point = key.to_encoded_point(false); let mut result = [0u8; 64]; diff --git a/fuel-merkle/benches/smt.rs b/fuel-merkle/benches/smt.rs index 5e221115f..d66cf272b 100644 --- a/fuel-merkle/benches/smt.rs +++ b/fuel-merkle/benches/smt.rs @@ -70,7 +70,7 @@ fn sparse_merkle_tree(c: &mut Criterion) { let rng = &mut StdRng::seed_from_u64(8586); let gen = || Some((MerkleTreeKey::new(random_bytes32(rng)), random_bytes32(rng))); - let data = std::iter::from_fn(gen).take(50_000).collect::>(); + let data = core::iter::from_fn(gen).take(50_000).collect::>(); let expected_root = baseline_root(data.clone().into_iter()); let root = subject_root(data.clone().into_iter()); diff --git a/fuel-tx/Cargo.toml b/fuel-tx/Cargo.toml index b3644e488..a1162a540 100644 --- a/fuel-tx/Cargo.toml +++ b/fuel-tx/Cargo.toml @@ -16,14 +16,16 @@ fuel-asm = { workspace = true, default-features = false } fuel-crypto = { workspace = true, default-features = false } fuel-merkle = { workspace = true, default-features = false, optional = true } fuel-types = { workspace = true, default-features = false } +hashbrown = { version = "0.14", optional = true } itertools = { version = "0.10", default-features = false, optional = true } num-integer = { version = "0.1", default-features = false, optional = true } -num_enum = { version = "0.7", optional = true } +num_enum = { version = "0.7", default-features = false, optional = true } rand = { version = "0.8", default-features = false, features = ["std_rng"], optional = true } serde = { version = "1.0", default-features = false, features = ["alloc", "derive"], optional = true } serde_json = { version = "1.0", default-features = false, features = ["alloc"], optional = true } -strum = { version = "0.24", optional = true } +strum = { version = "0.24", default-features = false, optional = true } strum_macros = { version = "0.24", optional = true } +thiserror = { version = "1.0", optional = true } [dev-dependencies] bincode = { workspace = true } @@ -31,7 +33,7 @@ fuel-crypto = { workspace = true, default-features = false, features = ["random" fuel-tx = { path = ".", features = ["builder", "random"] } fuel-tx-test-helpers = { path = "test-helpers" } fuel-types = { workspace = true, default-features = false, features = ["random"] } -hex = { version = "0.4" } +hex = { version = "0.4", default-features = false } insta = "1.0" quickcheck = "1.0" quickcheck_macros = "1.0" @@ -40,10 +42,10 @@ rstest = "0.15" [features] default = ["fuel-asm/default", "fuel-crypto/default", "fuel-merkle/default", "fuel-types/default", "std"] -alloc = ["fuel-types/alloc", "itertools/use_alloc", "derivative", "fuel-merkle", "num_enum", "num-integer", "strum", "strum_macros"] builder = ["alloc", "internals"] internals = [] random = ["fuel-crypto/random", "fuel-types/random", "rand"] -std = ["alloc", "fuel-asm/std", "fuel-crypto/std", "fuel-merkle/std", "fuel-types/std", "itertools/default", "rand?/default", "serde?/default"] +std = ["alloc", "dep:thiserror", "fuel-asm/std", "fuel-crypto/std", "fuel-merkle/std", "fuel-types/std", "itertools/default", "rand?/default", "serde?/default", "hex/std"] +alloc = ["hashbrown", "fuel-types/alloc", "itertools/use_alloc", "derivative", "fuel-merkle", "num_enum", "num-integer", "strum", "strum_macros"] # serde is requiring alloc because its mandatory for serde_json. to avoid adding a new feature only for serde_json, we just require `alloc` here since as of the moment we don't have a use case of serde without alloc. -serde = ["alloc", "dep:serde", "fuel-asm/serde", "fuel-crypto/serde", "fuel-types/serde", "serde_json"] +serde = ["alloc", "dep:serde", "fuel-asm/serde", "fuel-crypto/serde", "fuel-types/serde", "serde_json", "hashbrown/serde"] diff --git a/fuel-tx/src/builder.rs b/fuel-tx/src/builder.rs index 002e3c562..5b97b6a1f 100644 --- a/fuel-tx/src/builder.rs +++ b/fuel-tx/src/builder.rs @@ -11,7 +11,6 @@ use crate::{ Executable, Script, }, - Cacheable, ConsensusParameters, ContractParameters, FeeParameters, @@ -28,8 +27,10 @@ use crate::{ Witness, }; -#[cfg(feature = "std")] -use crate::Signable; +use crate::{ + Cacheable, + Signable, +}; use fuel_crypto::SecretKey; use fuel_types::{ @@ -59,13 +60,8 @@ where { } -#[cfg(feature = "std")] pub trait BuildableStd: Signable + Cacheable {} -#[cfg(not(feature = "std"))] -pub trait BuildableSet: BuildableAloc {} - -#[cfg(feature = "std")] pub trait BuildableSet: BuildableAloc + BuildableStd {} pub trait Buildable @@ -110,12 +106,8 @@ impl BuildableAloc for T where { } -#[cfg(feature = "std")] impl BuildableStd for T where T: Signable + Cacheable {} -#[cfg(feature = "std")] impl BuildableSet for T where T: BuildableAloc + BuildableStd {} -#[cfg(not(feature = "std"))] -impl BuildableSet for T where T: BuildableAloc {} impl Buildable for T where T: BuildableSet {} #[derive(Debug, Clone)] @@ -326,7 +318,6 @@ impl TransactionBuilder { self } - #[cfg(feature = "std")] pub fn add_unsigned_coin_input( &mut self, secret: SecretKey, @@ -353,7 +344,7 @@ impl TransactionBuilder { self } - #[cfg(all(feature = "rand", feature = "std"))] + #[cfg(feature = "rand")] pub fn add_random_fee_input(&mut self) -> &mut Self { use rand::{ Rng, @@ -370,7 +361,6 @@ impl TransactionBuilder { ) } - #[cfg(feature = "std")] pub fn add_unsigned_message_input( &mut self, secret: SecretKey, @@ -421,7 +411,6 @@ impl TransactionBuilder { } /// Adds a secret to the builder, and adds a corresponding witness if it's a new entry - #[cfg(feature = "std")] fn upsert_secret(&mut self, secret_key: SecretKey) -> u8 { let witness_len = self.witnesses().len() as u8; @@ -434,7 +423,6 @@ impl TransactionBuilder { *witness_index } - #[cfg(feature = "std")] fn prepare_finalize(&mut self) { if self.should_prepare_predicate { self.tx.prepare_init_predicate(); @@ -445,7 +433,6 @@ impl TransactionBuilder { } } - #[cfg(feature = "std")] fn finalize_inner(&mut self) -> Tx { self.prepare_finalize(); @@ -461,7 +448,6 @@ impl TransactionBuilder { tx } - #[cfg(feature = "std")] pub fn finalize_without_signature_inner(&mut self) -> Tx { self.prepare_finalize(); @@ -487,7 +473,6 @@ pub trait Finalizable { fn finalize_without_signature(&mut self) -> Tx; } -#[cfg(feature = "std")] impl Finalizable for TransactionBuilder { fn finalize(&mut self) -> Mint { let mut tx = core::mem::take(&mut self.tx); @@ -501,7 +486,6 @@ impl Finalizable for TransactionBuilder { } } -#[cfg(feature = "std")] impl Finalizable for TransactionBuilder { fn finalize(&mut self) -> Create { self.finalize_inner() @@ -512,7 +496,6 @@ impl Finalizable for TransactionBuilder { } } -#[cfg(feature = "std")] impl Finalizable