{"id":723,"date":"2024-05-20T12:37:59","date_gmt":"2024-05-20T10:37:59","guid":{"rendered":"https:\/\/ackee.xyz\/blog\/?p=723"},"modified":"2024-07-04T12:24:07","modified_gmt":"2024-07-04T10:24:07","slug":"introducing-trident-the-first-open-source-fuzzer-for-solana-programs","status":"publish","type":"post","link":"https:\/\/ackee.xyz\/blog\/introducing-trident-the-first-open-source-fuzzer-for-solana-programs\/","title":{"rendered":"Introducing Trident: The First Open-Source Fuzzer for Solana Programs"},"content":{"rendered":"<p><span style=\"font-weight: 400;\">Trident is a Rust-based framework designed to help developers fuzz test Solana programs written in Anchor. Developed by Ackee Blockchain and supported by the Solana Foundation, Trident simplifies the testing process and helps developers ship secure code by uncovering edge-case vulnerabilities.<\/span><\/p>\n<h2>Trident Fuzzing Video Tutorial<\/h2>\n<p>For <a href=\"https:\/\/ackee.xyz\/school-of-solana\" target=\"_blank\" rel=\"noopener\">School of Solana<\/a> we prepared a bonus lecture for developers to learn how to fuzz test Solana programs with Trident.<\/p>\n<p><iframe loading=\"lazy\" title=\"Fuzz Testing Solana Programs with Trident\" width=\"1170\" height=\"658\" src=\"https:\/\/www.youtube.com\/embed\/5Lq8iEbMFbs?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" referrerpolicy=\"strict-origin-when-cross-origin\" allowfullscreen><\/iframe><\/p>\n<p>&nbsp;<\/p>\n<h2>Trident is powerful<\/h2>\n<p><span style=\"font-weight: 400;\">Trident&#8217;s development began over 2.5 years ago in 2021, originally under the name Trdeln\u00edk. Trident has won the Marinade Finance community prize during the Solana Riptide Hackathon in 2022 and has received a development grant from the Solana Foundation in 2023.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Features<\/span><\/p>\n<ol>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><b>Automated Fuzz Test Generation:<\/b><span style=\"font-weight: 400;\"> Simplifies the creation of test templates for Anchor programs, reducing setup time and effort.<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><b>Adaptive Inputs:<\/b><span style=\"font-weight: 400;\"> Generates dynamic and adaptive inputs to improve test coverage and uncover hidden vulnerabilities.<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><b>Guided Instruction Sequences:<\/b><span style=\"font-weight: 400;\"> Uses customizable sequences of instructions for faster, more effective testing results.<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><b>Invariant Checks:<\/b><span style=\"font-weight: 400;\"> Allows developers to implement custom checks to spot vulnerabilities and unwanted behavior.<\/span><\/li>\n<\/ol>\n<p>&nbsp;<\/p>\n<h2><strong>Getting Started<\/strong><\/h2>\n<p><span style=\"font-weight: 400;\">Installation<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Trident is distributed via Rust&#8217;s cargo package manager. To install Trident and its dependencies, follow these steps:<\/span><\/p>\n<ol>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Install Trident CLI and honggfuzz:<br \/>\n<\/span><\/p>\n<pre><code class=\"language-rust\">cargo install trident-cli\ncargo install honggfuzz<\/code><\/pre>\n<\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\">Initialize Trident in Your Project:\n<pre><code class=\"language-rust\">trident init<\/code><\/pre>\n<p>This command sets up Trident in your project, generating necessary files and configurations.<\/li>\n<\/ol>\n<p>&nbsp;<\/p>\n<h2>Fuzz Testing Solana Programs<\/h2>\n<p>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. Trident integrates the well-known fuzzer honggfuzz, developed by Google, to facilitate fuzz testing for Solana programs.<\/p>\n<p>Example: Setting Up a New Anchor Project<\/p>\n<ol>\n<li style=\"list-style-type: none;\">\n<ol>\n<li>Initialize the Project:\n<pre><code class=\"language-rust\">anchor init my-trident-fuzz-test\ncd my-trident-fuzz-test\nanchor build<\/code><\/pre>\n<\/li>\n<li><span style=\"font-weight: 400;\">Create a Buggy Program:<br \/>\n<\/span><span style=\"font-weight: 400;\"><span style=\"font-weight: 400;\">Create a program named <code class=\"codehl\">unchecked_arithmetic_0<\/code> with intentional bugs for testing.<br \/>\n<\/span><\/span><\/p>\n<pre><code class=\"language-rust\">use anchor_lang::prelude::*;\n\nconst MAGIC_NUMBER: u8 = 254;\n\ndeclare_id!(&quot;....&quot;); \/\/ paste your program ID here\n\n#[program]\npub mod unchecked_arithmetic_0 {\n\tuse super::*;\n\n\tpub fn initialize(ctx: Context&lt;Initialize&gt;) -&gt; Result&lt;()&gt; {\n    \tlet counter = &amp;mut ctx.accounts.counter;\n\n    \tcounter.count = 0;\n    \tcounter.authority = ctx.accounts.user.key();\n\n    \tOk(())\n\t}\n\n\tpub fn update(ctx: Context&lt;Update&gt;, input1: u8, input2: u8) -&gt; Result&lt;()&gt; {\n    \tlet counter = &amp;mut ctx.accounts.counter;\n\n    \tmsg!(&quot;input1 = {}, input2 = {}&quot;, input1, input2);\n\n    \tcounter.count = buggy_math_function(input1, input2).into();\n    \tOk(())\n\t}\n}\npub fn buggy_math_function(input1: u8, input2: u8) -&gt; u8 {\n\t\/\/ INFO uncommenting the if statement can prevent\n\t\/\/ div-by-zero and subtract with overflow panic\n\t\/\/ if input2 &gt;= MAGIC_NUMBER {\n\t\/\/ \treturn 0;\n\t\/\/ }\n\tlet divisor = MAGIC_NUMBER - input2;\n\tinput1 \/ divisor\n}\n\n#[derive(Accounts)]\npub struct Initialize&lt;&#039;info&gt; {\n\t#[account(init, payer = user, space = 8 + 40)]\n\tpub counter: Account&lt;&#039;info, Counter&gt;,\n\n\t#[account(mut)]\n\tpub user: Signer&lt;&#039;info&gt;,\n\n\tpub system_program: Program&lt;&#039;info, System&gt;,\n}\n\n#[derive(Accounts)]\npub struct Update&lt;&#039;info&gt; {\n\t#[account(mut, has_one = authority)]\n\tpub counter: Account&lt;&#039;info, Counter&gt;,\n\tpub authority: Signer&lt;&#039;info&gt;,\n}\n\n#[account]\npub struct Counter {\n\tpub authority: Pubkey,\n\tpub count: u64,\n}<\/code><\/pre>\n<\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\"><span style=\"font-weight: 400;\">Initialize Trident:<br \/>\n<\/span><\/span><\/p>\n<pre><code class=\"language-rust\">trident init\n<\/code><\/pre>\n<\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Write a Fuzz Test:<br \/>\nModify the fuzz test template located at \u2018trident-tests\/fuzz_tests\/fuzz_0\/fuzz_instructions.rs\u2019 and finish the implementation of <code class=\"codehl\">get_data<\/code> and <code class=\"codehl\">get_accounts<\/code> methods and <code class=\"codehl\">FuzzAccounts<\/code> struct:<br \/>\n<\/span><\/p>\n<pre><code class=\"language-rust\">pub mod unchecked_arithmetic_0_fuzz_instructions {\n\tuse crate::accounts_snapshots::*;\n\tuse trident_client::{fuzzing::*, solana_sdk::native_token::LAMPORTS_PER_SOL};\n\t#[derive(Arbitrary, DisplayIx, FuzzTestExecutor, FuzzDeserialize)]\n\tpub enum FuzzInstruction {\n    \tInitialize(Initialize),\n    \tUpdate(Update),\n\t}\n\t#[derive(Arbitrary, Debug)]\n\tpub struct Initialize {\n    \tpub accounts: InitializeAccounts,\n    \tpub data: InitializeData,\n\t}\n\t#[derive(Arbitrary, Debug)]\n\tpub struct InitializeAccounts {\n    \tpub counter: AccountId,\n    \tpub user: AccountId,\n    \tpub system_program: AccountId,\n\t}\n\t#[derive(Arbitrary, Debug)]\n\tpub struct InitializeData {}\n\t#[derive(Arbitrary, Debug)]\n\tpub struct Update {\n    \tpub accounts: UpdateAccounts,\n    \tpub data: UpdateData,\n\t}\n\t#[derive(Arbitrary, Debug)]\n\tpub struct UpdateAccounts {\n    \tpub counter: AccountId,\n    \tpub authority: AccountId,\n\t}\n\t#[derive(Arbitrary, Debug)]\n\tpub struct UpdateData {\n    \tpub input1: u8,\n    \tpub input2: u8,\n\t}\n\timpl&lt;&#039;info&gt; IxOps&lt;&#039;info&gt; for Initialize {\n    \ttype IxData = unchecked_arithmetic_0::instruction::Initialize;\n    \ttype IxAccounts = FuzzAccounts;\n    \ttype IxSnapshot = InitializeSnapshot&lt;&#039;info&gt;;\n    \tfn get_data(\n        \t&amp;self,\n        \t_client: &amp;mut impl FuzzClient,\n        \t_fuzz_accounts: &amp;mut FuzzAccounts,\n    \t) -&gt; Result&lt;Self::IxData, FuzzingError&gt; {\n        \tlet data = unchecked_arithmetic_0::instruction::Initialize {};\n        \tOk(data)\n    \t}\n    \tfn get_accounts(\n        \t&amp;self,\n        \tclient: &amp;mut impl FuzzClient,\n        \tfuzz_accounts: &amp;mut FuzzAccounts,\n    \t) -&gt; Result&lt;(Vec&lt;Keypair&gt;, Vec&lt;AccountMeta&gt;), FuzzingError&gt; {\n        \tlet user = fuzz_accounts.user.get_or_create_account(\n            \tself.accounts.user,\n            \tclient,\n            \t5 * LAMPORTS_PER_SOL,\n        \t);\n        \tlet counter = fuzz_accounts.counter.get_or_create_account(\n            \tself.accounts.counter,\n            \tclient,\n            \t5 * LAMPORTS_PER_SOL,\n        \t);\n\n        \tlet acc_meta = unchecked_arithmetic_0::accounts::Initialize {\n            \tcounter: counter.pubkey(),\n            \tuser: user.pubkey(),\n            \tsystem_program: SYSTEM_PROGRAM_ID,\n        \t}\n        \t.to_account_metas(None);\n        \tOk((vec![user, counter], acc_meta))\n    \t}\n\t}\n\timpl&lt;&#039;info&gt; IxOps&lt;&#039;info&gt; for Update {\n    \ttype IxData = unchecked_arithmetic_0::instruction::Update;\n    \ttype IxAccounts = FuzzAccounts;\n    \ttype IxSnapshot = UpdateSnapshot&lt;&#039;info&gt;;\n    \tfn get_data(\n        \t&amp;self,\n        \t_client: &amp;mut impl FuzzClient,\n        \t_fuzz_accounts: &amp;mut FuzzAccounts,\n    \t) -&gt; Result&lt;Self::IxData, FuzzingError&gt; {\n        \tlet data = unchecked_arithmetic_0::instruction::Update {\n            \tinput1: self.data.input1,\n            \tinput2: self.data.input2,\n        \t};\n        \tOk(data)\n    \t}\n    \tfn get_accounts(\n        \t&amp;self,\n        \tclient: &amp;mut impl FuzzClient,\n        \tfuzz_accounts: &amp;mut FuzzAccounts,\n    \t) -&gt; Result&lt;(Vec&lt;Keypair&gt;, Vec&lt;AccountMeta&gt;), FuzzingError&gt; {\n        \tlet user = fuzz_accounts.user.get_or_create_account(\n            \tself.accounts.authority,\n            \tclient,\n            \t15 * LAMPORTS_PER_SOL,\n        \t);\n        \tlet counter = fuzz_accounts.counter.get_or_create_account(\n            \tself.accounts.counter,\n            \tclient,\n            \t5 * LAMPORTS_PER_SOL,\n        \t);\n\n        \tlet acc_meta = unchecked_arithmetic_0::accounts::Update {\n            \tcounter: counter.pubkey(),\n            \tauthority: user.pubkey(),\n        \t}\n        \t.to_account_metas(None);\n        \tOk((vec![user], acc_meta))\n    \t}\n\t}\n\t#[doc = r&quot; Use AccountsStorage&lt;T&gt; where T can be one of:&quot;]\n\t#[doc = r&quot; Keypair, PdaStore, TokenStore, MintStore, ProgramStore&quot;]\n\t#[derive(Default)]\n\tpub struct FuzzAccounts {\n    \t\/\/ The &#039;authority&#039; and &#039;system_program&#039; were automatically\n    \t\/\/ generated in the FuzzAccounts struct, as they are both\n    \t\/\/ used in the program. However, the &#039;authority&#039; is in fact\n    \t\/\/ the user account, just named differently. Therefore, we will use only\n    \t\/\/ the generated user accounts for both &#039;user&#039; and &#039;authority account&#039; fields\n    \t\/\/ in this fuzz test. Additionally, there is no need to fuzz the &#039;system_program&#039; account.\n    \tuser: AccountsStorage&lt;Keypair&gt;,\n    \tcounter: AccountsStorage&lt;Keypair&gt;,\n\t}\n}<\/code><\/pre>\n<p><span style=\"font-weight: 400;\"><span style=\"font-weight: 400;\">Modify the fuzz test template located at \u2018trident-tests\/fuzz_tests\/fuzz_0\/test_fuzz.rs\u2019:<br \/>\n<\/span><\/span><\/p>\n<pre><code class=\"language-rust\">use fuzz_instructions::unchecked_arithmetic_0_fuzz_instructions::FuzzInstruction;\nuse fuzz_instructions::unchecked_arithmetic_0_fuzz_instructions::Initialize;\nuse trident_client::{convert_entry, fuzz_trident, fuzzing::*};\nuse unchecked_arithmetic_0::entry;\nuse unchecked_arithmetic_0::ID as PROGRAM_ID;\nmod accounts_snapshots;\nmod fuzz_instructions;\n\nconst PROGRAM_NAME: &amp;str = &quot;unchecked_arithmetic_0&quot;;\n\nstruct MyFuzzData;\n\nimpl FuzzDataBuilder&lt;FuzzInstruction&gt; for MyFuzzData {\n\tfn pre_ixs(u: &amp;mut arbitrary::Unstructured) -&gt; arbitrary::Result&lt;Vec&lt;FuzzInstruction&gt;&gt; {\n    \tlet init = FuzzInstruction::Initialize(Initialize::arbitrary(u)?);\n    \tOk(vec![init])\n\t}\n}\n\nfn main() {\n\tloop {\n    \tfuzz_trident!(fuzz_ix: FuzzInstruction, |fuzz_data: MyFuzzData| {\n        \tlet mut client =\n            \tProgramTestClientBlocking::new(PROGRAM_NAME, PROGRAM_ID, processor!(convert_entry!(entry)))\n                \t.unwrap();\n        \tlet _ = fuzz_data.run_with_runtime(PROGRAM_ID, &amp;mut client);\n    \t});\n\t}\n}<\/code><\/pre>\n<\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Run the Fuzz Test:<\/span>\n<pre><code class=\"language-rust\">trident fuzz run fuzz_0<\/code><\/pre>\n<\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\">Debugging with Crash Files:<span style=\"font-weight: 400;\"><span style=\"font-weight: 400;\">Use crash files to debug and inspect issues:<br \/>\n<\/span><\/span><\/p>\n<pre><code class=\"language-rust\">trident fuzz run-debug fuzz_0 \ntrident-tests\/fuzz_tests\/fuzzing\/hfuzz_workspace\/fuzz_0\/&lt;CRASH_FILE&gt;.fuzz<\/code><\/pre>\n<\/li>\n<\/ol>\n<\/li>\n<\/ol>\n<p>&nbsp;<\/p>\n<h2>Integration Testing<\/h2>\n<p><span style=\"font-weight: 400;\">Trident also supports integration testing, allowing developers to test their Solana programs in a simulated environment that closely mirrors the actual Solana blockchain. This ensures that programs interact correctly with the blockchain and other programs.<\/span><\/p>\n<p>&nbsp;<\/p>\n<h2>Trident Developer Support<\/h2>\n<p><span style=\"font-weight: 400;\">For developer support find us in our <\/span><a href=\"https:\/\/discord.gg\/Ay5fWuygJH\"><span style=\"font-weight: 400;\">Discord #trident-chat<\/span><\/a><span style=\"font-weight: 400;\"> and on <\/span><a href=\"https:\/\/warpcast.com\/~\/channel\/trident\"><span style=\"font-weight: 400;\">warpcast \/trident channel<\/span><\/a><span style=\"font-weight: 400;\">. Please read the <a href=\"https:\/\/ackee.xyz\/trident\/docs\/\">documentation<\/a>, star our <a href=\"https:\/\/github.com\/Ackee-Blockchain\/trident\">GitHub repo<\/a> and follow Trident on Twitter\/X <a href=\"https:\/\/twitter.com\/TridentSolana\">@TridentSolana<\/a> for updates. <\/span><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Trident is a Rust-based framework designed to help developers fuzz test Solana programs written in Anchor. Developed by Ackee Blockchain and supported by the Solana Foundation, Trident simplifies the testing process and helps developers ship secure code by uncovering edge-case vulnerabilities. Trident Fuzzing Video Tutorial For School of Solana we prepared a bonus lecture for developers to learn how to fuzz test&hellip;<\/p>\n","protected":false},"author":20,"featured_media":738,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[5,113,63],"tags":[6,114,102],"class_list":["post-723","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-solana","category-trident","category-tutorial","tag-solana","tag-trident","tag-tutorial"],"aioseo_notices":[],"featured_image_src":"https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2024\/06\/Trident-helps-you-ship-secure-code-600x400.png","featured_image_src_square":"https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2024\/06\/Trident-helps-you-ship-secure-code-600x600.png","author_info":{"display_name":"Adam Hrazdira","author_link":"https:\/\/ackee.xyz\/blog\/author\/adam-hrazdira\/"},"_links":{"self":[{"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/posts\/723","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/users\/20"}],"replies":[{"embeddable":true,"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/comments?post=723"}],"version-history":[{"count":0,"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/posts\/723\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/media\/738"}],"wp:attachment":[{"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/media?parent=723"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/categories?post=723"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/tags?post=723"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}