Skip to content

Commit

Permalink
idl: Check ambiguous discriminators (#3157)
Browse files Browse the repository at this point in the history
  • Loading branch information
acheroncrypto authored Aug 7, 2024
1 parent dfb2de5 commit 438c481
Show file tree
Hide file tree
Showing 7 changed files with 112 additions and 1 deletion.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ The minor version will be incremented upon a breaking change and the patch versi
- lang: Use associated discriminator constants instead of hardcoding in `#[account]` ([#3144](https://github.com/coral-xyz/anchor/pull/3144)).
- lang: Add `discriminator` argument to `#[account]` attribute ([#3149](https://github.com/coral-xyz/anchor/pull/3149)).
- lang: Add `discriminator` argument to `#[event]` attribute ([#3152](https://github.com/coral-xyz/anchor/pull/3152)).
- idl: Check ambiguous discriminators ([#3157](https://github.com/coral-xyz/anchor/pull/3157)).

### Fixes

Expand Down
24 changes: 24 additions & 0 deletions idl/src/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -293,5 +293,29 @@ fn verify(idl: &Idl) -> Result<()> {
));
}

// Check potential discriminator collisions
macro_rules! check_discriminator_collision {
($field:ident) => {
if let Some((outer, inner)) = idl.$field.iter().find_map(|outer| {
idl.$field
.iter()
.filter(|inner| inner.name != outer.name)
.find(|inner| outer.discriminator.starts_with(&inner.discriminator))
.map(|inner| (outer, inner))
}) {
return Err(anyhow!(
"Ambiguous discriminators for {} `{}` and `{}`",
stringify!($field),
outer.name,
inner.name
));
}
};
}

check_discriminator_collision!(accounts);
check_discriminator_collision!(events);
check_discriminator_collision!(instructions);

Ok(())
}
13 changes: 12 additions & 1 deletion tests/custom-discriminator/Anchor.toml
Original file line number Diff line number Diff line change
@@ -1,8 +1,19 @@
[workspace]
exclude = ["programs/ambiguous-discriminator"]

[features]
resolution = true
skip-lint = false

[programs.localnet]
ambiguous-discriminator = "AmbiguousDiscriminator111111111111111111111"
custom_discriminator = "CustomDiscriminator111111111111111111111111"

[registry]
url = "https://api.apr.dev"

[provider]
cluster = "localnet"
cluster = "Localnet"
wallet = "~/.config/solana/id.json"

[scripts]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
[package]
name = "ambiguous-discriminator"
version = "0.1.0"
description = "Created with Anchor"
edition = "2021"

[lib]
crate-type = ["cdylib", "lib"]
name = "ambiguous_discriminator"

[features]
default = []
cpi = ["no-entrypoint"]
no-entrypoint = []
no-idl = []
no-log-ix-name = []
idl-build = ["anchor-lang/idl-build"]

[dependencies]
anchor-lang = { path = "../../../../lang" }
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[target.bpfel-unknown-unknown.dependencies.std]
features = []
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
use anchor_lang::prelude::*;

declare_id!("AmbiguousDiscriminator111111111111111111111");

#[program]
pub mod ambiguous_discriminator {
use super::*;

/// Compilation should error due to ambiguous discriminators.
pub fn check_accounts(_ctx: Context<CheckAccounts>) -> Result<()> {
Ok(())
}
}

#[derive(Accounts)]
pub struct CheckAccounts<'info> {
pub some_account: Account<'info, SomeAccount>,
pub another_account: Account<'info, AnotherAccount>,
}

#[account(discriminator = 1)]
pub struct SomeAccount {
pub a: u8,
pub b: u16,
pub c: u32,
}

#[account(discriminator = [1, 2, 3, 4])]
pub struct AnotherAccount {
pub a: u32,
}
22 changes: 22 additions & 0 deletions tests/custom-discriminator/tests/ambiguous-discriminator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { spawnSync } from "child_process";

describe("ambiguous-discriminator", () => {
it("Returns ambiguous discriminator error on builds", () => {
const result = spawnSync("anchor", [
"idl",
"build",
"-p",
"ambiguous-discriminator",
]);
if (result.status === 0) {
throw new Error("Ambiguous errors did not make building the IDL fail");
}

const output = result.output.toString();
if (!output.includes("Error: Program ambiguous-discriminator not found")) {
throw new Error(
`Ambiguous discriminators did not return the expected error: "${output}"`
);
}
});
});

0 comments on commit 438c481

Please sign in to comment.