Browse Source

lang, ts: Update discriminator-related documentation (#3211)

acheron 1 year ago
parent
commit
5c67b04625

+ 10 - 5
lang/attribute/account/src/lib.rs

@@ -25,14 +25,16 @@ mod id;
 /// - [`Owner`](./trait.Owner.html)
 ///
 /// When implementing account serialization traits the first 8 bytes are
-/// reserved for a unique account discriminator, self described by the first 8
-/// bytes of the SHA256 of the account's Rust ident.
+/// reserved for a unique account discriminator by default, self described by
+/// the first 8 bytes of the SHA256 of the account's Rust ident. This is unless
+/// the discriminator was overridden with the `discriminator` argument (see
+/// [Arguments](#arguments)).
 ///
 /// As a result, any calls to `AccountDeserialize`'s `try_deserialize` will
 /// check this discriminator. If it doesn't match, an invalid account was given,
 /// and the account deserialization will exit with an error.
 ///
-/// # Args
+/// # Arguments
 ///
 /// - `discriminator`: Override the default 8-byte discriminator
 ///
@@ -83,8 +85,11 @@ mod id;
 /// [`safety`](https://docs.rs/bytemuck/latest/bytemuck/trait.Pod.html#safety)
 /// section before using.
 ///
-/// Using `zero_copy` requires adding the following to your `cargo.toml` file:
-/// `bytemuck = { version = "1.4.0", features = ["derive", "min_const_generics"]}`
+/// Using `zero_copy` requires adding the following dependency to your `Cargo.toml` file:
+///
+/// ```toml
+/// bytemuck = { version = "1.17", features = ["derive", "min_const_generics"] }
+/// ```
 #[proc_macro_attribute]
 pub fn account(
     args: proc_macro::TokenStream,

+ 1 - 1
lang/attribute/event/src/lib.rs

@@ -11,7 +11,7 @@ use syn::parse_macro_input;
 /// their programs that clients can subscribe to. Currently, this macro is for
 /// structs only.
 ///
-/// # Args
+/// # Arguments
 ///
 /// - `discriminator`: Override the default 8-byte discriminator
 ///

+ 1 - 1
lang/attribute/program/src/lib.rs

@@ -111,7 +111,7 @@ pub fn interface(
 
 /// This attribute is used to override the Anchor defaults of program instructions.
 ///
-/// # Args
+/// # Arguments
 ///
 /// - `discriminator`: Override the default 8-byte discriminator
 ///

+ 20 - 4
lang/src/lib.rs

@@ -273,9 +273,8 @@ pub trait AccountDeserialize: Sized {
 pub trait ZeroCopy: Discriminator + Copy + Clone + Zeroable + Pod {}
 
 /// Calculates the data for an instruction invocation, where the data is
-/// `Sha256(<namespace>:<method_name>)[..8] || BorshSerialize(args)`.
-/// `args` is a borsh serialized struct of named fields for each argument given
-/// to an instruction.
+/// `Discriminator + BorshSerialize(args)`. `args` is a borsh serialized
+/// struct of named fields for each argument given to an instruction.
 pub trait InstructionData: Discriminator + AnchorSerialize {
     fn data(&self) -> Vec<u8> {
         let mut data = Vec::with_capacity(256);
@@ -300,8 +299,25 @@ pub trait Event: AnchorSerialize + AnchorDeserialize + Discriminator {
     fn data(&self) -> Vec<u8>;
 }
 
-/// 8 byte unique identifier for a type.
+/// Unique identifier for a type.
+///
+/// This is not a trait you should derive manually, as various Anchor macros already derive it
+/// internally.
+///
+/// Prior to Anchor v0.31, discriminators were always 8 bytes in size. However, starting with Anchor
+/// v0.31, it is possible to override the default discriminators, and discriminator length is no
+/// longer fixed, which means this trait can also be implemented for non-Anchor programs.
+///
+/// It's important that the discriminator is always unique for the type you're implementing it
+/// for. While the discriminator can be at any length (including zero), the IDL generation does not
+/// currently allow empty discriminators for safety and convenience reasons. However, the trait
+/// definition still allows empty discriminators because some non-Anchor programs, e.g. the SPL
+/// Token program, don't have account discriminators. In that case, safety checks should never
+/// depend on the discriminator.
 pub trait Discriminator {
+    /// Discriminator slice.
+    ///
+    /// See [`Discriminator`] trait documentation for more information.
     const DISCRIMINATOR: &'static [u8];
 }
 

+ 6 - 11
lang/syn/src/codegen/program/dispatch.rs

@@ -61,19 +61,14 @@ pub fn generate(program: &Program) -> proc_macro2::TokenStream {
     quote! {
         /// Performs method dispatch.
         ///
-        /// Each method in an anchor program is uniquely defined by a namespace
-        /// and a rust identifier (i.e., the name given to the method). These
-        /// two pieces can be combined to create a method identifier,
-        /// specifically, Anchor uses
+        /// Each instruction's discriminator is checked until the given instruction data starts with
+        /// the current discriminator.
         ///
-        /// Sha256("<namespace>:<rust-identifier>")[..8],
+        /// If a match is found, the instruction handler is called using the given instruction data
+        /// excluding the prepended discriminator bytes.
         ///
-        /// where the namespace can be one type. "global" for a
-        /// regular instruction.
-        ///
-        /// With this 8 byte identifier, Anchor performs method dispatch,
-        /// matching the given 8 byte identifier to the associated method
-        /// handler, which leads to user defined code being eventually invoked.
+        /// If no match is found, the fallback function is executed if it exists, or an error is
+        /// returned if it doesn't exist.
         fn dispatch<'info>(
             program_id: &Pubkey,
             accounts: &'info [AccountInfo<'info>],

+ 4 - 11
lang/syn/src/codegen/program/entry.rs

@@ -25,17 +25,10 @@ pub fn generate(program: &Program) -> proc_macro2::TokenStream {
         /// The execution flow of the generated code can be roughly outlined:
         ///
         /// * Start program via the entrypoint.
-        /// * Strip method identifier off the first 8 bytes of the instruction
-        ///   data and invoke the identified method. The method identifier
-        ///   is a variant of sighash. See docs.rs for `anchor_lang` for details.
-        /// * If the method identifier is an IDL identifier, execute the IDL
-        ///   instructions, which are a special set of hardcoded instructions
-        ///   baked into every Anchor program. Then exit.
-        /// * Otherwise, the method identifier is for a user defined
-        ///   instruction, i.e., one of the methods in the user defined
-        ///   `#[program]` module. Perform method dispatch, i.e., execute the
-        ///   big match statement mapping method identifier to method handler
-        ///   wrapper.
+        /// * Check whether the declared program id matches the input program
+        ///   id. If it's not, return an error.
+        /// * Find and invoke the method based on whether the instruction data
+        ///   starts with the method's discriminator.
         /// * Run the method handler wrapper. This wraps the code the user
         ///   actually wrote, deserializing the accounts, constructing the
         ///   context, invoking the user's code, and finally running the exit

+ 2 - 2
ts/packages/anchor/src/coder/borsh/accounts.ts

@@ -107,9 +107,9 @@ export class BorshAccountsCoder<A extends string = string>
   }
 
   /**
-   * Calculates and returns a unique 8 byte discriminator prepended to all anchor accounts.
+   * Get the unique discriminator prepended to all anchor accounts.
    *
-   * @param name The name of the account to calculate the discriminator.
+   * @param name The name of the account to get the discriminator of.
    */
   public accountDiscriminator(name: string): Buffer {
     const account = this.idl.accounts?.find((acc) => acc.name === name);