diff --git a/dev/CHANGELOG/index.html b/dev/CHANGELOG/index.html index 0aa1a76c..84657e92 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

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

Changed

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

Removed

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

[0.7.0] - 2024-08-14#

Added

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

Fixed

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

Removed

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

[0.6.0] - 2024-05-20#

Added

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

Fixed

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

[0.5.0] - 2023-08-28#

Added

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

[0.4.1] - 2023-08-21#

Changed

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

Fixed

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

[0.3.0] - 2022-09-23#

Changed

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

Added

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

[0.2.0] - 2022-07-27#

Added

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

Changelog#

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

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

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

[dev] - Unreleased#

[0.8.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 d3c75464..e0a1dd62 100644 --- a/dev/commands/commands/index.html +++ b/dev/commands/commands/index.html @@ -32,4 +32,4 @@ #### Output -TBD -->

trident fuzz debug-hfuzz#

Output#

Important

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

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

alt text

trident fuzz add#


trident clean#

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

trident fuzz debug-hfuzz#

Output#

Important

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

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

alt text

trident fuzz add#


trident clean#

\ No newline at end of file diff --git a/dev/examples/examples/index.html b/dev/examples/examples/index.html index 1b08ae2c..80073420 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 9f300445..36729c8c 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 and it has to have access to the AccountsSnapshots derived for each Instruction Context.

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 and it has to have access to the AccountsSnapshots derived for each Instruction Context.

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 7bdfd669..19a059f7 100644 --- a/dev/features/account-storages/index.html +++ b/dev/features/account-storages/index.html @@ -5,4 +5,4 @@ mint: AccountsStorage<MintStore>, // ... } -

Tip

Keep in mind:

Tip

Consider checking the Examples section for more tips.

\ No newline at end of file +

Tip

Keep in mind:

Tip

Consider checking the Examples section for more tips.

\ No newline at end of file diff --git a/dev/features/arbitrary-data/index.html b/dev/features/arbitrary-data/index.html index b674c229..4920a5c6 100644 --- a/dev/features/arbitrary-data/index.html +++ b/dev/features/arbitrary-data/index.html @@ -72,4 +72,4 @@ // ------------------------------------------------------------------- // ------------------------------------------------------------------- } -

Tip

Consider checking the Examples section for more tips.

\ No newline at end of file +

Tip

Consider checking the Examples section for more tips.

\ No newline at end of file diff --git a/dev/features/error-handlers/index.html b/dev/features/error-handlers/index.html index a56109d0..99ca7ce6 100644 --- a/dev/features/error-handlers/index.html +++ b/dev/features/error-handlers/index.html @@ -16,4 +16,4 @@ ) -> Result<(), FuzzClientErrorWithOrigin> { Ok(()) } -
\ No newline at end of file +
\ No newline at end of file diff --git a/dev/features/features/index.html b/dev/features/features/index.html index 28d6b715..3333afb6 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 b2845b3f..b75e55cf 100644 --- a/dev/features/fuzz-instructions/index.html +++ b/dev/features/fuzz-instructions/index.html @@ -122,4 +122,4 @@ seeds: vec_of_seeds, } }).pubkey(); -

Check#

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

Tx Error Handler#

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

Example#

Tip

Consider checking the Examples section for more tips.

\ No newline at end of file +

Check#

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

Tx Error Handler#

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

Example#

Tip

Consider checking the Examples section for more tips.

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

Available Statistics#

Simple#

Note

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

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

Tip

Consider checking the Examples section for more tips.

\ No newline at end of file +

Available Statistics#

Simple#

Note

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

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

Tip

Consider checking the Examples section for more tips.

\ No newline at end of file diff --git a/dev/features/genesis-accounts/index.html b/dev/features/genesis-accounts/index.html index 821a3ffa..7168f003 100644 --- a/dev/features/genesis-accounts/index.html +++ b/dev/features/genesis-accounts/index.html @@ -33,4 +33,4 @@

Important

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

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

Tip

Consider checking the Examples section for more tips.

\ No newline at end of file +

Tip

Consider checking the Examples section for more tips.

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

Tip

Consider checking the Examples section for more tips.

