Skip to content

Commit a1e4453

Browse files
cli: Make conflicting account names a compile-time error (solana-foundation#2621)
1 parent b9fa898 commit a1e4453

6 files changed

Lines changed: 121 additions & 0 deletions

File tree

cli/src/lib.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2501,6 +2501,22 @@ fn generate_idl_build(no_docs: bool) -> Result<Vec<Idl>> {
25012501
})
25022502
.collect::<Vec<_>>();
25032503

2504+
// Verify IDLs are valid
2505+
for idl in &idls {
2506+
let full_path_account = idl
2507+
.accounts
2508+
.iter()
2509+
.find(|account| account.name.contains("::"));
2510+
2511+
if let Some(account) = full_path_account {
2512+
return Err(anyhow!(
2513+
"Conflicting accounts names are not allowed.\nProgram: {}\nAccount: {}",
2514+
idl.name,
2515+
account.name
2516+
));
2517+
}
2518+
}
2519+
25042520
Ok(idls)
25052521
}
25062522

tests/idl/Anchor.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ docs = "Docs111111111111111111111111111111111111111"
77
external = "Externa1111111111111111111111111111111111111"
88
generics = "Generics111111111111111111111111111111111111"
99
idl = "id11111111111111111111111111111111111111111"
10+
idl_build_features = "id1Bui1dFeatures111111111111111111111111111"
1011
relations_derivation = "Re1ationsDerivation111111111111111111111111"
1112
non_existent = { address = "NonExistent11111111111111111111111111111111", idl = "non-existent.json" }
1213
numbers_123 = { address = "Numbers111111111111111111111111111111111111", idl = "idls/relations_build.json" }
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
[package]
2+
name = "idl-build-features"
3+
version = "0.1.0"
4+
description = "Created with Anchor"
5+
rust-version = "1.60"
6+
edition = "2021"
7+
8+
[lib]
9+
crate-type = ["cdylib", "lib"]
10+
name = "idl_build_features"
11+
12+
[features]
13+
no-entrypoint = []
14+
no-idl = []
15+
cpi = ["no-entrypoint"]
16+
idl-build = ["anchor-lang/idl-build"]
17+
default = []
18+
19+
[dependencies]
20+
anchor-lang = { path = "../../../../lang" }
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
[target.bpfel-unknown-unknown.dependencies.std]
2+
features = []
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
use anchor_lang::prelude::*;
2+
3+
declare_id!("id1Bui1dFeatures111111111111111111111111111");
4+
5+
#[program]
6+
pub mod idl_build_features {
7+
use super::*;
8+
9+
pub fn full_path(
10+
ctx: Context<FullPath>,
11+
my_struct: MyStruct,
12+
some_module_my_struct: some_module::MyStruct,
13+
) -> Result<()> {
14+
ctx.accounts.account.my_struct = my_struct;
15+
ctx.accounts.account.some_module_my_struct = some_module_my_struct;
16+
Ok(())
17+
}
18+
}
19+
20+
#[derive(Accounts)]
21+
pub struct FullPath<'info> {
22+
#[account(zero)]
23+
pub account: Account<'info, FullPathAccount>,
24+
}
25+
26+
#[account]
27+
pub struct FullPathAccount {
28+
pub my_struct: MyStruct,
29+
pub some_module_my_struct: some_module::MyStruct,
30+
}
31+
32+
mod some_module {
33+
use super::*;
34+
35+
#[derive(AnchorSerialize, AnchorDeserialize, Clone)]
36+
pub struct MyStruct {
37+
pub data: u8,
38+
}
39+
}
40+
41+
#[derive(AnchorSerialize, AnchorDeserialize, Clone)]
42+
pub struct MyStruct {
43+
pub u8: u8,
44+
pub u16: u16,
45+
pub u32: u32,
46+
pub u64: u64,
47+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import * as anchor from "@coral-xyz/anchor";
2+
import { assert } from "chai";
3+
4+
import { IdlBuildFeatures } from "../target/types/idl_build_features";
5+
6+
describe("idl-build features", () => {
7+
anchor.setProvider(anchor.AnchorProvider.env());
8+
const program = anchor.workspace
9+
.idlBuildFeatures as anchor.Program<IdlBuildFeatures>;
10+
11+
it("Can use full module path types", async () => {
12+
const kp = anchor.web3.Keypair.generate();
13+
14+
const outerMyStructArg = { u8: 1, u16: 2, u32: 3, u64: new anchor.BN(4) };
15+
const someModuleMyStructArg = { data: 5 };
16+
17+
await program.methods
18+
.fullPath(outerMyStructArg, someModuleMyStructArg)
19+
.accounts({ account: kp.publicKey })
20+
.preInstructions([
21+
await program.account.fullPathAccount.createInstruction(kp),
22+
])
23+
.signers([kp])
24+
.rpc();
25+
26+
const fullPathAccount = await program.account.fullPathAccount.fetch(
27+
kp.publicKey
28+
);
29+
assert.strictEqual(fullPathAccount.myStruct.u8, outerMyStructArg.u8);
30+
assert.strictEqual(fullPathAccount.myStruct.u16, outerMyStructArg.u16);
31+
assert.strictEqual(fullPathAccount.myStruct.u32, outerMyStructArg.u32);
32+
assert(fullPathAccount.myStruct.u64.eq(outerMyStructArg.u64));
33+
assert.deepEqual(fullPathAccount.someModuleMyStruct, someModuleMyStructArg);
34+
});
35+
});

0 commit comments

Comments
 (0)