Skip to content
Open
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
22 changes: 22 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,28 @@ jobs:
- name: make - build-wasm
run: make build-wasm

build-no-std:
name: Build bare metal (no_std)
runs-on: warp-ubuntu-latest-x64-8x
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
with:
persist-credentials: false
- name: Cleanup large tools for build space
uses: ./.github/actions/cleanup-runner
- name: Install Rust toolchain
run: |
rustup update --no-self-update
rustup target add thumbv7em-none-eabihf
- name: Add Rust Cache
uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1
with:
shared-key: rust-release
prefix-key: ${{ env.RUST_CACHE_KEY }}
save-if: false
- name: make - build-no-std
run: make build-no-std

install:
name: Install ${{ matrix.target }}
runs-on: ubuntu-latest
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

### Fixes

* [FIX][rust] `miden-client` no longer pulls the `tonic` runtime into builds without the `tonic` or `std` features, restoring support for bare-metal `no_std` targets.
* [FIX][rust] Added validation of cached transaction encryption keys during deserialization. Unsupported encryption schemes and empty or oversized key IDs are rejected before reading the key ID bytes ([#2411](https://github.com/0xMiden/rust-sdk/pull/2411)).
* [FIX][cli] `miden-client import` now rejects invocations without a file path instead of silently succeeding ([#2450](https://github.com/0xMiden/rust-sdk/pull/2450)).
* [FIX][rust] `TransactionRequestBuilder::build_swap` and `build_pswap_create` now reject a zero-amount asset on either side of the exchange. A zero requested asset produced a payback P2ID note carrying nothing, and a zero offered asset produced a note whose consumer pays and receives nothing ([#2459](https://github.com/0xMiden/rust-sdk/pull/2459)).
Expand Down
1 change: 0 additions & 1 deletion Cargo.lock

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

4 changes: 4 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,10 @@ build: ## Build the CLI binary, client library and tests binary in release mode
build-wasm: ## Build the client library for wasm32 with no_std (no default features)
cargo build --package miden-client --target wasm32-unknown-unknown --no-default-features --locked

.PHONY: build-no-std
build-no-std: ## Build the client library for a bare-metal no_std target
cargo build --package miden-client --target thumbv7em-none-eabihf --no-default-features --locked

# --- Check ---------------------------------------------------------------------------------------

.PHONY: check
Expand Down
36 changes: 24 additions & 12 deletions crates/rust-client/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -52,16 +52,24 @@ dap = ["dep:miden-debug", "std"]
default = ["std"]
std = [
"concurrent",
"dep:chrono",
"dep:tempfile",
"dep:tokio",
"dep:tonic-prost",
"futures/std",
"hex/std",
"miden-agglayer/std",
"miden-assembly-syntax/std",
"miden-processor/std",
"miden-protocol/std",
"miden-tx/std",
"rand/std",
"rand/thread_rng",
"serde/std",
"tonic/tls-native-roots",
"tonic/tls-ring",
"tonic/transport",
"tracing/std",
]
testing = [
"dep:miden-testing",
Expand All @@ -71,7 +79,12 @@ testing = [
"miden-standards/testing",
"miden-tx/testing",
]
tonic = []
tonic = [
"dep:tonic",
"dep:tonic-health",
"dep:tonic-prost",
"dep:tonic-web-wasm-client",
]

[dependencies]
# Miden dependencies
Expand All @@ -88,28 +101,27 @@ miden-tx-batch = { workspace = true }
# External dependencies
anyhow = { workspace = true }
async-trait = { workspace = true }
chrono = { workspace = true }
futures = { version = "0.3" }
hex = { workspace = true }
chrono = { optional = true, workspace = true }
futures = { default-features = false, features = ["alloc", "async-await"], version = "0.3" }
hex = { default-features = false, features = ["alloc"], workspace = true }
prost = { features = ["derive"], workspace = true }
prost-types = { version = "0.14" }
rand = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true }
rand = { default-features = false, workspace = true }
serde = { default-features = false, features = ["derive"], workspace = true }
tempfile = { optional = true, workspace = true }
thiserror = { workspace = true }
tokio = { features = ["sync", "time"], optional = true, workspace = true }
tonic = { features = ["codegen"], workspace = true }
tonic-health = { version = "0.14" }
tonic-prost = { version = "0.14" }
tracing = { workspace = true }
tonic = { features = ["codegen"], optional = true, workspace = true }
tonic-health = { optional = true, version = "0.14" }
tonic-prost = { optional = true, version = "0.14" }
tracing = { default-features = false, workspace = true }
uuid = { features = ["js", "serde", "v4"], optional = true, workspace = true }

[target.'cfg(target_arch = "wasm32")'.dependencies]
getrandom = { features = ["wasm_js"], version = "0.3" }
gloo-timers = { features = ["futures"], version = "0.3" }
tokio = { default-features = false, features = ["sync"], version = "1.48" }
tonic-web-wasm-client = { default-features = false, version = "0.9" }
tonic-web-wasm-client = { default-features = false, optional = true, version = "0.9" }

[build-dependencies]
miden-node-proto-build = { workspace = true }
Expand Down
8 changes: 8 additions & 0 deletions crates/rust-client/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,11 @@ fn main() -> miette::Result<()> {
Ok(())
}

/// Whether transport-capable client bindings are needed for a no-std build.
fn tonic_feature_enabled() -> bool {
std::env::var_os("CARGO_FEATURE_TONIC").is_some()
}

// REMOTE PROVER CLIENT PROTO CODEGEN
// ===============================================================================================

Expand All @@ -61,6 +66,7 @@ fn compile_tonic_remote_prover_proto(out_dir: &Path) -> miette::Result<()> {
// The `nostd` bindings target `wasm32`, where the transport is provided by
// `tonic-web-wasm-client`, so tonic's own transport codegen must be disabled.
tonic_prost_build::configure()
.build_client(tonic_feature_enabled())
.build_transport(false)
.build_server(false)
.out_dir(&nostd_out)
Expand Down Expand Up @@ -98,6 +104,7 @@ fn compile_tonic_note_transport_proto(out_dir: &Path) -> miette::Result<()> {

// Generate the header of the user facing server from its proto file
tonic_prost_build::configure()
.build_client(tonic_feature_enabled())
.build_transport(false)
.build_server(false)
.out_dir(&nostd_out)
Expand Down Expand Up @@ -136,6 +143,7 @@ fn compile_tonic_client_proto(out_dir: &Path) -> miette::Result<()> {

// Generate the header of the user facing server from its proto file
tonic_prost_build::configure()
.build_client(tonic_feature_enabled())
.build_transport(false)
.build_server(false)
.out_dir(&nostd_out)
Expand Down
14 changes: 11 additions & 3 deletions crates/rust-client/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -474,9 +474,17 @@ where
let rng = if let Some(user_rng) = self.rng {
user_rng
} else {
let mut seed_rng = rand::rng();
let coin_seed: [u64; 4] = seed_rng.random();
Box::new(RandomCoin::new(coin_seed.map(Felt::new_unchecked).into()))
#[cfg(not(feature = "std"))]
return Err(ClientError::ClientInitializationError(
"RNG is required in no_std builds. Call `.rng(...)`.".into(),
));

#[cfg(feature = "std")]
{
let mut seed_rng = rand::rng();
let coin_seed: [u64; 4] = seed_rng.random();
Box::new(RandomCoin::new(coin_seed.map(Felt::new_unchecked).into()))
}
};

let tx_prover: Arc<dyn TransactionProver + Send + Sync> =
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use alloc::string::ToString;
use alloc::string::{String, ToString};
use core::fmt::{self, Display};

#[cfg(feature = "std")]
use chrono::{Local, TimeZone};
use miden_protocol::account::AccountId;
use miden_protocol::block::{BlockHeader, BlockNumber};
Expand Down Expand Up @@ -308,17 +309,7 @@ impl Display for InputNoteState {
write!(
f,
"Processing (submitted at {} by account {})",
submission_data.submitted_at.map_or("?".to_string(), |submitted_at| {
Local
.timestamp_opt(
i64::try_from(submitted_at)
.expect("i64::MAX as timestamp is year 2262"),
0,
)
.single()
.expect("timestamp should be valid")
.to_string()
}),
submission_data.submitted_at.map_or("?".to_string(), format_timestamp),
submission_data.consumer_account
)
},
Expand Down Expand Up @@ -355,6 +346,23 @@ impl Display for InputNoteState {
}
}

#[cfg(feature = "std")]
fn format_timestamp(timestamp: u64) -> String {
Local
.timestamp_opt(
i64::try_from(timestamp).expect("i64::MAX as timestamp is year 2262"),
0,
)
.single()
.expect("timestamp should be valid")
.to_string()
}

#[cfg(not(feature = "std"))]
fn format_timestamp(timestamp: u64) -> String {
timestamp.to_string()
}

pub trait NoteStateHandler {
fn metadata(&self) -> Option<&NoteMetadata>;

Expand Down