\ No newline at end of file +

Tip

Consider checking the Examples section for more tips.

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

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 95a687f1..3e884330 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 5cd0f03f..4945b3ee 100644 --- a/dev/features/limitations/index.html +++ b/dev/features/limitations/index.html @@ -1 +1 @@ - Current limitations - Trident
Skip to content

Current limitations#

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

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

Current limitations#

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

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

Tip

Consider checking the Examples section for more tips.

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

Tip

Consider checking the Examples section for more tips.

\ No newline at end of file diff --git a/dev/get-help/get-help/index.html b/dev/get-help/get-help/index.html index cff7e43a..93cf9c6b 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 4cd9d0b5..4df5175a 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 d932c892..36196ed0 100644 --- a/dev/installation/installation/index.html +++ b/dev/installation/installation/index.html @@ -16,6 +16,6 @@

Install Trident#

cargo install trident-cli
-

Supported versions#

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

    Supported versions#

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

    Docker Image#

    TBD

    \ No newline at end of file +

Docker Image#

TBD

\ No newline at end of file diff --git a/dev/search/search_index.json b/dev/search/search_index.json index a05f84db..a252f0a3 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

Changed

Removed

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

Added

Fixed

Removed

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

Added

Fixed

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

Added

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

Changed

Fixed

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

Changed

Added

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

Added

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

Important

The output provided by Honggfuzz is as follows:

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

Important

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

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

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

Trident allows developers to generate random accounts for fuzzing.

However, the Accounts are not completely random, and neither are the Account addresses.

Instead, Trident generates random AccountIDs which are indexes to Account Storages. Each unique Account contained within the Anchor generated IDL has its own AccountStorage. The FuzzAccounts containing the Accounts Storages is global to all Instructions to use.

Note

Details:

Always generating only random accounts would in most cases lead to a situation where the fuzzer would be stuck because the accounts would be almost every time rejected by your Anchor program. Therefore it is necessary to specify, what accounts should be used and also limit the number of newly created accounts to reduce the space complexity.

Important

Currently, supported types of Account Storages:

Then use the corresponding AccountsStorage.

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

Tip

Keep in mind:

Tip

Consider checking the Examples section for more tips.

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

Trident allows you to customize Instruction Data to provide structure.

For example your Initialize Instruction expects two arguments start_at and end_at you know that in order for the Instruction to make sense, it is required that the start_at < end_at. Moreover, there should be significant difference between these two. This can be utilized with the Arbitrary crate.

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

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

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

Tip

Consider checking the Examples section for more tips.

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

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

This can be particularly helpful:

Tip

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

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

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

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

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

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

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

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

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

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

"},{"location":"features/fuzz-instructions/#get-program-id","title":"Get Program ID","text":"

This method specifies program ID to which the Instruction corresponds.

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

"},{"location":"features/fuzz-instructions/#get-data","title":"Get Data","text":"

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

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

You can also use always constant values

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

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

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

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

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

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

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

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

Tip

Consider checking the Examples section for more tips.

"},{"location":"features/fuzz-instructions/#get-accounts","title":"Get Accounts","text":"

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

Important

Source Code below

