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

🧑‍💻 add help comment + update documentation #120

Merged
merged 3 commits into from
Feb 16, 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
36 changes: 19 additions & 17 deletions Fuzzing.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,18 @@ trdelnik init
The command will generate the required folder structure and fuzz test files:
```shell
project-root
├── .trdelnik_client
├── .program_client
├── trdelnik-tests
│ ├── src # fuzz tests folder
│ │ ├── bin
│ │ │ └── fuzz_target.rs # the binary target of your fuzz test
│ │ ├── fuzz_instructions.rs # the definition of your fuzz test
│ │ ├── accounts_snapshots.rs # generated accounts deserialization methods
│ │ └── lib.rs
│ ├── tests # integration tests folder
│ └── Cargo.toml
│ ├── fuzz_tests # fuzz tests folder
│ │ ├── fuzz_0 # particular fuzz test
│ │ │ ├── accounts_snapshots.rs # generated accounts deserialization methods
│ │ │ ├── test_fuzz.rs # the binary target of your fuzz test
│ │ │ └── fuzz_instructions.rs # the definition of your fuzz test
│ │ ├── fuzz_1
│ │ ├── fuzz_X # possible multiple fuzz tests
│ │ ├── fuzzing # compilations and crashes folder
│ │ └── Cargo.toml
│ ├── poc_tests # integration tests folder
├── Trdelnik.toml
└── ...
```
Expand All @@ -43,7 +45,7 @@ project-root
Once you have finished the implementation of `get_accounts` and `get_data` methods (see below), you can run the fuzz test as follows:

```shell
# Replace <TARGET_NAME> with the name of your fuzz target (by default "fuzz_target")
# Replace <TARGET_NAME> with the name of particular fuzz test (for example: "fuzz_0")
trdelnik fuzz run <TARGET_NAME>
```

Expand All @@ -61,7 +63,7 @@ iterations = 1000 # Number of fuzzing iterations
exit_upon_crash = true # Stop the fuzzer upon crash.
```

Or you can pass any parameter via [environment variables](https://github.com/rust-fuzz/honggfuzz-rs#environment-variables). A list of hongfuzz parameters can be found in honggfuzz [usage documentation](https://github.com/google/honggfuzz/blob/master/docs/USAGE.md#cmdline---help). The parameters passed via environment variables have higher priority. For example:
Or you can pass any parameter via [environment variables](https://github.com/rust-fuzz/honggfuzz-rs#environment-variables). A list of hongfuzz parameters can be found in honggfuzz [usage documentation](https://github.com/google/honggfuzz/blob/master/docs/USAGE.md#cmdline---help). The parameters passed via **environment variables** have **higher priority**. For example:
```shell
# Time-out: 10 secs
# Number of concurrent fuzzing threads: 1
Expand Down Expand Up @@ -96,13 +98,13 @@ Some diagram states are labeled with emojis:

## Write a fuzz test
At the current development stage, there are some manual steps required to make your fuzz test compile:
1. Add dependencies specific to your program to `trdelnik-tests/Cargo.toml` (such as anchor-spl etc.).
2. Add necessary `use` statements into `trdelnik-tests/src/accounts_snapshots.rs` to import missing types.
1. Add dependencies specific to your program to `trdelnik-tests/fuzz_tests/Cargo.toml` (such as anchor-spl etc.).
2. Add necessary `use` statements into `trdelnik-tests/fuzz_tests/<FUZZ_TEST_NAME>/accounts_snapshots.rs` to import missing types.

### Specify accounts to reuse
Trdelnik fuzzer helps you to generate only a limited amount of pseudo-random accounts and reuse them in the instructions. Always generating only random accounts would in most cases lead to a situation where the fuzzer would be stuck because the accounts would be almost every time rejected by your Anchor program. Therefore it is necessary to specify, what accounts should be used and also limit the number of newly created accounts to reduce the space complexity.

Go to the `trdelnik-tests/src/fuzz_instructions.rs` file and complete the pre-generated `FuzzAccounts` structure. It contains all accounts used in your program. You have to determine, if the account is a signer, a PDA, a token account or program account. Than use the corresponding `AccountsStorage` types such as:
Go to the `trdelnik-tests/fuzz_tests/<FUZZ_TEST_NAME>/fuzz_instructions.rs` file and complete the pre-generated `FuzzAccounts` structure. It contains all accounts used in your program. You have to determine, if the account is a signer, a PDA, a token account or program account. Than use the corresponding `AccountsStorage` types such as:
```rust
pub struct FuzzAccounts {
signer: AccountsStorage<Keypair>,
Expand All @@ -113,7 +115,7 @@ pub struct FuzzAccounts {
```

### Specify instruction data
Trdelnik fuzzer generates random instruction data for you. Currently it is however required, that you manually assign the random fuzzer data to the instruction data. It is done using the `IxOps` trait and its method `get_data`. Go to the `trdelnik-tests/src/fuzz_instructions.rs` file and complete the pre-generated `get_data` methods for each instruction such as:
Trdelnik fuzzer generates random instruction data for you. Currently it is however required, that you manually assign the random fuzzer data to the instruction data. It is done using the `IxOps` trait and its method `get_data`. Go to the `trdelnik-tests/fuzz_tests/<FUZZ_TEST_NAME>/fuzz_instructions.rs` file and complete the pre-generated `get_data` methods for each instruction such as:
```rust
fn get_data(
&self,
Expand All @@ -128,7 +130,7 @@ fn get_data(
```

