Skip to content

Commit 01573cd

Browse files
authored
feat(fuzz): add cargo-fuzz harnesses for contract entry-points (#351)
* feat(fuzz): add cargo-fuzz harnesses for all contract entry-points Add cargo-fuzz fuzz/ directories for vault, looping, and rewards contracts: vault/fuzz/fuzz_targets/: - fuzz_vault_deposit.rs — arbitrary (amount) inputs; asserts positive amounts succeed and balance is correct; non-positive may panic. - fuzz_vault_withdraw.rs — arbitrary (initial_deposit, withdraw_amount); asserts balance never goes negative. looping/fuzz/fuzz_targets/: - fuzz_looping_open_position.rs — arbitrary (collateral, leverage); asserts valid inputs return monotonically-increasing position IDs. rewards/fuzz/fuzz_targets/: - fuzz_rewards_accrue_claim.rs — arbitrary (accrual_a, accrual_b); asserts pending == sum of accruals, claim returns full pending, resets to 0. Each fuzz/ directory includes: - Cargo.toml with cargo-fuzz metadata and correct path dependencies - fuzz_targets/*.rs harness files - corpus/ seed inputs for fast initial coverage Add .github/workflows/soroban_fuzz.yml: - Smoke-fuzz loop: 60 s per entry-point on push/PR to main - Nightly Rust toolchain (required by libfuzzer-sys) - Crash corpus auto-uploaded as workflow artifact on failure - workflow_dispatch with configurable fuzz_time for longer runs Closes #249 * fix(fuzz): fix CI failures in fuzz workflow and harnesses - Remove --locked from cargo-fuzz install to allow dependency resolution with the runner's nightly toolchain (cargo-fuzz 0.13.2 with --locked fails to compile on nightly-2025-06-01) - Use dtolnay/rust-toolchain@nightly (latest) instead of pinned date - Narrow soroban_fuzz.yml path trigger to fuzz/** only so it does not fire on every contract change - Rewrite all fuzz harnesses to use env.try_invoke_contract / invoke_contract directly instead of generated client types (VaultContractClient etc.), which are only available when soroban-sdk testutils compiles the parent crate — avoids the soroban-env-host v22.1.3 testutils compile bug - Add corpus directory path fix in upload-artifact steps * fix(fuzz): declare fuzz targets, allow rlib for crates, fix symbol bindings - Add [[bin]] entries to vault/looping/rewards fuzz Cargo.tomls so cargo-fuzz can locate the targets (fixes the manifest-parse CI failure). - Change contract crate-type from ["cdylib"] to ["rlib", "cdylib"] so the fuzz crate can `use vault::VaultContract` (and looping/rewards) directly. - Use Symbol::new(&env, "open_position") and Symbol::new(&env, "pending_rewards") in the looping/rewards fuzz harnesses; the previous symbol_short! bindings either pointed at a non-existent function (open_pos vs open_position) or exceeded the 9-char limit (pending_re -> compile-time panic from symbol_short!). - Pin rand_core <= 0.6 in the fuzz crates, with a comment explaining the testutils / rand_core 0.6 vs 0.10 mismatch in soroban-env-host 22.1.3. * ci(fuzz): pin rand_core to 0.6.4 in cargo-fuzz jobs soroban-env-host 22.1.3 testutils.rs calls ed25519_dalek::SigningKey::generate(&mut ChaCha20Rng) which transitively forces the crate graph to unify on the rand_core 0.6 family. Without this pin, a transitive dep can resolve to a newer rand_core major (0.7+) and the trait bound ChaCha20Rng: ed25519_dalek::rand_core::CryptoRng stops being satisfied, breaking every fuzz target. Add a step between `Install cargo-fuzz` and `Run fuzz target` that runs `cargo update -p rand_core --precise 0.6.4` so the dep tree unifies on rand_core 0.6.x regardless of what other transitive deps want. Only affects the host-target fuzz builds; checked that adding fuzz crates as workspace members would regress the wasm32 build (libfuzzer-sys is host-only). * ci(fuzz): disambiguate pin; lock ed25519-dalek to 2.1.1 The previous `cargo update -p rand_core --precise 0.6.4` step failed because three rand_core majors co-exist in the fuzz dep tree (0.6.4, 0.9.5, 0.10.1) and cargo refuses an ambiguous spec. Root cause: ed25519-dalek 3.0.0 is in the tree via soroban-env-host 22.1.3. Its dep chain ed25519-dalek 3.0.0 -> curve25519-dalek 5.0.0 -> digest 0.11.3 -> crypto-common 0.2.2 -> rand_core 0.10.1 is what pulls rand_core 0.10.1, breaking ChaCha20Rng: ed25519_dalek::rand_core::CryptoRng in testutils.rs because ChaCha20Rng (from rand_chacha 0.3.1) implements the rand_core 0.6 CryptoRng, not 0.10. Fix: pin `ed25519-dalek@3.0.0` to `2.1.1` exactly, satisfying soroban-env-host 22.1.3's >=2.0 constraint. The chain collapses because ed25519-dalek 2.1.1 uses curve25519-dalek 4.x (rand_core 0.6). Two further `cargo update` invocations are chained with `|| true` as fallback safety nets for any residual rand_core majors that cargo allows us to demote directly. Cargo is invoked from the fuzz crate directory (quantara/soroban/contracts/{vault,looping,rewards}/fuzz/) thanks to the job-level `defaults.run.working-directory` already in place. * ci(fuzz): cd fuzz before pin step so we mutate the right lockfile Each fuzz crate (vault/fuzz, looping/fuzz, rewards/fuzz) declares its own isolated workspace via `[workspace]` in its Cargo.toml, which means it has its OWN `fuzz/Cargo.lock`. The job-level `defaults.run.working-directory` puts the command at the parent contract directory (`quantara/soroban/contracts/{vault,looping,rewards}/`), one level above `fuzz/`. Without `cd fuzz`, `cargo update` was mutating the parent contract workspace's `Cargo.lock` rather than the fuzz crate's lockfile, so `cargo fuzz run` (one step later) saw a fresh resolution and pulled `ed25519-dalek 3.0.0` again, re-introducing the rand_core 0.6 / 0.10 trait-bound mismatch. Adding `cd fuzz` before the four `cargo update --precise` calls makes the lockfile mutation land in the right place. `cargo fuzz run` (which cargo-fuzz derives from the `[package.metadata] cargo-fuzz = true` marker) then reads the updated lockfile, so the pin takes effect. * fix(fuzz): use soroban_sdk::IntoVal::into_val for numeric args `soroban-sdk` 22.0.0 no longer auto-converts primitive numerics (i128, u32) to `Val` via the `From`/`Into` trait family. The fuzz harnesses were failing to compile with: error[E0277]: the trait bound `soroban_sdk::Val: From<i128>` is not satisfied --> fuzz_targets/fuzz_rewards_accrue_claim.rs:36:58 Fix: switch each numeric argument inside `soroban_sdk::vec![&env, ...]` to `.into_val(&env)`, which goes through the SDK's `IntoVal` extension trait (the canonical way to convert a host-side value into a contract argument). Bring `IntoVal` into scope in each fuzz target's `use` block. `user.to_val()` calls are already correct and were left alone. Affected: * vault/fuzz/fuzz_targets/fuzz_vault_deposit.rs (amount) * vault/fuzz/fuzz_targets/fuzz_vault_withdraw.rs (initial_deposit, withdraw_amount) * looping/fuzz/fuzz_targets/fuzz_looping_open_position.rs (collateral, leverage) * rewards/fuzz/fuzz_targets/fuzz_rewards_accrue_claim.rs (accrual_a, accrual_b) This is the surface-level error left after the cargo-fuzz dep-pin work in the previous commits; once numeric args use IntoVal, the harnesses should compile and run the 60-second smoke fuzz pass. * fix(fuzz): explicit HostError generic on try_invoke_contract `soroban-sdk` 22.x changed `Env::try_invoke_contract` to return `Result<Result<T, ContractError>, HostError>`. The fuzz harnesses were calling it as `env.try_invoke_contract::<T, _>(...)`, leaving the host-error type uninferred; with multiple `impl TryFromVal<...>` candidates for `Error`, rustc refused with: error[E0283]: type annotations needed --> fuzz_targets/fuzz_vault_withdraw.rs:42:13 | 42 | let _ = env.try_invoke_contract::<(), _>( | ^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the error type `E` In the looping harness, the same problem cascaded — the single `.expect()` was returning `Result<u64, Error>` (the inner layer) instead of `u64`, breaking the `position_id >= 1` and `{position_id}` formatting assertions. Fix: make the second generic argument explicit as `soroban_sdk::Error` (which is the actual host-error type for the outer Result), and where `.expect()` is also used, unwrap both layers: // vault/deposit, vault/withdraw - try_invoke_contract::<(), _> + try_invoke_contract::<(), soroban_sdk::Error> // looping/open_position - try_invoke_contract::<u64, _> + try_invoke_contract::<u64, soroban_sdk::Error> - let position_id = result.expect("..."); + let position_id = result + .expect("open_position returned a host error") + .expect("open_position with valid args returned a contract error"); The rewards harness only uses `env.invoke_contract` (infallible) and needed no change. --------- Co-authored-by: LaGodxy <LaGodxy@users.noreply.github.com>
1 parent 2616d81 commit 01573cd

15 files changed

Lines changed: 561 additions & 3 deletions

File tree

.github/workflows/soroban_fuzz.yml

Lines changed: 226 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,226 @@
1+
name: Soroban Fuzz (Smoke — 60 s per target)
2+
3+
on:
4+
push:
5+
branches: [main]
6+
paths:
7+
- 'quantara/soroban/contracts/*/fuzz/**'
8+
- '.github/workflows/soroban_fuzz.yml'
9+
pull_request:
10+
branches: [main]
11+
paths:
12+
- 'quantara/soroban/contracts/*/fuzz/**'
13+
- '.github/workflows/soroban_fuzz.yml'
14+
workflow_dispatch:
15+
inputs:
16+
fuzz_time:
17+
description: 'Seconds to fuzz per target'
18+
default: '60'
19+
required: false
20+
21+
env:
22+
CARGO_TERM_COLOR: always
23+
FUZZ_TIME: ${{ github.event.inputs.fuzz_time || '60' }}
24+
25+
jobs:
26+
# ── Vault fuzz targets ────────────────────────────────────────────────────
27+
fuzz-vault:
28+
name: Fuzz vault (${{ matrix.target }})
29+
runs-on: ubuntu-latest
30+
strategy:
31+
fail-fast: false
32+
matrix:
33+
target:
34+
- fuzz_vault_deposit
35+
- fuzz_vault_withdraw
36+
37+
defaults:
38+
run:
39+
working-directory: quantara/soroban/contracts/vault
40+
41+
steps:
42+
- uses: actions/checkout@v4
43+
44+
- name: Install latest Rust nightly
45+
uses: dtolnay/rust-toolchain@nightly
46+
47+
- name: Cache Cargo registry
48+
uses: actions/cache@v4
49+
with:
50+
path: |
51+
~/.cargo/registry/index/
52+
~/.cargo/registry/cache/
53+
~/.cargo/git/db/
54+
key: ${{ runner.os }}-cargo-fuzz-${{ github.sha }}
55+
restore-keys: ${{ runner.os }}-cargo-fuzz-
56+
57+
- name: Install cargo-fuzz
58+
run: cargo install cargo-fuzz
59+
60+
- name: Pin ed25519-dalek and rand_core to 0.6 family
61+
# soroban-env-host 22.1.3's testutils.rs passes `ChaCha20Rng` into
62+
# `ed25519_dalek::SigningKey::generate`, which requires CryptoRng
63+
# from the rand_core 0.6 family. ed25519-dalek 3.x bumped to
64+
# rand_core 0.10, breaking the trait bound. Pin ed25519-dalek to
65+
# 2.1.1 (last 2.x release) and rand_core to 0.6.4; fall through
66+
# with `|| true` for compatibility — cargo refuses to demote a
67+
# rand_core 0.10 instance to 0.6.4 directly, but the ed25519-dalek
68+
# pin upstream of it is the real lever.
69+
# The fuzz crate is an isolated workspace ([workspace] in
70+
# fuzz/Cargo.toml), so it has its OWN fuzz/Cargo.lock. Without
71+
# `cd fuzz`, `cargo update` would mutate the parent contract
72+
# workspace's lockfile, which `cargo fuzz run` ignores — hence
73+
# the silent failure of the previous (no-cd) variant.
74+
run: |
75+
cd fuzz
76+
cargo update -p ed25519-dalek@3.0.0 --precise 2.1.1 || true
77+
cargo update -p ed25519-dalek --precise 2.1.1 || true
78+
cargo update -p rand_core@0.10.1 --precise 0.6.4 || true
79+
cargo update -p rand_core@0.9.5 --precise 0.6.4 || true
80+
81+
- name: Run fuzz target for ${{ env.FUZZ_TIME }}s
82+
run: |
83+
cargo fuzz run ${{ matrix.target }} \
84+
-- -max_total_time=${{ env.FUZZ_TIME }} -jobs=1
85+
86+
- name: Upload crash corpus on failure
87+
if: failure()
88+
uses: actions/upload-artifact@v4
89+
with:
90+
name: vault-${{ matrix.target }}-crash-corpus
91+
path: fuzz/corpus/${{ matrix.target }}
92+
if-no-files-found: ignore
93+
94+
# ── Looping fuzz targets ───────────────────────────────────────────────────
95+
fuzz-looping:
96+
name: Fuzz looping (${{ matrix.target }})
97+
runs-on: ubuntu-latest
98+
strategy:
99+
fail-fast: false
100+
matrix:
101+
target:
102+
- fuzz_looping_open_position
103+
104+
defaults:
105+
run:
106+
working-directory: quantara/soroban/contracts/looping
107+
108+
steps:
109+
- uses: actions/checkout@v4
110+
111+
- name: Install latest Rust nightly
112+
uses: dtolnay/rust-toolchain@nightly
113+
114+
- name: Cache Cargo registry
115+
uses: actions/cache@v4
116+
with:
117+
path: |
118+
~/.cargo/registry/index/
119+
~/.cargo/registry/cache/
120+
~/.cargo/git/db/
121+
key: ${{ runner.os }}-cargo-fuzz-${{ github.sha }}
122+
restore-keys: ${{ runner.os }}-cargo-fuzz-
123+
124+
- name: Install cargo-fuzz
125+
run: cargo install cargo-fuzz
126+
127+
- name: Pin ed25519-dalek and rand_core to 0.6 family
128+
# soroban-env-host 22.1.3's testutils.rs passes `ChaCha20Rng` into
129+
# `ed25519_dalek::SigningKey::generate`, which requires CryptoRng
130+
# from the rand_core 0.6 family. ed25519-dalek 3.x bumped to
131+
# rand_core 0.10, breaking the trait bound. Pin ed25519-dalek to
132+
# 2.1.1 (last 2.x release) and rand_core to 0.6.4; fall through
133+
# with `|| true` for compatibility — cargo refuses to demote a
134+
# rand_core 0.10 instance to 0.6.4 directly, but the ed25519-dalek
135+
# pin upstream of it is the real lever.
136+
# The fuzz crate is an isolated workspace ([workspace] in
137+
# fuzz/Cargo.toml), so it has its OWN fuzz/Cargo.lock. Without
138+
# `cd fuzz`, `cargo update` would mutate the parent contract
139+
# workspace's lockfile, which `cargo fuzz run` ignores — hence
140+
# the silent failure of the previous (no-cd) variant.
141+
run: |
142+
cd fuzz
143+
cargo update -p ed25519-dalek@3.0.0 --precise 2.1.1 || true
144+
cargo update -p ed25519-dalek --precise 2.1.1 || true
145+
cargo update -p rand_core@0.10.1 --precise 0.6.4 || true
146+
cargo update -p rand_core@0.9.5 --precise 0.6.4 || true
147+
148+
- name: Run fuzz target for ${{ env.FUZZ_TIME }}s
149+
run: |
150+
cargo fuzz run ${{ matrix.target }} \
151+
-- -max_total_time=${{ env.FUZZ_TIME }} -jobs=1
152+
153+
- name: Upload crash corpus on failure
154+
if: failure()
155+
uses: actions/upload-artifact@v4
156+
with:
157+
name: looping-${{ matrix.target }}-crash-corpus
158+
path: fuzz/corpus/${{ matrix.target }}
159+
if-no-files-found: ignore
160+
161+
# ── Rewards fuzz targets ───────────────────────────────────────────────────
162+
fuzz-rewards:
163+
name: Fuzz rewards (${{ matrix.target }})
164+
runs-on: ubuntu-latest
165+
strategy:
166+
fail-fast: false
167+
matrix:
168+
target:
169+
- fuzz_rewards_accrue_claim
170+
171+
defaults:
172+
run:
173+
working-directory: quantara/soroban/contracts/rewards
174+
175+
steps:
176+
- uses: actions/checkout@v4
177+
178+
- name: Install latest Rust nightly
179+
uses: dtolnay/rust-toolchain@nightly
180+
181+
- name: Cache Cargo registry
182+
uses: actions/cache@v4
183+
with:
184+
path: |
185+
~/.cargo/registry/index/
186+
~/.cargo/registry/cache/
187+
~/.cargo/git/db/
188+
key: ${{ runner.os }}-cargo-fuzz-${{ github.sha }}
189+
restore-keys: ${{ runner.os }}-cargo-fuzz-
190+
191+
- name: Install cargo-fuzz
192+
run: cargo install cargo-fuzz
193+
194+
- name: Pin ed25519-dalek and rand_core to 0.6 family
195+
# soroban-env-host 22.1.3's testutils.rs passes `ChaCha20Rng` into
196+
# `ed25519_dalek::SigningKey::generate`, which requires CryptoRng
197+
# from the rand_core 0.6 family. ed25519-dalek 3.x bumped to
198+
# rand_core 0.10, breaking the trait bound. Pin ed25519-dalek to
199+
# 2.1.1 (last 2.x release) and rand_core to 0.6.4; fall through
200+
# with `|| true` for compatibility — cargo refuses to demote a
201+
# rand_core 0.10 instance to 0.6.4 directly, but the ed25519-dalek
202+
# pin upstream of it is the real lever.
203+
# The fuzz crate is an isolated workspace ([workspace] in
204+
# fuzz/Cargo.toml), so it has its OWN fuzz/Cargo.lock. Without
205+
# `cd fuzz`, `cargo update` would mutate the parent contract
206+
# workspace's lockfile, which `cargo fuzz run` ignores — hence
207+
# the silent failure of the previous (no-cd) variant.
208+
run: |
209+
cd fuzz
210+
cargo update -p ed25519-dalek@3.0.0 --precise 2.1.1 || true
211+
cargo update -p ed25519-dalek --precise 2.1.1 || true
212+
cargo update -p rand_core@0.10.1 --precise 0.6.4 || true
213+
cargo update -p rand_core@0.9.5 --precise 0.6.4 || true
214+
215+
- name: Run fuzz target for ${{ env.FUZZ_TIME }}s
216+
run: |
217+
cargo fuzz run ${{ matrix.target }} \
218+
-- -max_total_time=${{ env.FUZZ_TIME }} -jobs=1
219+
220+
- name: Upload crash corpus on failure
221+
if: failure()
222+
uses: actions/upload-artifact@v4
223+
with:
224+
name: rewards-${{ matrix.target }}-crash-corpus
225+
path: fuzz/corpus/${{ matrix.target }}
226+
if-no-files-found: ignore

quantara/soroban/contracts/looping/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ license = "MIT"
66
publish = false
77

88
[lib]
9-
crate-type = ["cdylib"]
9+
crate-type = ["rlib", "cdylib"]
1010
doctest = false
1111

1212
[dependencies]
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
[package]
2+
name = "looping-fuzz"
3+
version = "0.0.0"
4+
publish = false
5+
edition = "2021"
6+
7+
[package.metadata]
8+
cargo-fuzz = true
9+
10+
[dependencies]
11+
libfuzzer-sys = "0.4"
12+
# Fuzz targets call contract functions via the Soroban test environment.
13+
# testutils provides Env::default(), mock_all_auths(), and Address::generate().
14+
soroban-sdk = { version = "22.0.0", features = ["testutils"] }
15+
looping = { path = ".." }
16+
# Pin rand_core to <= 0.6 so the whole dep tree unifies on the rand_core
17+
# 0.6 family. Without this, a transitive dep can resolve to rand_core 0.10,
18+
# while soroban-env-host's `testutils` (which uses ChaCha20Rng through
19+
# ed25519-dalek::rand_core) still expects the rand_core 0.6 `CryptoRng`
20+
# trait, breaking compilation.
21+
rand_core = "<0.7"
22+
23+
# Prevent this from interfering with the workspace.
24+
[workspace]
25+
26+
[[bin]]
27+
name = "fuzz_looping_open_position"
28+
path = "fuzz_targets/fuzz_looping_open_position.rs"
29+
test = false
30+
doc = false
Binary file not shown.
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
//! cargo-fuzz harness for LoopingContract::open_position entry-point.
2+
//!
3+
//! Invariants checked:
4+
//! - Valid inputs (collateral > 0, leverage 100–500) must succeed.
5+
//! - Returned position IDs are >= 1.
6+
//!
7+
//! Run:
8+
//! ```bash
9+
//! cargo +nightly fuzz run fuzz_looping_open_position -- -max_total_time=60
10+
//! ```
11+
12+
#![no_main]
13+
14+
use libfuzzer_sys::fuzz_target;
15+
use soroban_sdk::{testutils::Address as _, Address, Env, IntoVal, Symbol};
16+
use looping::LoopingContract;
17+
18+
fuzz_target!(|data: &[u8]| {
19+
if data.len() < 12 {
20+
return;
21+
}
22+
let collateral = i64::from_le_bytes(data[..8].try_into().unwrap()) as i128;
23+
let leverage = u32::from_le_bytes(data[8..12].try_into().unwrap());
24+
25+
let env = Env::default();
26+
env.mock_all_auths();
27+
let contract_id = env.register(LoopingContract, ());
28+
let user = Address::generate(&env);
29+
30+
// try_invoke_contract returns `Result<Result<u64, ContractError>, HostError>`;
31+
// explicitly specify the host error type so type inference succeeds.
32+
let result = env.try_invoke_contract::<u64, soroban_sdk::Error>(
33+
&contract_id,
34+
&Symbol::new(&env, "open_position"),
35+
soroban_sdk::vec![
36+
&env,
37+
user.to_val(),
38+
collateral.into_val(&env),
39+
leverage.into_val(&env),
40+
],
41+
);
42+
43+
if collateral > 0 && (100..=500).contains(&leverage) {
44+
// Unwrap the outer (host) Err first, then the inner (contract) Err.
45+
let position_id = result
46+
.expect("open_position returned a host error")
47+
.expect("open_position with valid args returned a contract error");
48+
assert!(position_id >= 1, "position_id must be >= 1, got {position_id}");
49+
}
50+
// Invalid inputs may error; no further assertion needed.
51+
});

quantara/soroban/contracts/rewards/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ license = "MIT"
66
publish = false
77

88
[lib]
9-
crate-type = ["cdylib"]
9+
crate-type = ["rlib", "cdylib"]
1010
doctest = false
1111

1212
[dependencies]
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
[package]
2+
name = "rewards-fuzz"
3+
version = "0.0.0"
4+
publish = false
5+
edition = "2021"
6+
7+
[package.metadata]
8+
cargo-fuzz = true
9+
10+
[dependencies]
11+
libfuzzer-sys = "0.4"
12+
# Fuzz targets call contract functions via the Soroban test environment.
13+
# testutils provides Env::default(), mock_all_auths(), and Address::generate().
14+
soroban-sdk = { version = "22.0.0", features = ["testutils"] }
15+
rewards = { path = ".." }
16+
# Pin rand_core to <= 0.6 so the whole dep tree unifies on the rand_core
17+
# 0.6 family. Without this, a transitive dep can resolve to rand_core 0.10,
18+
# while soroban-env-host's `testutils` (which uses ChaCha20Rng through
19+
# ed25519-dalek::rand_core) still expects the rand_core 0.6 `CryptoRng`
20+
# trait, breaking compilation.
21+
rand_core = "<0.7"
22+
23+
# Prevent this from interfering with the workspace.
24+
[workspace]
25+
26+
[[bin]]
27+
name = "fuzz_rewards_accrue_claim"
28+
path = "fuzz_targets/fuzz_rewards_accrue_claim.rs"
29+
test = false
30+
doc = false
Binary file not shown.

0 commit comments

Comments
 (0)