Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

idl: Check ambiguous discriminators #3157

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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}"`
);
}
});
});
Loading