fn get_accounts(\n    &self,\n    client: &mut impl FuzzClient,\n    fuzz_accounts: &mut FuzzAccounts,\n) -> Result<(Vec<Keypair>, Vec<AccountMeta>), FuzzingError> {\n    let author = fuzz_accounts.author.get_or_create_account(\n        self.accounts.author,\n        client,\n        5 * LAMPORTS_PER_SOL,\n    );\n\n    let hello_world_account = fuzz_accounts\n        .hello_world_account\n        .get_or_create_account(\n            self.accounts.hello_world_account,\n            &[b\"hello_world_seed\"],\n            &hello_world::ID,\n        )\n        .unwrap();\n    let signers = vec![author.clone()];\n    let acc_meta = hello_world::accounts::InitializeContext {\n        author: author.pubkey(),\n        hello_world_account: hello_world_account.pubkey(),\n        system_program: solana_sdk::system_program::ID,\n    }\n    .to_account_metas(None);\n    Ok((signers, acc_meta))\n}\n
"},{"location":"features/fuzz-instructions/#create-an-arbitrary-account","title":"Create an arbitrary account","text":"

The AccountsStorage<T> type provides an implementation of the get_or_create_account method that helps you create new or read already existing accounts. There are different implementations for different types of storage (Keypair, TokenStore, MintStore, PdaStore) to simplify the creation of new accounts.

However, there are cases when the provided implementation is not sufficient and it is necessary to create an account manually. These cases can be (but are not limited to) for example:

In that case, you can use the storage method of the AccountsStorage<T> struct that exposes the underlying HashMap<AccountId, T> and you can add new accounts directly to it.

It is possible to create and store any kind of account. For example:

let state = fuzz_accounts\n    .state\n    // gets the storage of all `state` account variants\n    .storage()\n    // returns the Keypair of the `state` account with\n    // the given `AccountId` if it has been added previously\n    .entry(self.accounts.state)\n    .or_insert_with(|| {\n        let space = State::SIZE;\n        let rent_exempt_lamports = client.get_rent().unwrap()\n                            .minimum_balance(space);\n        let keypair = Keypair::new();\n        let account = AccountSharedData::new_data_with_space::<[u8; 0]>(\n            rent_exempt_lamports,\n            &[],\n            space,\n            &my_program::id(),\n        ).unwrap();\n        // insert the custom account also into the client\n        client.set_account_custom(&keypair.pubkey(), &account);\n        keypair\n    });\n
let rent_exempt_for_token_acc = client\n    .get_rent()\n    .unwrap()\n    .minimum_balance(anchor_spl::token::spl_token::state::Account::LEN);\n\nlet my_pda = fuzz_accounts\n    .my_pda\n    // gets the storage of all `my_pda` account variants\n    .storage()\n    // returns the PdaStore struct of the `my_pda` account with\n    // the given `AccountId` if it has been added previously\n    .entry(self.accounts.my_pda)\n    .or_insert_with(|| {\n        let seeds = &[b\"some-seeds\"];\n        let pda = Pubkey::find_program_address(seeds, &my_program::id()).0;\n        let account = AccountSharedData::new_data_with_space::<[u8; 0]>(\n            rent_exempt_for_token_acc,\n            &[],\n            0,\n            &SYSTEM_PROGRAM_ID,\n        ).unwrap();\n        // insert the custom account also into the client\n        client.set_account_custom(&pda, &account);\n        let vec_of_seeds: Vec<Vec<u8>> = seeds.iter().map(|&seed| seed.to_vec())\n                            .collect();\n        PdaStore {\n            pubkey: pda,\n            seeds: vec_of_seeds,\n        }\n    }).pubkey();\n
"},{"location":"features/fuzz-instructions/#check","title":"Check","text":"

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

"},{"location":"features/fuzz-instructions/#tx-error-handler","title":"Tx Error Handler","text":"

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

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

Tip

Consider checking the Examples section for more tips.

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

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

Important

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

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

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

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

Tip

Consider checking the Examples section for more tips.

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

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

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

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

Important

Source code below:

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

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

Tip

If you want to obtain Program from Mainnet use

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

Important

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

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

Tip

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

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

Important

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

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

Tip

Consider checking the Examples section for more tips.

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

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

Possible Instruction sequences are split into 3 parts

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

Tip

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

Tip

Consider checking the Examples section for more tips.

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

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

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

Important

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

fn check(\n    &self,\n    _pre_ix: Self::IxSnapshot,\n    post_ix: Self::IxSnapshot,\n    _ix_data: Self::IxData,\n) -> Result<(), FuzzingError> {\n    if let Some(hello_world_account) = post_ix.hello_world_account {\n        if hello_world_account.input == 253 {\n            return Err(FuzzingError::Custom(1));\n        }\n    }\n    Ok(())\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/trident-manifest/","title":"Trident Manifest","text":"

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

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

Tip

Consider checking the Examples section for more tips.

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

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

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

Tip

Docker Image down below.

Important

Prerequisite

It is expected that you have installed:

For supported versions check the Supported Versions

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

Update your package list and install the required packages:

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

Install honggfuzz

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

TBD

"},{"location":"writing-fuzz-test/writing-fuzz-test/","title":"Writing fuzz test","text":""},{"location":"writing-fuzz-test/writing-fuzz-test/#initialize-trident","title":"Initialize Trident","text":"

Initialize Trident in the Anchor-based workspace.

trident init\n

Info

Trident under the hood

Tip

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

"},{"location":"writing-fuzz-test/writing-fuzz-test/#fill-the-fuzz-test-template","title":"Fill the Fuzz test Template","text":""},{"location":"writing-fuzz-test/writing-fuzz-test/#derive-accountssnapshots","title":"Derive AccountsSnapshots","text":"

For every Account Context specified in the Anchor project derive AccountsSnapshots such as:

// ...\n\nuse trident_derive_accounts_snapshots::AccountsSnapshots;\n\n// ...\n\n\n#[derive(Accounts, AccountsSnapshots)]\npub struct InitializeContext<'info> {\n    #[account(mut)]\n    pub author: Signer<'info>,\n    #[account(\n        init,\n        payer=author,\n        space=8+100,\n        seeds=[b\"hello_world_seed\"],\n        bump\n    )]\n    pub hello_world_account: Account<'info, StoreHelloWorld>,\n    pub system_program: Program<'info, System>,\n    // ...\n\n}\n
"},{"location":"writing-fuzz-test/writing-fuzz-test/#link-the-accountssnapshots","title":"Link the AccountsSnapshots","text":"

Fuzz Instructions use the derived AccountsSnapshots. You need to link the derived AccountsSnapshots to the corresponding aliases.

Important

Modules where the Contexts (with the derived AccountsSnapshots) are specified need to be public.

// fuzz_instructions.rs\n\nuse hello_world::trident_fuzz_initialize_context_snapshot::InitializeContextAlias;\n\ntype InitializeFnSnapshot<'info> = InitializeContextAlias<'info>;\n

Tip

For more examples, check the Examples.

"},{"location":"writing-fuzz-test/writing-fuzz-test/#define-fuzz-accounts","title":"Define Fuzz Accounts","text":"

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

Important

Keep in mind:

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

Tip

For more details about the AccountsStorage check AccountsStorage.

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

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

Tip

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

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

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

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

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

Tip

By default, the crashfiles are stored in the

Tip

For more info about the fuzzing outputs chech the Commands

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

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

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

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

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

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

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

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

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

Added

Changed

Removed

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

Added

Fixed

Removed

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

Added

Fixed

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

Added

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

Changed

Fixed

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

Changed

Added

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

Added

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

Important

The output provided by Honggfuzz is as follows:

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

Important

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

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

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

Trident allows developers to generate random accounts for fuzzing.

However, the Accounts are not completely random, and neither are the Account addresses.

Instead, Trident generates random AccountIDs which are indexes to Account Storages. Each unique Account contained within the Anchor generated IDL has its own AccountStorage. The FuzzAccounts containing the Accounts Storages is global to all Instructions to use.

Note

Details:

Always generating only random accounts would in most cases lead to a situation where the fuzzer would be stuck because the accounts would be almost every time rejected by your Anchor program. Therefore it is necessary to specify, what accounts should be used and also limit the number of newly created accounts to reduce the space complexity.

Important

Currently, supported types of Account Storages:

Then use the corresponding AccountsStorage.

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

Tip

Keep in mind:

Tip

Consider checking the Examples section for more tips.

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

Trident allows you to customize Instruction Data to provide structure.

For example your Initialize Instruction expects two arguments start_at and end_at you know that in order for the Instruction to make sense, it is required that the start_at < end_at. Moreover, there should be significant difference between these two. This can be utilized with the Arbitrary crate.

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

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

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

Tip

Consider checking the Examples section for more tips.

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

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

This can be particularly helpful:

Tip

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

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

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

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

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

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

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

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

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

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

"},{"location":"features/fuzz-instructions/#get-program-id","title":"Get Program ID","text":"

This method specifies program ID to which the Instruction corresponds.

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

"},{"location":"features/fuzz-instructions/#get-data","title":"Get Data","text":"

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

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

You can also use always constant values

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

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

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

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

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

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

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

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

Tip

Consider checking the Examples section for more tips.

"},{"location":"features/fuzz-instructions/#get-accounts","title":"Get Accounts","text":"

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

Important

Source Code below

fn get_accounts(\n    &self,\n    client: &mut impl FuzzClient,\n    fuzz_accounts: &mut FuzzAccounts,\n) -> Result<(Vec<Keypair>, Vec<AccountMeta>), FuzzingError> {\n    let author = fuzz_accounts.author.get_or_create_account(\n        self.accounts.author,\n        client,\n        5 * LAMPORTS_PER_SOL,\n    );\n\n    let hello_world_account = fuzz_accounts\n        .hello_world_account\n        .get_or_create_account(\n            self.accounts.hello_world_account,\n            &[b\"hello_world_seed\"],\n            &hello_world::ID,\n        )\n        .unwrap();\n    let signers = vec![author.clone()];\n    let acc_meta = hello_world::accounts::InitializeContext {\n        author: author.pubkey(),\n        hello_world_account: hello_world_account.pubkey(),\n        system_program: solana_sdk::system_program::ID,\n    }\n    .to_account_metas(None);\n    Ok((signers, acc_meta))\n}\n
"},{"location":"features/fuzz-instructions/#create-an-arbitrary-account","title":"Create an arbitrary account","text":"

The AccountsStorage<T> type provides an implementation of the get_or_create_account method that helps you create new or read already existing accounts. There are different implementations for different types of storage (Keypair, TokenStore, MintStore, PdaStore) to simplify the creation of new accounts.

However, there are cases when the provided implementation is not sufficient and it is necessary to create an account manually. These cases can be (but are not limited to) for example:

In that case, you can use the storage method of the AccountsStorage<T> struct that exposes the underlying HashMap<AccountId, T> and you can add new accounts directly to it.

It is possible to create and store any kind of account. For example:

let state = fuzz_accounts\n    .state\n    // gets the storage of all `state` account variants\n    .storage()\n    // returns the Keypair of the `state` account with\n    // the given `AccountId` if it has been added previously\n    .entry(self.accounts.state)\n    .or_insert_with(|| {\n        let space = State::SIZE;\n        let rent_exempt_lamports = client.get_rent().unwrap()\n                            .minimum_balance(space);\n        let keypair = Keypair::new();\n        let account = AccountSharedData::new_data_with_space::<[u8; 0]>(\n            rent_exempt_lamports,\n            &[],\n            space,\n            &my_program::id(),\n        ).unwrap();\n        // insert the custom account also into the client\n        client.set_account_custom(&keypair.pubkey(), &account);\n        keypair\n    });\n
let rent_exempt_for_token_acc = client\n    .get_rent()\n    .unwrap()\n    .minimum_balance(anchor_spl::token::spl_token::state::Account::LEN);\n\nlet my_pda = fuzz_accounts\n    .my_pda\n    // gets the storage of all `my_pda` account variants\n    .storage()\n    // returns the PdaStore struct of the `my_pda` account with\n    // the given `AccountId` if it has been added previously\n    .entry(self.accounts.my_pda)\n    .or_insert_with(|| {\n        let seeds = &[b\"some-seeds\"];\n        let pda = Pubkey::find_program_address(seeds, &my_program::id()).0;\n        let account = AccountSharedData::new_data_with_space::<[u8; 0]>(\n            rent_exempt_for_token_acc,\n            &[],\n            0,\n            &SYSTEM_PROGRAM_ID,\n        ).unwrap();\n        // insert the custom account also into the client\n        client.set_account_custom(&pda, &account);\n        let vec_of_seeds: Vec<Vec<u8>> = seeds.iter().map(|&seed| seed.to_vec())\n                            .collect();\n        PdaStore {\n            pubkey: pda,\n            seeds: vec_of_seeds,\n        }\n    }).pubkey();\n
"},{"location":"features/fuzz-instructions/#check","title":"Check","text":"

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

"},{"location":"features/fuzz-instructions/#tx-error-handler","title":"Tx Error Handler","text":"

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

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

Tip

Consider checking the Examples section for more tips.

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

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

Important

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

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

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

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

Tip

Consider checking the Examples section for more tips.

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

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

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

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

Important

Source code below:

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

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

Tip

If you want to obtain Program from Mainnet use

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

Important

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

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

Tip

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

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

Important

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

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

Tip

Consider checking the Examples section for more tips.

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

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

Possible Instruction sequences are split into 3 parts

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

Tip

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

Tip

Consider checking the Examples section for more tips.

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

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

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

Important

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

fn check(\n    &self,\n    _pre_ix: Self::IxSnapshot,\n    post_ix: Self::IxSnapshot,\n    _ix_data: Self::IxData,\n) -> Result<(), FuzzingError> {\n    if let Some(hello_world_account) = post_ix.hello_world_account {\n        if hello_world_account.input == 253 {\n            return Err(FuzzingError::Custom(1));\n        }\n    }\n    Ok(())\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/trident-manifest/","title":"Trident Manifest","text":"

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

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

Tip

Consider checking the Examples section for more tips.

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

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

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

Tip

Docker Image down below.

Important

Prerequisite

It is expected that you have installed:

For supported versions check the Supported Versions

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

Update your package list and install the required packages:

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

Install honggfuzz

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

TBD

"},{"location":"writing-fuzz-test/writing-fuzz-test/","title":"Writing fuzz test","text":""},{"location":"writing-fuzz-test/writing-fuzz-test/#initialize-trident","title":"Initialize Trident","text":"

Initialize Trident in the Anchor-based workspace.

trident init\n

Info

Trident under the hood

Tip

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

"},{"location":"writing-fuzz-test/writing-fuzz-test/#fill-the-fuzz-test-template","title":"Fill the Fuzz test Template","text":""},{"location":"writing-fuzz-test/writing-fuzz-test/#derive-accountssnapshots","title":"Derive AccountsSnapshots","text":"

For every Account Context specified in the Anchor project derive AccountsSnapshots such as:

// ...\n\nuse trident_derive_accounts_snapshots::AccountsSnapshots;\n\n// ...\n\n\n#[derive(Accounts, AccountsSnapshots)]\npub struct InitializeContext<'info> {\n    #[account(mut)]\n    pub author: Signer<'info>,\n    #[account(\n        init,\n        payer=author,\n        space=8+100,\n        seeds=[b\"hello_world_seed\"],\n        bump\n    )]\n    pub hello_world_account: Account<'info, StoreHelloWorld>,\n    pub system_program: Program<'info, System>,\n    // ...\n\n}\n
"},{"location":"writing-fuzz-test/writing-fuzz-test/#link-the-accountssnapshots","title":"Link the AccountsSnapshots","text":"

Fuzz Instructions use the derived AccountsSnapshots. You need to link the derived AccountsSnapshots to the corresponding aliases.

Important

Modules where the Contexts (with the derived AccountsSnapshots) are specified need to be public.

// fuzz_instructions.rs\n\nuse hello_world::trident_fuzz_initialize_context_snapshot::InitializeContextAlias;\n\ntype InitializeFnSnapshot<'info> = InitializeContextAlias<'info>;\n

Tip

For more examples, check the Examples.

"},{"location":"writing-fuzz-test/writing-fuzz-test/#define-fuzz-accounts","title":"Define Fuzz Accounts","text":"

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

Important

Keep in mind:

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

Tip

For more details about the AccountsStorage check AccountsStorage.

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

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

Tip

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

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

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

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

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

Tip

By default, the crashfiles are stored in the

Tip

For more info about the fuzzing outputs chech the Commands

"}]} \ No newline at end of file diff --git a/dev/writing-fuzz-test/writing-fuzz-test/index.html b/dev/writing-fuzz-test/writing-fuzz-test/index.html index 159e2bd5..92769f0f 100644 --- a/dev/writing-fuzz-test/writing-fuzz-test/index.html +++ b/dev/writing-fuzz-test/writing-fuzz-test/index.html @@ -48,4 +48,4 @@

Tip

By default, the crashfiles are stored in the

Tip

For more info about the fuzzing outputs chech the Commands

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

Tip

By default, the crashfiles are stored in the

Tip

For more info about the fuzzing outputs chech the Commands

\ No newline at end of file