From 258c3c075d70960a7b3038f08722348a79ee64d2 Mon Sep 17 00:00:00 2001 From: Trident bot Date: Thu, 14 Nov 2024 16:21:05 +0000 Subject: [PATCH] Deployed ad43ecc to dev with MkDocs 1.6.1 and mike 2.1.3 --- dev/CHANGELOG/index.html | 2 +- dev/commands/commands/index.html | 2 +- dev/examples/examples/index.html | 2 +- dev/faq/faq/index.html | 2 +- dev/features/account-storages/index.html | 2 +- dev/features/arbitrary-data/index.html | 2 +- dev/features/error-handlers/index.html | 2 +- dev/features/features/index.html | 2 +- dev/features/fuzz-instructions/index.html | 2 +- dev/features/fuzzing-statistics/index.html | 2 +- dev/features/genesis-accounts/index.html | 2 +- dev/features/instructions-sequences/index.html | 2 +- dev/features/invariant-checks/index.html | 2 +- dev/features/lifecycle/index.html | 2 +- dev/features/limitations/index.html | 2 +- dev/features/trident-manifest/index.html | 2 +- dev/get-help/get-help/index.html | 2 +- dev/index.html | 2 +- dev/installation/installation/index.html | 4 ++-- dev/search/search_index.json | 2 +- dev/writing-fuzz-test/writing-fuzz-test/index.html | 2 +- 21 files changed, 22 insertions(+), 22 deletions(-) diff --git a/dev/CHANGELOG/index.html b/dev/CHANGELOG/index.html index ac9b8487..4bc10415 100644 --- a/dev/CHANGELOG/index.html +++ b/dev/CHANGELOG/index.html @@ -1 +1 @@ - Changelog - Trident
Skip to content

Changelog#

All notable changes to this project will be documented in this file.

The format is based on Keep a Changelog, and this project adheres to Semantic Versioning (SemVer).

Note: Version 0 of Semantic Versioning is handled differently from version 1 and above. The minor version will be incremented upon a breaking change and the patch version will be incremented for features.

[dev] - Unreleased#

Removed

  • removed unnecesarry deserialization with AccountsSnapshots, to deserialize data implementation AccountDeserialize can be used (221)

Changed

  • improve AccountsStorage module structure and remove unnecessary methods in FuzzClient (223)
  • improve manipulations with AccountsStorages in get_accounts() function (219)

Added

  • add pre_sequence!, middle_sequence! and post_sequence! for easier sequence definition (220)
  • add/ add support for Clock sysvar manipulations with the client(i.e. warp to slot/epoch and forward in time) (217)

[0.8.0] - 2024-10-21#

Added

  • impr/ allow to specify programs and accounts in the Trident Manifest (207)
  • impr/ added get_program_id function to the IxOps and FuzzTestExecutor (199)

Changed

  • impr/ improve init command, modify program manifest automatically, add init force, add howto subcommand (208)
  • impr/ allow to derive AccountsSnapshots for empty Account Context (209)
  • impr/ fuzz flags are read at start of fuzzing session from Config instead of env variable and transaction dispatch was added to increase FuzzTestExecutor readability (204)
  • impr/ allow various instructions to be generated in case of multiple programs in the Anchor workspace (200)
  • feat/ option to add account into Fuzz Test environment with base64 data (197)
  • impr/ instead of parsing source code and creating our IDL, read anchor IDL (198)

Removed

  • del/remove integration tests supported by Trident, this feature adds more unnecessary overhead compared to its value (196)

[0.7.0] - 2024-08-14#

