Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Macro to generate desired Ix Sequences #220

Merged
merged 1 commit into from
Oct 31, 2024
Merged
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ incremented upon a breaking change and the patch version will be incremented for

**Added**

- add pre_sequence!, middle_sequence! and post_sequence! for easier sequence definition ([220](https://github.com/Ackee-Blockchain/trident/pull/220))
- add/ add support for Clock sysvar manipulations with the client(i.e. warp to slot/epoch and forward in time) ([217](https://github.com/Ackee-Blockchain/trident/pull/217))

## [0.8.0] - 2024-10-21
Expand Down
3 changes: 3 additions & 0 deletions crates/client/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ pub mod fuzzing {
/// trident macros
pub use trident_fuzz::convert_entry;
pub use trident_fuzz::fuzz_trident;
pub use trident_fuzz::middle_sequence;
pub use trident_fuzz::post_sequence;
pub use trident_fuzz::pre_sequence;
pub use trident_fuzz::show_account;
pub use trident_fuzz::*;

Expand Down
18 changes: 9 additions & 9 deletions crates/client/src/source_code_generators/test_fuzz_generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,20 @@ pub fn generate_source_code(idl_instructions: &[Idl]) -> String {

#(#program_names)*

struct MyFuzzData;
struct InstructionsSequence;


/// Define instruction sequences for invocation.
/// `pre_ixs` runs at the start, `ixs` in the middle, and `post_ixs` at the end.
/// For example, to call `InitializeFn` at the start of each fuzzing iteration:
/// `pre` runs at the start, `middle` in the middle, and `post` at the end.
/// For example, to call `InitializeFn`, `UpdateFn` and then `WithdrawFn` during each fuzzing iteration:
/// ```
/// fn pre_ixs(u: &mut arbitrary::Unstructured) -> arbitrary::Result<Vec<FuzzInstruction>> {
/// let init = FuzzInstruction::InitializeFn(InitializeFn::arbitrary(u)?);
/// Ok(vec![init])
/// }
/// impl FuzzDataBuilder<FuzzInstruction> for InstructionsSequence {
/// pre_sequence!(InitializeFn,UpdateFn);
/// middle_sequence!(WithdrawFn);
///}
/// ```
/// For more details, see: https://ackee.xyz/trident/docs/latest/features/instructions-sequences/#instructions-sequences
impl FuzzDataBuilder<FuzzInstruction> for MyFuzzData {}
impl FuzzDataBuilder<FuzzInstruction> for InstructionsSequence {}

/// `fn fuzz_iteration` runs during every fuzzing iteration.
/// Modification is not required.
Expand All @@ -47,7 +47,7 @@ pub fn generate_source_code(idl_instructions: &[Idl]) -> String {

fn main() {
let config = Config::new();
fuzz_trident!(fuzz_ix: FuzzInstruction, |fuzz_data: MyFuzzData| {
fuzz_trident!(fuzz_ix: FuzzInstruction, |fuzz_data: InstructionsSequence| {

fuzz_iteration(fuzz_data,&config);

Expand Down
20 changes: 10 additions & 10 deletions crates/client/tests/expected_source_codes/expected_test_fuzz.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,19 @@ use dummy_example::ID as PROGRAM_ID_DUMMY_EXAMPLE;
use fuzz_instructions::FuzzInstruction;
const PROGRAM_NAME_DUMMY_2: &str = "dummy_2";
const PROGRAM_NAME_DUMMY_EXAMPLE: &str = "dummy_example";
struct MyFuzzData;
struct InstructionsSequence;
/// Define instruction sequences for invocation.
/// `pre_ixs` runs at the start, `ixs` in the middle, and `post_ixs` at the end.
/// For example, to call `InitializeFn` at the start of each fuzzing iteration:
/// `pre` runs at the start, `middle` in the middle, and `post` at the end.
/// For example, to call `InitializeFn`, `UpdateFn` and then `WithdrawFn` during
/// each fuzzing iteration:
/// ```
/// fn pre_ixs(u: &mut arbitrary::Unstructured) ->
/// arbitrary::Result<Vec<FuzzInstruction>> {
/// let init = FuzzInstruction::InitializeFn(InitializeFn::arbitrary(u)?);
/// Ok(vec![init])
/// }
/// impl FuzzDataBuilder<FuzzInstruction> for InstructionsSequence {
/// pre_sequence!(InitializeFn,UpdateFn);
/// middle_sequence!(WithdrawFn);
///}
/// ```
/// For more details, see: https://ackee.xyz/trident/docs/latest/features/instructions-sequences/#instructions-sequences
impl FuzzDataBuilder<FuzzInstruction> for MyFuzzData {}
impl FuzzDataBuilder<FuzzInstruction> for InstructionsSequence {}
/// `fn fuzz_iteration` runs during every fuzzing iteration.
/// Modification is not required.
fn fuzz_iteration<T: FuzzTestExecutor<U> + std::fmt::Display, U>(
Expand All @@ -45,5 +45,5 @@ fn fuzz_iteration<T: FuzzTestExecutor<U> + std::fmt::Display, U>(
}
fn main() {
let config = Config::new();
fuzz_trident ! (fuzz_ix : FuzzInstruction , | fuzz_data : MyFuzzData | { fuzz_iteration (fuzz_data , & config) ; });
fuzz_trident ! (fuzz_ix : FuzzInstruction , | fuzz_data : InstructionsSequence | { fuzz_iteration (fuzz_data , & config) ; });
}
46 changes: 46 additions & 0 deletions crates/fuzz/src/instructions_sequence.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#[macro_export]
macro_rules! pre_sequence {
// Accept a list of FuzzInstruction variants using parentheses `()`
($($ix_variant:ident),* $(,)?) => {
fn pre_ixs(_u: &mut arbitrary::Unstructured) -> arbitrary::Result<Vec<FuzzInstruction>> {
let mut instructions = Vec::new();
$(
let ix = FuzzInstruction::$ix_variant($ix_variant::arbitrary(_u)?);
instructions.push(ix);
)*
Ok(instructions)
}
};
}

#[macro_export]
macro_rules! middle_sequence {
// Accept a list of FuzzInstruction variants (which may include duplicates)
($($ix_variant:ident),* $(,)?) => {
fn ixs(_u: &mut arbitrary::Unstructured) -> arbitrary::Result<Vec<FuzzInstruction>> {
#[allow(unused_mut)]
let mut instructions = Vec::new();
$(
let ix = FuzzInstruction::$ix_variant($ix_variant::arbitrary(_u)?);
instructions.push(ix);
)*
Ok(instructions)
}
};
}

#[macro_export]
macro_rules! post_sequence {
// Accept a list of FuzzInstruction variants (which may include duplicates)
($($ix_variant:ident),* $(,)?) => {
fn post_ixs(_u: &mut arbitrary::Unstructured) -> arbitrary::Result<Vec<FuzzInstruction>> {
#[allow(unused_mut)]
let mut instructions = Vec::new();
$(
let ix = FuzzInstruction::$ix_variant($ix_variant::arbitrary(_u)?);
instructions.push(ix);
)*
Ok(instructions)
}
};
}
1 change: 1 addition & 0 deletions crates/fuzz/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,6 @@ pub mod fuzz_client;
pub mod fuzz_deserialize;
pub mod fuzz_test_executor;
pub mod fuzz_trident;
pub mod instructions_sequence;
pub mod ix_ops;
pub mod transaction_executor;
42 changes: 36 additions & 6 deletions documentation/docs/features/instructions-sequences.md
Original file line number Diff line number Diff line change
@@ -1,22 +1,52 @@
# Instructions Sequences

Trident allows you to specify Custom Instruction Sequences you would like to execute.
Trident allows you to specify __custom Instruction squences__ you would like to execute.

Possible Instruction sequences are split into 3 parts

- pre-Instructions
- Instructions
- post-Instructions
- __pre-Instructions__
- __Instructions__
- __post-Instructions__

For example if you program always needs to start with some kind of Initialization instruction, you can specify this Initialize Instruction in `pre_ixs` as shown in the source code below.
For example if you program always needs to start with some kind of Initialization instruction, you can specify this Initialize Instruction using the `pre_sequence()` macro as shown in the source code below.

```rust
// test_fuzz.rs

/// ...

struct InstructionsSequence;
/// Define instruction sequences for invocation.
/// `pre` runs at the start, `middle` in the middle, and `post` at the end.
/// For example, to call `InitializeFn`, `UpdateFn` and then `WithdrawFn` during
/// each fuzzing iteration:
/// ```
/// impl FuzzDataBuilder<FuzzInstruction> for InstructionsSequence {
/// pre_sequence!(InitializeFn,UpdateFn);
/// middle_sequence!(WithdrawFn);
///}
/// ```
/// For more details, see: https://ackee.xyz/trident/docs/dev/features/instructions-sequences/#instructions-sequences
impl FuzzDataBuilder<FuzzInstruction> for InstructionsSequence {
pre_sequence!(InitializeFn);
middle_sequence!();
post_sequence!();
}

/// ...

```

!!! tip

- returning `Ok(vec![])` will result in None Instructions executed in the corresponding part.
- The arguments to the macro are variants of `FuzzInstruction` specified in `fuzz_instructions.rs`.
- Empty macro parameters (such as `middle_sequence!()`), will skip that section, meaning no instructions will be executed during the section.
- If no macro is defined for a section, a random instruction sequence will be generated for the section.


## Manual trait override

It is not necessary to use the macro as explained above. The trait implementation (i.e., the methods) can be implemented manually, as shown in the code below. This approach allows for greater customization if needed. The rules are the same as described above.

```rust
// test_fuzz.rs
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,20 @@ use arbitrary_custom_types_4::entry as entry_arbitrary_custom_types_4;
use arbitrary_custom_types_4::ID as PROGRAM_ID_ARBITRARY_CUSTOM_TYPES_4;
use fuzz_instructions::FuzzInstruction;
const PROGRAM_NAME_ARBITRARY_CUSTOM_TYPES_4: &str = "arbitrary_custom_types_4";
struct MyFuzzData;
struct InstructionsSequence;
/// Define instruction sequences for invocation.
/// `pre_ixs` runs at the start, `ixs` in the middle, and `post_ixs` at the end.
/// For example, to call `InitializeFn` at the start of each fuzzing iteration:
/// `pre` runs at the start, `middle` in the middle, and `post` at the end.
/// For example, to call `InitializeFn`, `UpdateFn` and then `WithdrawFn` during
/// each fuzzing iteration:
/// ```
/// fn pre_ixs(u: &mut arbitrary::Unstructured) ->
/// arbitrary::Result<Vec<FuzzInstruction>> {
/// let init = FuzzInstruction::InitializeFn(InitializeFn::arbitrary(u)?);
/// Ok(vec![init])
/// }
/// impl FuzzDataBuilder<FuzzInstruction> for InstructionsSequence {
/// pre_sequence!(InitializeFn,UpdateFn);
/// middle_sequence!(WithdrawFn);
///}
/// ```
/// For more details, see: https://ackee.xyz/trident/docs/dev/features/instructions-sequences/#instructions-sequences
impl FuzzDataBuilder<FuzzInstruction> for MyFuzzData {
fn pre_ixs(u: &mut arbitrary::Unstructured) -> arbitrary::Result<Vec<FuzzInstruction>> {
let init = FuzzInstruction::Initialize(Initialize::arbitrary(u)?);
let update = FuzzInstruction::Update(Update::arbitrary(u)?);
Ok(vec![init, update])
}
impl FuzzDataBuilder<FuzzInstruction> for InstructionsSequence {
pre_sequence!(Initialize, Update);
}
/// `fn fuzz_iteration` runs during every fuzzing iteration.
/// Modification is not required.
Expand All @@ -43,5 +39,5 @@ fn fuzz_iteration<T: FuzzTestExecutor<U> + std::fmt::Display, U>(
}
fn main() {
let config = Config::new();
fuzz_trident ! (fuzz_ix : FuzzInstruction , | fuzz_data : MyFuzzData | { fuzz_iteration (fuzz_data , & config) ; });
fuzz_trident ! (fuzz_ix : FuzzInstruction , | fuzz_data : InstructionsSequence | { fuzz_iteration (fuzz_data , & config) ; });
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,31 +6,22 @@ use arbitrary_limit_inputs_5::entry as entry_arbitrary_limit_inputs_5;
use arbitrary_limit_inputs_5::ID as PROGRAM_ID_ARBITRARY_LIMIT_INPUTS_5;
use fuzz_instructions::FuzzInstruction;
const PROGRAM_NAME_ARBITRARY_LIMIT_INPUTS_5: &str = "arbitrary_limit_inputs_5";
struct MyFuzzData;
struct InstructionsSequence;
/// Define instruction sequences for invocation.
/// `pre_ixs` runs at the start, `ixs` in the middle, and `post_ixs` at the end.
/// For example, to call `InitializeFn` at the start of each fuzzing iteration:
/// `pre` runs at the start, `middle` in the middle, and `post` at the end.
/// For example, to call `InitializeFn`, `UpdateFn` and then `WithdrawFn` during
/// each fuzzing iteration:
/// ```
/// fn pre_ixs(u: &mut arbitrary::Unstructured) ->
/// arbitrary::Result<Vec<FuzzInstruction>> {
/// let init = FuzzInstruction::InitializeFn(InitializeFn::arbitrary(u)?);
/// Ok(vec![init])
/// }
/// impl FuzzDataBuilder<FuzzInstruction> for InstructionsSequence {
/// pre_sequence!(InitializeFn,UpdateFn);
/// middle_sequence!(WithdrawFn);
///}
/// ```
/// For more details, see: https://ackee.xyz/trident/docs/dev/features/instructions-sequences/#instructions-sequences
impl FuzzDataBuilder<FuzzInstruction> for MyFuzzData {
fn pre_ixs(u: &mut arbitrary::Unstructured) -> arbitrary::Result<Vec<FuzzInstruction>> {
let init_ix = FuzzInstruction::InitVesting(InitVesting::arbitrary(u)?);

Ok(vec![init_ix])
}
fn ixs(u: &mut arbitrary::Unstructured) -> arbitrary::Result<Vec<FuzzInstruction>> {
let withdraw_ix = FuzzInstruction::WithdrawUnlocked(WithdrawUnlocked::arbitrary(u)?);
Ok(vec![withdraw_ix])
}
fn post_ixs(_u: &mut arbitrary::Unstructured) -> arbitrary::Result<Vec<FuzzInstruction>> {
Ok(vec![])
}
impl FuzzDataBuilder<FuzzInstruction> for InstructionsSequence {
pre_sequence!(InitVesting);
middle_sequence!(WithdrawUnlocked);
post_sequence!();
}
/// `fn fuzz_iteration` runs during every fuzzing iteration.
/// Modification is not required.
Expand All @@ -50,5 +41,5 @@ fn fuzz_iteration<T: FuzzTestExecutor<U> + std::fmt::Display, U>(
}
fn main() {
let config = Config::new();
fuzz_trident ! (fuzz_ix : FuzzInstruction , | fuzz_data : MyFuzzData | { fuzz_iteration (fuzz_data , & config) ; });
fuzz_trident ! (fuzz_ix : FuzzInstruction , | fuzz_data : InstructionsSequence | { fuzz_iteration (fuzz_data , & config) ; });
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,29 +5,22 @@ use cpi_metaplex_7::entry as entry_cpi_metaplex_7;
use cpi_metaplex_7::ID as PROGRAM_ID_CPI_METAPLEX_7;
use fuzz_instructions::FuzzInstruction;
const PROGRAM_NAME_CPI_METAPLEX_7: &str = "cpi_metaplex_7";
struct MyFuzzData;
struct InstructionsSequence;
/// Define instruction sequences for invocation.
/// `pre_ixs` runs at the start, `ixs` in the middle, and `post_ixs` at the end.
/// For example, to call `InitializeFn` at the start of each fuzzing iteration:
/// `pre` runs at the start, `middle` in the middle, and `post` at the end.
/// For example, to call `InitializeFn`, `UpdateFn` and then `WithdrawFn` during
/// each fuzzing iteration:
/// ```
/// fn pre_ixs(u: &mut arbitrary::Unstructured) ->
/// arbitrary::Result<Vec<FuzzInstruction>> {
/// let init = FuzzInstruction::InitializeFn(InitializeFn::arbitrary(u)?);
/// Ok(vec![init])
/// }
/// impl FuzzDataBuilder<FuzzInstruction> for InstructionsSequence {
/// pre_sequence!(InitializeFn,UpdateFn);
/// middle_sequence!(WithdrawFn);
///}
/// ```
/// For more details, see: https://ackee.xyz/trident/docs/dev/features/instructions-sequences/#instructions-sequences
impl FuzzDataBuilder<FuzzInstruction> for MyFuzzData {
fn pre_ixs(u: &mut arbitrary::Unstructured) -> arbitrary::Result<Vec<FuzzInstruction>> {
let init = FuzzInstruction::Initialize(Initialize::arbitrary(u)?);
Ok(vec![init])
}
fn ixs(_u: &mut arbitrary::Unstructured) -> arbitrary::Result<Vec<FuzzInstruction>> {
Ok(vec![])
}
fn post_ixs(_u: &mut arbitrary::Unstructured) -> arbitrary::Result<Vec<FuzzInstruction>> {
Ok(vec![])
}
impl FuzzDataBuilder<FuzzInstruction> for InstructionsSequence {
pre_sequence!(Initialize);
middle_sequence!();
post_sequence!();
}
/// `fn fuzz_iteration` runs during every fuzzing iteration.
/// Modification is not required.
Expand All @@ -46,5 +39,5 @@ fn fuzz_iteration<T: FuzzTestExecutor<U> + std::fmt::Display, U>(
}
fn main() {
let config = Config::new();
fuzz_trident ! (fuzz_ix : FuzzInstruction , | fuzz_data : MyFuzzData | { fuzz_iteration (fuzz_data , & config) ; });
fuzz_trident ! (fuzz_ix : FuzzInstruction , | fuzz_data : InstructionsSequence | { fuzz_iteration (fuzz_data , & config) ; });
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,29 +5,22 @@ use fuzz_instructions::FuzzInstruction;
use hello_world::entry as entry_hello_world;
use hello_world::ID as PROGRAM_ID_HELLO_WORLD;
const PROGRAM_NAME_HELLO_WORLD: &str = "hello_world";
struct MyFuzzData;
struct InstructionsSequence;
/// Define instruction sequences for invocation.
/// `pre_ixs` runs at the start, `ixs` in the middle, and `post_ixs` at the end.
/// For example, to call `InitializeFn` at the start of each fuzzing iteration:
/// `pre` runs at the start, `middle` in the middle, and `post` at the end.
/// For example, to call `InitializeFn`, `UpdateFn` and then `WithdrawFn` during
/// each fuzzing iteration:
/// ```
/// fn pre_ixs(u: &mut arbitrary::Unstructured) ->
/// arbitrary::Result<Vec<FuzzInstruction>> {
/// let init = FuzzInstruction::InitializeFn(InitializeFn::arbitrary(u)?);
/// Ok(vec![init])
/// }
/// impl FuzzDataBuilder<FuzzInstruction> for InstructionsSequence {
/// pre_sequence!(InitializeFn,UpdateFn);
/// middle_sequence!(WithdrawFn);
///}
/// ```
/// For more details, see: https://ackee.xyz/trident/docs/dev/features/instructions-sequences/#instructions-sequences
impl FuzzDataBuilder<FuzzInstruction> for MyFuzzData {
fn pre_ixs(u: &mut arbitrary::Unstructured) -> arbitrary::Result<Vec<FuzzInstruction>> {
let init = FuzzInstruction::InitializeFn(InitializeFn::arbitrary(u)?);
Ok(vec![init])
}
fn ixs(_u: &mut arbitrary::Unstructured) -> arbitrary::Result<Vec<FuzzInstruction>> {
Ok(vec![])
}
fn post_ixs(_u: &mut arbitrary::Unstructured) -> arbitrary::Result<Vec<FuzzInstruction>> {
Ok(vec![])
}
impl FuzzDataBuilder<FuzzInstruction> for InstructionsSequence {
pre_sequence!(InitializeFn);
middle_sequence!();
post_sequence!();
}
/// `fn fuzz_iteration` runs during every fuzzing iteration.
/// Modification is not required.
Expand All @@ -46,5 +39,5 @@ fn fuzz_iteration<T: FuzzTestExecutor<U> + std::fmt::Display, U>(
}
fn main() {
let config = Config::new();
fuzz_trident ! (fuzz_ix : FuzzInstruction , | fuzz_data : MyFuzzData | { fuzz_iteration (fuzz_data , & config) ; });
fuzz_trident ! (fuzz_ix : FuzzInstruction , | fuzz_data : InstructionsSequence | { fuzz_iteration (fuzz_data , & config) ; });
}
Loading
Loading