π [BUG] - Trident codegen merges multiple programs with same type/instruction names => duplicate/conflicting structs in types.rs
Description
Summary
When a workspace contains multiple Anchor programs that reuse the same type/instruction names but with different field layouts, trident init appears to flatten the IDLs into a single fuzz scaffold. The generated fuzz_0/types.rs defines the same struct name twice with different shapes, leading to duplicate/conflicting derives and compilation failures.
PoC (minimal)
Workspace layout
βββ Anchor.toml
βββ Cargo.lock
βββ Cargo.toml
βββ programs
β βββ program_a
β β βββ Cargo.toml
β β βββ src
β β βββ lib.rs
β βββ program_b
β βββ Cargo.toml
β βββ src
β βββ lib.rs
programs/program_a/src/lib.rs
use anchor_lang::prelude::*;
declare_id!("2zT2BuYjCaiMvrYyuyG3EWAJpBJgtaV5n78wZdkDUxGw");
#[program]
pub mod program_a {
use super::*;
pub fn create_item(_ctx: Context<CreateItem>, _params: CreateItemParams) -> Result<()> {
Ok(())
}
}
#[derive(AnchorSerialize, AnchorDeserialize, Clone)]
pub struct CreateItemParams {
pub name: String,
}
#[derive(Accounts)]
pub struct CreateItem {}
programs/program_b/src/lib.rs
use anchor_lang::prelude::*;
declare_id!("2zT2BuYwyEanAzmxp6wVLCxUx5zhbEZzngYqYEHRnK2P");
#[program]
pub mod program_b {
use super::*;
pub fn create_item(_ctx: Context<CreateItem>, _params: CreateItemParams) -> Result<()> {
Ok(())
}
}
#[derive(AnchorSerialize, AnchorDeserialize, Clone)]
pub struct CreateItemParams {
pub name: String,
pub extra: u64,
}
#[derive(Accounts)]
pub struct CreateItem {}
Suggested fix
Codegen should namespace per program (e.g., types/program_a.rs, types/program_b.rs, and similarly for instructions/ & transactions/), so identical names across programs donβt collide and each structβs shape matches its programβs IDL.
Reproduction steps
1. Build to produce IDLs:
anchor build
2. Generate Trident fuzz scaffold:
trident init
3. Observe generated `fuzz_0/types.rs` contains **two** `CreateItemParams`:
#[derive(Debug, BorshDeserialize, BorshSerialize, Clone, Default)]
pub struct CreateItemParams {
pub name: String,
pub extra: u64,
}
#[derive(Debug, BorshDeserialize, BorshSerialize, Clone, Default)]
pub struct CreateItemParams {
pub name: String,
}
4. Run fuzzer:
trident fuzz run fuzz_0
Reproduction URL
No response
Screenshots
Logs
error[E0119]: conflicting implementations of trait `Default` for type `types::CreateItemParams`
--> fuzz_0/types.rs:15:58
|
9 | #[derive(Debug, BorshDeserialize, BorshSerialize, Clone, Default)]
| ------- first implementation here
...
15 | #[derive(Debug, BorshDeserialize, BorshSerialize, Clone, Default)]
| ^^^^^^^ conflicting implementation for `types::CreateItemParams`
error[E0119]: conflicting implementations of trait `std::fmt::Debug` for type `types::CreateItemParams`
--> fuzz_0/types.rs:15:10
|
9 | #[derive(Debug, BorshDeserialize, BorshSerialize, Clone, Default)]
| ----- first implementation here
...
15 | #[derive(Debug, BorshDeserialize, BorshSerialize, Clone, Default)]
| ^^^^^ conflicting implementation for `types::CreateItemParams`
error[E0119]: conflicting implementations of trait `Clone` for type `types::CreateItemParams`
--> fuzz_0/types.rs:15:51
|
9 | #[derive(Debug, BorshDeserialize, BorshSerialize, Clone, Default)]
| ----- first implementation here
...
15 | #[derive(Debug, BorshDeserialize, BorshSerialize, Clone, Default)]
| ^^^^^ conflicting implementation for `types::CreateItemParams`
error[E0119]: conflicting implementations of trait `BorshDeserialize` for type `types::CreateItemParams`
--> fuzz_0/types.rs:15:17
|
9 | #[derive(Debug, BorshDeserialize, BorshSerialize, Clone, Default)]
| ---------------- first implementation here
...
15 | #[derive(Debug, BorshDeserialize, BorshSerialize, Clone, Default)]
| ^^^^^^^^^^^^^^^^ conflicting implementation for `types::CreateItemParams`
|
= note: this error originates in the derive macro `BorshDeserialize` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0119]: conflicting implementations of trait `BorshSerialize` for type `types::CreateItemParams`
--> fuzz_0/types.rs:15:35
|
9 | #[derive(Debug, BorshDeserialize, BorshSerialize, Clone, Default)]
| -------------- first implementation here
...
15 | #[derive(Debug, BorshDeserialize, BorshSerialize, Clone, Default)]
| ^^^^^^^^^^^^^^ conflicting implementation for `types::CreateItemParams`
|
= note: this error originates in the derive macro `BorshSerialize` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0063]: missing field `extra` in initializer of `types::CreateItemParams`
--> fuzz_0/types.rs:15:17
|
15 | #[derive(Debug, BorshDeserialize, BorshSerialize, Clone, Default)]
| ^^^^^^^^^^^^^^^^ missing `extra`
|
= note: this error originates in the derive macro `BorshDeserialize` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0063]: missing field `extra` in initializer of `types::CreateItemParams`
--> fuzz_0/types.rs:15:51
|
15 | #[derive(Debug, BorshDeserialize, BorshSerialize, Clone, Default)]
| ^ missing `extra`
error[E0063]: missing field `extra` in initializer of `types::CreateItemParams`
--> fuzz_0/types.rs:15:58
|
15 | #[derive(Debug, BorshDeserialize, BorshSerialize, Clone, Default)]
| ^ missing `extra`
OS
Linux
Thanks for saving the time of your fellow Trident user and reporting this issue for us all, @Ectario!
@lukacan, wdyt about adding the program name to the name of the type derived from it, in order to disambiguate the same-name-different-programs types?
e.g. [PROGRAM_NAME]_[TYPE_NAME]
Hey guys, thanks for the issue, ye, I'm aware of this. Adding the program name at the start would help, but on the other hand, we are still exploring other options for how the folder layout could be structured, something that would make transaction creation much easier. Hopefully, this is nota big blocker for you, as I'm not 100% sure we will implement the fix immediately.
we are still exploring other options for how the folder layout could be structured
No worries, take your time! A better solution > a fast one π
Hopefully, this is nota big blocker for you
For now, I've fixed the issue manually.