Added

  • impr/ add feature flag to the AccountsSnapshots macro (183)
  • feat/ add Support for CPI (182)
  • feat/ add option to initialize Trident with Macro/File (for Snapshots) option based on preference (179)
  • feat/create AccountsSnapshots derive macro for Snapshots creation (#177)
  • feat/fuzzing moved to separate crate trident-fuzz (#175)
  • feat/unify dependencies provided by the Trident (#172)
  • feat/fuzzer-stats-logging, an optional statistics output for fuzzing session (#144)

Fixed

  • fix/in case of fuzzing failure throw error instead of only printing message (#167)
  • fix/snapshot's zeroed account as optional (#170)

Removed

  • del/remove localnet subcommand (178)
  • del/remove unnecessary fuzzing feature as trident is mainly fuzzer (#176)
  • del/remove Trident explorer (#171)

[0.6.0] - 2024-05-20#

Added

  • feat/anchor 0.30.0 support (#148)
  • fix/allow to process duplicate transactions (#147)
  • feat/possibility to implement custom transaction error handling (#145)
  • feat/support of automatically obtaining fully qualified paths of Data Accounts Custom types for accounts_snapshots.rs (#141)
  • feat/allow direct accounts manipulation and storage (#142)
  • feat/support of non-corresponding instruction and context names (#130)
  • feat/refactored and improved program flow during init and build, added activity indicator (#129)
  • feat/allow solana versions up to v1.17.* and pin Rust 1.77 nightly compiler (#128)
  • feat/new init command option to initialize fuzz or poc tests only (#124)
  • feat/debug-mode detailed output (#125)
  • feat/anchor 0.29.0 support (#121)
  • doc/add help comment + update documentation (#120)
  • feat/fuzzer error handling (#118)
  • feat/convert fuzz Pubkey to AccountId (#116)
  • feat/additional anchor types (#115)
  • feat/import ToAccountInfo trait in fuzzing prelude (#113)
  • test/added code generation and macros tests (#112)
  • feat/fuzzer framework core, macros, helpers, templates, and examples. (#111)
  • feat/improved trident-tests folder structure for PoC and Fuzz Tests (#109)
  • feat/support for additional fuzzer parameters in Trident.toml config file (#107)
  • feat/posibility to pass params to the fuzzer via Trident.toml config file (#106)
  • feat/client now reads by default keypair from default location (#105)
  • feat/added new --exit-code option to return corresponding exit code based on fuzz test result (#104)
  • feat/removed/updated deprecated functions, removed allow deprecated macros (#103)
  • feat/added new function to read keypair file generated by Anchor (#102)
  • feat/clean command (#101)
  • feat/improved program_client generated code (#100)
  • feat/automatically add hfuzz_target to .gitignore file (#99)
  • feat/support for dynamic templates. (#98)

Fixed

  • fix/refactored fuzz test executor error handling (#127)
  • fix/warn user on composite accounts and continue fuzz test generation (#133)
  • fix/progress bar loop lock release (#132)
  • fix/fixed fuzz test generation with init-if-needed Anchor feature (#131)
  • fix/program client custom types (#117)
  • fix/check fuzz test name collision by checking the name against HashSet (#114)

[0.5.0] - 2023-08-28#

Added

  • cli: Added trident subcommand fuzz to run and debug fuzz tests using honggfuzz-rs.
  • cli: Added trident --skip-fuzzer option for init subcommand to skip generation of fuzz test templates.
  • client: Added new Cargo feature fuzzing that enables optional dependencies related to fuzz testing.

[0.4.1] - 2023-08-21#

Changed

  • Upgrade Solana (=1.16.6) and Anchor framework (=0.28.0) versions.

Fixed

  • Implemented Anchor Client logic was not able to work with newer version of Anchor. Fixed with async_rpc and async feature.
  • Trident init IDL Parse Error on newer version of Rust, fixed with updated accounts token.

[0.3.0] - 2022-09-23#

Changed

  • Upgrade Solana (~1.10) and Anchor framework (~0.25) versions

Added

  • Custom Solana RPC error reporter. If the Solana RPC error is thrown, the error code, message and data (logs) are reported to the output.
  • Custom imports in the .program_client. User is able to import custom types and structures into program client. The import part of the code would not be re-generated.

[0.2.0] - 2022-07-27#

Added

  • Trident is now configurable. This requires Trident.toml file to exist in the project's root directory - without this file the execution will fail. To solve this re-run trident init or just create an empty Trident.toml file in the project's root directory.
\ No newline at end of file + Changelog - Trident
Skip to content

Changelog#

All notable changes to this project will be documented in this file.

The format is based on Keep a Changelog, and this project adheres to Semantic Versioning (SemVer).

Note: Version 0 of Semantic Versioning is handled differently from version 1 and above. The minor version will be incremented upon a breaking change and the patch version will be incremented for features.

[dev] - Unreleased#

[0.8.1] - 2024-11-14#

Removed

  • removed unnecesarry deserialization with AccountsSnapshots, to deserialize data implementation AccountDeserialize can be used (221)

Changed

  • improve AccountsStorage module structure and remove unnecessary methods in FuzzClient (223)
  • improve manipulations with AccountsStorages in get_accounts() function (219)

Added

  • add pre_sequence!, middle_sequence! and post_sequence! for easier sequence definition (220)
  • add/ add support for Clock sysvar manipulations with the client(i.e. warp to slot/epoch and forward in time) (217)

[0.8.0] - 2024-10-21#

Added

  • impr/ allow to specify programs and accounts in the Trident Manifest (207)
  • impr/ added get_program_id function to the IxOps and FuzzTestExecutor (199)

Changed

  • impr/ improve init command, modify program manifest automatically, add init force, add howto subcommand (208)
  • impr/ allow to derive AccountsSnapshots for empty Account Context (209)
  • impr/ fuzz flags are read at start of fuzzing session from Config instead of env variable and transaction dispatch was added to increase FuzzTestExecutor readability (204)
  • impr/ allow various instructions to be generated in case of multiple programs in the Anchor workspace (200)
  • feat/ option to add account into Fuzz Test environment with base64 data (197)
  • impr/ instead of parsing source code and creating our IDL, read anchor IDL (198)

Removed

  • del/remove integration tests supported by Trident, this feature adds more unnecessary overhead compared to its value (196)

[0.7.0] - 2024-08-14#

Added

  • impr/ add feature flag to the AccountsSnapshots macro (183)
  • feat/ add Support for CPI (182)
  • feat/ add option to initialize Trident with Macro/File (for Snapshots) option based on preference (179)
  • feat/create AccountsSnapshots derive macro for Snapshots creation (#177)
  • feat/fuzzing moved to separate crate trident-fuzz (#175)
  • feat/unify dependencies provided by the Trident (#172)
  • feat/fuzzer-stats-logging, an optional statistics output for fuzzing session (#144)

Fixed

  • fix/in case of fuzzing failure throw error instead of only printing message (#167)
  • fix/snapshot's zeroed account as optional (#170)

Removed

  • del/remove localnet subcommand (178)
  • del/remove unnecessary fuzzing feature as trident is mainly fuzzer (#176)
  • del/remove Trident explorer (#171)

[0.6.0] - 2024-05-20#

Added

  • feat/anchor 0.30.0 support (#148)
  • fix/allow to process duplicate transactions (#147)
  • feat/possibility to implement custom transaction error handling (#145)
  • feat/support of automatically obtaining fully qualified paths of Data Accounts Custom types for accounts_snapshots.rs (#141)
  • feat/allow direct accounts manipulation and storage (#142)
  • feat/support of non-corresponding instruction and context names (#130)
  • feat/refactored and improved program flow during init and build, added activity indicator (#129)
  • feat/allow solana versions up to v1.17.* and pin Rust 1.77 nightly compiler (#128)
  • feat/new init command option to initialize fuzz or poc tests only (#124)
  • feat/debug-mode detailed output (#125)
  • feat/anchor 0.29.0 support (#121)
  • doc/add help comment + update documentation (#120)
  • feat/fuzzer error handling (#118)
  • feat/convert fuzz Pubkey to AccountId (#116)
  • feat/additional anchor types (#115)
  • feat/import ToAccountInfo trait in fuzzing prelude (#113)
  • test/added code generation and macros tests (#112)
  • feat/fuzzer framework core, macros, helpers, templates, and examples. (#111)
  • feat/improved trident-tests folder structure for PoC and Fuzz Tests (#109)
  • feat/support for additional fuzzer parameters in Trident.toml config file (#107)
  • feat/posibility to pass params to the fuzzer via Trident.toml config file (#106)
  • feat/client now reads by default keypair from default location (#105)
  • feat/added new --exit-code option to return corresponding exit code based on fuzz test result (#104)
  • feat/removed/updated deprecated functions, removed allow deprecated macros (#103)
  • feat/added new function to read keypair file generated by Anchor (#102)
  • feat/clean command (#101)
  • feat/improved program_client generated code (#100)
  • feat/automatically add hfuzz_target to .gitignore file (#99)
  • feat/support for dynamic templates. (#98)

Fixed

  • fix/refactored fuzz test executor error handling (#127)
  • fix/warn user on composite accounts and continue fuzz test generation (#133)
  • fix/progress bar loop lock release (#132)
  • fix/fixed fuzz test generation with init-if-needed Anchor feature (#131)
  • fix/program client custom types (#117)
  • fix/check fuzz test name collision by checking the name against HashSet (#114)

[0.5.0] - 2023-08-28#

Added

  • cli: Added trident subcommand fuzz to run and debug fuzz tests using honggfuzz-rs.
  • cli: Added trident --skip-fuzzer option for init subcommand to skip generation of fuzz test templates.
  • client: Added new Cargo feature fuzzing that enables optional dependencies related to fuzz testing.

[0.4.1] - 2023-08-21#

Changed

  • Upgrade Solana (=1.16.6) and Anchor framework (=0.28.0) versions.

Fixed

  • Implemented Anchor Client logic was not able to work with newer version of Anchor. Fixed with async_rpc and async feature.
  • Trident init IDL Parse Error on newer version of Rust, fixed with updated accounts token.

[0.3.0] - 2022-09-23#

Changed

  • Upgrade Solana (~1.10) and Anchor framework (~0.25) versions

Added

  • Custom Solana RPC error reporter. If the Solana RPC error is thrown, the error code, message and data (logs) are reported to the output.
  • Custom imports in the .program_client. User is able to import custom types and structures into program client. The import part of the code would not be re-generated.

[0.2.0] - 2022-07-27#

Added

  • Trident is now configurable. This requires Trident.toml file to exist in the project's root directory - without this file the execution will fail. To solve this re-run trident init or just create an empty Trident.toml file in the project's root directory.
\ No newline at end of file diff --git a/dev/commands/commands/index.html b/dev/commands/commands/index.html index d3757df0..ff26fad3 100644 --- a/dev/commands/commands/index.html +++ b/dev/commands/commands/index.html @@ -32,4 +32,4 @@ #### Output -TBD -->

trident fuzz debug-hfuzz#

Output#

Important

The debug output is at current development stage really verbose and contains lldb parts. We are working on improving this experience. In the picture below you can see an example of provided debug output.

  1. Series of Transaction Logs
  2. Structures of data send within the Instructions
  3. Panic or Crash, based on if the Fuzzing panicked within the Solana Program or Invariant Check failed.

alt text

trident fuzz add#


trident clean#

\ No newline at end of file +TBD -->

trident fuzz debug-hfuzz#

Output#

Important

The debug output is at current development stage really verbose and contains lldb parts. We are working on improving this experience. In the picture below you can see an example of provided debug output.

  1. Series of Transaction Logs
  2. Structures of data send within the Instructions
  3. Panic or Crash, based on if the Fuzzing panicked within the Solana Program or Invariant Check failed.

alt text

trident fuzz add#


trident clean#

\ No newline at end of file diff --git a/dev/examples/examples/index.html b/dev/examples/examples/index.html index d87206ff..18474c6b 100644 --- a/dev/examples/examples/index.html +++ b/dev/examples/examples/index.html @@ -1 +1 @@ - Trident by Examples - Trident
Skip to content

Trident by Examples#

\ No newline at end of file + Trident by Examples - Trident
Skip to content

Trident by Examples#

\ No newline at end of file diff --git a/dev/faq/faq/index.html b/dev/faq/faq/index.html index 0578b39e..a6562abb 100644 --- a/dev/faq/faq/index.html +++ b/dev/faq/faq/index.html @@ -1 +1 @@ - FAQ - Trident
Skip to content

FAQ#

Is Trident supported only with Anchor ?#

  • Currently yes, Trident under the hood obtains data from the IDL generated by Anchor.

I created the Fuzz Test what should I do next ?#

My program Instruction contains custom type such as Struct or Enum on its input, but it does not derive Arbitrary.#

Is Trident open-source ?#

I would like to report Issue with Trident, what should I do ?#

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".
\ No newline at end of file + FAQ - Trident
Skip to content

FAQ#

Is Trident supported only with Anchor ?#

  • Currently yes, Trident under the hood obtains data from the IDL generated by Anchor.

I created the Fuzz Test what should I do next ?#

My program Instruction contains custom type such as Struct or Enum on its input, but it does not derive Arbitrary.#

Is Trident open-source ?#

I would like to report Issue with Trident, what should I do ?#

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".
\ No newline at end of file diff --git a/dev/features/account-storages/index.html b/dev/features/account-storages/index.html index d6896072..fb97f082 100644 --- a/dev/features/account-storages/index.html +++ b/dev/features/account-storages/index.html @@ -5,4 +5,4 @@ mint: AccountsStorage<MintStore>, // ... } -

Tip

Keep in mind:

Tip

Consider checking the Examples section for more tips.

\ No newline at end of file +

Tip

Keep in mind:

Tip

Consider checking the Examples section for more tips.

\ No newline at end of file diff --git a/dev/features/arbitrary-data/index.html b/dev/features/arbitrary-data/index.html index 75b3192f..95461c4b 100644 --- a/dev/features/arbitrary-data/index.html +++ b/dev/features/arbitrary-data/index.html @@ -72,4 +72,4 @@ // ------------------------------------------------------------------- // ------------------------------------------------------------------- } -

Tip

Consider checking the Examples section for more tips.

\ No newline at end of file +

Tip

Consider checking the Examples section for more tips.

\ No newline at end of file diff --git a/dev/features/error-handlers/index.html b/dev/features/error-handlers/index.html index 901c945a..f7eee380 100644 --- a/dev/features/error-handlers/index.html +++ b/dev/features/error-handlers/index.html @@ -16,4 +16,4 @@ ) -> Result<(), FuzzClientErrorWithOrigin> { Ok(()) } -
\ No newline at end of file +
\ No newline at end of file diff --git a/dev/features/features/index.html b/dev/features/features/index.html index 6cacb0b3..39280346 100644 --- a/dev/features/features/index.html +++ b/dev/features/features/index.html @@ -41,4 +41,4 @@ 2. Specify instruction sequences [Instruction sequences](../writing-fuzz-test-extra/instruction-sequences.md). 3. Specify custom data types [Custom Data types](../writing-fuzz-test-extra/custom-data-types.md). 4. Well structured data [Arbitrary](../writing-fuzz-test-extra/arbitrary.md). - 4. AccountsSnapshots macro [AccountsSnapshots](../writing-fuzz-test-extra/accounts-snapshots.md). -->
\ No newline at end of file + 4. AccountsSnapshots macro [AccountsSnapshots](../writing-fuzz-test-extra/accounts-snapshots.md). -->
\ No newline at end of file diff --git a/dev/features/fuzz-instructions/index.html b/dev/features/fuzz-instructions/index.html index 4128a11a..3e942bb5 100644 --- a/dev/features/fuzz-instructions/index.html +++ b/dev/features/fuzz-instructions/index.html @@ -59,4 +59,4 @@ address.pubkey(), AccountSharedData::new(10 * LAMPORTS_PER_SOL, 0, &solana_sdk::system_program::ID), ); - The code above will generate a new random keypair. The set_account function will insert the specified AccountSharedData into the client and create a record in the corresponding AccountsStorage based on the entered account_id.

check()#

This method provides Invariant Check for the corresponding Instruction. Check Invariant Checks.

tx_error_handler()#

This method provides Tx Error Handler for the corresponding Instruction. Check Error Handler.

Example#

Tip

Consider checking the Examples section for more tips.

\ No newline at end of file + The code above will generate a new random keypair. The set_account function will insert the specified AccountSharedData into the client and create a record in the corresponding AccountsStorage based on the entered account_id.

check()#

This method provides Invariant Check for the corresponding Instruction. Check Invariant Checks.

tx_error_handler()#

This method provides Tx Error Handler for the corresponding Instruction. Check Error Handler.

Example#

Tip

Consider checking the Examples section for more tips.

\ No newline at end of file diff --git a/dev/features/fuzzing-statistics/index.html b/dev/features/fuzzing-statistics/index.html index 3c3323a4..a233c24f 100644 --- a/dev/features/fuzzing-statistics/index.html +++ b/dev/features/fuzzing-statistics/index.html @@ -2,4 +2,4 @@ # ... fuzzing_with_stats = true # ... -

Available Statistics#

Simple#

Note

Keep in mind that the number of fuzz iterations does not directly correspond to the total number of invocations. In one fuzz iteration, the fuzzer might be unable to deserialize fuzz data into instructions, causing the entire iteration to be skipped.

On the other hand this is expected behavior as the underlying data are randomly (with coverage feedback) generated, so the Honggfuzz will not necessarily find appropriate data each iteration.

Tip

Consider checking the Examples section for more tips.

\ No newline at end of file +

Available Statistics#

Simple#

Note

Keep in mind that the number of fuzz iterations does not directly correspond to the total number of invocations. In one fuzz iteration, the fuzzer might be unable to deserialize fuzz data into instructions, causing the entire iteration to be skipped.

On the other hand this is expected behavior as the underlying data are randomly (with coverage feedback) generated, so the Honggfuzz will not necessarily find appropriate data each iteration.

Tip

Consider checking the Examples section for more tips.

\ No newline at end of file diff --git a/dev/features/genesis-accounts/index.html b/dev/features/genesis-accounts/index.html index 617db380..80f96fed 100644 --- a/dev/features/genesis-accounts/index.html +++ b/dev/features/genesis-accounts/index.html @@ -33,4 +33,4 @@

Important

To include desired accounts in the fuzz testing environment, add then using the Trident.toml.

[[fuzz.accounts]]
 address = "6YG3J7PaxyMnnbU67ifyrgF3BzNzc7cD8hPkqK6ATweE"
 filename = "tests/accounts/core_bridge_mainnet/guardian_set_5_mock.json"
-

Tip

Consider checking the Examples section for more tips.

\ No newline at end of file +

Tip

Consider checking the Examples section for more tips.

\ No newline at end of file diff --git a/dev/features/instructions-sequences/index.html b/dev/features/instructions-sequences/index.html index ad48037f..f671b2e3 100644 --- a/dev/features/instructions-sequences/index.html +++ b/dev/features/instructions-sequences/index.html @@ -50,4 +50,4 @@ Ok(vec![]) } } -

Tip

Consider checking the Examples section for more tips.

\ No newline at end of file +

Tip

Consider checking the Examples section for more tips.

\ No newline at end of file diff --git a/dev/features/invariant-checks/index.html b/dev/features/invariant-checks/index.html index fc0f76a4..76f357d6 100644 --- a/dev/features/invariant-checks/index.html +++ b/dev/features/invariant-checks/index.html @@ -13,4 +13,4 @@ } Ok(()) } -

Important

Order of accounts within the array is the same as the order of accounts on the instruction input of your program.

Account Deserialization#

The SnapshotAccount provides methods to obtain parts of the account (e.g. address, its data, owner etc.). If you want to deserialize data into struct defined within your program (or within for example anchor-spl), you can use approach from source code above, meaning utilze try_deserialize generated by anchor within your program.

Tip

Consider checking the Examples section for more tips.

\ No newline at end of file +

Important

Order of accounts within the array is the same as the order of accounts on the instruction input of your program.

Account Deserialization#

The SnapshotAccount provides methods to obtain parts of the account (e.g. address, its data, owner etc.). If you want to deserialize data into struct defined within your program (or within for example anchor-spl), you can use approach from source code above, meaning utilze try_deserialize generated by anchor within your program.

Tip

Consider checking the Examples section for more tips.

\ No newline at end of file diff --git a/dev/features/lifecycle/index.html b/dev/features/lifecycle/index.html index 4721dd8a..8059ad85 100644 --- a/dev/features/lifecycle/index.html +++ b/dev/features/lifecycle/index.html @@ -1 +1 @@ - Fuzz Test Lifecycle - Trident
Skip to content

Fuzz Test Lifecycle#

In the sequence diagram below you can see a simplified fuzz test lifecycle.

Some diagram states are labeled with emojis:

  • âš¡ Mandatory methods that must be implemented by the user.
  • 👤 Optional methods that can be implemented by the user.

Lifecycle#

  1. The fuzzer is running until:
    1. The maximal number of iterations is reached (if specified).
    2. A crash was detected and the exit_upon_crash parameter was set.
    3. User interrupted the test manually (for example by hitting CTRL+C).
  2. In each iteration, the fuzzer generates a sequence of random instructions to execute.
    1. User can optionally customize how the instructions are generated and can specify the instructions that should be executed at the beginning (pre_ixs), in the middle (ixs) and at the end (post_ixs) of each iteration. This can be useful for example if your program needs an initialization or you want to fuzz some specific program state.
  3. For each instruction:
    1. User defined mandatory method get_accounts() is called to collect necessary instruction accounts.
    2. User defined mandatory method get_data() is called to collect instruction data.
    3. A snapshot of all instruction accounts before the instruction execution is saved.
    4. The instruction is executed.
    5. A snapshot of all instruction accounts after the instruction execution is saved.
    6. User defined optional method check() is called to check accounts data and evaluate invariants.
fuzzer_iterations = 0
fuzzer_iterations = 0
fuzzer_iterations < 
max_iterations
fuzzer_iterations <...
done
done
create pre-instruction 
accounts snapshots
create pre-instruction...
execute instruction
execute instruction
create post-instruction 
accounts snapshots
create post-instruction...
check invariants 👤
check invariants 👤
fuzzer_iterations++
fuzzer_iterations++
Generate instructions
pre_ixs 👤
pre_ixs 👤
ixs 👤
ixs 👤
post_ixs 👤
post_ixs 👤
end
end
for ix in instructions
for ix in instructions
get instruction accounts âš¡
get instruction accounts âš¡
get instruction data âš¡
get instruction data âš¡
next ix
next ix
Text is not SVG - cannot display
\ No newline at end of file + Fuzz Test Lifecycle - Trident
Skip to content

Fuzz Test Lifecycle#

In the sequence diagram below you can see a simplified fuzz test lifecycle.

Some diagram states are labeled with emojis:

  • âš¡ Mandatory methods that must be implemented by the user.
  • 👤 Optional methods that can be implemented by the user.

Lifecycle#

  1. The fuzzer is running until:
    1. The maximal number of iterations is reached (if specified).
    2. A crash was detected and the exit_upon_crash parameter was set.
    3. User interrupted the test manually (for example by hitting CTRL+C).
  2. In each iteration, the fuzzer generates a sequence of random instructions to execute.
    1. User can optionally customize how the instructions are generated and can specify the instructions that should be executed at the beginning (pre_ixs), in the middle (ixs) and at the end (post_ixs) of each iteration. This can be useful for example if your program needs an initialization or you want to fuzz some specific program state.
  3. For each instruction:
    1. User defined mandatory method get_accounts() is called to collect necessary instruction accounts.
    2. User defined mandatory method get_data() is called to collect instruction data.
    3. A snapshot of all instruction accounts before the instruction execution is saved.
    4. The instruction is executed.
    5. A snapshot of all instruction accounts after the instruction execution is saved.
    6. User defined optional method check() is called to check accounts data and evaluate invariants.
fuzzer_iterations = 0
fuzzer_iterations = 0
fuzzer_iterations < 
max_iterations
fuzzer_iterations <...
done
done
create pre-instruction 
accounts snapshots
create pre-instruction...
execute instruction
execute instruction
create post-instruction 
accounts snapshots
create post-instruction...
check invariants 👤
check invariants 👤
fuzzer_iterations++
fuzzer_iterations++
Generate instructions
pre_ixs 👤
pre_ixs 👤
ixs 👤
ixs 👤
post_ixs 👤
post_ixs 👤
end
end
for ix in instructions
for ix in instructions
get instruction accounts âš¡
get instruction accounts âš¡
get instruction data âš¡
get instruction data âš¡
next ix
next ix
Text is not SVG - cannot display
\ No newline at end of file diff --git a/dev/features/limitations/index.html b/dev/features/limitations/index.html index 258de697..f4027727 100644 --- a/dev/features/limitations/index.html +++ b/dev/features/limitations/index.html @@ -1 +1 @@ - Current limitations - Trident
Skip to content

Current limitations#

This section summarizes some known limitations in the current development stage. Further development will be focused on resolving these limitations.

  • Remaining accounts in check methods are not supported.
  • Composite accounts are not supported.
\ No newline at end of file + Current limitations - Trident
Skip to content

Current limitations#

This section summarizes some known limitations in the current development stage. Further development will be focused on resolving these limitations.

  • Remaining accounts in check methods are not supported.
  • Composite accounts are not supported.
\ No newline at end of file diff --git a/dev/features/trident-manifest/index.html b/dev/features/trident-manifest/index.html index 1b312b25..655e5c05 100644 --- a/dev/features/trident-manifest/index.html +++ b/dev/features/trident-manifest/index.html @@ -127,4 +127,4 @@ bytes_count = 20 ---- -->

Tip

Consider checking the Examples section for more tips.

\ No newline at end of file +--- -->

Tip

Consider checking the Examples section for more tips.

\ No newline at end of file diff --git a/dev/get-help/get-help/index.html b/dev/get-help/get-help/index.html index 475cb172..fe66b0d8 100644 --- a/dev/get-help/get-help/index.html +++ b/dev/get-help/get-help/index.html @@ -1 +1 @@ - Get Help - Trident
Skip to content

Get Help#

Need help writing Fuzz Tests? Do not hesitate to join our Discord server!

\ No newline at end of file + Get Help - Trident
Skip to content

Get Help#

Need help writing Fuzz Tests? Do not hesitate to join our Discord server!

\ No newline at end of file diff --git a/dev/index.html b/dev/index.html index 7e8313ce..dcc6c9f0 100644 --- a/dev/index.html +++ b/dev/index.html @@ -25,4 +25,4 @@ - **Instruction Accounts**: Explore the impact of different account states on the software's functionality, ensuring comprehensive account testing. - **Comprehensive Testing**: Conduct thorough and effective fuzz testing by combining any of the above aspects. - -->
\ No newline at end of file + -->
\ No newline at end of file diff --git a/dev/installation/installation/index.html b/dev/installation/installation/index.html index 34dd63e7..bf30e485 100644 --- a/dev/installation/installation/index.html +++ b/dev/installation/installation/index.html @@ -16,6 +16,6 @@

Install Trident#

cargo install trident-cli
-

Supported versions#

Trident CLI Anchor Solana Rust Honggfuzz
develop 0.30.1 ^1.17.4 nightly 0.5.56
0.8.0 0.30.1 ^1.17.4 nightly 0.5.56
0.7.0 >=0.29.*1 ^1.17.4 nightly 0.5.56
0.6.0 >=0.29.*1 ^1.17 nightly 0.5.55
0.5.0 ~0.28.* =1.16.6 - -
0.4.0 ~0.27.* >=1.15 - -
0.3.0 ~0.25.* >=1.10 - -
0.2.0 ~0.24.* >=1.9 - -
  1. To use Trident with Anchor 0.29.0, run the following commands from your project's root directory after Trident initialization:
    cargo update anchor-client@0.30.0 --precise 0.29.0
    +

    Supported versions#

    Trident CLI Anchor Solana Rust Honggfuzz
    develop 0.30.1 ^1.17.4 nightly 0.5.56
    0.8.* 0.30.1 ^1.17.4 nightly 0.5.56
    0.7.0 >=0.29.*1 ^1.17.4 nightly 0.5.56
    0.6.0 >=0.29.*1 ^1.17 nightly 0.5.55
    0.5.0 ~0.28.* =1.16.6 - -
    0.4.0 ~0.27.* >=1.15 - -
    0.3.0 ~0.25.* >=1.10 - -
    0.2.0 ~0.24.* >=1.9 - -
    1. To use Trident with Anchor 0.29.0, run the following commands from your project's root directory after Trident initialization:
      cargo update anchor-client@0.30.0 --precise 0.29.0
       cargo update anchor-spl@0.30.0 --precise 0.29.0
      -
    \ No newline at end of file +
\ No newline at end of file diff --git a/dev/search/search_index.json b/dev/search/search_index.json index e19966a9..9dfa8ec6 100644 --- a/dev/search/search_index.json +++ b/dev/search/search_index.json @@ -1 +1 @@ -{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"Home","text":"Trident

Rust-based Fuzzing framework for Solana programs to help you ship secure code.

"},{"location":"#what-is-fuzzing","title":"What is Fuzzing ?","text":"

\"Fuzz testing is an automated technique that provides generated random, invalid, or unexpected input data to your program. This helps discover unknown bugs and vulnerabilities, potentially preventing zero-day exploits.\"

"},{"location":"CHANGELOG/","title":"Changelog","text":"

All notable changes to this project will be documented in this file.

The format is based on Keep a Changelog, and this project adheres to Semantic Versioning (SemVer).

Note: Version 0 of Semantic Versioning is handled differently from version 1 and above. The minor version will be incremented upon a breaking change and the patch version will be incremented for features.

"},{"location":"CHANGELOG/#dev-unreleased","title":"[dev] - Unreleased","text":"

Removed

Changed

Added

"},{"location":"CHANGELOG/#080-2024-10-21","title":"[0.8.0] - 2024-10-21","text":"

Added

Changed

Removed

"},{"location":"CHANGELOG/#070-2024-08-14","title":"[0.7.0] - 2024-08-14","text":"

Added

Fixed

Removed

"},{"location":"CHANGELOG/#060-2024-05-20","title":"[0.6.0] - 2024-05-20","text":"

Added

Fixed

"},{"location":"CHANGELOG/#050-2023-08-28","title":"[0.5.0] - 2023-08-28","text":"

Added

"},{"location":"CHANGELOG/#041-2023-08-21","title":"[0.4.1] - 2023-08-21","text":"

Changed

Fixed

"},{"location":"CHANGELOG/#030-2022-09-23","title":"[0.3.0] - 2022-09-23","text":"

Changed

Added

"},{"location":"CHANGELOG/#020-2022-07-27","title":"[0.2.0] - 2022-07-27","text":"

Added

"},{"location":"commands/commands/","title":"Commands","text":""},{"location":"commands/commands/#trident-init","title":"trident init","text":""},{"location":"commands/commands/#trident-how","title":"trident how","text":""},{"location":"commands/commands/#trident-fuzz","title":"trident fuzz","text":""},{"location":"commands/commands/#trident-fuzz-run-hfuzz","title":"trident fuzz run-hfuzz","text":""},{"location":"commands/commands/#output","title":"Output","text":"

Important

The output provided by Honggfuzz is as follows:

  1. Number of Fuzzing Iterations.
  2. Feedback Driven Mode = Honggfuzz generates data based on the feedback (i.e. feedback based on Coverage progress).
  3. Average Iterations per second.
  4. Number of crashes it found (panics or failed invariant checks).
------------------------[  0 days 00 hrs 00 mins 01 secs ]----------------------\n  Iterations : 688 (out of: 1000 [68%]) # -- 1. --\n  Mode [3/3] : Feedback Driven Mode # -- 2. --\n      Target : trident-tests/fuzz_tests/fuzzing.....wn-linux-gnu/release/fuzz_0\n     Threads : 16, CPUs: 32, CPU%: 1262% [39%/CPU]\n       Speed : 680/sec [avg: 688] # -- 3. --\n     Crashes : 1 [unique: 1, blocklist: 0, verified: 0] # -- 4. --\n    Timeouts : 0 [10 sec]\n Corpus Size : 98, max: 1048576 bytes, init: 0 files\n  Cov Update : 0 days 00 hrs 00 mins 00 secs ago\n    Coverage : edge: 10345/882951 [1%] pc: 163 cmp: 622547\n---------------------------------- [ LOGS ] ------------------/ honggfuzz 2.6 /-\n
"},{"location":"commands/commands/#trident-fuzz-debug-hfuzz","title":"trident fuzz debug-hfuzz","text":""},{"location":"commands/commands/#output_1","title":"Output","text":"

Important

The debug output is at current development stage really verbose and contains lldb parts. We are working on improving this experience. In the picture below you can see an example of provided debug output.

  1. Series of Transaction Logs
  2. Structures of data send within the Instructions
  3. Panic or Crash, based on if the Fuzzing panicked within the Solana Program or Invariant Check failed.

"},{"location":"commands/commands/#trident-fuzz-add","title":"trident fuzz add","text":""},{"location":"commands/commands/#trident-clean","title":"trident clean","text":""},{"location":"examples/examples/","title":"Trident by Examples","text":""},{"location":"faq/faq/","title":"FAQ","text":""},{"location":"faq/faq/#is-trident-supported-only-with-anchor","title":"Is Trident supported only with Anchor ?","text":""},{"location":"faq/faq/#i-created-the-fuzz-test-what-should-i-do-next","title":"I created the Fuzz Test what should I do next ?","text":""},{"location":"faq/faq/#my-program-instruction-contains-custom-type-such-as-struct-or-enum-on-its-input-but-it-does-not-derive-arbitrary","title":"My program Instruction contains custom type such as Struct or Enum on its input, but it does not derive Arbitrary.","text":""},{"location":"faq/faq/#is-trident-open-source","title":"Is Trident open-source ?","text":""},{"location":"faq/faq/#i-would-like-to-report-issue-with-trident-what-should-i-do","title":"I would like to report Issue with Trident, what should I do ?","text":""},{"location":"faq/faq/#is-trident-deployed-on-mainnet-devnet-testenet","title":"Is Trident deployed on Mainnet / Devnet / Testenet ?","text":""},{"location":"faq/faq/#what-type-of-fuzzer-trident-is","title":"What type of Fuzzer Trident is ?","text":""},{"location":"features/account-storages/","title":"Account Storages","text":"

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:

Then use the corresponding AccountsStorage.

pub struct FuzzAccounts {\n    signer: AccountsStorage<KeypairStore>,\n    some_pda: AccountsStorage<PdaStore>,\n    token_vault: AccountsStorage<TokenStore>,\n    mint: AccountsStorage<MintStore>,\n    // ...\n}\n

Tip

Keep in mind:

Tip

Consider checking the Examples section for more tips.

"},{"location":"features/arbitrary-data/","title":"Arbitrary Data","text":"

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.

#[derive(Arbitrary, Debug)]\npub struct InitVestingData {\n    pub recipient: AccountId,\n    #[arbitrary(\n        with = |u: &mut arbitrary::Unstructured| u.int_in_range(1..=1_000_000)\n    )]\n    pub amount: u64,\n    // we want start_at smaller than end_at\n    // and for testing purposes we can run tests with times from the past\n    #[arbitrary(\n        with = |u: &mut arbitrary::Unstructured| u.int_in_range(0..=1_000_000)\n    )]\n    pub start_at: u64,\n    #[arbitrary(\n        with = |u: &mut arbitrary::Unstructured| u.int_in_range(1_001_001..=1_050_000)\n    )]\n    pub end_at: u64,\n    #[arbitrary(\n        with = |u: &mut arbitrary::Unstructured| u.int_in_range(1..=1000)\n    )]\n    pub interval: u64,\n}\n
"},{"location":"features/arbitrary-data/#implement-arbitrary","title":"Implement Arbitrary","text":"

There are macros available to use with Arbitrary, however, it is possible to Implement the arbitrary function by yourself.

// -------------------------------------------------------------------\n// -------------------------------------------------------------------\n// Implement Arbitrary\nimpl<'a> Arbitrary<'a> for InitVestingData {\n    fn arbitrary(\n        u: &mut arbitrary::Unstructured<'a>\n    ) -> arbitrary::Result<Self> {\n        // obtain AccountId\n        let recipient = AccountId::arbitrary(u)?;\n\n        // limit the generated amount to the 1_000_000\n        let amount = u.int_in_range(1..=1_000_000)?;\n\n        // now we want to obtain\n        // - start_at\n        // - end_at\n        // - interval\n        // however we want to limit the data such that:\n        // - start_at < end_at\n        // - end_at - start_at > interval\n        // - interval has lower limit of 500 and upper limit of 1000.\n\n        let start_at: u64 = u.int_in_range(1_000_000..=5_000_000)?;\n        let end_at: u64 = u.int_in_range(1_000_000..=5_000_000)?;\n        let interval: u64 = u.int_in_range(500..=1000)?;\n\n        // ensure that start_at < end_at\n        if start_at >= end_at {\n            return Err(arbitrary::Error::IncorrectFormat);\n        }\n\n        // ensure that end_at - start_at > interval\n        match end_at.checked_sub(start_at) {\n            Some(diff) => {\n                if diff <= interval {\n                    return Err(arbitrary::Error::IncorrectFormat);\n                }\n            }\n            None => return Err(arbitrary::Error::IncorrectFormat),\n        }\n\n        Ok(InitVestingData {\n            recipient,\n            amount,\n            start_at,\n            end_at,\n            interval,\n        })\n    }\n    // -------------------------------------------------------------------\n    // -------------------------------------------------------------------\n}\n

Tip

Consider checking the Examples section for more tips.

"},{"location":"features/error-handlers/","title":"Error Handler","text":"

Trident allows you to specify custom error handler for each Instruction.

This can be particularly helpful:

Tip

The default behavior of the function is that the error is returned.

/// default implementation\nfn tx_error_handler(\n    &self,\n    e: FuzzClientErrorWithOrigin,\n    ix_data: Self::IxData,\n    pre_ix_acc_infos: &[SnapshotAccount],,\n) -> Result<(), FuzzClientErrorWithOrigin> {\n    Err(e)\n}\n

To omit the Error and continue with the next Instruction in the iteration, you can do

/// default implementation\nfn tx_error_handler(\n    &self,\n    e: FuzzClientErrorWithOrigin,\n    ix_data: Self::IxData,\n    pre_ix_acc_infos: &'info mut [Option<AccountInfo<'info>>],\n) -> Result<(), FuzzClientErrorWithOrigin> {\n    Ok(())\n}\n
"},{"location":"features/features/","title":"Trident Features","text":"

Trident contains multiple features to enhance the fuzzing experience and increase ability to discover bugs.

"},{"location":"features/fuzz-instructions/","title":"Fuzz Instructions","text":"

Trident defines FuzzInstruction enum containing all available Instructions within your program.

The enum variants additionally contains their corresponding structures for Accounts and Input arguments.

#[derive(Arbitrary, DisplayIx, FuzzTestExecutor, FuzzDeserialize)]\npub enum FuzzInstruction {\n    Initialize(Initialize),\n    Update(Update),\n}\n#[derive(Arbitrary, Debug)]\npub struct Initialize {\n    pub accounts: InitializeAccounts,\n    pub data: InitializeData,\n}\n#[derive(Arbitrary, Debug)]\npub struct Update {\n    pub accounts: UpdateAccounts,\n    pub data: UpdateData,\n}\n// ...\n
"},{"location":"features/fuzz-instructions/#instruction-behavior","title":"Instruction behavior","text":"

Each Instruction variant has to define IxOps trait containing the following methods:

"},{"location":"features/fuzz-instructions/#get_program_id","title":"get_program_id()","text":"

This method specifies program ID to which the Instruction corresponds.

In case you have only one program in the Anchor Workspace it is not really important. The importance occurs when you have multiple programs in the Workspace and you want to call Instructions of every Program. In that case each Instruction Variant corresponds to its program by the Program ID.

"},{"location":"features/fuzz-instructions/#get_data","title":"get_data()","text":"

This method specifies what the Instruction Input Data should look like. You can use completely random data generated by the fuzzer, such as:

fn get_data(\n    &self,\n    _client: &mut impl FuzzClient,\n    _fuzz_accounts: &mut FuzzAccounts,\n) -> Result<Self::IxData, FuzzingError> {\n    let data = hello_world::instruction::InitializeFn {\n        input: self.data.input,\n    };\n    Ok(data)\n}\n

You can also use always constant values

fn get_data(\n    &self,\n    _client: &mut impl FuzzClient,\n    _fuzz_accounts: &mut FuzzAccounts,\n) -> Result<Self::IxData, FuzzingError> {\n    let data = hello_world::instruction::InitializeFn {\n        input: 5,\n    };\n    Ok(data)\n}\n

Or you can customize the Data using the Arbitrary crate. Check Arbitrary Data.

"},{"location":"features/fuzz-instructions/#custom-data-types","title":"Custom Data Types","text":"

If you use Custom Types as Instruction data arguments, you may encounter a problem that the Custom Type does not implement

"},{"location":"features/fuzz-instructions/#derive-debug-and-arbitrary-traits-inside-the-fuzz-test","title":"Derive Debug and Arbitrary traits inside the Fuzz Test","text":"

You can redefine the custom type within the fuzz_instructions.rs file, along with all the necessary traits.

// Redefine the Custom Type inside the fuzz_instructions.rs,\n// but this time with all of the required traits.\n#[derive(Arbitrary,Debug, Clone, Copy)]\npub enum CustomEnumInputFuzz {\n    InputVariant1,\n    InputVariant2,\n    InputVariant3,\n}\n

Then, you would also need to implement the std::convert::From<T> trait to enable conversion between the newly defined Custom Type and the Custom Type used within your program.

Tip

Consider checking the Examples section for more tips.

"},{"location":"features/fuzz-instructions/#get_accounts","title":"get_accounts()","text":"

This method specifies how the Accounts for the corresponding Instruction should be resolved. You can use accounts stored within the FuzzAccounts Account Storages, or you can define custom Account using the client.

There are two main functions to use within the get_accounts():

"},{"location":"features/fuzz-instructions/#get_or_create_account","title":"get_or_create_account()","text":"

Insert a new record into AccountsStorage based on the account_id. If a record with the entered account_id already exists, it is returned, and no insertion is performed.

Tip

Example:

let hello_world_account = fuzz_accounts.hello_world_account.get_or_create_account(\n    self.accounts.hello_world_account,\n    client,\n    &[b\"hello_world_seed\"],\n    &hello_world::ID,\n);\n
The code above will return the PDA from hello_world's AccountsStorage if a record for the entered account_id exists. If not, the function will create a new record corresponding to the PDA derived from the provided seeds and return the PDA.

"},{"location":"features/fuzz-instructions/#get","title":"get()","text":"

Retrieves a record from AccountsStorage based on the entered account_id. If no record exists for the account_id, a random public key is returned.

Tip

let hello_world_account = fuzz_accounts\n        .hello_world_account\n        .get(self.accounts.hello_world_account);\n
The code above will return the PDA from hello_world's AccountsStorage if a record for the entered account_id exists. If not, the function will return a random public key.

"},{"location":"features/fuzz-instructions/#set_custom","title":"set_custom()","text":"

If the previous two functions are insufficient, you can use set_custom() to manually set an account with data you select. This function accepts account_id, which specifies the record in the corresponding AccountsStorage; client, which handles the insertion of AccountSharedData; the account's address (particularly helpful if a predefined address is needed); and AccountSharedData, which you can configure as needed.

Tip

Example:\n

let address = Keypair::new();\nfuzz_accounts.hello_world_account.set_custom(\n    self.accounts.hello_world_account,\n    client,\n    address.pubkey(),\n    AccountSharedData::new(10 * LAMPORTS_PER_SOL, 0, &solana_sdk::system_program::ID),\n);\n
The code above will generate a new random keypair. The set_account function will insert the specified AccountSharedData into the client and create a record in the corresponding AccountsStorage based on the entered account_id.

"},{"location":"features/fuzz-instructions/#check","title":"check()","text":"

This method provides Invariant Check for the corresponding Instruction. Check Invariant Checks.

"},{"location":"features/fuzz-instructions/#tx_error_handler","title":"tx_error_handler()","text":"

This method provides Tx Error Handler for the corresponding Instruction. Check Error Handler.

"},{"location":"features/fuzz-instructions/#example","title":"Example","text":"

Tip

Consider checking the Examples section for more tips.

"},{"location":"features/fuzzing-statistics/","title":"Fuzzing Statistics","text":"

Trident allows you to see statistics after the fuzzing session ended.

Important

In order to show statistics set fuzzing_with_stats within the Trident.toml to true.

[fuzz]\n# ...\nfuzzing_with_stats = true\n# ...\n
"},{"location":"features/fuzzing-statistics/#available-statistics","title":"Available Statistics","text":""},{"location":"features/fuzzing-statistics/#simple","title":"Simple","text":" Note

Keep in mind that the number of fuzz iterations does not directly correspond to the total number of invocations. In one fuzz iteration, the fuzzer might be unable to deserialize fuzz data into instructions, causing the entire iteration to be skipped.

On the other hand this is expected behavior as the underlying data are randomly (with coverage feedback) generated, so the Honggfuzz will not necessarily find appropriate data each iteration.

Tip

Consider checking the Examples section for more tips.

"},{"location":"features/genesis-accounts/","title":"Genesis","text":""},{"location":"features/genesis-accounts/#genesis-programs","title":"Genesis Programs","text":"

Trident allows you to use Cross Program Invocation of both Native and SBF programs.

"},{"location":"features/genesis-accounts/#native","title":"Native","text":"

In case of multiple programs within the Anchor Workspace. Make sure that all of the programs you would like to call Cross Program Invocation to are included in the initial state of the Fuzz Test Environment.

Important

Source code below:

// test_fuzz.rs\n\nfn fuzz_iteration<T: FuzzTestExecutor<U> + std::fmt::Display, U>(\n    fuzz_data: FuzzData<T, U>\n) {\n    let fuzzing_program_callee = FuzzingProgram::new(\n        PROGRAM_NAME_CALLEE,\n        &PROGRAM_ID_CALLEE,\n        processor!(convert_entry!(entry_callee)),\n    );\n\n    let fuzzing_program_caller = FuzzingProgram::new(\n        PROGRAM_NAME_CALLER,\n        &PROGRAM_ID_CALLER,\n        processor!(convert_entry!(entry_caller)),\n    );\n\n    let mut client =\n        ProgramTestClientBlocking::new(\n            &[fuzzing_program_callee, fuzzing_program_caller],\n            &[]\n        ).unwrap();\n\n    let _ = fuzz_data.run_with_runtime(&mut client);\n}\n
"},{"location":"features/genesis-accounts/#sbf","title":"SBF","text":"

In case of SBF targets, compiled or dumped from whatever cluster. You can also use these within the Fuzz Tests.

Tip

If you want to obtain Program from Mainnet use

# -u m specifies to dump from mainnet\nsolana program dump -u m <PROGRAM_ID> <PROGRAM_NAME>.so\n

Important

[[fuzz.programs]]\naddress = \"metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s\"\nprogram = \"metaplex-program/metaplex-token-metadata.so\"\n
"},{"location":"features/genesis-accounts/#genesis-accounts","title":"Genesis Accounts","text":"

Trident allows you to include Accounts with data in base64 format.

Tip

If you want to obtain Account with base64 data format, use

# -u m specifies to dump from mainnet\nsolana account -u m <ADDRESS> --output json\n

Important

To include desired accounts in the fuzz testing environment, add then using the Trident.toml.

[[fuzz.accounts]]\naddress = \"6YG3J7PaxyMnnbU67ifyrgF3BzNzc7cD8hPkqK6ATweE\"\nfilename = \"tests/accounts/core_bridge_mainnet/guardian_set_5_mock.json\"\n

Tip

Consider checking the Examples section for more tips.

"},{"location":"features/instructions-sequences/","title":"Instructions Sequences","text":"

Trident allows you to specify custom Instruction squences you would like to execute.

Possible Instruction sequences are split into 3 parts

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.

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

Tip

"},{"location":"features/instructions-sequences/#manual-trait-override","title":"Manual trait override","text":"

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.

// test_fuzz.rs\n\n// do not forget to include the required structures\nuse fuzz_instructions::InitVesting;\nuse fuzz_instructions::WithdrawUnlocked;\n\nimpl FuzzDataBuilder<FuzzInstruction> for MyFuzzData {\n    fn pre_ixs(\n        u: &mut arbitrary::Unstructured\n    ) -> arbitrary::Result<Vec<FuzzInstruction>> {\n        let init_ix =\n            FuzzInstruction::InitVesting(InitVesting::arbitrary(u)?);\n\n        Ok(vec![init_ix])\n    }\n    fn ixs(\n        u: &mut arbitrary::Unstructured\n    ) -> arbitrary::Result<Vec<FuzzInstruction>> {\n        let withdraw_ix =\n            FuzzInstruction::WithdrawUnlocked(WithdrawUnlocked::arbitrary(u)?);\n\n        Ok(vec![withdraw_ix])\n    }\n    fn post_ixs(\n        _u: &mut arbitrary::Unstructured\n    ) -> arbitrary::Result<Vec<FuzzInstruction>> {\n        Ok(vec![])\n    }\n}\n

Tip

Consider checking the Examples section for more tips.

"},{"location":"features/invariant-checks/","title":"Invariant Checks","text":"

Trident allows you to (optionally) specify Invariant Checks for each Instruction.

The Invariant Check will be called after the Instruction was successfully invoked. Within the Invariant Check you can compare the contents of Accounts before and after the Instruction was called.

Important

Returning error in the Invariant Check is considered as detected undesired behavior (i.e. issue/crash detected).

fn check(\n    &self,\n    _pre_ix: &[SnapshotAccount],\n    post_ix: &[SnapshotAccount],\n    _ix_data: Self::IxData,\n) -> Result<(), FuzzingError> {\n    if let Ok(hello_world_account) =\n        hello_world::StoreHelloWorld::try_deserialize(&mut post_ix[1].data())\n    {\n        if hello_world_account.input == 253 {\n            return Err(FuzzingError::Custom(1));\n        }\n    }\n    Ok(())\n}\n

Important

Order of accounts within the array is the same as the order of accounts on the instruction input of your program.

"},{"location":"features/invariant-checks/#account-deserialization","title":"Account Deserialization","text":"

The SnapshotAccount provides methods to obtain parts of the account (e.g. address, its data, owner etc.). If you want to deserialize data into struct defined within your program (or within for example anchor-spl), you can use approach from source code above, meaning utilze try_deserialize generated by anchor within your program.

Tip

Consider checking the Examples section for more tips.

"},{"location":"features/lifecycle/","title":"Fuzz Test Lifecycle","text":"

In the sequence diagram below you can see a simplified fuzz test lifecycle.

Some diagram states are labeled with emojis:

"},{"location":"features/lifecycle/#lifecycle","title":"Lifecycle","text":"
  1. The fuzzer is running until:
    1. The maximal number of iterations is reached (if specified).
    2. A crash was detected and the exit_upon_crash parameter was set.
    3. User interrupted the test manually (for example by hitting CTRL+C).
  2. In each iteration, the fuzzer generates a sequence of random instructions to execute.
    1. User can optionally customize how the instructions are generated and can specify the instructions that should be executed at the beginning (pre_ixs), in the middle (ixs) and at the end (post_ixs) of each iteration. This can be useful for example if your program needs an initialization or you want to fuzz some specific program state.
  3. For each instruction:
    1. User defined mandatory method get_accounts() is called to collect necessary instruction accounts.
    2. User defined mandatory method get_data() is called to collect instruction data.
    3. A snapshot of all instruction accounts before the instruction execution is saved.
    4. The instruction is executed.
    5. A snapshot of all instruction accounts after the instruction execution is saved.
    6. User defined optional method check() is called to check accounts data and evaluate invariants.
fuzzer_iterations = 0fuzzer_iterations = 0fuzzer_iterations <\u00a0max_iterationsfuzzer_iterations <...donedonecreate pre-instruction\u00a0accounts snapshotscreate pre-instruction...execute instructionexecute instructioncreate post-instruction\u00a0accounts snapshotscreate post-instruction...check invariants \ud83d\udc64check invariants \ud83d\udc64fuzzer_iterations++fuzzer_iterations++Generate instructionspre_ixs \ud83d\udc64pre_ixs \ud83d\udc64ixs \ud83d\udc64ixs \ud83d\udc64post_ixs \ud83d\udc64post_ixs \ud83d\udc64endendfor ix in instructionsfor ix in instructionsget instruction accounts \u26a1get instruction accounts \u26a1get instruction data \u26a1get instruction data \u26a1next ixnext ixText is not SVG - cannot display"},{"location":"features/limitations/","title":"Current limitations","text":"

This section summarizes some known limitations in the current development stage. Further development will be focused on resolving these limitations.

"},{"location":"features/trident-manifest/","title":"Trident Manifest","text":"

You can pass supported parameters via the Trident.toml configuration file:

"},{"location":"features/trident-manifest/#fuzz","title":"[fuzz]","text":""},{"location":"features/trident-manifest/#programs","title":"programs","text":"
[[fuzz.programs]]\naddress = \"metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s\"\nprogram = \"metaplex-program/metaplex-token-metadata.so\"\n
"},{"location":"features/trident-manifest/#accounts","title":"accounts","text":"
[[fuzz.accounts]]\naddress = \"6YG3J7PaxyMnnbU67ifyrgF3BzNzc7cD8hPkqK6ATweE\"\nfilename = \"tests/accounts/core_bridge_mainnet/guardian_set_5_mock.json\"\n
"},{"location":"features/trident-manifest/#allow_duplicate_txs","title":"allow_duplicate_txs","text":"
[fuzz]\n# Allow processing of duplicate transactions.\n# Setting to true might speed up fuzzing but can cause\n# false positive crashes (default: false)\nallow_duplicate_txs = false\n
"},{"location":"features/trident-manifest/#fuzzing_with_stats","title":"fuzzing_with_stats","text":"
[fuzz]\n# Trident will show statistics after the fuzzing session.\n# This option forces use of honggfuzz parameter\n# `keep_output` as true in order to be able to catch fuzzer stdout.\n# (default: false)\nfuzzing_with_stats = true\n
"},{"location":"features/trident-manifest/#honggfuzz","title":"[honggfuzz]","text":""},{"location":"features/trident-manifest/#timeout","title":"timeout","text":"
[honggfuzz]\n# Timeout in seconds (default: 10)\ntimeout = 10\n
"},{"location":"features/trident-manifest/#iterations","title":"iterations","text":"
[honggfuzz]\n# Number of fuzzing iterations (default: 0 [no limit])\niterations = 0\n
"},{"location":"features/trident-manifest/#threads","title":"threads","text":"
[honggfuzz]\n# Number of concurrent fuzzing threads (default: 0 [number of CPUs / 2])\nthreads = 0\n
"},{"location":"features/trident-manifest/#keep_output","title":"keep_output","text":"
[honggfuzz]\n# Don't close children's stdin, stdout, stderr; can be noisy (default: false)\nkeep_output = false\n
"},{"location":"features/trident-manifest/#verbose","title":"verbose","text":"
[honggfuzz]\n# Disable ANSI console; use simple log output (default: false)\nverbose = false\n
"},{"location":"features/trident-manifest/#exit_upon_crash","title":"exit_upon_crash","text":"
[honggfuzz]\n# Exit upon seeing the first crash (default: false)\nexit_upon_crash = false\n
"},{"location":"features/trident-manifest/#mutations_per_run","title":"mutations_per_run","text":"
[honggfuzz]\n# Maximal number of mutations per one run (default: 6)\nmutations_per_run = 6\n
"},{"location":"features/trident-manifest/#cargo_target_dir","title":"cargo_target_dir","text":"
[honggfuzz]\n# Target compilation directory,\n# (default: \"\" [\"trident-tests/fuzz_tests/fuzzing/honggfuzz/hfuzz_target\"]).\n# To not clash with cargo build's default target directory.\ncargo_target_dir = \"\"\n
"},{"location":"features/trident-manifest/#hfuzz_workspace","title":"hfuzz_workspace","text":"
[honggfuzz]\n# Honggfuzz working directory,\n# (default: \"\" [\"trident-tests/fuzz_tests/fuzzing/honggfuzz/hfuzz_workspace\"]).\nhfuzz_workspace = \"\"\n
"},{"location":"features/trident-manifest/#crashdir","title":"crashdir","text":"
[honggfuzz]\n# Directory where crashes are saved to (default: \"\" [workspace directory])\ncrashdir = \"\"\n
"},{"location":"features/trident-manifest/#extension","title":"extension","text":"
[honggfuzz]\n# Input file extension (e.g. 'swf'), (default: \"\" ['fuzz'])\nextension = \"\"\n
"},{"location":"features/trident-manifest/#run_time","title":"run_time","text":"
[honggfuzz]\n# Number of seconds this fuzzing session will last (default: 0 [no limit])\nrun_time = 0\n
"},{"location":"features/trident-manifest/#max_file_size","title":"max_file_size","text":"
[honggfuzz]\n# Maximal size of files processed by the fuzzer in bytes\n# (default: 1048576 = 1MB)\nmax_file_size = 1048576\n
"},{"location":"features/trident-manifest/#save_all","title":"save_all","text":"
[honggfuzz]\n# Save all test-cases\n# (not only the unique ones) by appending the current\n# time-stamp to the filename (default: false)\nsave_all = false\n

Tip

Consider checking the Examples section for more tips.

"},{"location":"get-help/get-help/","title":"Get Help","text":"

Need help writing Fuzz Tests? Do not hesitate to join our Discord server!

"},{"location":"installation/installation/","title":"Installation","text":"

Important

Prerequisite

It is expected that you have installed:

For supported versions check the Supported Versions

"},{"location":"installation/installation/#install-system-dependencies","title":"Install System Dependencies","text":"

Update your package list and install the required packages:

sudo apt-get update\nsudo apt-get install -y \\\n    curl \\\n    git \\\n    build-essential \\\n    pkg-config \\\n    libssl-dev \\\n    npm \\\n    vim \\\n    nano \\\n    wget \\\n    binutils-dev \\\n    libunwind-dev \\\n    lldb\n
"},{"location":"installation/installation/#install-hongfuzz","title":"Install Hongfuzz","text":"

Install honggfuzz

cargo install honggfuzz\n
"},{"location":"installation/installation/#install-trident","title":"Install Trident","text":"
cargo install trident-cli\n
"},{"location":"installation/installation/#supported-versions","title":"Supported versions","text":"Trident CLI Anchor Solana Rust Honggfuzz develop 0.30.1 ^1.17.4 nightly 0.5.56 0.8.0 0.30.1 ^1.17.4 nightly 0.5.56 0.7.0 >=0.29.*1 ^1.17.4 nightly 0.5.56 0.6.0 >=0.29.*1 ^1.17 nightly 0.5.55 0.5.0 ~0.28.* =1.16.6 - - 0.4.0 ~0.27.* >=1.15 - - 0.3.0 ~0.25.* >=1.10 - - 0.2.0 ~0.24.* >=1.9 - -
  1. To use Trident with Anchor 0.29.0, run the following commands from your project's root directory after Trident initialization:
    cargo update anchor-client@0.30.0 --precise 0.29.0\ncargo update anchor-spl@0.30.0 --precise 0.29.0\n
"},{"location":"writing-fuzz-test/writing-fuzz-test/","title":"Writing fuzz test","text":""},{"location":"writing-fuzz-test/writing-fuzz-test/#initialize-trident","title":"Initialize Trident","text":"

Initialize Trident in the Anchor-based workspace.

trident init\n

Info

Trident under the hood

Tip

If you have Trident already initialized, you can add new fuzz test using trident fuzz add.

"},{"location":"writing-fuzz-test/writing-fuzz-test/#fill-the-fuzz-test-template","title":"Fill the Fuzz test Template","text":""},{"location":"writing-fuzz-test/writing-fuzz-test/#define-fuzz-accounts","title":"Define Fuzz Accounts","text":"

Define AccountsStorage type for each Account you would like to use.

Important

Keep in mind:

#[doc = r\" Use AccountsStorage<T> where T can be one of:\"]\n#[doc = r\" Keypair, PdaStore, TokenStore, MintStore, ProgramStore\"]\n#[derive(Default)]\npub struct FuzzAccounts {\n    author: AccountsStorage<Keypair>,\n    hello_world_account: AccountsStorage<PdaStore>,\n    // No need to fuzz system_program\n    // system_program: AccountsStorage<todo!()>,\n}\n

Tip

For more details about the AccountsStorage check AccountsStorage.

"},{"location":"writing-fuzz-test/writing-fuzz-test/#implement-fuzz-instructions","title":"Implement Fuzz Instructions","text":"

Each Instruction in the Fuzz Test has to have defined the following functions:

Tip

"},{"location":"writing-fuzz-test/writing-fuzz-test/#execute","title":"Execute","text":""},{"location":"writing-fuzz-test/writing-fuzz-test/#run-fuzz-test","title":"Run Fuzz Test","text":"

To execute the desired fuzz test using the Honggfuzz, run:

# Replace <TARGET_NAME> with the name of particular\n# fuzz test (for example: \"fuzz_0\")\ntrident fuzz run-hfuzz <TARGET_NAME>\n
"},{"location":"writing-fuzz-test/writing-fuzz-test/#debug-fuzz-test","title":"Debug Fuzz Test","text":"

To debug your program using Honggfuzz with values from a crash file:

# fuzzer will run the <TARGET_NAME> with the specified <CRASH_FILE_PATH>\ntrident fuzz debug-hfuzz <TARGET_NAME> <CRASH_FILE_PATH>\n

Tip

By default, the crashfiles are stored in the

Tip

For more info about the fuzzing outputs chech the Commands

"}]} \ No newline at end of file +{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"Home","text":"Trident

Rust-based Fuzzing framework for Solana programs to help you ship secure code.

"},{"location":"#what-is-fuzzing","title":"What is Fuzzing ?","text":"

\"Fuzz testing is an automated technique that provides generated random, invalid, or unexpected input data to your program. This helps discover unknown bugs and vulnerabilities, potentially preventing zero-day exploits.\"

"},{"location":"CHANGELOG/","title":"Changelog","text":"

All notable changes to this project will be documented in this file.

The format is based on Keep a Changelog, and this project adheres to Semantic Versioning (SemVer).

Note: Version 0 of Semantic Versioning is handled differently from version 1 and above. The minor version will be incremented upon a breaking change and the patch version will be incremented for features.

"},{"location":"CHANGELOG/#dev-unreleased","title":"[dev] - Unreleased","text":""},{"location":"CHANGELOG/#081-2024-11-14","title":"[0.8.1] - 2024-11-14","text":"

Removed

Changed

Added

"},{"location":"CHANGELOG/#080-2024-10-21","title":"[0.8.0] - 2024-10-21","text":"

Added

Changed

Removed

"},{"location":"CHANGELOG/#070-2024-08-14","title":"[0.7.0] - 2024-08-14","text":"

Added

Fixed

Removed

"},{"location":"CHANGELOG/#060-2024-05-20","title":"[0.6.0] - 2024-05-20","text":"

Added

Fixed

"},{"location":"CHANGELOG/#050-2023-08-28","title":"[0.5.0] - 2023-08-28","text":"

Added

"},{"location":"CHANGELOG/#041-2023-08-21","title":"[0.4.1] - 2023-08-21","text":"

Changed

Fixed

"},{"location":"CHANGELOG/#030-2022-09-23","title":"[0.3.0] - 2022-09-23","text":"

Changed

Added

"},{"location":"CHANGELOG/#020-2022-07-27","title":"[0.2.0] - 2022-07-27","text":"

Added

"},{"location":"commands/commands/","title":"Commands","text":""},{"location":"commands/commands/#trident-init","title":"trident init","text":""},{"location":"commands/commands/#trident-how","title":"trident how","text":""},{"location":"commands/commands/#trident-fuzz","title":"trident fuzz","text":""},{"location":"commands/commands/#trident-fuzz-run-hfuzz","title":"trident fuzz run-hfuzz","text":""},{"location":"commands/commands/#output","title":"Output","text":"

Important

The output provided by Honggfuzz is as follows:

  1. Number of Fuzzing Iterations.
  2. Feedback Driven Mode = Honggfuzz generates data based on the feedback (i.e. feedback based on Coverage progress).
  3. Average Iterations per second.
  4. Number of crashes it found (panics or failed invariant checks).
------------------------[  0 days 00 hrs 00 mins 01 secs ]----------------------\n  Iterations : 688 (out of: 1000 [68%]) # -- 1. --\n  Mode [3/3] : Feedback Driven Mode # -- 2. --\n      Target : trident-tests/fuzz_tests/fuzzing.....wn-linux-gnu/release/fuzz_0\n     Threads : 16, CPUs: 32, CPU%: 1262% [39%/CPU]\n       Speed : 680/sec [avg: 688] # -- 3. --\n     Crashes : 1 [unique: 1, blocklist: 0, verified: 0] # -- 4. --\n    Timeouts : 0 [10 sec]\n Corpus Size : 98, max: 1048576 bytes, init: 0 files\n  Cov Update : 0 days 00 hrs 00 mins 00 secs ago\n    Coverage : edge: 10345/882951 [1%] pc: 163 cmp: 622547\n---------------------------------- [ LOGS ] ------------------/ honggfuzz 2.6 /-\n
"},{"location":"commands/commands/#trident-fuzz-debug-hfuzz","title":"trident fuzz debug-hfuzz","text":""},{"location":"commands/commands/#output_1","title":"Output","text":"

Important

The debug output is at current development stage really verbose and contains lldb parts. We are working on improving this experience. In the picture below you can see an example of provided debug output.

  1. Series of Transaction Logs
  2. Structures of data send within the Instructions
  3. Panic or Crash, based on if the Fuzzing panicked within the Solana Program or Invariant Check failed.

"},{"location":"commands/commands/#trident-fuzz-add","title":"trident fuzz add","text":""},{"location":"commands/commands/#trident-clean","title":"trident clean","text":""},{"location":"examples/examples/","title":"Trident by Examples","text":""},{"location":"faq/faq/","title":"FAQ","text":""},{"location":"faq/faq/#is-trident-supported-only-with-anchor","title":"Is Trident supported only with Anchor ?","text":""},{"location":"faq/faq/#i-created-the-fuzz-test-what-should-i-do-next","title":"I created the Fuzz Test what should I do next ?","text":""},{"location":"faq/faq/#my-program-instruction-contains-custom-type-such-as-struct-or-enum-on-its-input-but-it-does-not-derive-arbitrary","title":"My program Instruction contains custom type such as Struct or Enum on its input, but it does not derive Arbitrary.","text":""},{"location":"faq/faq/#is-trident-open-source","title":"Is Trident open-source ?","text":""},{"location":"faq/faq/#i-would-like-to-report-issue-with-trident-what-should-i-do","title":"I would like to report Issue with Trident, what should I do ?","text":""},{"location":"faq/faq/#is-trident-deployed-on-mainnet-devnet-testenet","title":"Is Trident deployed on Mainnet / Devnet / Testenet ?","text":""},{"location":"faq/faq/#what-type-of-fuzzer-trident-is","title":"What type of Fuzzer Trident is ?","text":""},{"location":"features/account-storages/","title":"Account Storages","text":"

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:

Then use the corresponding AccountsStorage.

pub struct FuzzAccounts {\n    signer: AccountsStorage<KeypairStore>,\n    some_pda: AccountsStorage<PdaStore>,\n    token_vault: AccountsStorage<TokenStore>,\n    mint: AccountsStorage<MintStore>,\n    // ...\n}\n

Tip

Keep in mind:

Tip

Consider checking the Examples section for more tips.

"},{"location":"features/arbitrary-data/","title":"Arbitrary Data","text":"

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.

#[derive(Arbitrary, Debug)]\npub struct InitVestingData {\n    pub recipient: AccountId,\n    #[arbitrary(\n        with = |u: &mut arbitrary::Unstructured| u.int_in_range(1..=1_000_000)\n    )]\n    pub amount: u64,\n    // we want start_at smaller than end_at\n    // and for testing purposes we can run tests with times from the past\n    #[arbitrary(\n        with = |u: &mut arbitrary::Unstructured| u.int_in_range(0..=1_000_000)\n    )]\n    pub start_at: u64,\n    #[arbitrary(\n        with = |u: &mut arbitrary::Unstructured| u.int_in_range(1_001_001..=1_050_000)\n    )]\n    pub end_at: u64,\n    #[arbitrary(\n        with = |u: &mut arbitrary::Unstructured| u.int_in_range(1..=1000)\n    )]\n    pub interval: u64,\n}\n
"},{"location":"features/arbitrary-data/#implement-arbitrary","title":"Implement Arbitrary","text":"

There are macros available to use with Arbitrary, however, it is possible to Implement the arbitrary function by yourself.

// -------------------------------------------------------------------\n// -------------------------------------------------------------------\n// Implement Arbitrary\nimpl<'a> Arbitrary<'a> for InitVestingData {\n    fn arbitrary(\n        u: &mut arbitrary::Unstructured<'a>\n    ) -> arbitrary::Result<Self> {\n        // obtain AccountId\n        let recipient = AccountId::arbitrary(u)?;\n\n        // limit the generated amount to the 1_000_000\n        let amount = u.int_in_range(1..=1_000_000)?;\n\n        // now we want to obtain\n        // - start_at\n        // - end_at\n        // - interval\n        // however we want to limit the data such that:\n        // - start_at < end_at\n        // - end_at - start_at > interval\n        // - interval has lower limit of 500 and upper limit of 1000.\n\n        let start_at: u64 = u.int_in_range(1_000_000..=5_000_000)?;\n        let end_at: u64 = u.int_in_range(1_000_000..=5_000_000)?;\n        let interval: u64 = u.int_in_range(500..=1000)?;\n\n        // ensure that start_at < end_at\n        if start_at >= end_at {\n            return Err(arbitrary::Error::IncorrectFormat);\n        }\n\n        // ensure that end_at - start_at > interval\n        match end_at.checked_sub(start_at) {\n            Some(diff) => {\n                if diff <= interval {\n                    return Err(arbitrary::Error::IncorrectFormat);\n                }\n            }\n            None => return Err(arbitrary::Error::IncorrectFormat),\n        }\n\n        Ok(InitVestingData {\n            recipient,\n            amount,\n            start_at,\n            end_at,\n            interval,\n        })\n    }\n    // -------------------------------------------------------------------\n    // -------------------------------------------------------------------\n}\n

Tip

Consider checking the Examples section for more tips.

"},{"location":"features/error-handlers/","title":"Error Handler","text":"

Trident allows you to specify custom error handler for each Instruction.

This can be particularly helpful:

Tip

The default behavior of the function is that the error is returned.

/// default implementation\nfn tx_error_handler(\n    &self,\n    e: FuzzClientErrorWithOrigin,\n    ix_data: Self::IxData,\n    pre_ix_acc_infos: &[SnapshotAccount],,\n) -> Result<(), FuzzClientErrorWithOrigin> {\n    Err(e)\n}\n

To omit the Error and continue with the next Instruction in the iteration, you can do

/// default implementation\nfn tx_error_handler(\n    &self,\n    e: FuzzClientErrorWithOrigin,\n    ix_data: Self::IxData,\n    pre_ix_acc_infos: &'info mut [Option<AccountInfo<'info>>],\n) -> Result<(), FuzzClientErrorWithOrigin> {\n    Ok(())\n}\n
"},{"location":"features/features/","title":"Trident Features","text":"

Trident contains multiple features to enhance the fuzzing experience and increase ability to discover bugs.

"},{"location":"features/fuzz-instructions/","title":"Fuzz Instructions","text":"

Trident defines FuzzInstruction enum containing all available Instructions within your program.

The enum variants additionally contains their corresponding structures for Accounts and Input arguments.

#[derive(Arbitrary, DisplayIx, FuzzTestExecutor, FuzzDeserialize)]\npub enum FuzzInstruction {\n    Initialize(Initialize),\n    Update(Update),\n}\n#[derive(Arbitrary, Debug)]\npub struct Initialize {\n    pub accounts: InitializeAccounts,\n    pub data: InitializeData,\n}\n#[derive(Arbitrary, Debug)]\npub struct Update {\n    pub accounts: UpdateAccounts,\n    pub data: UpdateData,\n}\n// ...\n
"},{"location":"features/fuzz-instructions/#instruction-behavior","title":"Instruction behavior","text":"

Each Instruction variant has to define IxOps trait containing the following methods:

"},{"location":"features/fuzz-instructions/#get_program_id","title":"get_program_id()","text":"

This method specifies program ID to which the Instruction corresponds.

In case you have only one program in the Anchor Workspace it is not really important. The importance occurs when you have multiple programs in the Workspace and you want to call Instructions of every Program. In that case each Instruction Variant corresponds to its program by the Program ID.

"},{"location":"features/fuzz-instructions/#get_data","title":"get_data()","text":"

This method specifies what the Instruction Input Data should look like. You can use completely random data generated by the fuzzer, such as:

fn get_data(\n    &self,\n    _client: &mut impl FuzzClient,\n    _fuzz_accounts: &mut FuzzAccounts,\n) -> Result<Self::IxData, FuzzingError> {\n    let data = hello_world::instruction::InitializeFn {\n        input: self.data.input,\n    };\n    Ok(data)\n}\n

You can also use always constant values

fn get_data(\n    &self,\n    _client: &mut impl FuzzClient,\n    _fuzz_accounts: &mut FuzzAccounts,\n) -> Result<Self::IxData, FuzzingError> {\n    let data = hello_world::instruction::InitializeFn {\n        input: 5,\n    };\n    Ok(data)\n}\n

Or you can customize the Data using the Arbitrary crate. Check Arbitrary Data.

"},{"location":"features/fuzz-instructions/#custom-data-types","title":"Custom Data Types","text":"

If you use Custom Types as Instruction data arguments, you may encounter a problem that the Custom Type does not implement

"},{"location":"features/fuzz-instructions/#derive-debug-and-arbitrary-traits-inside-the-fuzz-test","title":"Derive Debug and Arbitrary traits inside the Fuzz Test","text":"

You can redefine the custom type within the fuzz_instructions.rs file, along with all the necessary traits.

// Redefine the Custom Type inside the fuzz_instructions.rs,\n// but this time with all of the required traits.\n#[derive(Arbitrary,Debug, Clone, Copy)]\npub enum CustomEnumInputFuzz {\n    InputVariant1,\n    InputVariant2,\n    InputVariant3,\n}\n

Then, you would also need to implement the std::convert::From<T> trait to enable conversion between the newly defined Custom Type and the Custom Type used within your program.

Tip

Consider checking the Examples section for more tips.

"},{"location":"features/fuzz-instructions/#get_accounts","title":"get_accounts()","text":"

This method specifies how the Accounts for the corresponding Instruction should be resolved. You can use accounts stored within the FuzzAccounts Account Storages, or you can define custom Account using the client.

There are two main functions to use within the get_accounts():

"},{"location":"features/fuzz-instructions/#get_or_create_account","title":"get_or_create_account()","text":"

Insert a new record into AccountsStorage based on the account_id. If a record with the entered account_id already exists, it is returned, and no insertion is performed.

Tip

Example:

let hello_world_account = fuzz_accounts.hello_world_account.get_or_create_account(\n    self.accounts.hello_world_account,\n    client,\n    &[b\"hello_world_seed\"],\n    &hello_world::ID,\n);\n
The code above will return the PDA from hello_world's AccountsStorage if a record for the entered account_id exists. If not, the function will create a new record corresponding to the PDA derived from the provided seeds and return the PDA.

"},{"location":"features/fuzz-instructions/#get","title":"get()","text":"

Retrieves a record from AccountsStorage based on the entered account_id. If no record exists for the account_id, a random public key is returned.

Tip

let hello_world_account = fuzz_accounts\n        .hello_world_account\n        .get(self.accounts.hello_world_account);\n
The code above will return the PDA from hello_world's AccountsStorage if a record for the entered account_id exists. If not, the function will return a random public key.

"},{"location":"features/fuzz-instructions/#set_custom","title":"set_custom()","text":"

If the previous two functions are insufficient, you can use set_custom() to manually set an account with data you select. This function accepts account_id, which specifies the record in the corresponding AccountsStorage; client, which handles the insertion of AccountSharedData; the account's address (particularly helpful if a predefined address is needed); and AccountSharedData, which you can configure as needed.

Tip

Example:\n

let address = Keypair::new();\nfuzz_accounts.hello_world_account.set_custom(\n    self.accounts.hello_world_account,\n    client,\n    address.pubkey(),\n    AccountSharedData::new(10 * LAMPORTS_PER_SOL, 0, &solana_sdk::system_program::ID),\n);\n
The code above will generate a new random keypair. The set_account function will insert the specified AccountSharedData into the client and create a record in the corresponding AccountsStorage based on the entered account_id.

"},{"location":"features/fuzz-instructions/#check","title":"check()","text":"

This method provides Invariant Check for the corresponding Instruction. Check Invariant Checks.

"},{"location":"features/fuzz-instructions/#tx_error_handler","title":"tx_error_handler()","text":"

This method provides Tx Error Handler for the corresponding Instruction. Check Error Handler.

"},{"location":"features/fuzz-instructions/#example","title":"Example","text":"

Tip

Consider checking the Examples section for more tips.

"},{"location":"features/fuzzing-statistics/","title":"Fuzzing Statistics","text":"

Trident allows you to see statistics after the fuzzing session ended.

Important

In order to show statistics set fuzzing_with_stats within the Trident.toml to true.

[fuzz]\n# ...\nfuzzing_with_stats = true\n# ...\n
"},{"location":"features/fuzzing-statistics/#available-statistics","title":"Available Statistics","text":""},{"location":"features/fuzzing-statistics/#simple","title":"Simple","text":" Note

Keep in mind that the number of fuzz iterations does not directly correspond to the total number of invocations. In one fuzz iteration, the fuzzer might be unable to deserialize fuzz data into instructions, causing the entire iteration to be skipped.

On the other hand this is expected behavior as the underlying data are randomly (with coverage feedback) generated, so the Honggfuzz will not necessarily find appropriate data each iteration.

Tip

Consider checking the Examples section for more tips.

"},{"location":"features/genesis-accounts/","title":"Genesis","text":""},{"location":"features/genesis-accounts/#genesis-programs","title":"Genesis Programs","text":"

Trident allows you to use Cross Program Invocation of both Native and SBF programs.

"},{"location":"features/genesis-accounts/#native","title":"Native","text":"

In case of multiple programs within the Anchor Workspace. Make sure that all of the programs you would like to call Cross Program Invocation to are included in the initial state of the Fuzz Test Environment.

Important

Source code below:

// test_fuzz.rs\n\nfn fuzz_iteration<T: FuzzTestExecutor<U> + std::fmt::Display, U>(\n    fuzz_data: FuzzData<T, U>\n) {\n    let fuzzing_program_callee = FuzzingProgram::new(\n        PROGRAM_NAME_CALLEE,\n        &PROGRAM_ID_CALLEE,\n        processor!(convert_entry!(entry_callee)),\n    );\n\n    let fuzzing_program_caller = FuzzingProgram::new(\n        PROGRAM_NAME_CALLER,\n        &PROGRAM_ID_CALLER,\n        processor!(convert_entry!(entry_caller)),\n    );\n\n    let mut client =\n        ProgramTestClientBlocking::new(\n            &[fuzzing_program_callee, fuzzing_program_caller],\n            &[]\n        ).unwrap();\n\n    let _ = fuzz_data.run_with_runtime(&mut client);\n}\n
"},{"location":"features/genesis-accounts/#sbf","title":"SBF","text":"

In case of SBF targets, compiled or dumped from whatever cluster. You can also use these within the Fuzz Tests.

Tip

If you want to obtain Program from Mainnet use

# -u m specifies to dump from mainnet\nsolana program dump -u m <PROGRAM_ID> <PROGRAM_NAME>.so\n

Important

[[fuzz.programs]]\naddress = \"metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s\"\nprogram = \"metaplex-program/metaplex-token-metadata.so\"\n
"},{"location":"features/genesis-accounts/#genesis-accounts","title":"Genesis Accounts","text":"

Trident allows you to include Accounts with data in base64 format.

Tip

If you want to obtain Account with base64 data format, use

# -u m specifies to dump from mainnet\nsolana account -u m <ADDRESS> --output json\n

Important

To include desired accounts in the fuzz testing environment, add then using the Trident.toml.

[[fuzz.accounts]]\naddress = \"6YG3J7PaxyMnnbU67ifyrgF3BzNzc7cD8hPkqK6ATweE\"\nfilename = \"tests/accounts/core_bridge_mainnet/guardian_set_5_mock.json\"\n

Tip

Consider checking the Examples section for more tips.

"},{"location":"features/instructions-sequences/","title":"Instructions Sequences","text":"

Trident allows you to specify custom Instruction squences you would like to execute.

Possible Instruction sequences are split into 3 parts

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.

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

Tip

"},{"location":"features/instructions-sequences/#manual-trait-override","title":"Manual trait override","text":"

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.

// test_fuzz.rs\n\n// do not forget to include the required structures\nuse fuzz_instructions::InitVesting;\nuse fuzz_instructions::WithdrawUnlocked;\n\nimpl FuzzDataBuilder<FuzzInstruction> for MyFuzzData {\n    fn pre_ixs(\n        u: &mut arbitrary::Unstructured\n    ) -> arbitrary::Result<Vec<FuzzInstruction>> {\n        let init_ix =\n            FuzzInstruction::InitVesting(InitVesting::arbitrary(u)?);\n\n        Ok(vec![init_ix])\n    }\n    fn ixs(\n        u: &mut arbitrary::Unstructured\n    ) -> arbitrary::Result<Vec<FuzzInstruction>> {\n        let withdraw_ix =\n            FuzzInstruction::WithdrawUnlocked(WithdrawUnlocked::arbitrary(u)?);\n\n        Ok(vec![withdraw_ix])\n    }\n    fn post_ixs(\n        _u: &mut arbitrary::Unstructured\n    ) -> arbitrary::Result<Vec<FuzzInstruction>> {\n        Ok(vec![])\n    }\n}\n

Tip

Consider checking the Examples section for more tips.

"},{"location":"features/invariant-checks/","title":"Invariant Checks","text":"

Trident allows you to (optionally) specify Invariant Checks for each Instruction.

The Invariant Check will be called after the Instruction was successfully invoked. Within the Invariant Check you can compare the contents of Accounts before and after the Instruction was called.

Important

Returning error in the Invariant Check is considered as detected undesired behavior (i.e. issue/crash detected).

fn check(\n    &self,\n    _pre_ix: &[SnapshotAccount],\n    post_ix: &[SnapshotAccount],\n    _ix_data: Self::IxData,\n) -> Result<(), FuzzingError> {\n    if let Ok(hello_world_account) =\n        hello_world::StoreHelloWorld::try_deserialize(&mut post_ix[1].data())\n    {\n        if hello_world_account.input == 253 {\n            return Err(FuzzingError::Custom(1));\n        }\n    }\n    Ok(())\n}\n

Important

Order of accounts within the array is the same as the order of accounts on the instruction input of your program.

"},{"location":"features/invariant-checks/#account-deserialization","title":"Account Deserialization","text":"

The SnapshotAccount provides methods to obtain parts of the account (e.g. address, its data, owner etc.). If you want to deserialize data into struct defined within your program (or within for example anchor-spl), you can use approach from source code above, meaning utilze try_deserialize generated by anchor within your program.

Tip

Consider checking the Examples section for more tips.

"},{"location":"features/lifecycle/","title":"Fuzz Test Lifecycle","text":"

In the sequence diagram below you can see a simplified fuzz test lifecycle.

Some diagram states are labeled with emojis:

"},{"location":"features/lifecycle/#lifecycle","title":"Lifecycle","text":"
  1. The fuzzer is running until:
    1. The maximal number of iterations is reached (if specified).
    2. A crash was detected and the exit_upon_crash parameter was set.
    3. User interrupted the test manually (for example by hitting CTRL+C).
  2. In each iteration, the fuzzer generates a sequence of random instructions to execute.
    1. User can optionally customize how the instructions are generated and can specify the instructions that should be executed at the beginning (pre_ixs), in the middle (ixs) and at the end (post_ixs) of each iteration. This can be useful for example if your program needs an initialization or you want to fuzz some specific program state.
  3. For each instruction:
    1. User defined mandatory method get_accounts() is called to collect necessary instruction accounts.
    2. User defined mandatory method get_data() is called to collect instruction data.
    3. A snapshot of all instruction accounts before the instruction execution is saved.
    4. The instruction is executed.
    5. A snapshot of all instruction accounts after the instruction execution is saved.
    6. User defined optional method check() is called to check accounts data and evaluate invariants.
fuzzer_iterations = 0fuzzer_iterations = 0fuzzer_iterations <\u00a0max_iterationsfuzzer_iterations <...donedonecreate pre-instruction\u00a0accounts snapshotscreate pre-instruction...execute instructionexecute instructioncreate post-instruction\u00a0accounts snapshotscreate post-instruction...check invariants \ud83d\udc64check invariants \ud83d\udc64fuzzer_iterations++fuzzer_iterations++Generate instructionspre_ixs \ud83d\udc64pre_ixs \ud83d\udc64ixs \ud83d\udc64ixs \ud83d\udc64post_ixs \ud83d\udc64post_ixs \ud83d\udc64endendfor ix in instructionsfor ix in instructionsget instruction accounts \u26a1get instruction accounts \u26a1get instruction data \u26a1get instruction data \u26a1next ixnext ixText is not SVG - cannot display"},{"location":"features/limitations/","title":"Current limitations","text":"

This section summarizes some known limitations in the current development stage. Further development will be focused on resolving these limitations.

"},{"location":"features/trident-manifest/","title":"Trident Manifest","text":"

You can pass supported parameters via the Trident.toml configuration file:

"},{"location":"features/trident-manifest/#fuzz","title":"[fuzz]","text":""},{"location":"features/trident-manifest/#programs","title":"programs","text":"
[[fuzz.programs]]\naddress = \"metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s\"\nprogram = \"metaplex-program/metaplex-token-metadata.so\"\n
"},{"location":"features/trident-manifest/#accounts","title":"accounts","text":"
[[fuzz.accounts]]\naddress = \"6YG3J7PaxyMnnbU67ifyrgF3BzNzc7cD8hPkqK6ATweE\"\nfilename = \"tests/accounts/core_bridge_mainnet/guardian_set_5_mock.json\"\n
"},{"location":"features/trident-manifest/#allow_duplicate_txs","title":"allow_duplicate_txs","text":"
[fuzz]\n# Allow processing of duplicate transactions.\n# Setting to true might speed up fuzzing but can cause\n# false positive crashes (default: false)\nallow_duplicate_txs = false\n
"},{"location":"features/trident-manifest/#fuzzing_with_stats","title":"fuzzing_with_stats","text":"
[fuzz]\n# Trident will show statistics after the fuzzing session.\n# This option forces use of honggfuzz parameter\n# `keep_output` as true in order to be able to catch fuzzer stdout.\n# (default: false)\nfuzzing_with_stats = true\n
"},{"location":"features/trident-manifest/#honggfuzz","title":"[honggfuzz]","text":""},{"location":"features/trident-manifest/#timeout","title":"timeout","text":"
[honggfuzz]\n# Timeout in seconds (default: 10)\ntimeout = 10\n
"},{"location":"features/trident-manifest/#iterations","title":"iterations","text":"
[honggfuzz]\n# Number of fuzzing iterations (default: 0 [no limit])\niterations = 0\n
"},{"location":"features/trident-manifest/#threads","title":"threads","text":"
[honggfuzz]\n# Number of concurrent fuzzing threads (default: 0 [number of CPUs / 2])\nthreads = 0\n
"},{"location":"features/trident-manifest/#keep_output","title":"keep_output","text":"
[honggfuzz]\n# Don't close children's stdin, stdout, stderr; can be noisy (default: false)\nkeep_output = false\n
"},{"location":"features/trident-manifest/#verbose","title":"verbose","text":"
[honggfuzz]\n# Disable ANSI console; use simple log output (default: false)\nverbose = false\n
"},{"location":"features/trident-manifest/#exit_upon_crash","title":"exit_upon_crash","text":"
[honggfuzz]\n# Exit upon seeing the first crash (default: false)\nexit_upon_crash = false\n
"},{"location":"features/trident-manifest/#mutations_per_run","title":"mutations_per_run","text":"
[honggfuzz]\n# Maximal number of mutations per one run (default: 6)\nmutations_per_run = 6\n
"},{"location":"features/trident-manifest/#cargo_target_dir","title":"cargo_target_dir","text":"
[honggfuzz]\n# Target compilation directory,\n# (default: \"\" [\"trident-tests/fuzz_tests/fuzzing/honggfuzz/hfuzz_target\"]).\n# To not clash with cargo build's default target directory.\ncargo_target_dir = \"\"\n
"},{"location":"features/trident-manifest/#hfuzz_workspace","title":"hfuzz_workspace","text":"
[honggfuzz]\n# Honggfuzz working directory,\n# (default: \"\" [\"trident-tests/fuzz_tests/fuzzing/honggfuzz/hfuzz_workspace\"]).\nhfuzz_workspace = \"\"\n
"},{"location":"features/trident-manifest/#crashdir","title":"crashdir","text":"
[honggfuzz]\n# Directory where crashes are saved to (default: \"\" [workspace directory])\ncrashdir = \"\"\n
"},{"location":"features/trident-manifest/#extension","title":"extension","text":"
[honggfuzz]\n# Input file extension (e.g. 'swf'), (default: \"\" ['fuzz'])\nextension = \"\"\n
"},{"location":"features/trident-manifest/#run_time","title":"run_time","text":"
[honggfuzz]\n# Number of seconds this fuzzing session will last (default: 0 [no limit])\nrun_time = 0\n
"},{"location":"features/trident-manifest/#max_file_size","title":"max_file_size","text":"
[honggfuzz]\n# Maximal size of files processed by the fuzzer in bytes\n# (default: 1048576 = 1MB)\nmax_file_size = 1048576\n
"},{"location":"features/trident-manifest/#save_all","title":"save_all","text":"
[honggfuzz]\n# Save all test-cases\n# (not only the unique ones) by appending the current\n# time-stamp to the filename (default: false)\nsave_all = false\n

Tip

Consider checking the Examples section for more tips.

"},{"location":"get-help/get-help/","title":"Get Help","text":"

Need help writing Fuzz Tests? Do not hesitate to join our Discord server!

"},{"location":"installation/installation/","title":"Installation","text":"

Important

Prerequisite

It is expected that you have installed:

For supported versions check the Supported Versions

"},{"location":"installation/installation/#install-system-dependencies","title":"Install System Dependencies","text":"

Update your package list and install the required packages:

sudo apt-get update\nsudo apt-get install -y \\\n    curl \\\n    git \\\n    build-essential \\\n    pkg-config \\\n    libssl-dev \\\n    npm \\\n    vim \\\n    nano \\\n    wget \\\n    binutils-dev \\\n    libunwind-dev \\\n    lldb\n
"},{"location":"installation/installation/#install-hongfuzz","title":"Install Hongfuzz","text":"

Install honggfuzz

cargo install honggfuzz\n
"},{"location":"installation/installation/#install-trident","title":"Install Trident","text":"
cargo install trident-cli\n
"},{"location":"installation/installation/#supported-versions","title":"Supported versions","text":"Trident CLI Anchor Solana Rust Honggfuzz develop 0.30.1 ^1.17.4 nightly 0.5.56 0.8.* 0.30.1 ^1.17.4 nightly 0.5.56 0.7.0 >=0.29.*1 ^1.17.4 nightly 0.5.56 0.6.0 >=0.29.*1 ^1.17 nightly 0.5.55 0.5.0 ~0.28.* =1.16.6 - - 0.4.0 ~0.27.* >=1.15 - - 0.3.0 ~0.25.* >=1.10 - - 0.2.0 ~0.24.* >=1.9 - -
  1. To use Trident with Anchor 0.29.0, run the following commands from your project's root directory after Trident initialization:
    cargo update anchor-client@0.30.0 --precise 0.29.0\ncargo update anchor-spl@0.30.0 --precise 0.29.0\n
"},{"location":"writing-fuzz-test/writing-fuzz-test/","title":"Writing fuzz test","text":""},{"location":"writing-fuzz-test/writing-fuzz-test/#initialize-trident","title":"Initialize Trident","text":"

Initialize Trident in the Anchor-based workspace.

trident init\n

Info

Trident under the hood

Tip

If you have Trident already initialized, you can add new fuzz test using trident fuzz add.

"},{"location":"writing-fuzz-test/writing-fuzz-test/#fill-the-fuzz-test-template","title":"Fill the Fuzz test Template","text":""},{"location":"writing-fuzz-test/writing-fuzz-test/#define-fuzz-accounts","title":"Define Fuzz Accounts","text":"

Define AccountsStorage type for each Account you would like to use.

Important

Keep in mind:

#[doc = r\" Use AccountsStorage<T> where T can be one of:\"]\n#[doc = r\" Keypair, PdaStore, TokenStore, MintStore, ProgramStore\"]\n#[derive(Default)]\npub struct FuzzAccounts {\n    author: AccountsStorage<Keypair>,\n    hello_world_account: AccountsStorage<PdaStore>,\n    // No need to fuzz system_program\n    // system_program: AccountsStorage<todo!()>,\n}\n

Tip

For more details about the AccountsStorage check AccountsStorage.

"},{"location":"writing-fuzz-test/writing-fuzz-test/#implement-fuzz-instructions","title":"Implement Fuzz Instructions","text":"

Each Instruction in the Fuzz Test has to have defined the following functions:

Tip

"},{"location":"writing-fuzz-test/writing-fuzz-test/#execute","title":"Execute","text":""},{"location":"writing-fuzz-test/writing-fuzz-test/#run-fuzz-test","title":"Run Fuzz Test","text":"

To execute the desired fuzz test using the Honggfuzz, run:

# Replace <TARGET_NAME> with the name of particular\n# fuzz test (for example: \"fuzz_0\")\ntrident fuzz run-hfuzz <TARGET_NAME>\n
"},{"location":"writing-fuzz-test/writing-fuzz-test/#debug-fuzz-test","title":"Debug Fuzz Test","text":"

To debug your program using Honggfuzz with values from a crash file:

# fuzzer will run the <TARGET_NAME> with the specified <CRASH_FILE_PATH>\ntrident fuzz debug-hfuzz <TARGET_NAME> <CRASH_FILE_PATH>\n

Tip

By default, the crashfiles are stored in the

Tip

For more info about the fuzzing outputs chech the Commands

"}]} \ No newline at end of file diff --git a/dev/writing-fuzz-test/writing-fuzz-test/index.html b/dev/writing-fuzz-test/writing-fuzz-test/index.html index ac9e3afa..b8ad806a 100644 --- a/dev/writing-fuzz-test/writing-fuzz-test/index.html +++ b/dev/writing-fuzz-test/writing-fuzz-test/index.html @@ -20,4 +20,4 @@

Tip

By default, the crashfiles are stored in the

Tip

For more info about the fuzzing outputs chech the Commands

\ No newline at end of file +``` -->

Tip

By default, the crashfiles are stored in the

Tip

For more info about the fuzzing outputs chech the Commands

\ No newline at end of file