### Specify instruction accounts
Trdelnik fuzzer generates random indexes of accounts to use in each instruction. Each created account is saved in the `FuzzAccounts` structure which helps you to reuse already existing accounts. You are required to define, how these accounts should be created and which accounts should be passed to an instruction. It is done using the `IxOps` trait and its method `get_accounts`. Go to the `trdelnik-tests/src/fuzz_instructions.rs` file and complete the pre-generated `get_accounts` methods for each instruction such as:
Trdelnik fuzzer generates random indexes of accounts to use in each instruction. Each created account is saved in the `FuzzAccounts` structure which helps you to reuse already existing accounts. You are required to define, how these accounts should be created and which accounts should be passed to an instruction. It is done using the `IxOps` trait and its method `get_accounts`. Go to the `trdelnik-tests/fuzz_tests/<FUZZ_TEST_NAME>/fuzz_instructions.rs` file and complete the pre-generated `get_accounts` methods for each instruction such as:
```rust
fn get_accounts(
&self,
Expand Down Expand Up @@ -188,7 +190,7 @@ fn check(
```

### Customize instructions generation
It is possible to customize how the instructions are generated and which instructions will be executed at the beginning (`pre_ixs`), in the middle (`ixs`) and at the end (`post_ixs`) of each fuzz iteration. This can be useful for example if your program needs an initialization or you want to fuzz some specific program state. Go to the bin target file of your fuzz test and implement the corresponding optional method of the `FuzzDataBuilder<FuzzInstruction>` trait. For example, in order to always call the `initialize` instruction for the default fuzz target, modify the trait's implementation in `trdelnik-tests/src/bin/fuzz_target.rs` file as follows:
It is possible to customize how the instructions are generated and which instructions will be executed at the beginning (`pre_ixs`), in the middle (`ixs`) and at the end (`post_ixs`) of each fuzz iteration. This can be useful for example if your program needs an initialization or you want to fuzz some specific program state. Go to the bin target file of your fuzz test and implement the corresponding optional method of the `FuzzDataBuilder<FuzzInstruction>` trait. For example, in order to always call the `initialize` instruction for the default fuzz target, modify the trait's implementation in `trdelnik-tests/fuzz_tests/<FUZZ_TEST_NAME>/test_fuzz.rs` file as follows:
```rust
impl FuzzDataBuilder<FuzzInstruction> for MyFuzzData {
fn pre_ixs(u: &mut arbitrary::Unstructured) -> arbitrary::Result<Vec<FuzzInstruction>> {
Expand Down
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,11 @@ trdelnik fuzz run <TARGET_NAME>
trdelnik --help
```
### How to write fuzz tests?
Once you initialize Trdelnik in your Anchor project, you will find a fuzz test template in the `trdelnik-tests/src/bin` folder that you can modify according to your needs or create new targets. Do not forget to install honggfuzz-rs using `cargo install honggfuzz`.
Once you initialize Trdelnik in your Anchor project, you will find a fuzz test template in the `trdelnik-tests/fuzz_tests/fuzz_0` folder that you can modify according to your needs or create new targets. Do not forget to install honggfuzz-rs using `cargo install honggfuzz`.


```shell
# To run the fuzz test, execute this command from your terminal and replace <TARGET_NAME> with the name of your fuzz target (by default "fuzz_target")
# To run the fuzz test, execute this command from your terminal and replace <TARGET_NAME> with the name of particular fuzz test (for example: "fuzz_0")
trdelnik fuzz run <TARGET_NAME>

# To debug your fuzz target crash with parameters from a crash file
Expand All @@ -84,8 +84,8 @@ Trdelnik also supports writing integration tests in Rust.
</div>

```rust
// <my_project>/trdelnik-tests/tests/test.rs
// TODO: do not forget to add all necessary dependencies to the generated `trdelnik-tests/Cargo.toml`
// <my_project>/trdelnik-tests/poc_tests/tests/test.rs
// TODO: do not forget to add all necessary dependencies to the generated `trdelnik-tests/poc_tests/Cargo.toml`
use program_client::my_instruction;
use trdelnik_client::*;
use my_program;
Expand Down Expand Up @@ -174,14 +174,14 @@ async fn test() {}
- `Trdelnik` does not export `anchor-spl` and `spl-associated-token-account`, so you have to add it manually.

```toml
# <my-project>/trdelnik-tests/Cargo.toml
# <my-project>/trdelnik-tests/poc_tests/Cargo.toml
# import the correct versions manually
anchor-spl = "0.28.0"
spl-associated-token-account = "2.0.0"
```

```rust
// <my-project>/trdelnik-tests/tests/test.rs
// <my-project>/trdelnik-tests/poc_tests/tests/test.rs
use anchor_spl::token::Token;
use spl_associated_token_account;

Expand Down
1 change: 1 addition & 0 deletions crates/cli/src/command/fuzz.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ pub enum FuzzCommand {
/// Path to the crash file
crash_file_path: String,
},
/// Add new fuzz test. Explicit fuzz test name is not yet supported. Implicit name is fuzz_ID, where ID is automatically derived.
Add,
}

Expand Down
4 changes: 2 additions & 2 deletions crates/cli/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,13 @@ enum Command {
#[clap(subcommand)]
subcmd: KeyPairCommand,
},
/// Run program tests
/// Run program Integration tests
Test {
/// Anchor project root
#[clap(short, long, default_value = "./")]
root: String,
},
/// Run and debug fuzz tests
/// Run and debug Fuzz tests
Fuzz {
/// Anchor project root
#[clap(short, long)]
Expand Down
Loading