-
Notifications
You must be signed in to change notification settings - Fork 18
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
📝 Update documentation, removed integration tests and better describe…
… Trident Features
- Loading branch information
Showing
36 changed files
with
1,261 additions
and
1,113 deletions.
There are no files selected for viewing
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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
--- | ||
hide: | ||
- navigation | ||
--- | ||
|
||
--- | ||
|
||
|
||
## trident init | ||
|
||
- This command Initializes Trident Workspace and generates new Fuzz Test Template. | ||
|
||
- The command will generate the following folder structure: | ||
```bash | ||
project-root | ||
├── trident-tests | ||
│ ├── fuzz_tests # fuzz tests folder | ||
│ │ ├── fuzz_0 # particular fuzz test | ||
│ │ │ ├── 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 | ||
├── Trident.toml | ||
└── ... | ||
``` | ||
|
||
--- | ||
|
||
## trident fuzz | ||
|
||
- This command behavior depends on the subcommands. | ||
|
||
### trident fuzz run | ||
|
||
- Run Fuzzer on the specified Fuzz Target (i.e. the Fuzz Template, for example fuzz_0). | ||
|
||
### trident fuzz run-debug | ||
|
||
- Run debug on the specified Fuzz Target (i.e. the Fuzz Template, for example fuzz_0), with specified crash file, to see where the crash file found an issue. | ||
|
||
### trident fuzz add | ||
|
||
- Adds new Fuzz Test Template. | ||
|
||
--- | ||
|
||
## trident clean | ||
|
||
- Calls `anchor clean` and cleans targets created by the underlying Honggfuzz. Crashfiles and Fuzzing Inputs are preserved. |
1 change: 1 addition & 0 deletions
1
documentation/docs/fuzzing/extra/examples.md → documentation/docs/examples/examples.md
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,6 @@ | ||
--- | ||
hide: | ||
- navigation | ||
- toc | ||
--- | ||
|
||
|
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
--- | ||
hide: | ||
- navigation | ||
--- | ||
|
||
# FAQ | ||
|
||
### Is Trident supported only with Anchor ? | ||
|
||
- Currently yes, Trident under the hood obtains data from the IDL generated by Anchor and it has to have access to the AccountsSnapshots derived for each Instruction Context. | ||
|
||
|
||
### I created the Fuzz Test what should I do next ? | ||
|
||
- Start here [Writing Fuzz Tests](../writing-fuzz-test/writing-fuzz-test.md). For additional features check [Features](../features/features.md). If you are not sure about anything check [Get Help](../get-help/get-help.md) | ||
|
||
|
||
### My program Instruction contains custom type such as Struct or Enum on its input, but it does not derive Arbitrary. | ||
|
||
- In this case you need to specify same type in the Fuzz Test (with the same fields). And implement From Trait to convert to your type. Check [Custom Data Types](../features/arbitrary-data.md/#custom-data-types) or [Examples of Arbitrary](../examples/examples.md). | ||
|
||
|
||
### Is Trident open-source ? | ||
|
||
- Yes, here [Trident](https://github.com/Ackee-Blockchain/trident) | ||
|
||
### I would like to report Issue with Trident, what should I do ? | ||
|
||
- Write Issue [Issues](https://github.com/Ackee-Blockchain/trident/issues) | ||
|
||
### Is Trident deployed on Mainnet / Devnet / Testenet ? | ||
|
||
- No, Trident is Fuzz Testing Framework, not Solana Program. | ||
|
||
### What type of Fuzzer Trident is ? | ||
|
||
- Currently, we refer to it as *"coverage guided gray box fuzzer"*. |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
# Account Storages | ||
|
||
|
||
Trident allows developers to generate random accounts for fuzzing. | ||
|
||
However, the Accounts are not completely random, and neither are the Account addresses. | ||
|
||
Instead, Trident generates random **AccountIDs** which are indexes to **Account Storages**. Each unique Account contained within the Anchor generated IDL has its own AccountStorage. The FuzzAccounts containing the Accounts Storages is global to all Instructions to use. | ||
|
||
|
||
??? note | ||
|
||
**Details:** | ||
|
||
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. | ||
|
||
!!! important | ||
|
||
Currently, supported types of Account Storages: | ||
|
||
- Signer | ||
- PDA | ||
- Token Account | ||
- Program account | ||
|
||
Then use the corresponding AccountsStorage. | ||
|
||
```rust | ||
pub struct FuzzAccounts { | ||
signer: AccountsStorage<Keypair>, | ||
some_pda: AccountsStorage<PdaStore>, | ||
token_vault: AccountsStorage<TokenStore>, | ||
mint: AccountsStorage<MintStore>, | ||
// ... | ||
} | ||
``` | ||
|
||
!!! tip | ||
|
||
Keep in mind: | ||
|
||
- You do not need to specify every `AccountStorage`, some accounts do not necessarily need to be stored in their corresponding storage. | ||
- For example `System Program` does not need to be stored, rather can be used from the `solana_sdk`. | ||
- If you are about to Initialize `Mint` or `Token Account` in your Solana Program. | ||
- use `Keypair` or `PdaStore` (not `MintStore` or `TokenStore`). | ||
- If you are going to initialize `Associated Token Account` in your Solana Program. | ||
- use `PdaStore`. | ||
- You can rename fields of `FuzzAccounts` to whatever you want. The default names are generated based on the Program's `IDL`. | ||
|
||
|
||
!!! tip | ||
|
||
Consider checking the [Examples](../examples/examples.md) section for more tips. |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
# Arbitrary Data | ||
|
||
|
||
Trident allows you to customize Instruction Data to provide structure. | ||
|
||
For example your Initialize Instruction expects two arguments `start_at` and `end_at` you know that in order for the Instruction to make sense, it is required that the `start_at` < `end_at`. Moreover, there should be significant difference between these two. This can be utilized with the **Arbitrary crate**. | ||
|
||
|
||
```rust | ||
#[derive(Arbitrary, Debug)] | ||
pub struct InitVestingData { | ||
pub recipient: AccountId, | ||
#[arbitrary( | ||
with = |u: &mut arbitrary::Unstructured| u.int_in_range(1..=1_000_000) | ||
)] | ||
pub amount: u64, | ||
// we want start_at smaller than end_at | ||
// and for testing purposes we can run tests with times from the past | ||
#[arbitrary( | ||
with = |u: &mut arbitrary::Unstructured| u.int_in_range(0..=1_000_000) | ||
)] | ||
pub start_at: u64, | ||
#[arbitrary( | ||
with = |u: &mut arbitrary::Unstructured| u.int_in_range(1_001_001..=1_050_000) | ||
)] | ||
pub end_at: u64, | ||
#[arbitrary( | ||
with = |u: &mut arbitrary::Unstructured| u.int_in_range(1..=1000) | ||
)] | ||
pub interval: u64, | ||
} | ||
``` | ||
|
||
## Implement Arbitrary | ||
|
||
There are macros available to use with Arbitrary, however, it is possible to Implement the arbitrary function by yourself. | ||
|
||
|
||
```rust | ||
// ------------------------------------------------------------------- | ||
// ------------------------------------------------------------------- | ||
// Implement Arbitrary | ||
impl<'a> Arbitrary<'a> for InitVestingData { | ||
fn arbitrary( | ||
u: &mut arbitrary::Unstructured<'a> | ||
) -> arbitrary::Result<Self> { | ||
// obtain AccountId | ||
let recipient = AccountId::arbitrary(u)?; | ||
|
||
// limit the generated amount to the 1_000_000 | ||
let amount = u.int_in_range(1..=1_000_000)?; | ||
|
||
// now we want to obtain | ||
// - start_at | ||
// - end_at | ||
// - interval | ||
// however we want to limit the data such that: | ||
// - start_at < end_at | ||
// - end_at - start_at > interval | ||
// - interval has lower limit of 500 and upper limit of 1000. | ||
|
||
let start_at: u64 = u.int_in_range(1_000_000..=5_000_000)?; | ||
let end_at: u64 = u.int_in_range(1_000_000..=5_000_000)?; | ||
let interval: u64 = u.int_in_range(500..=1000)?; | ||
|
||
// ensure that start_at < end_at | ||
if start_at >= end_at { | ||
return Err(arbitrary::Error::IncorrectFormat); | ||
} | ||
|
||
// ensure that end_at - start_at > interval | ||
match end_at.checked_sub(start_at) { | ||
Some(diff) => { | ||
if diff <= interval { | ||
return Err(arbitrary::Error::IncorrectFormat); | ||
} | ||
} | ||
None => return Err(arbitrary::Error::IncorrectFormat), | ||
} | ||
|
||
Ok(InitVestingData { | ||
recipient, | ||
amount, | ||
start_at, | ||
end_at, | ||
interval, | ||
}) | ||
} | ||
// ------------------------------------------------------------------- | ||
// ------------------------------------------------------------------- | ||
} | ||
``` | ||
|
||
## Custom Data Types | ||
|
||
If you use Custom Types as Instruction data arguments, you may encounter a problem that the Custom Type does not implement | ||
|
||
- [Debug](https://doc.rust-lang.org/std/fmt/trait.Debug.html) trait | ||
- [Arbitrary](https://docs.rs/arbitrary/latest/arbitrary/trait.Arbitrary.html) trait | ||
|
||
### Derive Debug and Arbitrary traits inside the Fuzz Test | ||
|
||
You can redefine the custom type within the `fuzz_instructions.rs` file, along with all the necessary traits. | ||
|
||
```rust | ||
// Redefine the Custom Type inside the fuzz_instructions.rs, | ||
// but this time with all of the required traits. | ||
#[derive(Arbitrary,Debug, Clone, Copy)] | ||
pub enum CustomEnumInputFuzz { | ||
InputVariant1, | ||
InputVariant2, | ||
InputVariant3, | ||
} | ||
``` | ||
|
||
|
||
Then, you would also need to implement the [`std::convert::From<T>`](https://doc.rust-lang.org/std/convert/trait.From.html) trait to enable conversion between the newly defined Custom Type and the Custom Type used within your program. | ||
|
||
!!! tip | ||
|
||
Consider checking the [Examples](../examples/examples.md) section for more tips. |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
# Error Handler | ||
|
||
Trident allows you to specify custom error handler for each Instruction. | ||
|
||
This can be particularly helpful: | ||
|
||
- If Transaction returns Error, you can specify to omit this error and continue with the fuzzing instruction. | ||
- Using the `tx_error_handler` you can check if the error returned is desired based on the Accounts and Input data that were used. | ||
|
||
!!! tip | ||
|
||
The default behavior of the function is that the error is returned. | ||
|
||
```rust | ||
/// default implementation | ||
fn tx_error_handler( | ||
&self, | ||
e: FuzzClientErrorWithOrigin, | ||
ix_data: Self::IxData, | ||
pre_ix_acc_infos: &'info mut [Option<AccountInfo<'info>>], | ||
) -> Result<(), FuzzClientErrorWithOrigin> { | ||
Err(e) | ||
} | ||
``` | ||
|
||
To omit the Error and continue with the next Instruction in the iteration, you can do | ||
|
||
```rust | ||
/// default implementation | ||
fn tx_error_handler( | ||
&self, | ||
e: FuzzClientErrorWithOrigin, | ||
ix_data: Self::IxData, | ||
pre_ix_acc_infos: &'info mut [Option<AccountInfo<'info>>], | ||
) -> Result<(), FuzzClientErrorWithOrigin> { | ||
Ok(()) | ||
} | ||
``` |
Oops, something went wrong.