Created
March 7, 2023 20:49
-
-
Save Aimeedeer/10afb7985a2a4df1f31ebe5330812515 to your computer and use it in GitHub Desktop.
Notes: Cargo fuzz coverage for Soroban timelock
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Cargo fuzz coverage for Soroban timelock | |
``` | |
$ cargo +nightly fuzz coverage fuzz_target_2 | |
warning: Patch `soroban-auth v0.6.0 (/rs-soroban-sdk/soroban-auth)` was not used in the crate graph. | |
Check that the patched package version and available features are compatible | |
with the dependency requirements. If the patch has a different version from | |
what is locked in the Cargo.lock file, run `cargo update` to use the new | |
version. This may also occur with an optional dependency that is not enabled. | |
Finished release [optimized + debuginfo] target(s) in 1.68s | |
Generating coverage data for "01ac89a78eba9e594865a5c872784b2b9058b92d" | |
warning: Patch `soroban-auth v0.6.0 (/rs-soroban-sdk/soroban-auth)` was not used in the crate graph. | |
Check that the patched package version and available features are compatible | |
with the dependency requirements. If the patch has a different version from | |
what is locked in the Cargo.lock file, run `cargo update` to use the new | |
version. This may also occur with an optional dependency that is not enabled. | |
Finished release [optimized + debuginfo] target(s) in 0.27s | |
Running `fuzz/target/x86_64-unknown-linux-gnu/release/fuzz_target_2 -artifact_prefix=/soroban-examples/timelock/fuzz/artifacts/fuzz_target_2/ /soroban-examples/timelock/fuzz/corpus/fuzz_target_2/01ac89a78eba9e594865a5c872784b2b9058b92d` | |
INFO: Running with entropic power schedule (0xFF, 100). | |
INFO: Seed: 3549841290 | |
INFO: Loaded 1 modules (1091042 inline 8-bit counters): 1091042 [0x562c0d1e59d0, 0x562c0d2effb2), | |
INFO: Loaded 1 PC tables (1091042 PCs): 1091042 [0x562c0d2effb8,0x562c0e395dd8), | |
fuzz/target/x86_64-unknown-linux-gnu/release/fuzz_target_2: Running 1 inputs 1 time(s) each. | |
Running: /soroban-examples/timelock/fuzz/corpus/fuzz_target_2/01ac89a78eba9e594865a5c872784b2b9058b92d | |
Executed /soroban-examples/timelock/fuzz/corpus/fuzz_target_2/01ac89a78eba9e594865a5c872784b2b9058b92d in 115 ms | |
*** | |
*** NOTE: fuzzing was not performed, you have only | |
*** executed the target code on a fixed set of inputs. | |
*** | |
Generating coverage data for "98ca8d9b3777aa379e144b8342f428ace51baaf0" | |
warning: Patch `soroban-auth v0.6.0 (/rs-soroban-sdk/soroban-auth)` was not used in the crate graph. | |
``` | |
use `llvm-profdata`: | |
``` | |
$ llvm-profdata merge -sparse fuzz/coverage/fuzz_target_2/raw -o fuzz/coverage/fuzz_target_2/coverage.profdata | |
``` | |
use `llvm-cov show`: | |
<screenshot> | |
``` | |
$ llvm-cov show target/x86_64-unknown-linux-gnu/coverage/x | |
86_64-unknown-linux-gnu/release/fuzz_target_2 -instr-profile=fuzz/coverage/fuzz_target_2/coverage.profdata | |
/rs-soroban-env/soroban-env-common/src/arbitrary.rs: | |
1| |//! Implementations of [`Arbitrary`] for contract types. | |
2| | | |
3| |#![cfg(feature = "testutils")] | |
4| | | |
5| |extern crate alloc; | |
6| | | |
7| |use crate::symbol::Symbol; | |
8| |use crate::xdr::{ScStatic, ScStatus}; | |
9| |use crate::{BitSet, RawVal, Static, Status}; | |
10| |use alloc::string::String; | |
11| |use alloc::vec::Vec as RustVec; | |
12| |use arbitrary::{Arbitrary, Unstructured}; | |
13| | | |
14| |impl<'a> Arbitrary<'a> for Symbol { | |
15| 0| fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> { | |
16| 0| let choices = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"; | |
17| 0| let choices: RustVec<char> = choices.chars().collect(); | |
18| 0| | |
19| 0| let mut buf = String::new(); | |
20| | | |
21| 0| let len = u.int_in_range(0..=10)?; | |
22| | | |
23| 0| for _ in 0..len { | |
24| 0| let choice = u.choose(&choices); | |
25| 0| match choice { | |
26| 0| Ok(ch) => { | |
27| 0| buf.push(*ch); | |
28| 0| } | |
29| | Err(_) => { | |
30| 0| break; | |
31| | } | |
32| | } | |
33| | } | |
34| | | |
``` | |
use `llvm-cov report`: | |
``` | |
$ llvm-cov report target/x86_64-unknown-linux-gnu/coverage/x86_64-unknown-linux-gnu/release/fuzz_target_2 -instr-profile=fuzz/coverage/fuzz_target_2/coverage.profdata | |
Filename Regions Missed Regions Cover Functions Missed Functions Executed Lines Missed Lines Cover Branches Missed Branches Cover | |
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | |
/rs-soroban-env/soroban-env-common/src/arbitrary.rs 28 28 0.00% 4 4 0.00% 37 37 0.00% 0 0 - | |
/rs-soroban-env/soroban-env-common/src/array.rs 38 38 0.00% 10 10 0.00% 46 46 0.00% 0 0 - | |
/rs-soroban-env/soroban-env-common/src/bitset.rs 12 12 0.00% 9 9 0.00% 25 25 0.00% 0 0 - | |
/rs-soroban-env/soroban-env-common/src/compare.rs 56 33 41.07% 9 3 66.67% 72 39 45.83% 0 0 - | |
/rs-soroban-env/soroban-env-common/src/env_val.rs 135 83 38.52% 24 17 29.17% 141 84 40.43% 0 0 - | |
/rs-soroban-env/soroban-env-common/src/invoker.rs 12 12 0.00% 7 7 0.00% 16 16 0.00% 0 0 - | |
... | |
-------------------------------------------------------------------------------------------- | |
TOTAL 78785 73158 7.14% 23042 21502 6.68% 114236 103496 9.40% 0 0 - | |
``` | |
`llvm-cov show` with filter `-name=timelock`: | |
``` | |
$ llvm-cov show target/x86_64-unknown-linux-gnu/coverage/x86_64-unknown-linux-gnu/release/fuzz_target_2 -instr-profile=fuzz/coverage/fuzz_target_2/coverage.profdata -name=timelock | |
_RNvXNtCsebBT0MTtZjd_18soroban_env_common7env_valNtNtB4_7raw_val6RawValINtB2_10TryIntoValNtNtCs3kZVoCPPN4x_11soroban_sdk3env3EnvNtCscznx7R4neHg_25soroban_timelock_contract13TimeBoundKindE12try_into_valCscUqQUv7tGtL_13fuzz_target_2: | |
34| 32.6k| fn try_into_val(&self, env: &E) -> Result<T, Self::Error> { | |
35| 32.6k| T::try_from_val(env, self) | |
36| 32.6k| } | |
_RNvXNtCsebBT0MTtZjd_18soroban_env_common7env_valNtNtB4_7raw_val6RawValINtB2_10TryIntoValNtNtCs3kZVoCPPN4x_11soroban_sdk3env3EnvNtCscznx7R4neHg_25soroban_timelock_contract9TimeBoundE12try_into_valCscUqQUv7tGtL_13fuzz_target_2: | |
34| 32.6k| fn try_into_val(&self, env: &E) -> Result<T, Self::Error> { | |
35| 32.6k| T::try_from_val(env, self) | |
36| 32.6k| } | |
_RNvXNtCsebBT0MTtZjd_18soroban_env_common7env_valNtNtB4_7raw_val6RawValINtB2_10TryIntoValNtNtCs3kZVoCPPN4x_11soroban_sdk3env3EnvINtNtB1s_3vec3VecBK_EE12try_into_valCscznx7R4neHg_25soroban_timelock_contract: | |
34| 10.6k| fn try_into_val(&self, env: &E) -> Result<T, Self::Error> { | |
35| 10.6k| T::try_from_val(env, self) | |
36| 10.6k| } | |
_RNCNvXs7_NtCsebBT0MTtZjd_18soroban_env_common7env_valNtNtNtCskkZpHXSrmTK_11stellar_xdr4next9generated5ScValINtB7_10TryFromValNtNtCs3kZVoCPPN4x_11soroban_sdk3env3EnvNtNtB9_7raw_val6RawValE12try_from_val0Cscznx7R4neHg_25soroban_timelock_contract: | |
197| 0| let scob = ScObject::try_from_val(&env, &ob).map_err(|_| ConversionError)?; | |
_RINvNtCsebBT0MTtZjd_18soroban_env_common7env_val15log_err_convertyNtNtCs3kZVoCPPN4x_11soroban_sdk3env3EnvNtNtB4_7raw_val6RawValECscznx7R4neHg_25soroban_timelock_contract: | |
39| 0|pub(crate) fn log_err_convert<T>(env: &impl Env, val: &impl AsRef<RawVal>) { | |
40| 0| // Logging here is best-effort; ignore failures (they only arise if we're | |
41| 0| // out of gas or something otherwise-unrecoverable). | |
42| 0| let _ = env.log_static_fmt_val_static_str( | |
43| 0| "can't convert {} to {}", | |
44| 0| *val.as_ref(), | |
45| 0| core::any::type_name::<T>(), | |
46| 0| ); | |
47| 0|} | |
... | |
``` | |
use `llvm-cov show` with `-Xdemangler=rustfilt`: | |
``` | |
$ llvm-cov show -Xdemangler=rustfilt target/x86_64-unknown-linux-gnu/coverage/x86_64-unknown-linux-gnu/release/fuzz_target_2 -instr-profile=fuzz/coverage/fuzz_target_2/coverage.profdata -name=timelock | |
<soroban_env_common::raw_val::RawVal as soroban_env_common::env_val::TryIntoVal<soroban_sdk::env::Env, soroban_timelock_contract::TimeBoundKind>>::try_into_val: | |
34| 32.6k| fn try_into_val(&self, env: &E) -> Result<T, Self::Error> { | |
35| 32.6k| T::try_from_val(env, self) | |
36| 32.6k| } | |
<soroban_env_common::raw_val::RawVal as soroban_env_common::env_val::TryIntoVal<soroban_sdk::env::Env, soroban_timelock_contract::TimeBound>>::try_into_val: | |
34| 32.6k| fn try_into_val(&self, env: &E) -> Result<T, Self::Error> { | |
35| 32.6k| T::try_from_val(env, self) | |
36| 32.6k| } | |
<soroban_env_common::raw_val::RawVal as soroban_env_common::env_val::TryIntoVal<soroban_sdk::env::Env, soroban_sdk::vec::Vec<soroban_env_common::raw_val::RawVal>>>::try_into_val: | |
34| 10.6k| fn try_into_val(&self, env: &E) -> Result<T, Self::Error> { | |
35| 10.6k| T::try_from_val(env, self) | |
36| 10.6k| } | |
<stellar_xdr::next::generated::ScVal as soroban_env_common::env_val::TryFromVal<soroban_sdk::env::Env, soroban_env_common::raw_val::RawVal>>::try_from_val::{closure#0}: | |
197| 0| let scob = ScObject::try_from_val(&env, &ob).map_err(|_| ConversionError)?; | |
soroban_env_common::env_val::log_err_convert::<u64, soroban_sdk::env::Env, soroban_env_common::raw_val::RawVal>: | |
39| 0|pub(crate) fn log_err_convert<T>(env: &impl Env, val: &impl AsRef<RawVal>) { | |
40| 0| // Logging here is best-effort; ignore failures (they only arise if we're | |
41| 0| // out of gas or something otherwise-unrecoverable). | |
42| 0| let _ = env.log_static_fmt_val_static_str( | |
43| 0| "can't convert {} to {}", | |
44| 0| *val.as_ref(), | |
45| 0| core::any::type_name::<T>(), | |
46| 0| ); | |
47| 0|} | |
... | |
``` | |
`llvm-cov show` with filter `-name=fuzz_target_2` and demangler: | |
``` | |
$ llvm-cov show -Xdemangler=rustfilt target/x86_64-unknown-linux-gnu/coverage/x86_64-unknown-linux-gnu/release/fuzz_target_2 -instr-profile=fuzz/coverage/fuzz_target_2/coverage.profdata -name=fuzz_target_2 | |
<soroban_env_common::raw_val::RawVal as soroban_env_common::env_val::TryIntoVal<soroban_sdk::env::Env, i128>>::try_into_val: | |
34| 32.6k| fn try_into_val(&self, env: &E) -> Result<T, Self::Error> { | |
35| 32.6k| T::try_from_val(env, self) | |
36| 32.6k| } | |
<u64 as soroban_env_common::env_val::TryFromVal<soroban_sdk::env::Env, soroban_env_common::raw_val::RawVal>>::try_from_val::{closure#0}: | |
90| 0| Ok(env.obj_to_u64(obj).map_err(|_| ConversionError)?) | |
<i128 as soroban_env_common::env_val::TryFromVal<soroban_sdk::env::Env, soroban_env_common::raw_val::RawVal>>::try_from_val: | |
111| 70.6k| fn try_from_val(env: &E, v: &RawVal) -> Result<Self, Self::Error> { | |
112| 70.6k| let v = *v; | |
113| 70.6k| let obj = v.try_into()?; | |
114| 70.6k| let lo = env.obj_to_i128_lo64(obj).map_err(|_| ConversionError)?; | |
115| 70.6k| let hi = env.obj_to_i128_hi64(obj).map_err(|_| ConversionError)?; | |
116| 70.6k| let u: u128 = (lo as u128) | ((hi as u128) << 64); | |
117| 70.6k| Ok(u as i128) | |
118| 70.6k| } | |
``` | |
filter with `name=deposit`: | |
``` | |
$ llvm-cov show -Xdemangler=rustfilt target/x86_64-unknown-linux-gnu/coverage/x86_64-unknown-linux-gnu/release/fuzz_target_2 -instr-profile=fuzz/coverage/fuzz_target_2/coverage.profdata -name=deposit | |
soroban_timelock_contract::__deposit::invoke_raw_slice: | |
58| 9.82k|#[contractimpl] | |
<soroban_timelock_contract::ClaimableBalanceContract>::deposit: | |
60| 9.82k| pub fn deposit( | |
61| 9.82k| env: Env, | |
62| 9.82k| from: Address, | |
63| 9.82k| token: BytesN<32>, | |
64| 9.82k| amount: i128, | |
65| 9.82k| claimants: Vec<Address>, | |
66| 9.82k| time_bound: TimeBound, | |
67| 9.82k| ) { | |
68| 9.82k| if claimants.len() > 10 { | |
69| 98| panic!("too many claimants"); | |
70| 9.72k| } | |
71| 9.72k| if is_initialized(&env) { | |
72| 5.19k| panic!("contract has been already initialized"); | |
73| 4.53k| } | |
74| 4.53k| // Make sure `from` address authorized the deposit call with all the | |
75| 4.53k| // arguments. | |
76| 4.53k| from.require_auth(); | |
77| 4.53k| | |
78| 4.53k| // Transfer token from `from` to this contract address. | |
79| 4.53k| token::Client::new(&env, &token).xfer(&from, &env.current_contract_address(), &amount); | |
80| 4.53k| // Store all the necessary info to allow one of the claimants to claim it. | |
81| 4.53k| env.storage().set( | |
82| 4.53k| &DataKey::Balance, | |
83| 4.53k| &ClaimableBalance { | |
84| 4.53k| token, | |
85| 4.53k| amount, | |
86| 4.53k| time_bound, | |
87| 4.53k| claimants, | |
88| 4.53k| }, | |
89| 4.53k| ); | |
90| 4.53k| // Mark contract as initialized to prevent double-usage. | |
91| 4.53k| // Note, that this is just one way to approach initialization - it may | |
92| 4.53k| // be viable to allow one contract to manage several claimable balances. | |
93| 4.53k| env.storage().set(&DataKey::Init, &()); | |
94| 4.53k| } | |
<soroban_timelock_contract::ClaimableBalanceContractClient>::try_deposit: | |
58| 0|#[contractimpl] | |
soroban_timelock_contract::__deposit::invoke_raw: | |
58| 9.82k|#[contractimpl] | |
<soroban_timelock_contract::ClaimableBalanceContractClient>::deposit: | |
58| 9.82k|#[contractimpl] | |
<soroban_timelock_contract::ClaimableBalanceContractClient>::try_deposit::{closure#0}: | |
58| 0|#[contractimpl] | |
<soroban_timelock_contract::ClaimableBalanceContractClient>::with_env::<(), <soroban_timelock_contract::ClaimableBalanceContractClient>::deposit::{closure#0}>: | |
58| 9.82k|#[contractimpl] | |
<soroban_timelock_contract::ClaimableBalanceContractClient>::deposit::{closure#0}: | |
58| 9.82k|#[contractimpl] | |
<soroban_timelock_contract::ClaimableBalanceContract>::spec_xdr_deposit: | |
58| 0|#[contractimpl] | |
<soroban_timelock_contract::ClaimableBalanceContractClient>::with_env::<core::result::Result<core::result::Result<(), soroban_env_common::raw_val::ConversionError>, core::result::Result<soroban_env_common::status::Status, core::convert::Infallible>>, <soroban_timelock_contract::ClaimableBalanceContractClient>::try_deposit::{closure#0}>: | |
58| 0|#[contractimpl] | |
``` | |
filter with `name=claim`: | |
``` | |
$ llvm-cov show -Xdemangler=rustfilt target/x86_64-unknown-linux-gnu/coverage/x86_64-unknown-linux-gnu/release/fuzz_target_2 -instr-profile=fuzz/coverage/fuzz_target_2/coverage.profdata -name=claim | |
fuzz_target_2::create_claimable_balance_contract: | |
271| 2.28k|fn create_claimable_balance_contract(e: &Env) -> ClaimableBalanceContractClient { | |
272| 2.28k| ClaimableBalanceContractClient::new(e, &e.register_contract(None, ClaimableBalanceContract {})) | |
273| 2.28k|} | |
<soroban_timelock_contract::ClaimableBalanceContract>::spec_xdr_claim: | |
58| 0|#[contractimpl] | |
<soroban_timelock_contract::ClaimableBalanceContractClient>::with_env::<core::result::Result<core::result::Result<(), soroban_env_common::raw_val::ConversionError>, core::result::Result<soroban_env_common::status::Status, core::convert::Infallible>>, <soroban_timelock_contract::ClaimableBalanceContractClient>::try_claim::{closure#0}>: | |
58| 0|#[contractimpl] | |
<soroban_timelock_contract::ClaimableBalanceContract>::claim: | |
96| 2.08k| pub fn claim(env: Env, claimant: Address) { | |
97| 2.08k| // Make sure claimant has authorized this call, which ensures their | |
98| 2.08k| // identity. | |
99| 2.08k| claimant.require_auth(); | |
100| 2.08k| | |
101| 2.08k| let claimable_balance: ClaimableBalance = | |
102| 2.08k| env.storage().get_unchecked(&DataKey::Balance).unwrap(); | |
103| 2.08k| | |
104| 2.08k| if !check_time_bound(&env, &claimable_balance.time_bound) { | |
105| 692| panic!("time predicate is not fulfilled"); | |
106| 1.39k| } | |
107| 1.39k| | |
108| 1.39k| let claimants = &claimable_balance.claimants; | |
109| 1.39k| if !claimants.contains(&claimant) { | |
110| 90| panic!("claimant is not allowed to claim this balance"); | |
111| 1.30k| } | |
112| 1.30k| | |
113| 1.30k| // Transfer the stored amount of token to claimant after passing | |
114| 1.30k| // all the checks. | |
115| 1.30k| token::Client::new(&env, &claimable_balance.token).xfer( | |
116| 1.30k| &env.current_contract_address(), | |
117| 1.30k| &claimant, | |
118| 1.30k| &claimable_balance.amount, | |
119| 1.30k| ); | |
120| 1.30k| // Remove the balance entry to prevent any further claims. | |
121| 1.30k| env.storage().remove(&DataKey::Balance); | |
122| 1.30k| } | |
<soroban_timelock_contract::ClaimableBalanceContractClient>::claim::{closure#0}: | |
58| 2.08k|#[contractimpl] | |
soroban_timelock_contract::__claim::invoke_raw: | |
58| 2.08k|#[contractimpl] | |
<soroban_timelock_contract::ClaimableBalanceContractClient>::with_env::<(), <soroban_timelock_contract::ClaimableBalanceContractClient>::claim::{closure#0}>: | |
58| 2.08k|#[contractimpl] | |
<soroban_timelock_contract::ClaimableBalanceContractClient>::claim: | |
58| 2.08k|#[contractimpl] | |
<soroban_timelock_contract::ClaimableBalanceContractClient>::try_claim: | |
58| 0|#[contractimpl] | |
soroban_timelock_contract::__claim::invoke_raw_slice: | |
58| 2.08k|#[contractimpl] | |
<soroban_timelock_contract::ClaimableBalanceContractClient>::try_claim::{closure#0}: | |
58| 0|#[contractimpl] | |
``` | |
add file allowlist.txt: | |
``` | |
<soroban_timelock_contract::ClaimableBalanceContract>::deposit | |
<soroban_timelock_contract::ClaimableBalanceContract>::claim | |
``` | |
It doesn't work so far. | |
``` | |
$ llvm-cov show -Xdemangler=rustfilt target/x86_64-unknown-linux-gnu/coverage/x86_64-unknown-linux-gnu/release/fuzz_target_2 -instr-profile=fuzz/coverage/fuzz_target_2/coverage.profdata -name-allowlist=fuzz/allowlist.txt | |
``` |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment