From 8cab00823f041efcc963c13ae9f7efa2e917b9d6 Mon Sep 17 00:00:00 2001 From: Trident bot Date: Wed, 15 Jan 2025 22:07:38 +0000 Subject: [PATCH] Deployed 63ddb84 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/customize-ix-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/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/programs-n-accounts/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 | 2 +- dev/search/search_index.json | 2 +- dev/writing-fuzz-test/writing-fuzz-test/index.html | 2 +- 21 files changed, 21 insertions(+), 21 deletions(-) diff --git a/dev/CHANGELOG/index.html b/dev/CHANGELOG/index.html index 87a91669..1b4e1b07 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#

Added

  • added support for composite accounts (245)
  • Trident SVM + AFL (see the PR for more details) (234)

Removed

  • removed fuzz_iteration from test_fuzz.rs (243)

Changed

  • renamed Config to TridentConfig (246)
  • errors are simplified and transaction error contains only transaction error (244)

[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 + 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.9.0] - 2025-01-15#

Added

  • added support for composite accounts (245)
  • Trident SVM + AFL (see the PR for more details) (234)

Removed

  • removed fuzz_iteration from test_fuzz.rs (243)

Changed

  • renamed Config to TridentConfig (246)
  • errors are simplified and transaction error contains only transaction error (244)

[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 9dfb7c95..e864ffeb 100644 --- a/dev/commands/commands/index.html +++ b/dev/commands/commands/index.html @@ -31,4 +31,4 @@

Output#

TBD

trident fuzz debug-hfuzz#

trident fuzz debug-hfuzz <fuzz_target> <crash_file_path>
 

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 fuzz add
 

trident clean#

trident clean
-
\ No newline at end of file +
\ No newline at end of file diff --git a/dev/examples/examples/index.html b/dev/examples/examples/index.html index 87f0f87b..8e0e0afc 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 cadb363e..1a7ffb42 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 52b97f84..e962d19d 100644 --- a/dev/features/account-storages/index.html +++ b/dev/features/account-storages/index.html @@ -3,4 +3,4 @@ some_pda: AccountsStorage<PdaStore>, // ... } -

Tip

Keep in mind:

Account Storage Methods#

There are multiple methods to interact with Account Storages.

get_or_create_account()#

Retrieves a record from AccountsStorage based on the entered account_id. If no record exists for the account_id, a new empty account is created.

get()#

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.

get_or_create_token_account()#

Retrieves a record from AccountsStorage based on the entered account_id. If no record exists for the account_id, a new Token account is created.

get_or_create_mint_account()#

Retrieves a record from AccountsStorage based on the entered account_id. If no record exists for the account_id, a new Mint account is created.

get_or_create_delegated_account()#

Retrieves a record from AccountsStorage based on the entered account_id. If no record exists for the account_id, a new Delegated account is created.

get_or_create_initialized_account()#

Retrieves a record from AccountsStorage based on the entered account_id. If no record exists for the account_id, a new Initialized account is created.

get_or_create_vote_account()#

Retrieves a record from AccountsStorage based on the entered account_id. If no record exists for the account_id, a new Vote account is created.

Tip

Consider checking the Examples section for more tips.

\ No newline at end of file +

Tip

Keep in mind:

Account Storage Methods#

There are multiple methods to interact with Account Storages.

get_or_create_account()#

Retrieves a record from AccountsStorage based on the entered account_id. If no record exists for the account_id, a new empty account is created.

get()#

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.

get_or_create_token_account()#

Retrieves a record from AccountsStorage based on the entered account_id. If no record exists for the account_id, a new Token account is created.

get_or_create_mint_account()#

Retrieves a record from AccountsStorage based on the entered account_id. If no record exists for the account_id, a new Mint account is created.

get_or_create_delegated_account()#

Retrieves a record from AccountsStorage based on the entered account_id. If no record exists for the account_id, a new Delegated account is created.

get_or_create_initialized_account()#

Retrieves a record from AccountsStorage based on the entered account_id. If no record exists for the account_id, a new Initialized account is created.

get_or_create_vote_account()#

Retrieves a record from AccountsStorage based on the entered account_id. If no record exists for the account_id, a new Vote account is created.

Tip

Consider checking the Examples section for more tips.

\ No newline at end of file diff --git a/dev/features/customize-ix-data/index.html b/dev/features/customize-ix-data/index.html index 052578e3..2ce53de8 100644 --- a/dev/features/customize-ix-data/index.html +++ b/dev/features/customize-ix-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 d9a07424..40178197 100644 --- a/dev/features/error-handlers/index.html +++ b/dev/features/error-handlers/index.html @@ -16,4 +16,4 @@ ) -> Result<(), TransactionError> { 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 76932963..3213c6c8 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 2a67fc67..d93d91f2 100644 --- a/dev/features/fuzz-instructions/index.html +++ b/dev/features/fuzz-instructions/index.html @@ -61,4 +61,4 @@ 0, ), ); -

check()#

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

tx_error_handler()#

This method provides a 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 +

check()#

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

tx_error_handler()#

This method provides a 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 db5145c3..31cb6695 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/instructions-sequences/index.html b/dev/features/instructions-sequences/index.html index 478c2e6a..6fe671ed 100644 --- a/dev/features/instructions-sequences/index.html +++ b/dev/features/instructions-sequences/index.html @@ -51,4 +51,4 @@ Ok(vec![]) } } -

Tip

Consider checking the Examples section for more tips on implementing instruction sequences effectively.

\ No newline at end of file +

Tip

Consider checking the Examples section for more tips on implementing instruction sequences effectively.

\ No newline at end of file diff --git a/dev/features/invariant-checks/index.html b/dev/features/invariant-checks/index.html index b6dee8f1..85dba40e 100644 --- a/dev/features/invariant-checks/index.html +++ b/dev/features/invariant-checks/index.html @@ -18,4 +18,4 @@ recipient: Pubkey, input: u8, } -

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/lifecycle/index.html b/dev/features/lifecycle/index.html index f532b24d..5a67d29c 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 97cb48f5..edaa3dd2 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.
\ 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.
\ No newline at end of file diff --git a/dev/features/programs-n-accounts/index.html b/dev/features/programs-n-accounts/index.html index 8ab275cf..e295df3c 100644 --- a/dev/features/programs-n-accounts/index.html +++ b/dev/features/programs-n-accounts/index.html @@ -40,4 +40,4 @@ (fuzz_ix : FuzzInstruction , | fuzz_data : InstructionsSequence | { fuzz_iteration (fuzz_data , & config , & mut client) ; }); } -

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/trident-manifest/index.html b/dev/features/trident-manifest/index.html index 0c63fbad..a1f89d6e 100644 --- a/dev/features/trident-manifest/index.html +++ b/dev/features/trident-manifest/index.html @@ -97,4 +97,4 @@ # Number of randomly generated bytes. # (default: 0). 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 00ce326d..fd91ada3 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 0f042f15..2b835b8c 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 059ccc5f..1c9b0e64 100644 --- a/dev/installation/installation/index.html +++ b/dev/installation/installation/index.html @@ -19,4 +19,4 @@ ```bash 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 f8ba828c..7c71935a 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":"

Added

Removed

Changed

"},{"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":"
trident init\n
"},{"location":"commands/commands/#trident-how","title":"trident how","text":"
trident how\n
"},{"location":"commands/commands/#trident-fuzz","title":"trident fuzz","text":"
trident fuzz <subcommand>\n
"},{"location":"commands/commands/#trident-fuzz-run-afl","title":"trident fuzz run-afl","text":"

Warning

To execute and debug fuzz tests, navigate to the trident-tests directory.

trident fuzz run-afl <fuzz_target>\n
"},{"location":"commands/commands/#output","title":"Output","text":"

TBD

"},{"location":"commands/commands/#trident-fuzz-run-hfuzz","title":"trident fuzz run-hfuzz","text":"

Warning

To execute and debug fuzz tests, navigate to the trident-tests directory.

trident fuzz run-hfuzz <fuzz_target>\n
"},{"location":"commands/commands/#output_1","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-afl","title":"trident fuzz debug-afl","text":"
trident fuzz debug-afl <fuzz_target> <crash_file_path>\n
"},{"location":"commands/commands/#output_2","title":"Output","text":"

TBD

"},{"location":"commands/commands/#trident-fuzz-debug-hfuzz","title":"trident fuzz debug-hfuzz","text":"
trident fuzz debug-hfuzz <fuzz_target> <crash_file_path>\n
"},{"location":"commands/commands/#output_3","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":"
trident fuzz add\n
"},{"location":"commands/commands/#trident-clean","title":"trident clean","text":"
trident clean\n
"},{"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 fuzzer cannot generate account addresses completely randomly, as the address has 32 bytes; this means that the fuzzer will, in most cases, generate incorrect addresses.

Thus, 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 Account Storages are global to all instructions.

Important

There are two types of Account Storages:

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

Tip

Keep in mind:

"},{"location":"features/account-storages/#account-storage-methods","title":"Account Storage Methods","text":"

There are multiple methods to interact with Account Storages.

"},{"location":"features/account-storages/#get_or_create_account","title":"get_or_create_account()","text":"

Retrieves a record from AccountsStorage based on the entered account_id. If no record exists for the account_id, a new empty account is created.

"},{"location":"features/account-storages/#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.

"},{"location":"features/account-storages/#get_or_create_token_account","title":"get_or_create_token_account()","text":"

Retrieves a record from AccountsStorage based on the entered account_id. If no record exists for the account_id, a new Token account is created.

"},{"location":"features/account-storages/#get_or_create_mint_account","title":"get_or_create_mint_account()","text":"

Retrieves a record from AccountsStorage based on the entered account_id. If no record exists for the account_id, a new Mint account is created.

"},{"location":"features/account-storages/#get_or_create_delegated_account","title":"get_or_create_delegated_account()","text":"

Retrieves a record from AccountsStorage based on the entered account_id. If no record exists for the account_id, a new Delegated account is created.

"},{"location":"features/account-storages/#get_or_create_initialized_account","title":"get_or_create_initialized_account()","text":"

Retrieves a record from AccountsStorage based on the entered account_id. If no record exists for the account_id, a new Initialized account is created.

"},{"location":"features/account-storages/#get_or_create_vote_account","title":"get_or_create_vote_account()","text":"

Retrieves a record from AccountsStorage based on the entered account_id. If no record exists for the account_id, a new Vote account is created.

Tip

Consider checking the Examples section for more tips.

"},{"location":"features/customize-ix-data/","title":"Costomize Instruction Data","text":"

Trident allows you to customize instruction data.

Trident by default generates random data for instructions, however, you can customize the data to select specific values.

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 start_at < end_at. Moreover, there should be a 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/customize-ix-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 a custom error handler for each instruction.

This can be particularly helpful in the following scenarios:

Tip

By default, transaction errors are propagated, meaning that if the transaction fails, the fuzzing iteration is stopped, and a new fuzzing iteration is started.

/// Default implementation\nfn tx_error_handler(\n    &self,\n    e: TransactionError,\n    ix_data: Vec<u8>,\n    pre_ix_acc_infos: &[SnapshotAccount],\n) -> Result<(), TransactionError> {\n    Err(e)\n}\n

To omit the error and continue with the next instruction in the iteration, you can use the following implementation:

/// Custom implementation\nfn tx_error_handler(\n    &self,\n    e: TransactionError,\n    ix_data: Vec<u8>,\n    pre_ix_acc_infos: &[SnapshotAccount],\n) -> Result<(), TransactionError> {\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 the FuzzInstruction enum, which contains all available Instructions within your program. Each enum variant corresponds to one instruction within your program. This enum is crucial for defining how different instructions behave during fuzz testing.

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

#[derive(Arbitrary, DisplayIx, FuzzTestExecutor)]\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 must define the IxOps trait, which contains the following methods:

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

This method specifies the discriminator of the instruction.

Tip

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

This method specifies the program ID to which the Instruction corresponds.

"},{"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<Vec<u8>, FuzzingError> {\n    let mut args: Vec<u8> = self.get_discriminator();\n    {\n        args.extend(borsh::to_vec(&self.data.input).unwrap());\n    }\n    Ok(args)\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<Vec<u8>, FuzzingError> {\n    let mut args: Vec<u8> = self.get_discriminator();\n    {\n        // The constant value 5 is used as an example\n        args.extend(borsh::to_vec(5).unwrap());\n    }\n    Ok(args)\n}\n

Additionally, you can limit the range of the data generated using the Arbitrary crate. Check Arbitrary Data.

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

This method specifies the Accounts that will be used for the corresponding Instruction. To use multiple combinations of accounts, Trident utilizes the AccountStorage, where accounts are stored across the fuzzing process.

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

For additional methods, check Account Storage Methods.

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

Retrieves a record from AccountsStorage based on the entered account_id. If no record exists for the account_id, a new empty account is created.

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
"},{"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

Example:

let hello_world_account = fuzz_accounts\n        .hello_world_account\n        .get(self.accounts.hello_world_account);\n
"},{"location":"features/fuzz-instructions/#set_account_custom","title":"set_account_custom()","text":"

If the previous two functions are insufficient, you can use set_account_custom() to manually set an account with data you select.

Tip

Example:

let author = fuzz_accounts.author_hello_world.get_or_create_account(\n    self.accounts.author,\n    client,\n    500 * LAMPORTS_PER_SOL,\n);\nclient.set_account_custom(\n    &author.pubkey(),\n    &AccountSharedData::create(\n        10 * LAMPORTS_PER_SOL,\n        vec![1, 2, 3, 4, 5, 6, 7, 8, 9],\n        solana_sdk::system_program::ID,\n        false,\n        0,\n    ),\n);\n
"},{"location":"features/fuzz-instructions/#check","title":"check()","text":"

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

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

This method provides a 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/instructions-sequences/","title":"Instructions Sequences","text":"

Trident allows you to specify custom instruction sequences that you would like to execute.

Possible instruction sequences are divided into three parts:

For example, if your program requires an Initialization instruction at the start, you can specify it 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:\n/// 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, allowing 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 on implementing instruction sequences effectively.

"},{"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 has been successfully invoked. Within the invariant check, you can compare the contents of accounts before and after the Instruction.

Important

Returning an error in the Invariant Check is considered a detection of undesired behavior (i.e., issue/crash detected).

fn check(\n    &self,\n    pre_ix: &[SnapshotAccount],\n    post_ix: &[SnapshotAccount],\n    ix_data: Vec<u8>,\n) -> Result<(), FuzzingError> {\n    if let Ok(hello_world_account) =\n        StoreHelloWorld::deserialize(&mut post_ix[1].data_no_discriminator())\n    {\n        if hello_world_account.input == 253 {\n            return Err(FuzzingError::Custom(1));\n        }\n    }\n    Ok(())\n}\n

Important

The order of accounts within the array is the same as the order of accounts in 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 a struct defined within your program, ensure that the struct is present in the fuzz test template and has derived the BorshDeserialize and BorshSerialize traits, as shown in the example below:

#[derive(Debug, BorshDeserialize, BorshSerialize, Clone)]\npub struct StoreHelloWorld {\n    recipient: Pubkey,\n    input: u8,\n}\n

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/programs-n-accounts/","title":"Programs and Accounts","text":"

Trident allows for usage of programs and accounts from the desired cluster (Mainnet, Devnet, etc.).

"},{"location":"features/programs-n-accounts/#include-mainnet-programs","title":"Include Mainnet Programs","text":"

In case you want to include programs from Mainnet, you can do so by specifying the address and path to the program in the Trident.toml.

[[fuzz.programs]]\naddress = \"metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s\"\nprogram = \"metaplex-program/metaplex-token-metadata.so\"\n

Tip

If you want to dump a program from Mainnet, use

# -u m specifies to dump from mainnet\nsolana program dump -u m <PROGRAM_ID> <PROGRAM_NAME>.so\n
"},{"location":"features/programs-n-accounts/#include-mainnet-accounts","title":"Include Mainnet Accounts","text":"

In case you want to include accounts from Mainnet, you can do so by specifying the address and path to the account in the Trident.toml.

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

Tip

If you want to obtain an account with base64 data format, use

# -u m specifies to dump from mainnet\nsolana account -u m <ADDRESS> --output json\n
"},{"location":"features/programs-n-accounts/#include-programs-through-the-entrypoint","title":"Include Programs Through the Entrypoint","text":"

There is another way to include programs in the Fuzz Test Environment. Including programs through the entrypoint is better for fuzzing, as the program is built together with the fuzz test, so that it will contain instrumentation which helps the fuzzer to better cover all possible program branches. However, the source code is required to do so.

You can include additional programs using the program entrypoint, as shown in the example below:

// test_fuzz.rs\n\nuse callee::entry as entry_callee;\nuse caller::entry as entry_caller;\n\n// ...\n\nfn main() {\n    // Program 1\n    let program_callee = ProgramEntrypoint::new(\n        pubkey!(\"HJR1TK8bgrUWzysdpS1pBGBYKF7zi1tU9cS4qj8BW8ZL\"),\n        None,\n        processor!(entry_callee),\n    );\n\n    // Program 2\n    let program_caller = ProgramEntrypoint::new(\n        pubkey!(\"FWtSodrkUnovFPnNRCxneP6VWh6JH6jtQZ4PHoP8Ejuz\"),\n        None,\n        processor!(entry_caller),\n    );\n    let config = Config::new();\n\n    let mut client = TridentSVM::new_client(\n        &[program_callee, program_caller],\n        &config\n    );\n\n    fuzz_trident !\n        (fuzz_ix : FuzzInstruction , | fuzz_data : InstructionsSequence |\n            { fuzz_iteration (fuzz_data , & config , & mut client) ; });\n}\n

Tip

Consider checking the Examples section for more tips.

"},{"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/#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/#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/#timeout","title":"timeout","text":"
[honggfuzz]\n# Timeout in seconds (default: 10)\ntimeout = 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
"},{"location":"features/trident-manifest/#afl","title":"[afl]","text":""},{"location":"features/trident-manifest/#run_time_1","title":"run_time","text":"
[afl]\n# Number of seconds this fuzzing session will last (default: 0 [no limit])\nrun_time = 0\n
"},{"location":"features/trident-manifest/#iterations_1","title":"iterations","text":"
[afl]\n# Number of fuzzing iterations (default: 0 [no limit])\niterations = 0\n
"},{"location":"features/trident-manifest/#cargo_target_dir_1","title":"cargo_target_dir","text":"
[afl]\n# Target compilation directory,\n# (default: \"\" [\"trident-tests/fuzz_tests/fuzzing/afl/afl_target\"]).\n# To not clash with cargo build's default target directory.\ncargo_target_dir = \"\"\n
"},{"location":"features/trident-manifest/#afl_workspace_in","title":"afl_workspace_in","text":"
[afl]\n# AFL working input directory,\n# (default: \"\" [\"trident-tests/fuzz_tests/fuzzing/afl/afl_workspace/in\"]).\nafl_workspace_in = \"\"\n
"},{"location":"features/trident-manifest/#afl_workspace_out","title":"afl_workspace_out","text":"
[afl]\n# AFL working output directory,\n# (default: \"\" [\"trident-tests/fuzz_tests/fuzzing/afl/afl_workspace/out\"]).\nafl_workspace_out = \"\"\n
"},{"location":"features/trident-manifest/#seeds","title":"seeds","text":"

Important

bytes_count has precedence before seed, in that case if both are specified. Seed is generated as random array of bytes_count bytes.

[[afl.seeds]]\n# Filename under which the test input is generated.\n# The location of file is afl_workspace_in directory.\n# (default: \"\" [\"trident-seed\"]).\nfile_name = \"\"\n# String used as seed.\n# (default: \"\" [\"trident\"]).\nseed = \"\"\n# If the file already exists at specific location,\n# select if override.\n# (default: false).\noverride_file = true\n# Number of randomly generated bytes.\n# (default: 0).\nbytes_count = 20\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 and AFL

cargo install honggfuzz\n
cargo install cargo-afl\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 AFL develop >=0.29.0 >=1.17.3 nightly 0.5.56 0.15.11 0.8.* >=0.29.0 >=1.17.3 nightly 0.5.56 - 0.8.* 0.30.1 ^1.17.4 nightly 0.5.56 - 0.7.0 >=0.29.* ^1.17.4 nightly 0.5.56 - 0.6.0 >=0.29.* ^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 - - -"},{"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 a 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<KeypairStore>,\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 must define the following functions:

Tip

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

Warning

To execute and debug fuzz tests, navigate to the trident-tests directory.

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

In principle there are two possible fuzzing engines that the Trident supports, Honggfuzz and AFL.

To execute the desired fuzz test using the Honggfuzz, run the following command from the trident-tests directory:

# Replace <TARGET_NAME> with the name of particular\n# fuzz test (for example: \"fuzz_0\")\ntrident fuzz run-hfuzz <TARGET_NAME>\n

To execute the desired fuzz test using the AFL, run the following command from the trident-tests directory:

# Replace <TARGET_NAME> with the name of particular\n# fuzz test (for example: \"fuzz_0\")\ntrident fuzz run-afl <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, run the following command from the trident-tests directory:

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

To debug your program using AFL with values from a crash file, run the following command from the trident-tests directory:

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

Tip

By default, the crash files are stored in:

Tip

For more info about the fuzzing outputs, check 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/#090-2025-01-15","title":"[0.9.0] - 2025-01-15","text":"

Added

Removed

Changed

"},{"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":"
trident init\n
"},{"location":"commands/commands/#trident-how","title":"trident how","text":"
trident how\n
"},{"location":"commands/commands/#trident-fuzz","title":"trident fuzz","text":"
trident fuzz <subcommand>\n
"},{"location":"commands/commands/#trident-fuzz-run-afl","title":"trident fuzz run-afl","text":"

Warning

To execute and debug fuzz tests, navigate to the trident-tests directory.

trident fuzz run-afl <fuzz_target>\n
"},{"location":"commands/commands/#output","title":"Output","text":"

TBD

"},{"location":"commands/commands/#trident-fuzz-run-hfuzz","title":"trident fuzz run-hfuzz","text":"

Warning

To execute and debug fuzz tests, navigate to the trident-tests directory.

trident fuzz run-hfuzz <fuzz_target>\n
"},{"location":"commands/commands/#output_1","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-afl","title":"trident fuzz debug-afl","text":"
trident fuzz debug-afl <fuzz_target> <crash_file_path>\n
"},{"location":"commands/commands/#output_2","title":"Output","text":"

TBD

"},{"location":"commands/commands/#trident-fuzz-debug-hfuzz","title":"trident fuzz debug-hfuzz","text":"
trident fuzz debug-hfuzz <fuzz_target> <crash_file_path>\n
"},{"location":"commands/commands/#output_3","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":"
trident fuzz add\n
"},{"location":"commands/commands/#trident-clean","title":"trident clean","text":"
trident clean\n
"},{"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 fuzzer cannot generate account addresses completely randomly, as the address has 32 bytes; this means that the fuzzer will, in most cases, generate incorrect addresses.

Thus, 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 Account Storages are global to all instructions.

Important

There are two types of Account Storages:

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

Tip

Keep in mind:

"},{"location":"features/account-storages/#account-storage-methods","title":"Account Storage Methods","text":"

There are multiple methods to interact with Account Storages.

"},{"location":"features/account-storages/#get_or_create_account","title":"get_or_create_account()","text":"

Retrieves a record from AccountsStorage based on the entered account_id. If no record exists for the account_id, a new empty account is created.

"},{"location":"features/account-storages/#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.

"},{"location":"features/account-storages/#get_or_create_token_account","title":"get_or_create_token_account()","text":"

Retrieves a record from AccountsStorage based on the entered account_id. If no record exists for the account_id, a new Token account is created.

"},{"location":"features/account-storages/#get_or_create_mint_account","title":"get_or_create_mint_account()","text":"

Retrieves a record from AccountsStorage based on the entered account_id. If no record exists for the account_id, a new Mint account is created.

"},{"location":"features/account-storages/#get_or_create_delegated_account","title":"get_or_create_delegated_account()","text":"

Retrieves a record from AccountsStorage based on the entered account_id. If no record exists for the account_id, a new Delegated account is created.

"},{"location":"features/account-storages/#get_or_create_initialized_account","title":"get_or_create_initialized_account()","text":"

Retrieves a record from AccountsStorage based on the entered account_id. If no record exists for the account_id, a new Initialized account is created.

"},{"location":"features/account-storages/#get_or_create_vote_account","title":"get_or_create_vote_account()","text":"

Retrieves a record from AccountsStorage based on the entered account_id. If no record exists for the account_id, a new Vote account is created.

Tip

Consider checking the Examples section for more tips.

"},{"location":"features/customize-ix-data/","title":"Costomize Instruction Data","text":"

Trident allows you to customize instruction data.

Trident by default generates random data for instructions, however, you can customize the data to select specific values.

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 start_at < end_at. Moreover, there should be a 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/customize-ix-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 a custom error handler for each instruction.

This can be particularly helpful in the following scenarios:

Tip

By default, transaction errors are propagated, meaning that if the transaction fails, the fuzzing iteration is stopped, and a new fuzzing iteration is started.

/// Default implementation\nfn tx_error_handler(\n    &self,\n    e: TransactionError,\n    ix_data: Vec<u8>,\n    pre_ix_acc_infos: &[SnapshotAccount],\n) -> Result<(), TransactionError> {\n    Err(e)\n}\n

To omit the error and continue with the next instruction in the iteration, you can use the following implementation:

/// Custom implementation\nfn tx_error_handler(\n    &self,\n    e: TransactionError,\n    ix_data: Vec<u8>,\n    pre_ix_acc_infos: &[SnapshotAccount],\n) -> Result<(), TransactionError> {\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 the FuzzInstruction enum, which contains all available Instructions within your program. Each enum variant corresponds to one instruction within your program. This enum is crucial for defining how different instructions behave during fuzz testing.

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

#[derive(Arbitrary, DisplayIx, FuzzTestExecutor)]\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 must define the IxOps trait, which contains the following methods:

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

This method specifies the discriminator of the instruction.

Tip

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

This method specifies the program ID to which the Instruction corresponds.

"},{"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<Vec<u8>, FuzzingError> {\n    let mut args: Vec<u8> = self.get_discriminator();\n    {\n        args.extend(borsh::to_vec(&self.data.input).unwrap());\n    }\n    Ok(args)\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<Vec<u8>, FuzzingError> {\n    let mut args: Vec<u8> = self.get_discriminator();\n    {\n        // The constant value 5 is used as an example\n        args.extend(borsh::to_vec(5).unwrap());\n    }\n    Ok(args)\n}\n

Additionally, you can limit the range of the data generated using the Arbitrary crate. Check Arbitrary Data.

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

This method specifies the Accounts that will be used for the corresponding Instruction. To use multiple combinations of accounts, Trident utilizes the AccountStorage, where accounts are stored across the fuzzing process.

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

For additional methods, check Account Storage Methods.

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

Retrieves a record from AccountsStorage based on the entered account_id. If no record exists for the account_id, a new empty account is created.

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
"},{"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

Example:

let hello_world_account = fuzz_accounts\n        .hello_world_account\n        .get(self.accounts.hello_world_account);\n
"},{"location":"features/fuzz-instructions/#set_account_custom","title":"set_account_custom()","text":"

If the previous two functions are insufficient, you can use set_account_custom() to manually set an account with data you select.

Tip

Example:

let author = fuzz_accounts.author_hello_world.get_or_create_account(\n    self.accounts.author,\n    client,\n    500 * LAMPORTS_PER_SOL,\n);\nclient.set_account_custom(\n    &author.pubkey(),\n    &AccountSharedData::create(\n        10 * LAMPORTS_PER_SOL,\n        vec![1, 2, 3, 4, 5, 6, 7, 8, 9],\n        solana_sdk::system_program::ID,\n        false,\n        0,\n    ),\n);\n
"},{"location":"features/fuzz-instructions/#check","title":"check()","text":"

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

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

This method provides a 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/instructions-sequences/","title":"Instructions Sequences","text":"

Trident allows you to specify custom instruction sequences that you would like to execute.

Possible instruction sequences are divided into three parts:

For example, if your program requires an Initialization instruction at the start, you can specify it 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:\n/// 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, allowing 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 on implementing instruction sequences effectively.

"},{"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 has been successfully invoked. Within the invariant check, you can compare the contents of accounts before and after the Instruction.

Important

Returning an error in the Invariant Check is considered a detection of undesired behavior (i.e., issue/crash detected).

fn check(\n    &self,\n    pre_ix: &[SnapshotAccount],\n    post_ix: &[SnapshotAccount],\n    ix_data: Vec<u8>,\n) -> Result<(), FuzzingError> {\n    if let Ok(hello_world_account) =\n        StoreHelloWorld::deserialize(&mut post_ix[1].data_no_discriminator())\n    {\n        if hello_world_account.input == 253 {\n            return Err(FuzzingError::Custom(1));\n        }\n    }\n    Ok(())\n}\n

Important

The order of accounts within the array is the same as the order of accounts in 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 a struct defined within your program, ensure that the struct is present in the fuzz test template and has derived the BorshDeserialize and BorshSerialize traits, as shown in the example below:

#[derive(Debug, BorshDeserialize, BorshSerialize, Clone)]\npub struct StoreHelloWorld {\n    recipient: Pubkey,\n    input: u8,\n}\n

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/programs-n-accounts/","title":"Programs and Accounts","text":"

Trident allows for usage of programs and accounts from the desired cluster (Mainnet, Devnet, etc.).

"},{"location":"features/programs-n-accounts/#include-mainnet-programs","title":"Include Mainnet Programs","text":"

In case you want to include programs from Mainnet, you can do so by specifying the address and path to the program in the Trident.toml.

[[fuzz.programs]]\naddress = \"metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s\"\nprogram = \"metaplex-program/metaplex-token-metadata.so\"\n

Tip

If you want to dump a program from Mainnet, use

# -u m specifies to dump from mainnet\nsolana program dump -u m <PROGRAM_ID> <PROGRAM_NAME>.so\n
"},{"location":"features/programs-n-accounts/#include-mainnet-accounts","title":"Include Mainnet Accounts","text":"

In case you want to include accounts from Mainnet, you can do so by specifying the address and path to the account in the Trident.toml.

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

Tip

If you want to obtain an account with base64 data format, use

# -u m specifies to dump from mainnet\nsolana account -u m <ADDRESS> --output json\n
"},{"location":"features/programs-n-accounts/#include-programs-through-the-entrypoint","title":"Include Programs Through the Entrypoint","text":"

There is another way to include programs in the Fuzz Test Environment. Including programs through the entrypoint is better for fuzzing, as the program is built together with the fuzz test, so that it will contain instrumentation which helps the fuzzer to better cover all possible program branches. However, the source code is required to do so.

You can include additional programs using the program entrypoint, as shown in the example below:

// test_fuzz.rs\n\nuse callee::entry as entry_callee;\nuse caller::entry as entry_caller;\n\n// ...\n\nfn main() {\n    // Program 1\n    let program_callee = ProgramEntrypoint::new(\n        pubkey!(\"HJR1TK8bgrUWzysdpS1pBGBYKF7zi1tU9cS4qj8BW8ZL\"),\n        None,\n        processor!(entry_callee),\n    );\n\n    // Program 2\n    let program_caller = ProgramEntrypoint::new(\n        pubkey!(\"FWtSodrkUnovFPnNRCxneP6VWh6JH6jtQZ4PHoP8Ejuz\"),\n        None,\n        processor!(entry_caller),\n    );\n    let config = Config::new();\n\n    let mut client = TridentSVM::new_client(\n        &[program_callee, program_caller],\n        &config\n    );\n\n    fuzz_trident !\n        (fuzz_ix : FuzzInstruction , | fuzz_data : InstructionsSequence |\n            { fuzz_iteration (fuzz_data , & config , & mut client) ; });\n}\n

Tip

Consider checking the Examples section for more tips.

"},{"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/#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/#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/#timeout","title":"timeout","text":"
[honggfuzz]\n# Timeout in seconds (default: 10)\ntimeout = 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
"},{"location":"features/trident-manifest/#afl","title":"[afl]","text":""},{"location":"features/trident-manifest/#run_time_1","title":"run_time","text":"
[afl]\n# Number of seconds this fuzzing session will last (default: 0 [no limit])\nrun_time = 0\n
"},{"location":"features/trident-manifest/#iterations_1","title":"iterations","text":"
[afl]\n# Number of fuzzing iterations (default: 0 [no limit])\niterations = 0\n
"},{"location":"features/trident-manifest/#cargo_target_dir_1","title":"cargo_target_dir","text":"
[afl]\n# Target compilation directory,\n# (default: \"\" [\"trident-tests/fuzz_tests/fuzzing/afl/afl_target\"]).\n# To not clash with cargo build's default target directory.\ncargo_target_dir = \"\"\n
"},{"location":"features/trident-manifest/#afl_workspace_in","title":"afl_workspace_in","text":"
[afl]\n# AFL working input directory,\n# (default: \"\" [\"trident-tests/fuzz_tests/fuzzing/afl/afl_workspace/in\"]).\nafl_workspace_in = \"\"\n
"},{"location":"features/trident-manifest/#afl_workspace_out","title":"afl_workspace_out","text":"
[afl]\n# AFL working output directory,\n# (default: \"\" [\"trident-tests/fuzz_tests/fuzzing/afl/afl_workspace/out\"]).\nafl_workspace_out = \"\"\n
"},{"location":"features/trident-manifest/#seeds","title":"seeds","text":"

Important

bytes_count has precedence before seed, in that case if both are specified. Seed is generated as random array of bytes_count bytes.

[[afl.seeds]]\n# Filename under which the test input is generated.\n# The location of file is afl_workspace_in directory.\n# (default: \"\" [\"trident-seed\"]).\nfile_name = \"\"\n# String used as seed.\n# (default: \"\" [\"trident\"]).\nseed = \"\"\n# If the file already exists at specific location,\n# select if override.\n# (default: false).\noverride_file = true\n# Number of randomly generated bytes.\n# (default: 0).\nbytes_count = 20\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 and AFL

cargo install honggfuzz\n
cargo install cargo-afl\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 AFL develop >=0.29.0 >=1.17.3 nightly 0.5.56 0.15.11 0.8.* >=0.29.0 >=1.17.3 nightly 0.5.56 - 0.8.* 0.30.1 ^1.17.4 nightly 0.5.56 - 0.7.0 >=0.29.* ^1.17.4 nightly 0.5.56 - 0.6.0 >=0.29.* ^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 - - -"},{"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 a 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<KeypairStore>,\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 must define the following functions:

Tip

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

Warning

To execute and debug fuzz tests, navigate to the trident-tests directory.

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

In principle there are two possible fuzzing engines that the Trident supports, Honggfuzz and AFL.

To execute the desired fuzz test using the Honggfuzz, run the following command from the trident-tests directory:

# Replace <TARGET_NAME> with the name of particular\n# fuzz test (for example: \"fuzz_0\")\ntrident fuzz run-hfuzz <TARGET_NAME>\n

To execute the desired fuzz test using the AFL, run the following command from the trident-tests directory:

# Replace <TARGET_NAME> with the name of particular\n# fuzz test (for example: \"fuzz_0\")\ntrident fuzz run-afl <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, run the following command from the trident-tests directory:

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

To debug your program using AFL with values from a crash file, run the following command from the trident-tests directory:

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

Tip

By default, the crash files are stored in:

Tip

For more info about the fuzzing outputs, check 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 8081dc6d..b3b195e8 100644 --- a/dev/writing-fuzz-test/writing-fuzz-test/index.html +++ b/dev/writing-fuzz-test/writing-fuzz-test/index.html @@ -18,4 +18,4 @@ trident fuzz debug-hfuzz <TARGET_NAME> <CRASH_FILE_PATH>

To debug your program using AFL with values from a crash file, run the following command from the trident-tests directory:

# The fuzzer will run the <TARGET_NAME> with the specified <CRASH_FILE_PATH>
 trident fuzz debug-afl <TARGET_NAME> <CRASH_FILE_PATH>
-

Tip

By default, the crash files are stored in:

Tip

For more info about the fuzzing outputs, check the Commands.

\ No newline at end of file +

Tip

By default, the crash files are stored in:

Tip

For more info about the fuzzing outputs, check the Commands.

\ No newline at end of file