From 3a0b5170b266bc0061b248f88a8bba56358f5892 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Wed, 17 Aug 2022 14:28:59 +0100 Subject: [PATCH] Add discriminator to idl Signed-off-by: Sean Young --- Cargo.lock | 10 +++++++ lang/Cargo.toml | 2 ++ lang/attribute/discriminator/Cargo.toml | 20 +++++++++++++ lang/attribute/discriminator/src/lib.rs | 10 +++++++ lang/src/lib.rs | 8 ++++-- lang/syn/src/idl/file.rs | 3 ++ lang/syn/src/idl/mod.rs | 2 ++ lang/syn/src/lib.rs | 1 + lang/syn/src/parser/program/instructions.rs | 32 +++++++++++++++++++++ 9 files changed, 85 insertions(+), 3 deletions(-) create mode 100644 lang/attribute/discriminator/Cargo.toml create mode 100644 lang/attribute/discriminator/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 1d96305059..45f0ba17a9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -135,6 +135,15 @@ dependencies = [ "syn 1.0.98", ] +[[package]] +name = "anchor-attribute-discriminator" +version = "0.25.0" +dependencies = [ + "anchor-syn", + "proc-macro2 1.0.40", + "syn 1.0.98", +] + [[package]] name = "anchor-attribute-error" version = "0.25.0" @@ -257,6 +266,7 @@ dependencies = [ "anchor-attribute-access-control", "anchor-attribute-account", "anchor-attribute-constant", + "anchor-attribute-discriminator", "anchor-attribute-error", "anchor-attribute-event", "anchor-attribute-interface", diff --git a/lang/Cargo.toml b/lang/Cargo.toml index a0a1836012..61586ab924 100644 --- a/lang/Cargo.toml +++ b/lang/Cargo.toml @@ -16,6 +16,7 @@ anchor-debug = [ "anchor-attribute-access-control/anchor-debug", "anchor-attribute-account/anchor-debug", "anchor-attribute-constant/anchor-debug", + "anchor-attribute-discriminator/anchor-debug", "anchor-attribute-error/anchor-debug", "anchor-attribute-event/anchor-debug", "anchor-attribute-interface/anchor-debug", @@ -29,6 +30,7 @@ anchor-debug = [ anchor-attribute-access-control = { path = "./attribute/access-control", version = "0.25.0" } anchor-attribute-account = { path = "./attribute/account", version = "0.25.0" } anchor-attribute-constant = { path = "./attribute/constant", version = "0.25.0" } +anchor-attribute-discriminator = { path = "./attribute/discriminator", version = "0.25.0" } anchor-attribute-error = { path = "./attribute/error", version = "0.25.0" } anchor-attribute-program = { path = "./attribute/program", version = "0.25.0" } anchor-attribute-state = { path = "./attribute/state", version = "0.25.0" } diff --git a/lang/attribute/discriminator/Cargo.toml b/lang/attribute/discriminator/Cargo.toml new file mode 100644 index 0000000000..2b03eeb7bb --- /dev/null +++ b/lang/attribute/discriminator/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "anchor-attribute-discriminator" +version = "0.25.0" +authors = ["Serum Foundation "] +repository = "https://github.com/coral-xyz/anchor" +license = "Apache-2.0" +description = "Anchor attribute macro for creating discriminator types" +rust-version = "1.56" +edition = "2021" + +[lib] +proc-macro = true + +[features] +anchor-debug = ["anchor-syn/anchor-debug"] + +[dependencies] +proc-macro2 = "1.0" +syn = { version = "1.0.60", features = ["full"] } +anchor-syn = { path = "../../syn", version = "0.25.0" } diff --git a/lang/attribute/discriminator/src/lib.rs b/lang/attribute/discriminator/src/lib.rs new file mode 100644 index 0000000000..f8e16c8458 --- /dev/null +++ b/lang/attribute/discriminator/src/lib.rs @@ -0,0 +1,10 @@ +extern crate proc_macro; + +/// A marker attribute used to override the discriminator value that should be used. +#[proc_macro_attribute] +pub fn discriminator( + _attr: proc_macro::TokenStream, + input: proc_macro::TokenStream, +) -> proc_macro::TokenStream { + input +} diff --git a/lang/src/lib.rs b/lang/src/lib.rs index 2d795a42c2..382cae36e4 100644 --- a/lang/src/lib.rs +++ b/lang/src/lib.rs @@ -47,6 +47,7 @@ pub use crate::bpf_upgradeable_state::*; pub use anchor_attribute_access_control::access_control; pub use anchor_attribute_account::{account, declare_id, zero_copy}; pub use anchor_attribute_constant::constant; +pub use anchor_attribute_discriminator::discriminator; pub use anchor_attribute_error::*; pub use anchor_attribute_event::{emit, event}; pub use anchor_attribute_interface::interface; @@ -238,9 +239,10 @@ pub mod prelude { accounts::account_loader::AccountLoader, accounts::program::Program, accounts::signer::Signer, accounts::system_account::SystemAccount, accounts::sysvar::Sysvar, accounts::unchecked_account::UncheckedAccount, constant, - context::Context, context::CpiContext, declare_id, emit, err, error, event, interface, - program, require, require_eq, require_gt, require_gte, require_keys_eq, require_keys_neq, - require_neq, solana_program::bpf_loader_upgradeable::UpgradeableLoaderState, source, state, + context::Context, context::CpiContext, declare_id, discriminator, emit, err, error, event, + interface, program, require, require_eq, require_gt, require_gte, require_keys_eq, + require_keys_neq, require_neq, + solana_program::bpf_loader_upgradeable::UpgradeableLoaderState, source, state, system_program::System, zero_copy, AccountDeserialize, AccountSerialize, Accounts, AccountsExit, AnchorDeserialize, AnchorSerialize, Id, Key, Owner, ProgramData, Result, ToAccountInfo, ToAccountInfos, ToAccountMetas, diff --git a/lang/syn/src/idl/file.rs b/lang/syn/src/idl/file.rs index 23e813aa52..55dc8a05a0 100644 --- a/lang/syn/src/idl/file.rs +++ b/lang/syn/src/idl/file.rs @@ -83,6 +83,7 @@ pub fn parse( ); IdlInstruction { name, + discriminator: None, docs: None, accounts, args, @@ -131,6 +132,7 @@ pub fn parse( idl_accounts(&ctx, accounts_strct, &accs, seeds_feature, no_docs); IdlInstruction { name, + discriminator: None, docs: None, accounts, args, @@ -216,6 +218,7 @@ pub fn parse( }; IdlInstruction { name: ix.ident.to_string().to_mixed_case(), + discriminator: ix.discriminator.clone(), docs: ix.docs.clone(), accounts, args, diff --git a/lang/syn/src/idl/mod.rs b/lang/syn/src/idl/mod.rs index b9220ef297..a611609df8 100644 --- a/lang/syn/src/idl/mod.rs +++ b/lang/syn/src/idl/mod.rs @@ -46,6 +46,8 @@ pub struct IdlState { pub struct IdlInstruction { pub name: String, #[serde(skip_serializing_if = "Option::is_none")] + pub discriminator: Option>, + #[serde(skip_serializing_if = "Option::is_none")] pub docs: Option>, pub accounts: Vec, pub args: Vec, diff --git a/lang/syn/src/lib.rs b/lang/syn/src/lib.rs index 5aeac91b4a..1ae57e97d5 100644 --- a/lang/syn/src/lib.rs +++ b/lang/syn/src/lib.rs @@ -85,6 +85,7 @@ pub struct StateInterface { pub struct Ix { pub raw_method: ItemFn, pub ident: Ident, + pub discriminator: Option>, pub docs: Option>, pub args: Vec, pub returns: IxReturn, diff --git a/lang/syn/src/parser/program/instructions.rs b/lang/syn/src/parser/program/instructions.rs index 66aaf1a765..2b20e9a59c 100644 --- a/lang/syn/src/parser/program/instructions.rs +++ b/lang/syn/src/parser/program/instructions.rs @@ -3,6 +3,7 @@ use crate::parser::program::ctx_accounts_ident; use crate::{FallbackFn, Ix, IxArg, IxReturn}; use syn::parse::{Error as ParseError, Result as ParseResult}; use syn::spanned::Spanned; +use syn::Lit; // Parse all non-state ix handlers from the program mod definition. pub fn parse(program_mod: &syn::ItemMod) -> ParseResult<(Vec, Option)> { @@ -25,11 +26,13 @@ pub fn parse(program_mod: &syn::ItemMod) -> ParseResult<(Vec, Option ParseResult { )), } } + +pub fn parse_discriminator(attrs: &[syn::Attribute]) -> ParseResult>> { + let mut discriminators = Vec::new(); + + for attr in attrs { + if attr.path.segments.last().unwrap().ident == "discriminator" { + if let Ok(Lit::Int(dis)) = attr.parse_args::() { + if let Ok(value) = dis.base10_parse::() { + discriminators.push((attr.span(), value)); + continue; + } + } + + return Err(ParseError::new( + attr.span(), + "Discriminator value like `#[discriminator(0xdeadbeeffeedcafe)]` expected", + )); + } + } + + match discriminators.len() { + 0 => Ok(None), + 1 => Ok(Some(discriminators[0].1.to_be_bytes().to_vec())), + _ => Err(ParseError::new( + discriminators[1].0, + "More than one discriminator function found", + )), + } +}