Przeglądaj źródła

ci: Add spellcheck step (#164)

* Add invoke instruction helper

* Typos

* Remove new helpers

* Remove unused

* Address review comments

* Tweak inline attributes

* Use invoke signed unchecked

* Refactor inline

* Renamed to with_bounds

* Update docs

* Revert change

* Add constant length check

* Add spellcheck step

* Tweak action

* Fix typos

* More fixes

* Yet more fixes

* Fixes

* Add j1 option

* More and more fixes

* Add missing acronym

* Fix merge

* Fix spelling

* Fix spelling
Fernando Otero 4 miesięcy temu
rodzic
commit
5af8a547c5

+ 6 - 0
.github/actions/setup/action.yml

@@ -98,6 +98,12 @@ runs:
         toolchain: ${{ env.TOOLCHAIN_LINT }}
         components: miri
 
+    - name: Install 'cargo-spellcheck'
+      if: ${{ contains(inputs.components, 'spellcheck') }}
+      uses: taiki-e/install-action@v2
+      with:
+        tool: cargo-spellcheck
+
     - name: Cache Cargo Dependencies
       if: ${{ inputs.cargo-cache-key }}
       uses: actions/cache@v4

+ 16 - 0
.github/workflows/main.yml

@@ -35,6 +35,22 @@ jobs:
         id: filter
         run: pnpm tsx ./scripts/setup/members.mts
 
+  spellcheck:
+    name: Spellcheck
+    runs-on: ubuntu-latest
+    steps:
+      - name: Git Checkout
+        uses: actions/checkout@v4
+
+      - name: Setup Environment
+        uses: ./.github/actions/setup
+        with:
+          cargo-cache-key: cargo-spellcheck
+          components: spellcheck
+
+      - name: cargo-spellcheck
+        run: pnpm spellcheck
+
   process:
     name: Check
     needs: sanity

+ 3 - 0
Cargo.toml

@@ -39,3 +39,6 @@ test = "1.84.1"
 pre-release-commit-message = "Publish {{crate_name}} v{{version}}"
 tag-message = "Publish {{crate_name}} v{{version}}"
 consolidate-commits = false
+
+[workspace.metadata.spellcheck]
+config = "scripts/setup/spellcheck.toml"

+ 1 - 0
package.json

@@ -10,6 +10,7 @@
     "lint": "tsx ./scripts/lint.mts",
     "miri": "tsx ./scripts/miri.mts",
     "semver": "tsx ./scripts/semver.mts",
+    "spellcheck": "cargo spellcheck -j1 --code 1",
     "test": "tsx ./scripts/test.mts"
   },
   "devDependencies": {

+ 2 - 2
programs/system/src/instructions/advance_nonce_account.rs

@@ -9,13 +9,13 @@ use pinocchio::{
 ///
 /// ### Accounts:
 ///   0. `[WRITE]` Nonce account
-///   1. `[]` RecentBlockhashes sysvar
+///   1. `[]` Recent blockhashes sysvar
 ///   2. `[SIGNER]` Nonce authority
 pub struct AdvanceNonceAccount<'a> {
     /// Nonce account.
     pub account: &'a AccountInfo,
 
-    /// RecentBlockhashes sysvar.
+    /// Recent blockhashes sysvar.
     pub recent_blockhashes_sysvar: &'a AccountInfo,
 
     /// Nonce authority.

+ 3 - 3
programs/system/src/instructions/initialize_nonce_account.rs

@@ -16,13 +16,13 @@ use pinocchio::{
 ///
 /// ### Accounts:
 ///   0. `[WRITE]` Nonce account
-///   1. `[]` RecentBlockhashes sysvar
+///   1. `[]` Recent blockhashes sysvar
 ///   2. `[]` Rent sysvar
 pub struct InitializeNonceAccount<'a, 'b> {
     /// Nonce account.
     pub account: &'a AccountInfo,
 
-    /// RecentBlockhashes sysvar.
+    /// Recent blockhashes sysvar.
     pub recent_blockhashes_sysvar: &'a AccountInfo,
 
     /// Rent sysvar.
@@ -30,7 +30,7 @@ pub struct InitializeNonceAccount<'a, 'b> {
 
     /// Lamports to withdraw.
     ///
-    /// The account balance muat be left above the rent exempt reserve
+    /// The account balance must be left above the rent exempt reserve
     /// or at zero.
     pub authority: &'b Pubkey,
 }

+ 3 - 3
programs/system/src/instructions/withdraw_nonce_account.rs

@@ -13,7 +13,7 @@ use pinocchio::{
 /// ### Accounts:
 ///   0. `[WRITE]` Nonce account
 ///   1. `[WRITE]` Recipient account
-///   2. `[]` RecentBlockhashes sysvar
+///   2. `[]` Recent blockhashes sysvar
 ///   3. `[]` Rent sysvar
 ///   4. `[SIGNER]` Nonce authority
 pub struct WithdrawNonceAccount<'a> {
@@ -23,7 +23,7 @@ pub struct WithdrawNonceAccount<'a> {
     /// Recipient account.
     pub recipient: &'a AccountInfo,
 
-    /// RecentBlockhashes sysvar.
+    /// Recent blockhashes sysvar.
     pub recent_blockhashes_sysvar: &'a AccountInfo,
 
     /// Rent sysvar.
@@ -34,7 +34,7 @@ pub struct WithdrawNonceAccount<'a> {
 
     /// Lamports to withdraw.
     ///
-    /// The account balance muat be left above the rent exempt reserve
+    /// The account balance must be left above the rent exempt reserve
     /// or at zero.
     pub lamports: u64,
 }

+ 1 - 1
programs/token/src/instructions/freeze_account.rs

@@ -5,7 +5,7 @@ use pinocchio::{
     ProgramResult,
 };
 
-/// Freeze an Initialized account using the Mint's freeze_authority
+/// Freeze an initialized account using the Mint's freeze authority.
 ///
 /// ### Accounts:
 ///   0. `[WRITE]` The account to freeze.

+ 1 - 1
programs/token/src/instructions/initialize_account.rs

@@ -10,7 +10,7 @@ use pinocchio::{
 /// ### Accounts:
 ///   0. `[WRITE]`  The account to initialize.
 ///   1. `[]` The mint this account will be associated with.
-///   2. `[]` The new account's owner/multisignature.
+///   2. `[]` The new account's owner/multi-signature.
 ///   3. `[]` Rent sysvar
 pub struct InitializeAccount<'a> {
     /// New Account.

+ 1 - 1
programs/token/src/instructions/thaw_account.rs

@@ -5,7 +5,7 @@ use pinocchio::{
     ProgramResult,
 };
 
-/// Thaw a Frozen account using the Mint's freeze_authority
+/// Thaw a frozen account using the Mint's freeze authority.
 ///
 /// ### Accounts:
 ///   0. `[WRITE]` The account to thaw.

+ 2 - 2
programs/token/src/instructions/transfer.rs

@@ -9,7 +9,7 @@ use pinocchio::{
 
 use crate::{write_bytes, UNINIT_BYTE};
 
-/// Transfer Tokens from one Token Account to another.
+/// Transfer tokens from one Token account to another.
 ///
 /// ### Accounts:
 ///   0. `[WRITE]` Sender account
@@ -22,7 +22,7 @@ pub struct Transfer<'a> {
     pub to: &'a AccountInfo,
     /// Authority account.
     pub authority: &'a AccountInfo,
-    /// Amount of microtokens to transfer.
+    /// Amount of micro-tokens to transfer.
     pub amount: u64,
 }
 

+ 1 - 1
programs/token/src/instructions/transfer_checked.rs

@@ -25,7 +25,7 @@ pub struct TransferChecked<'a> {
     pub to: &'a AccountInfo,
     /// Authority account.
     pub authority: &'a AccountInfo,
-    /// Amount of microtokens to transfer.
+    /// Amount of micro-tokens to transfer.
     pub amount: u64,
     /// Decimal for the Token
     pub decimals: u8,

+ 2 - 2
programs/token/src/state/mint.rs

@@ -62,8 +62,8 @@ impl Mint {
     ///
     /// # Safety
     ///
-    /// The caller must ensure that it is safe to borrow the account data – e.g., there are
-    /// no mutable borrows of the account data.
+    /// The caller must ensure that it is safe to borrow the account data (e.g., there are
+    /// no mutable borrows of the account data).
     #[inline]
     pub unsafe fn from_account_info_unchecked(
         account_info: &AccountInfo,

+ 5 - 5
programs/token/src/state/token.rs

@@ -32,9 +32,9 @@ pub struct TokenAccount {
     /// Indicates whether this account represents a native token or not.
     is_native: [u8; 4],
 
-    /// If is_native.is_some, this is a native token, and the value logs the
-    /// rent-exempt reserve. An Account is required to be rent-exempt, so
-    /// the value is used by the Processor to ensure that wrapped SOL
+    /// When `is_native.is_some()` is `true`, this is a native token, and the
+    /// value logs the rent-exempt reserve. An Account is required to be rent-exempt,
+    /// so the value is used by the Processor to ensure that wrapped SOL
     /// accounts do not drop below this threshold.
     native_amount: [u8; 8],
 
@@ -77,8 +77,8 @@ impl TokenAccount {
     ///
     /// # Safety
     ///
-    /// The caller must ensure that it is safe to borrow the account data – e.g., there are
-    /// no mutable borrows of the account data.
+    /// The caller must ensure that it is safe to borrow the account data (e.g., there are
+    /// no mutable borrows of the account data).
     #[inline]
     pub unsafe fn from_account_info_unchecked(
         account_info: &AccountInfo,

+ 66 - 0
scripts/setup/solana.dic

@@ -0,0 +1,66 @@
+1000
+config
+metadata
+json
+uri
+ui
+cli
+readme/S
+arg/S
+vec/S
+enum/S
+noop/S
+realloc/S
+overallocate/SGD
+namespace
+serde
+deserialize/SRGD
+deserialization
+struct/S
+param/S
+tuple/S
+metas
+infos
+async
+subcommand
+repo
+init
+solana
+sol/S
+blockchain/S
+permissionless
+composability
+runtime
+onchain
+offchain
+keypair/S
+decrypt/SGD
+lamport/S
+validator/S
+pubkey/S
+sysvar/S
+timestamp/S
+entrypoint/S
+spl
+pda/S
+PDA/S
+multisignature/S
+multisig/S
+staker/S
+APY
+codama
+autogenerated
+sdk
+blockhash/S
+VM
+SVM
+BPF
+SBF
+inlined
+CU/S
+borrowable
+callee
+RPC
+ed25519
+performant
+syscall/S

+ 5 - 0
scripts/setup/spellcheck.toml

@@ -0,0 +1,5 @@
+[Hunspell]
+use_builtin = true
+skip_os_lookups = false
+search_dirs = ["."]
+extra_dictionaries = ["solana.dic"]

+ 2 - 2
sdk/log/crate/src/logger.rs

@@ -424,7 +424,7 @@ impl_log_for_signed!(i64);
 impl_log_for_signed!(i128);
 impl_log_for_signed!(isize);
 
-/// Implement the log trait for the &str type.
+/// Implement the log trait for the `&str` type.
 unsafe impl Log for &str {
     #[inline]
     fn debug_with_args(&self, buffer: &mut [MaybeUninit<u8>], _args: &[Argument]) -> usize {
@@ -666,7 +666,7 @@ macro_rules! impl_log_for_slice {
 impl_log_for_slice!([T]);
 impl_log_for_slice!([T; N]);
 
-/// Implement the log trait for the bool type.
+/// Implement the log trait for the `bool` type.
 unsafe impl Log for bool {
     #[inline]
     fn debug_with_args(&self, buffer: &mut [MaybeUninit<u8>], args: &[Argument]) -> usize {

+ 1 - 1
sdk/log/macro/src/lib.rs

@@ -261,7 +261,7 @@ pub fn log(input: TokenStream) -> TokenStream {
 ///
 /// logging output will look like:
 ///
-/// "Program log: Function my_function consumed 36 compute units"
+/// "Program log: Function `my_function` consumed 36 compute units"
 ///
 /// # References
 ///

+ 5 - 5
sdk/pinocchio/src/account_info.rs

@@ -48,8 +48,8 @@ pub(crate) struct Account {
     ///
     ///   * lamport mutable borrow flag
     ///     - `7 6 5 4 3 2 1 0`
-    ///     - `x . . . . . . .`: `1` -> the lamport field can be mutably borrowed;
-    ///       `0` -> there is an outstanding mutable borrow for the lamports.
+    ///     - `x . . . . . . .`: `1` - the lamport field can be mutably borrowed;
+    ///       `0` - there is an outstanding mutable borrow for the lamports.
     ///
     ///   * lamport immutable borrow count
     ///     - `7 6 5 4 3 2 1 0`
@@ -59,8 +59,8 @@ pub(crate) struct Account {
     ///
     ///   * data mutable borrow flag
     ///     - `7 6 5 4 3 2 1 0`
-    ///     - `. . . . x . . .`:  `1` -> the account data can be mutably borrowed;
-    ///       `0` -> there is an outstanding mutable borrow for the account data.
+    ///     - `. . . . x . . .`:  `1` - the account data can be mutably borrowed;
+    ///       `0` - there is an outstanding mutable borrow for the account data.
     ///
     ///   * data immutable borrow count
     ///     - `7 6 5 4 3 2 1 0`
@@ -189,7 +189,7 @@ impl AccountInfo {
     ///
     /// # Safety
     ///
-    /// It is undefined behaviour to use this method while there is an active reference
+    /// It is undefined behavior to use this method while there is an active reference
     /// to the `owner` returned by [`Self::owner`].
     #[inline(always)]
     pub unsafe fn assign(&self, new_owner: &Pubkey) {

+ 3 - 3
sdk/pinocchio/src/cpi.rs

@@ -390,7 +390,7 @@ pub unsafe fn invoke_signed_unchecked(
         /// DO NOT EXPOSE THIS STRUCT:
         ///
         /// To ensure pointers are valid upon use, the scope of this struct should
-        /// only be limited to the stack where sol_invoke_signed_c happens and then
+        /// only be limited to the stack where `sol_invoke_signed_c` happens and then
         /// discarded immediately after.
         #[repr(C)]
         struct CInstruction<'a> {
@@ -466,12 +466,12 @@ pub fn set_return_data(data: &[u8]) {
 ///
 /// Return data is set by the callee with [`set_return_data`].
 ///
-/// Return data is cleared before every CPI invocation &mdash; a program that
+/// Return data is cleared before every CPI invocation - a program that
 /// has invoked no other programs can expect the return data to be `None`; if no
 /// return data was set by the previous CPI invocation, then this function
 /// returns `None`.
 ///
-/// Return data is not cleared after returning from CPI invocations &mdash; a
+/// Return data is not cleared after returning from CPI invocations. A
 /// program that has called another program may retrieve return data that was
 /// not set by the called program, but instead set by a program further down the
 /// call stack; or, if a program calls itself recursively, it is possible that

+ 1 - 1
sdk/pinocchio/src/entrypoint/lazy.rs

@@ -116,7 +116,7 @@ impl InstructionContext {
     /// Creates a new [`InstructionContext`] for the input buffer.
     ///
     /// The caller must ensure that the input buffer is valid, i.e., it represents
-    /// the program input parameters serialzed by the SVM loader.
+    /// the program input parameters serialized by the SVM loader.
     ///
     /// This method is deprecated and will be removed in a future version. It is
     /// missing the `unsafe` qualifier.

+ 3 - 3
sdk/pinocchio/src/instruction.rs

@@ -28,7 +28,7 @@ pub struct ProcessedSiblingInstruction {
     /// Length of the instruction data
     pub data_len: u64,
 
-    /// Number of AccountMeta structures
+    /// Number of `AccountMeta` structures
     pub accounts_len: u64,
 }
 
@@ -133,7 +133,7 @@ impl<'a> AccountMeta<'a> {
         }
     }
 
-    /// Creates a new readonly `AccountMeta`.
+    /// Creates a new read-only `AccountMeta`.
     #[inline(always)]
     pub const fn readonly(pubkey: &'a Pubkey) -> Self {
         Self::new(pubkey, false, false)
@@ -145,7 +145,7 @@ impl<'a> AccountMeta<'a> {
         Self::new(pubkey, true, false)
     }
 
-    /// Creates a new readonly and signer `AccountMeta`.
+    /// Creates a new read-only and signer `AccountMeta`.
     #[inline(always)]
     pub const fn readonly_signer(pubkey: &'a Pubkey) -> Self {
         Self::new(pubkey, false, true)

+ 4 - 4
sdk/pinocchio/src/lib.rs

@@ -3,7 +3,7 @@
 //! Pinocchio is a zero-dependency library to create Solana programs in Rust.
 //! It takes advantage of the way SVM loaders serialize the program input parameters
 //! into a byte array that is then passed to the program's entrypoint to define
-//! zero-copy types to read the input  these types are defined in an efficient way
+//! zero-copy types to read the input - these types are defined in an efficient way
 //! taking into consideration that they will be used in on-chain programs.
 //!
 //! It is intended to be used by on-chain programs only; for off-chain programs,
@@ -76,7 +76,7 @@
 //! `instruction_data` separately. This consumes compute units before the program
 //! begins its execution. In some cases, it is beneficial for a program to have
 //! more control when the input parsing is happening, even whether the parsing
-//! is needed or not &mdash; this is the purpose of the [`lazy_program_entrypoint!`]
+//! is needed or not - this is the purpose of the [`lazy_program_entrypoint!`]
 //! macro. This macro only wraps the program input and provides methods to parse
 //! the input on-demand.
 //!
@@ -182,8 +182,8 @@
 //!
 //! ## Advanced entrypoint configuration
 //!
-//! The symbols emitted by the entrypoint macros &mdash; program entrypoint, global
-//! allocator and default panic handler &mdash; can only be defined once globally. If
+//! The symbols emitted by the entrypoint macros - program entrypoint, global
+//! allocator and default panic handler - can only be defined once globally. If
 //! the program crate is also intended to be used as a library, it is common practice
 //! to define a Cargo [feature](https://doc.rust-lang.org/cargo/reference/features.html)
 //! in your program crate to conditionally enable the module that includes the [`entrypoint!`]

+ 1 - 1
sdk/pinocchio/src/log.rs

@@ -115,7 +115,7 @@ pub fn sol_log_64(arg1: u64, arg2: u64, arg3: u64, arg4: u64, arg5: u64) {
     core::hint::black_box((arg1, arg2, arg3, arg4, arg5));
 }
 
-/// Print some slices as base64.
+/// Print some slices as `base64`.
 pub fn sol_log_data(data: &[&[u8]]) {
     #[cfg(target_os = "solana")]
     unsafe {

+ 3 - 3
sdk/pinocchio/src/memory.rs

@@ -27,7 +27,7 @@ use crate::syscalls;
 /// # Safety
 ///
 /// This function does not verify that `n` is less than or equal to the
-/// lengths of the `dst` and `src` slices passed to it &mdash; it will copy
+/// lengths of the `dst` and `src` slices passed to it - it will copy
 /// bytes to and from beyond the slices.
 ///
 /// Specifying an `n` greater than either the length of `dst` or `src` will
@@ -124,7 +124,7 @@ pub unsafe fn sol_memmove(dst: *mut u8, src: *const u8, n: usize) {
 /// # Safety
 ///
 /// It does not verify that `n` is less than or equal to the lengths of the
-/// `dst` and `src` slices passed to it &mdash; it will read bytes beyond the
+/// `dst` and `src` slices passed to it - it will read bytes beyond the
 /// slices.
 ///
 /// Specifying an `n` greater than either the length of `dst` or `src` will
@@ -160,7 +160,7 @@ pub unsafe fn sol_memcmp(s1: &[u8], s2: &[u8], n: usize) -> i32 {
 /// # Safety
 ///
 /// This function does not verify that `n` is less than or equal to the length
-/// of the `s` slice passed to it &mdash; it will write bytes beyond the
+/// of the `s` slice passed to it - it will write bytes beyond the
 /// slice.
 ///
 /// Specifying an `n` greater than the length of `s` will likely introduce

+ 1 - 1
sdk/pinocchio/src/program_error.rs

@@ -10,7 +10,7 @@
 pub enum ProgramError {
     /// Allows on-chain programs to implement program-specific error types and see them returned
     /// by the Solana runtime. A program-specific error may be any type that is represented as
-    /// or serialized to a u32 integer.
+    /// or serialized to a `u32` integer.
     ///
     /// Custom program error: `{0:#x}`
     Custom(u32),

+ 3 - 3
sdk/pinocchio/src/pubkey.rs

@@ -84,13 +84,13 @@ pub fn log(pubkey: &Pubkey) {
 ///
 /// **Warning**: Because of the way the seeds are hashed there is a potential
 /// for program address collisions for the same program id.  The seeds are
-/// hashed sequentially which means that seeds {"abcdef"}, {"abc", "def"},
-/// and {"ab", "cd", "ef"} will all result in the same program address given
+/// hashed sequentially which means that seeds `"abcdef"`, `["abc", "def"]`,
+/// and `["ab", "cd", "ef"]` will all result in the same program address given
 /// the same program id. Since the chance of collision is local to a given
 /// program id, the developer of that program must take care to choose seeds
 /// that do not collide with each other. For seed schemes that are susceptible
 /// to this type of hash collision, a common remedy is to insert separators
-/// between seeds, e.g. transforming {"abc", "def"} into {"abc", "-", "def"}.
+/// between seeds, e.g. transforming `["abc", "def"]` into `["abc", "-", "def"]`.
 ///
 /// # Panics
 ///

+ 1 - 1
sdk/pinocchio/src/sysvars/clock.rs

@@ -101,7 +101,7 @@ impl Clock {
     ///
     /// # Safety
     ///
-    /// The caller must ensure that it is safe to borrow the account data  e.g., there are
+    /// The caller must ensure that it is safe to borrow the account data - e.g., there are
     /// no mutable borrows of the account data.
     #[inline]
     pub unsafe fn from_account_info_unchecked(

+ 2 - 2
sdk/pinocchio/src/sysvars/fees.rs

@@ -13,7 +13,7 @@ pub struct FeeCalculator {
 }
 
 impl FeeCalculator {
-    /// Create a new instance of the FeeCalculator
+    /// Create a new instance of the `FeeCalculator`.
     pub fn new(lamports_per_signature: u64) -> Self {
         Self {
             lamports_per_signature,
@@ -61,7 +61,7 @@ impl Default for FeeRateGovernor {
 }
 
 impl FeeRateGovernor {
-    /// Create a new FeeCalculator based on current cluster signature throughput
+    /// Create a new `FeeCalculator` based on current cluster signature throughput
     pub fn create_fee_calculator(&self) -> FeeCalculator {
         FeeCalculator::new(self.lamports_per_signature)
     }

+ 1 - 1
sdk/pinocchio/src/sysvars/instructions.rs

@@ -7,7 +7,7 @@ use crate::{
 
 use core::{marker::PhantomData, mem::size_of, ops::Deref};
 
-/// Sysvar1nstructions1111111111111111111111111
+/// Instructions sysvar ID `Sysvar1nstructions1111111111111111111111111`.
 pub const INSTRUCTIONS_ID: Pubkey = [
     0x06, 0xa7, 0xd5, 0x17, 0x18, 0x7b, 0xd1, 0x66, 0x35, 0xda, 0xd4, 0x04, 0x55, 0xfd, 0xc2, 0xc0,
     0xc1, 0x24, 0xc6, 0x8f, 0x21, 0x56, 0x75, 0xa5, 0xdb, 0xba, 0xcb, 0x5f, 0x08, 0x00, 0x00, 0x00,

+ 5 - 5
sdk/pinocchio/src/sysvars/rent.rs

@@ -19,10 +19,10 @@ pub const RENT_ID: Pubkey = [
 /// Default rental rate in lamports/byte-year.
 ///
 /// This calculation is based on:
-/// - 10^9 lamports per SOL
-/// - $1 per SOL
-/// - $0.01 per megabyte day
-/// - $3.65 per megabyte year
+/// - `10^9` lamports per SOL
+/// - `$1` per SOL
+/// - `$0.01` per megabyte day
+/// - `$3.65` per megabyte year
 pub const DEFAULT_LAMPORTS_PER_BYTE_YEAR: u64 = 1_000_000_000 / 100 * 365 / (1024 * 1024);
 
 /// Default amount of time (in years) the balance has to include rent for the
@@ -88,7 +88,7 @@ impl Rent {
     ///
     /// # Safety
     ///
-    /// The caller must ensure that it is safe to borrow the account data  e.g., there are
+    /// The caller must ensure that it is safe to borrow the account data - e.g., there are
     /// no mutable borrows of the account data.
     #[inline]
     pub unsafe fn from_account_info_unchecked(

+ 1 - 1
sdk/pubkey/src/lib.rs

@@ -170,7 +170,7 @@ macro_rules! declare_id {
     ( $id:expr ) => {
         use $crate::reexport::Pubkey;
 
-        #[doc = "The const program ID."]
+        #[doc = "The constant program ID."]
         pub const ID: Pubkey = $crate::from_str($id);
 
         #[doc = "Returns `true` if given pubkey is the program ID."]