From 4c95637875609a067088cc639dce2410c6f859c9 Mon Sep 17 00:00:00 2001 From: Tyera Eulberg Date: Tue, 23 Jun 2020 19:44:38 -0600 Subject: [PATCH 1/4] Add design proposal for ProgramInstruction procedural macro --- docs/src/SUMMARY.md | 1 + .../proposals/program-instruction-macro.md | 224 ++++++++++++++++++ 2 files changed, 225 insertions(+) create mode 100644 docs/src/proposals/program-instruction-macro.md diff --git a/docs/src/SUMMARY.md b/docs/src/SUMMARY.md index 05aa7a3f8745e1..cf856f82705469 100644 --- a/docs/src/SUMMARY.md +++ b/docs/src/SUMMARY.md @@ -117,3 +117,4 @@ * [Block Confirmation](proposals/block-confirmation.md) * [Rust Clients](proposals/rust-clients.md) * [Optimistic Confirmation](proposals/optimistic_confirmation.md) + * [Program Instruction Macro](proposals/program-instruction-macro.md) diff --git a/docs/src/proposals/program-instruction-macro.md b/docs/src/proposals/program-instruction-macro.md new file mode 100644 index 00000000000000..48b33f314d71b2 --- /dev/null +++ b/docs/src/proposals/program-instruction-macro.md @@ -0,0 +1,224 @@ +# Program Instruction Macro + +## Problem + +Currently, inspecting an on-chain transaction requires depending on a +client-side, language-specific decoding library to parse the instruction. If +rpc methods could return decoded instruction details, these custom solutions +would be unnecessary. + +We can deserialize instruction data using a program's Instruction enum, but +decoding the account-key list into human-readable identifiers requires manual +parsing. Our current Instruction enums have that account information, but only +in variant docs. + +Also, Instruction docs can vary between implementations, as there is no +mechanism to ensure consistency. + +## Proposed Solution + +Implement a procedural macro that parses an Instruction enum and generates a +second, verbose enum that contains account details and implements a conversion +method between the two enums. + +Parsing the account documentation as it is would be brittle; a better method +would be to store account information in an attribute for each Instruction +variant, which could be checked for correctness on compile. The macro would +parse this `accounts` attribute to generate the account fields on the new enum, +as well as generate pretty, consistent documentation for the Instruction enum +itself. + +The macro could also support a `verbose_derive` item-level attribute in order to +enable custom configuration of derived traits for the verbose enum. + +Here is an example of an Instruction enum using the new accounts format: + +```text +#[repr(C)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, ProgramInstruction)] +#[verbose_derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +pub enum TestInstruction { + /// Consumes a stored nonce, replacing it with a successor + #[accounts( + nonce_account(is_signer = true, is_writable = true, desc = "Nonce account"), + recent_blockhashes_sysvar(desc = "RecentBlockhashes sysvar"), + nonce_authority(is_signer = true, desc = "Nonce authority"), + )] + AdvanceNonceAccount, + + /// Transfer lamports + #[accounts( + funding_account(is_signer = true, is_writable = true, desc = "Funding account"), + recipient_account(is_writable = true, desc = "Recipient account"), + )] + Transfer { + lamports: u64, + }, + + /// Drive state of Uninitalized nonce account to Initialized, setting the nonce value + /// + /// No signatures are required to execute this instruction, enabling derived + /// nonce account addresses + #[accounts( + nonce_account(is_signer = true,is_writable = true, desc = "Nonce account"), + recent_blockhashes_sysvar(desc = "RecentBlockhashes sysvar"), + rent_sysvar(desc = "Rent sysvar"), + )] + InitializeNonceAccount { + /// Specifies the entity authorized to execute nonce instruction on the account + pubkey: Pubkey, + }, +} + +mod tests { + + #[test] + fn test_from() { + use super::*; + let transfer = TestInstruction::Transfer { lamports: 42 }; + let verbose_transfer = TestInstructionVerbose::from_instruction(transfer, vec![2, 3]); + assert_eq!( + verbose_transfer, + TestInstructionVerbose::Transfer { + funding_account: 2, + recipient_account: 3, + lamports: 42 + } + ); + + let advance = TestInstruction::AdvanceNonceAccount; + let verbose_advance = TestInstructionVerbose::from_instruction(advance, vec![2, 3, 4]); + assert_eq!( + verbose_advance, + TestInstructionVerbose::AdvanceNonceAccount { + nonce_account: 2, + recent_blockhashes_sysvar: 3, + nonce_authority: 4, + } + ); + + let nonce_address = Pubkey::new_rand(); + let initialize = TestInstruction::InitializeNonceAccount { + pubkey: nonce_address, + }; + let verbose_initialize = + TestInstructionVerbose::from_instruction(initialize, vec![2, 3, 4]); + assert_eq!( + verbose_initialize, + TestInstructionVerbose::InitializeNonceAccount { + nonce_account: 2, + recent_blockhashes_sysvar: 3, + rent_sysvar: 4, + pubkey: nonce_address, + } + ); + } +} +``` + +An example of the generated TestInstruction docs for AdvanceNonceAccount: +```text + /// Consumes a stored nonce, replacing it with a successor + /// + /// * Accounts expected by this instruction: + /// 0. `[writable, signer]` Nonce account + /// 1. `[]` RecentBlockhashes sysvar + /// 2. `[signer]` Nonce authority + AdvanceNonceAccount, +``` + +Generated TestInstructionVerbose enum: + +```text +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +pub enum TestInstruction { + /// Consumes a stored nonce, replacing it with a successor + AdvanceNonceAccount { + /// Nonce account + nonce_account: u8 + + /// RecentBlockhashes sysvar + recent_blockhashes_sysvar: u8 + + /// Nonce authority + nonce_authority: u8 + }, + + /// Transfer lamports + Transfer { + /// Funding account + funding_account: u8 + + /// Recipient account + recipient_account: u8 + + lamports: u64, + }, + + /// Drive state of Uninitialized nonce account to Initialized, setting the nonce value + /// + /// No signatures are required to execute this instruction, enabling derived + /// nonce account addresses + #[accounts( + nonce_account(is_signer = true,is_writable = true, desc = "Nonce account"), + recent_blockhashes_sysvar(desc = "RecentBlockhashes sysvar"), + rent_sysvar(desc = "Rent sysvar"), + )] + InitializeNonceAccount { + /// Nonce account + nonce_account: u8 + + /// RecentBlockhashes sysvar + recent_blockhashes_sysvar: u8 + + /// Rent sysvar + rent_sysvar: u8 + + /// Specifies the entity authorized to execute nonce instruction on the account + pubkey: Pubkey, + }, +} + +impl TestInstructionVerbose { + pub fn from_instruction(instruction: TestInstruction, account_keys: Vec) -> Self { + match instruction { + TestInstruction::AdvanceNonceAccount => TestInstructionVerbose::AdvanceNonceAccount { + nonce_account: account_keys[0], + recent_blockhashes_sysvar: account_keys[1], + nonce_authority: account_keys[2], + } + TestInstruction::Transfer { lamports } => TestInstructionVerbose::Transfer { + funding_account: account_keys[0], + recipient_account: account_keys[1], + lamports, + } + TestInstruction::InitializeNonceAccount => TestInstructionVerbose::InitializeNonceAccount { + nonce_account: account_keys[0], + recent_blockhashes_sysvar: account_keys[1], + rent_sysvar: account_keys[2], + pubkey, + } + } + } +} + +``` + +## Considerations + +1. **Named fields** - Since the resulting Verbose enum constructs variants with +named fields, any unnamed fields in the original Instruction variant will need +to have names generated. As such, it would be considerably more straightforward +if all Instruction enum fields are converted to named types, instead of unnamed +tuples. This seems worth doing anyway, adding more precision to the variants and +enabling real documentation (so developers don't have to do +[this](https://github.com/solana-labs/solana/blob/3aab13a1679ba2b7846d9ba39b04a52f2017d3e0/sdk/src/system_instruction.rs#L140) +This will cause a little churn in our current code base, but not a lot. +2. **Variable account lists** - This approach only handles account lists of known +length and composition; it doesn't offer a solution for variable account lists, +like +[spl-token](https://github.com/solana-labs/solana-program-library/blob/master/token/src/instruction.rs#L30). +With the exception of that one TokenInstruction variant, all the other existing +native and bpf Instruction variants support static accounts lists. So one +possible solution would be to require all Instruction variants to do so, forcing +TokenInstruction to implement a new variant, like `NewTokenWithMint`. From aeb8d06c2fd2d6984f91bd53eae6ae2c3e6217e5 Mon Sep 17 00:00:00 2001 From: Tyera Eulberg Date: Wed, 24 Jun 2020 17:15:38 -0600 Subject: [PATCH 2/4] Update examples and some verbiage --- .../proposals/program-instruction-macro.md | 280 +++++++++--------- 1 file changed, 140 insertions(+), 140 deletions(-) diff --git a/docs/src/proposals/program-instruction-macro.md b/docs/src/proposals/program-instruction-macro.md index 48b33f314d71b2..aef7f7d7e35324 100644 --- a/docs/src/proposals/program-instruction-macro.md +++ b/docs/src/proposals/program-instruction-macro.md @@ -12,138 +12,146 @@ decoding the account-key list into human-readable identifiers requires manual parsing. Our current Instruction enums have that account information, but only in variant docs. +Similarly, we have instruction constructor functions that duplicate nearly all +the information in the enum, but we can't generate that constructor from the +enum definition because the list of account references is in code comments. + Also, Instruction docs can vary between implementations, as there is no mechanism to ensure consistency. ## Proposed Solution -Implement a procedural macro that parses an Instruction enum and generates a -second, verbose enum that contains account details and implements a conversion -method between the two enums. - -Parsing the account documentation as it is would be brittle; a better method -would be to store account information in an attribute for each Instruction -variant, which could be checked for correctness on compile. The macro would -parse this `accounts` attribute to generate the account fields on the new enum, -as well as generate pretty, consistent documentation for the Instruction enum -itself. - -The macro could also support a `verbose_derive` item-level attribute in order to -enable custom configuration of derived traits for the verbose enum. +Move the data from code comments to attributes, such that the constructors +can be generated, and include all the documentation from the enum definition. Here is an example of an Instruction enum using the new accounts format: -```text -#[repr(C)] -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, ProgramInstruction)] -#[verbose_derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +```rust,ignore +#[instructions(test_program::id())] pub enum TestInstruction { - /// Consumes a stored nonce, replacing it with a successor - #[accounts( - nonce_account(is_signer = true, is_writable = true, desc = "Nonce account"), - recent_blockhashes_sysvar(desc = "RecentBlockhashes sysvar"), - nonce_authority(is_signer = true, desc = "Nonce authority"), - )] - AdvanceNonceAccount, - /// Transfer lamports #[accounts( - funding_account(is_signer = true, is_writable = true, desc = "Funding account"), - recipient_account(is_writable = true, desc = "Recipient account"), + from_account(signer, writable, desc = "Funding account"), + to_account(writable, desc = "Recipient account"), )] Transfer { lamports: u64, }, - /// Drive state of Uninitalized nonce account to Initialized, setting the nonce value - /// - /// No signatures are required to execute this instruction, enabling derived - /// nonce account addresses + /// Provide M of N required signatures #[accounts( - nonce_account(is_signer = true,is_writable = true, desc = "Nonce account"), - recent_blockhashes_sysvar(desc = "RecentBlockhashes sysvar"), - rent_sysvar(desc = "Rent sysvar"), + data_account(writable, desc = "Data account"), + signer(signer, multiple, desc = "Signer"), )] - InitializeNonceAccount { - /// Specifies the entity authorized to execute nonce instruction on the account - pubkey: Pubkey, - }, + Multisig, + + /// Consumes a stored nonce, replacing it with a successor + #[accounts( + nonce_account(signer, writable, desc = "Nonce account"), + recent_blockhashes_sysvar(signer, writable, desc = "RecentBlockhashes sysvar"), + nonce_authority(signer, optional, desc = "Nonce authority"), + )] + AdvanceNonceAccount, } +``` -mod tests { - - #[test] - fn test_from() { - use super::*; - let transfer = TestInstruction::Transfer { lamports: 42 }; - let verbose_transfer = TestInstructionVerbose::from_instruction(transfer, vec![2, 3]); - assert_eq!( - verbose_transfer, - TestInstructionVerbose::Transfer { - funding_account: 2, - recipient_account: 3, - lamports: 42 - } - ); - - let advance = TestInstruction::AdvanceNonceAccount; - let verbose_advance = TestInstructionVerbose::from_instruction(advance, vec![2, 3, 4]); - assert_eq!( - verbose_advance, - TestInstructionVerbose::AdvanceNonceAccount { - nonce_account: 2, - recent_blockhashes_sysvar: 3, - nonce_authority: 4, - } - ); - - let nonce_address = Pubkey::new_rand(); - let initialize = TestInstruction::InitializeNonceAccount { - pubkey: nonce_address, - }; - let verbose_initialize = - TestInstructionVerbose::from_instruction(initialize, vec![2, 3, 4]); - assert_eq!( - verbose_initialize, - TestInstructionVerbose::InitializeNonceAccount { - nonce_account: 2, - recent_blockhashes_sysvar: 3, - rent_sysvar: 4, - pubkey: nonce_address, - } - ); +An example of the generated TestInstruction with docs: +```rust,ignore + pub enum TestInstruction { + /// Transfer lamports + /// + /// * Accounts expected by this instruction: + /// 0. `[writable, signer]` Funding account + /// 1. `[writable]` Recipient account + Transfer { + lamports: u64, + }, + + /// Provide M of N required signatures + /// + /// * Accounts expected by this instruction: + /// 0. `[writable]` Data account + /// * (Multiple) `[signer]` Signers + Multisig, + + /// Consumes a stored nonce, replacing it with a successor + /// + /// * Accounts expected by this instruction: + /// 0. `[writable, signer]` Nonce account + /// 1. [] RecentBlockhashes sysvar + /// 2. (Optional) `[signer]` Nonce authority + AdvanceNonceAccount, + } +``` + +Generated constructors: +```rust,ignore +/// Transfer lamports +/// +/// * `from_account` - `[writable, signer]` Funding account +/// * `to_account` - `[writable]` Recipient account +pub fn transfer(from_account: &Pubkey, to_account: &Pubkey, lamports: u64) -> Instruction { + let account_metas = vec![ + AccountMeta::new(*from_pubkey, true), + AccountMeta::new(*to_pubkey, false), + ]; + Instruction::new( + system_program::id(), + &SystemInstruction::Transfer { lamports }, + account_metas, + ) +} + +/// Provide M of N required signatures +/// +/// * `data_account` - `[writable]` Data account +/// * `signers` - (Multiple) `[signer]` Signers +pub fn multisig(data_account: &Pubkey, signers: &[&Pubkey]) -> Instruction { + let mut account_metas = vec![ + AccountMeta::new(*nonce_pubkey, false), + ]; + for pubkey in signers.iter() { + account_metas.push(AccountMeta::new_readonly(*pubkey, true)); } + + Instruction::new( + test_program::id(), + &TestInstruction::Multisig, + account_metas, + ) +} + +/// Consumes a stored nonce, replacing it with a successor +/// +/// * nonce_account - `[writable, signer]` Nonce account +/// * recent_blockhashes_sysvar - [] RecentBlockhashes sysvar +/// * nonce_authority - (Optional) `[signer]` Nonce authority +pub fn advance_nonce_account( + nonce_account: &Pubkey, + recent_blockhashes_sysvar: &Pubkey, + nonce_authority: Option<&Pubkey>, +) -> Instruction { + let mut account_metas = vec![ + AccountMeta::new(*nonce_account, false), + AccountMeta::new_readonly(*recent_blockhashes_sysvar, false), + ]; + if let Some(pubkey) = authorized_pubkey { + account_metas.push(AccountMeta::new_readonly(*nonce_authority, true)); + } + Instruction::new( + test_program::id(), + &TestInstruction::AdvanceNonceAccount, + account_metas, + ) } -``` -An example of the generated TestInstruction docs for AdvanceNonceAccount: -```text - /// Consumes a stored nonce, replacing it with a successor - /// - /// * Accounts expected by this instruction: - /// 0. `[writable, signer]` Nonce account - /// 1. `[]` RecentBlockhashes sysvar - /// 2. `[signer]` Nonce authority - AdvanceNonceAccount, ``` Generated TestInstructionVerbose enum: -```text +```rust,ignore #[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] pub enum TestInstruction { - /// Consumes a stored nonce, replacing it with a successor - AdvanceNonceAccount { - /// Nonce account - nonce_account: u8 - - /// RecentBlockhashes sysvar - recent_blockhashes_sysvar: u8 - - /// Nonce authority - nonce_authority: u8 - }, - /// Transfer lamports Transfer { /// Funding account @@ -155,48 +163,36 @@ pub enum TestInstruction { lamports: u64, }, - /// Drive state of Uninitialized nonce account to Initialized, setting the nonce value - /// - /// No signatures are required to execute this instruction, enabling derived - /// nonce account addresses - #[accounts( - nonce_account(is_signer = true,is_writable = true, desc = "Nonce account"), - recent_blockhashes_sysvar(desc = "RecentBlockhashes sysvar"), - rent_sysvar(desc = "Rent sysvar"), - )] - InitializeNonceAccount { - /// Nonce account - nonce_account: u8 - - /// RecentBlockhashes sysvar - recent_blockhashes_sysvar: u8 - - /// Rent sysvar - rent_sysvar: u8 - - /// Specifies the entity authorized to execute nonce instruction on the account - pubkey: Pubkey, + /// Provide M of N required signatures + Multisig { + data_account: u8, + signers: Vec, }, + + /// Consumes a stored nonce, replacing it with a successor + AdvanceNonceAccount { + nonce_account: u8, + recent_blockhashes_sysvar: u8, + nonce_authority: Option, + } } impl TestInstructionVerbose { pub fn from_instruction(instruction: TestInstruction, account_keys: Vec) -> Self { match instruction { - TestInstruction::AdvanceNonceAccount => TestInstructionVerbose::AdvanceNonceAccount { - nonce_account: account_keys[0], - recent_blockhashes_sysvar: account_keys[1], - nonce_authority: account_keys[2], - } TestInstruction::Transfer { lamports } => TestInstructionVerbose::Transfer { funding_account: account_keys[0], recipient_account: account_keys[1], lamports, } - TestInstruction::InitializeNonceAccount => TestInstructionVerbose::InitializeNonceAccount { + TestInstruction::Multisig => TestInstructionVerbose::Multisig { + data_account: account_keys[0], + signers: account_keys[1..], + } + TestInstruction::AdvanceNonceAccount => TestInstructionVerbose::AdvanceNonceAccount { nonce_account: account_keys[0], recent_blockhashes_sysvar: account_keys[1], - rent_sysvar: account_keys[2], - pubkey, + nonce_authority: &account_keys.get(2), } } } @@ -214,11 +210,15 @@ tuples. This seems worth doing anyway, adding more precision to the variants and enabling real documentation (so developers don't have to do [this](https://github.com/solana-labs/solana/blob/3aab13a1679ba2b7846d9ba39b04a52f2017d3e0/sdk/src/system_instruction.rs#L140) This will cause a little churn in our current code base, but not a lot. -2. **Variable account lists** - This approach only handles account lists of known -length and composition; it doesn't offer a solution for variable account lists, -like -[spl-token](https://github.com/solana-labs/solana-program-library/blob/master/token/src/instruction.rs#L30). -With the exception of that one TokenInstruction variant, all the other existing -native and bpf Instruction variants support static accounts lists. So one -possible solution would be to require all Instruction variants to do so, forcing -TokenInstruction to implement a new variant, like `NewTokenWithMint`. +2. **Variable account lists** - This approach offers a couple options for +variable account lists. First, optional accounts may be added and tagged with +the `optional` keyword. However, currently only one optional account is +supported per instruction. Additional data will need to be added to the +instruction to support multiples, enabling identification of which accounts are +present when some but not all are included. Second, accounts that share the same +features may be added as a set, tagged with the `multiple` keyword. Like +optional accounts, only one multiple account set is supported per instruction +(and optional and multiple may not coexist). More complex instructions that +cannot be accommodated by `optional` or `multiple`, requiring logic to figure +out account order/representation, should probably be made into separate +instructions. From ebc6d80d1adf6f3e48afe2008849d6ce0f9c08c9 Mon Sep 17 00:00:00 2001 From: Tyera Eulberg Date: Thu, 25 Jun 2020 09:28:28 -0600 Subject: [PATCH 3/4] More constant-like --- .../proposals/program-instruction-macro.md | 76 +++++++++---------- 1 file changed, 38 insertions(+), 38 deletions(-) diff --git a/docs/src/proposals/program-instruction-macro.md b/docs/src/proposals/program-instruction-macro.md index aef7f7d7e35324..122a46cd53e05f 100644 --- a/docs/src/proposals/program-instruction-macro.md +++ b/docs/src/proposals/program-instruction-macro.md @@ -31,8 +31,8 @@ Here is an example of an Instruction enum using the new accounts format: pub enum TestInstruction { /// Transfer lamports #[accounts( - from_account(signer, writable, desc = "Funding account"), - to_account(writable, desc = "Recipient account"), + from_account(SIGNER, WRITABLE, desc = "Funding account"), + to_account(WRITABLE, desc = "Recipient account"), )] Transfer { lamports: u64, @@ -40,16 +40,16 @@ pub enum TestInstruction { /// Provide M of N required signatures #[accounts( - data_account(writable, desc = "Data account"), - signer(signer, multiple, desc = "Signer"), + data_account(WRITABLE, desc = "Data account"), + signers(SIGNER, multiple, desc = "Signer"), )] Multisig, /// Consumes a stored nonce, replacing it with a successor #[accounts( - nonce_account(signer, writable, desc = "Nonce account"), - recent_blockhashes_sysvar(signer, writable, desc = "RecentBlockhashes sysvar"), - nonce_authority(signer, optional, desc = "Nonce authority"), + nonce_account(SIGNER, WRITABLE, desc = "Nonce account"), + recent_blockhashes_sysvar(SIGNER, WRITABLE, desc = "RecentBlockhashes sysvar"), + nonce_authority(SIGNER, optional, desc = "Nonce authority"), )] AdvanceNonceAccount, } @@ -57,39 +57,39 @@ pub enum TestInstruction { An example of the generated TestInstruction with docs: ```rust,ignore - pub enum TestInstruction { - /// Transfer lamports - /// - /// * Accounts expected by this instruction: - /// 0. `[writable, signer]` Funding account - /// 1. `[writable]` Recipient account - Transfer { - lamports: u64, - }, - - /// Provide M of N required signatures - /// - /// * Accounts expected by this instruction: - /// 0. `[writable]` Data account - /// * (Multiple) `[signer]` Signers - Multisig, - - /// Consumes a stored nonce, replacing it with a successor - /// - /// * Accounts expected by this instruction: - /// 0. `[writable, signer]` Nonce account - /// 1. [] RecentBlockhashes sysvar - /// 2. (Optional) `[signer]` Nonce authority - AdvanceNonceAccount, - } +pub enum TestInstruction { + /// Transfer lamports + /// + /// * Accounts expected by this instruction: + /// 0. `[WRITABLE, SIGNER]` Funding account + /// 1. `[WRITABLE]` Recipient account + Transfer { + lamports: u64, + }, + + /// Provide M of N required signatures + /// + /// * Accounts expected by this instruction: + /// 0. `[WRITABLE]` Data account + /// * (Multiple) `[SIGNER]` Signers + Multisig, + + /// Consumes a stored nonce, replacing it with a successor + /// + /// * Accounts expected by this instruction: + /// 0. `[WRITABLE, SIGNER]` Nonce account + /// 1. [] RecentBlockhashes sysvar + /// 2. (Optional) `[SIGNER]` Nonce authority + AdvanceNonceAccount, +} ``` Generated constructors: ```rust,ignore /// Transfer lamports /// -/// * `from_account` - `[writable, signer]` Funding account -/// * `to_account` - `[writable]` Recipient account +/// * `from_account` - `[WRITABLE, SIGNER]` Funding account +/// * `to_account` - `[WRITABLE]` Recipient account pub fn transfer(from_account: &Pubkey, to_account: &Pubkey, lamports: u64) -> Instruction { let account_metas = vec![ AccountMeta::new(*from_pubkey, true), @@ -104,8 +104,8 @@ pub fn transfer(from_account: &Pubkey, to_account: &Pubkey, lamports: u64) -> In /// Provide M of N required signatures /// -/// * `data_account` - `[writable]` Data account -/// * `signers` - (Multiple) `[signer]` Signers +/// * `data_account` - `[WRITABLE]` Data account +/// * `signers` - (Multiple) `[SIGNER]` Signers pub fn multisig(data_account: &Pubkey, signers: &[&Pubkey]) -> Instruction { let mut account_metas = vec![ AccountMeta::new(*nonce_pubkey, false), @@ -123,9 +123,9 @@ pub fn multisig(data_account: &Pubkey, signers: &[&Pubkey]) -> Instruction { /// Consumes a stored nonce, replacing it with a successor /// -/// * nonce_account - `[writable, signer]` Nonce account +/// * nonce_account - `[WRITABLE, SIGNER]` Nonce account /// * recent_blockhashes_sysvar - [] RecentBlockhashes sysvar -/// * nonce_authority - (Optional) `[signer]` Nonce authority +/// * nonce_authority - (Optional) `[SIGNER]` Nonce authority pub fn advance_nonce_account( nonce_account: &Pubkey, recent_blockhashes_sysvar: &Pubkey, From 046e8b9a49e0b2cf9b4fdd2725dff8ac5c3282ed Mon Sep 17 00:00:00 2001 From: Tyera Eulberg Date: Thu, 25 Jun 2020 12:31:33 -0600 Subject: [PATCH 4/4] Generated helpers expect Pubkey by value --- .../proposals/program-instruction-macro.md | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/docs/src/proposals/program-instruction-macro.md b/docs/src/proposals/program-instruction-macro.md index 122a46cd53e05f..f5ba153cd493df 100644 --- a/docs/src/proposals/program-instruction-macro.md +++ b/docs/src/proposals/program-instruction-macro.md @@ -48,7 +48,7 @@ pub enum TestInstruction { /// Consumes a stored nonce, replacing it with a successor #[accounts( nonce_account(SIGNER, WRITABLE, desc = "Nonce account"), - recent_blockhashes_sysvar(SIGNER, WRITABLE, desc = "RecentBlockhashes sysvar"), + recent_blockhashes_sysvar(desc = "RecentBlockhashes sysvar"), nonce_authority(SIGNER, optional, desc = "Nonce authority"), )] AdvanceNonceAccount, @@ -78,7 +78,7 @@ pub enum TestInstruction { /// /// * Accounts expected by this instruction: /// 0. `[WRITABLE, SIGNER]` Nonce account - /// 1. [] RecentBlockhashes sysvar + /// 1. `[]` RecentBlockhashes sysvar /// 2. (Optional) `[SIGNER]` Nonce authority AdvanceNonceAccount, } @@ -90,13 +90,13 @@ Generated constructors: /// /// * `from_account` - `[WRITABLE, SIGNER]` Funding account /// * `to_account` - `[WRITABLE]` Recipient account -pub fn transfer(from_account: &Pubkey, to_account: &Pubkey, lamports: u64) -> Instruction { +pub fn transfer(from_account: Pubkey, to_account: Pubkey, lamports: u64) -> Instruction { let account_metas = vec![ - AccountMeta::new(*from_pubkey, true), - AccountMeta::new(*to_pubkey, false), + AccountMeta::new(from_pubkey, true), + AccountMeta::new(to_pubkey, false), ]; Instruction::new( - system_program::id(), + test_program::id(), &SystemInstruction::Transfer { lamports }, account_metas, ) @@ -106,12 +106,12 @@ pub fn transfer(from_account: &Pubkey, to_account: &Pubkey, lamports: u64) -> In /// /// * `data_account` - `[WRITABLE]` Data account /// * `signers` - (Multiple) `[SIGNER]` Signers -pub fn multisig(data_account: &Pubkey, signers: &[&Pubkey]) -> Instruction { +pub fn multisig(data_account: Pubkey, signers: &[Pubkey]) -> Instruction { let mut account_metas = vec![ - AccountMeta::new(*nonce_pubkey, false), + AccountMeta::new(nonce_pubkey, false), ]; for pubkey in signers.iter() { - account_metas.push(AccountMeta::new_readonly(*pubkey, true)); + account_metas.push(AccountMeta::new_readonly(pubkey, true)); } Instruction::new( @@ -124,19 +124,19 @@ pub fn multisig(data_account: &Pubkey, signers: &[&Pubkey]) -> Instruction { /// Consumes a stored nonce, replacing it with a successor /// /// * nonce_account - `[WRITABLE, SIGNER]` Nonce account -/// * recent_blockhashes_sysvar - [] RecentBlockhashes sysvar +/// * recent_blockhashes_sysvar - `[]` RecentBlockhashes sysvar /// * nonce_authority - (Optional) `[SIGNER]` Nonce authority pub fn advance_nonce_account( - nonce_account: &Pubkey, - recent_blockhashes_sysvar: &Pubkey, - nonce_authority: Option<&Pubkey>, + nonce_account: Pubkey, + recent_blockhashes_sysvar: Pubkey, + nonce_authority: Option, ) -> Instruction { let mut account_metas = vec![ - AccountMeta::new(*nonce_account, false), - AccountMeta::new_readonly(*recent_blockhashes_sysvar, false), + AccountMeta::new(nonce_account, false), + AccountMeta::new_readonly(recent_blockhashes_sysvar, false), ]; if let Some(pubkey) = authorized_pubkey { - account_metas.push(AccountMeta::new_readonly(*nonce_authority, true)); + account_metas.push(AccountMeta::new_readonly*nonce_authority, true)); } Instruction::new( test_program::id(),