From a73bd728fb828aaa41d395827cb721eaccb7d710 Mon Sep 17 00:00:00 2001 From: cyphersnake <57308842+cyphersnake@users.noreply.github.com> Date: Thu, 24 Nov 2022 20:19:39 +0400 Subject: [PATCH] lang: Add `Owner` & `Discriminator` implementation for ix structures (#2085) lang: Add into `Discriminator` trait constant `DISCRIMINATOR` So that during match instructions or other entities there is no explicit instruction call of `discriminator()` lang: Add `Owner` impl to instructions Co-authored-by: Mikhail Gorbachev --- CHANGELOG.md | 1 + lang/attribute/account/src/lib.rs | 8 ++--- lang/attribute/event/src/lib.rs | 4 +-- lang/src/lib.rs | 13 ++++++-- lang/syn/src/codegen/program/dispatch.rs | 37 +++++++++++++++------ lang/syn/src/codegen/program/instruction.rs | 36 +++++++++++--------- 6 files changed, 62 insertions(+), 37 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a74d73cd1..8c2b3e129 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -44,6 +44,7 @@ The minor version will be incremented upon a breaking change and the patch versi - ts: SPL coders have been removed from the main Anchor package. ([#2155](https://github.com/coral-xyz/anchor/pull/2155)) - lang: Remove `rent` from constraints ([#2265](https://github.com/coral-xyz/anchor/pull/2265)). - spl: Remove `rent` from `associated_token::Create` ([#2265](https://github.com/coral-xyz/anchor/pull/2265)). +- lang: Add `Discriminator` and `Owner` trait implementation for structures representing instructions ([#1997](https://github.com/coral-xyz/anchor/pull/1997)) ## [0.25.0] - 2022-07-05 diff --git a/lang/attribute/account/src/lib.rs b/lang/attribute/account/src/lib.rs index 4d46405a0..273be1732 100644 --- a/lang/attribute/account/src/lib.rs +++ b/lang/attribute/account/src/lib.rs @@ -139,9 +139,7 @@ pub fn account( #[automatically_derived] impl #impl_gen anchor_lang::Discriminator for #account_name #type_gen #where_clause { - fn discriminator() -> [u8; 8] { - #discriminator - } + const DISCRIMINATOR: [u8; 8] = #discriminator; } // This trait is useful for clients deserializing accounts. @@ -211,9 +209,7 @@ pub fn account( #[automatically_derived] impl #impl_gen anchor_lang::Discriminator for #account_name #type_gen #where_clause { - fn discriminator() -> [u8; 8] { - #discriminator - } + const DISCRIMINATOR: [u8; 8] = #discriminator; } #owner_impl diff --git a/lang/attribute/event/src/lib.rs b/lang/attribute/event/src/lib.rs index cabe676dd..2bc849f67 100644 --- a/lang/attribute/event/src/lib.rs +++ b/lang/attribute/event/src/lib.rs @@ -40,9 +40,7 @@ pub fn event( } impl anchor_lang::Discriminator for #event_name { - fn discriminator() -> [u8; 8] { - #discriminator - } + const DISCRIMINATOR: [u8; 8] = #discriminator; } }) } diff --git a/lang/src/lib.rs b/lang/src/lib.rs index 0db6e703c..966ca11f2 100644 --- a/lang/src/lib.rs +++ b/lang/src/lib.rs @@ -182,8 +182,12 @@ pub trait ZeroCopy: Discriminator + Copy + Clone + Zeroable + Pod {} /// `Sha256(:)[..8] || BorshSerialize(args)`. /// `args` is a borsh serialized struct of named fields for each argument given /// to an instruction. -pub trait InstructionData: AnchorSerialize { - fn data(&self) -> Vec; +pub trait InstructionData: Discriminator + AnchorSerialize { + fn data(&self) -> Vec { + let mut d = Self::discriminator().to_vec(); + d.append(&mut self.try_to_vec().expect("Should always serialize")); + d + } } /// An event that can be emitted via a Solana log. See [`emit!`](crate::prelude::emit) for an example. @@ -201,7 +205,10 @@ pub trait EventData: AnchorSerialize + Discriminator { /// 8 byte unique identifier for a type. pub trait Discriminator { - fn discriminator() -> [u8; 8]; + const DISCRIMINATOR: [u8; 8]; + fn discriminator() -> [u8; 8] { + Self::DISCRIMINATOR + } } /// Bump seed for program derived addresses. diff --git a/lang/syn/src/codegen/program/dispatch.rs b/lang/syn/src/codegen/program/dispatch.rs index 6d898c2a8..125db9f43 100644 --- a/lang/syn/src/codegen/program/dispatch.rs +++ b/lang/syn/src/codegen/program/dispatch.rs @@ -1,5 +1,6 @@ use crate::codegen::program::common::*; use crate::Program; +use heck::CamelCase; use quote::quote; pub fn generate(program: &Program) -> proc_macro2::TokenStream { @@ -35,14 +36,25 @@ pub fn generate(program: &Program) -> proc_macro2::TokenStream { methods .iter() .map(|ix: &crate::StateIx| { - let name = &ix.raw_method.sig.ident.to_string(); let ix_method_name: proc_macro2::TokenStream = - { format!("__{}", name).parse().unwrap() }; - let sighash_arr = sighash(SIGHASH_STATE_NAMESPACE, name); - let sighash_tts: proc_macro2::TokenStream = - format!("{:?}", sighash_arr).parse().unwrap(); + format!("__{}", ix.raw_method.sig.ident).parse().expect( + "Failed to parse ix method name with `__` as `TokenStream`", + ); + + let ix_name_camel: proc_macro2::TokenStream = ix + .raw_method + .sig + .ident + .to_string() + .as_str() + .to_camel_case() + .parse() + .expect( + "Failed to parse state ix method name in camel as `TokenStream`", + ); + quote! { - #sighash_tts => { + instruction::state::#ix_name_camel::DISCRIMINATOR => { __private::__state::#ix_method_name( program_id, accounts, @@ -99,11 +111,15 @@ pub fn generate(program: &Program) -> proc_macro2::TokenStream { .iter() .map(|ix| { let ix_method_name = &ix.raw_method.sig.ident; - let sighash_arr = sighash(SIGHASH_GLOBAL_NAMESPACE, &ix_method_name.to_string()); - let sighash_tts: proc_macro2::TokenStream = - format!("{:?}", sighash_arr).parse().unwrap(); + let ix_name_camel: proc_macro2::TokenStream = ix_method_name + .to_string() + .as_str() + .to_camel_case() + .parse() + .expect("Failed to parse ix method name in camel as `TokenStream`"); + quote! { - #sighash_tts => { + instruction::#ix_name_camel::DISCRIMINATOR => { __private::__global::#ix_method_name( program_id, accounts, @@ -162,6 +178,7 @@ pub fn generate(program: &Program) -> proc_macro2::TokenStream { } } + use anchor_lang::Discriminator; match sighash { #ctor_state_dispatch_arm #(#state_dispatch_arms)* diff --git a/lang/syn/src/codegen/program/instruction.rs b/lang/syn/src/codegen/program/instruction.rs index a5ba268a9..53e56271d 100644 --- a/lang/syn/src/codegen/program/instruction.rs +++ b/lang/syn/src/codegen/program/instruction.rs @@ -39,11 +39,13 @@ pub fn generate(program: &Program) -> proc_macro2::TokenStream { /// constructor. #strct - impl anchor_lang::InstructionData for New { - fn data(&self) -> Vec { - let mut d = #sighash_tts.to_vec(); - d.append(&mut self.try_to_vec().expect("Should always serialize")); - d + impl anchor_lang::Discriminator for New { + const DISCRIMINATOR: [u8; 8] = #sighash_tts; + } + impl anchor_lang::InstructionData for New {} + impl anchor_lang::Owner for New { + fn owner() -> Pubkey { + ID } } } @@ -82,11 +84,13 @@ pub fn generate(program: &Program) -> proc_macro2::TokenStream { let sighash_tts: proc_macro2::TokenStream = format!("{:?}", sighash_arr).parse().unwrap(); quote! { - impl anchor_lang::InstructionData for #ix_name_camel { - fn data(&self) -> Vec { - let mut d = #sighash_tts.to_vec(); - d.append(&mut self.try_to_vec().expect("Should always serialize")); - d + impl anchor_lang::Discriminator for #ix_name_camel { + const DISCRIMINATOR: [u8; 8] = #sighash_tts; + } + impl anchor_lang::InstructionData for #ix_name_camel {} + impl anchor_lang::Owner for #ix_name_camel { + fn owner() -> Pubkey { + ID } } } @@ -138,11 +142,13 @@ pub fn generate(program: &Program) -> proc_macro2::TokenStream { let sighash_tts: proc_macro2::TokenStream = format!("{:?}", sighash_arr).parse().unwrap(); quote! { - impl anchor_lang::InstructionData for #ix_name_camel { - fn data(&self) -> Vec { - let mut d = #sighash_tts.to_vec(); - d.append(&mut self.try_to_vec().expect("Should always serialize")); - d + impl anchor_lang::Discriminator for #ix_name_camel { + const DISCRIMINATOR: [u8; 8] = #sighash_tts; + } + impl anchor_lang::InstructionData for #ix_name_camel {} + impl anchor_lang::Owner for #ix_name_camel { + fn owner() -> Pubkey { + ID } } }