From 81f20711c9e12664a2f8347f5d0ee67071fb52ed Mon Sep 17 00:00:00 2001 From: samkim-crypto Date: Sun, 12 Mar 2023 10:22:03 +0900 Subject: [PATCH] [token-2022] Create proof-program feature (#4040) --- token/client/Cargo.toml | 1 + token/client/src/token.rs | 50 ++++++++++-- token/program-2022-test/Cargo.toml | 3 +- .../tests/confidential_transfer.rs | 2 +- token/program-2022/Cargo.toml | 1 + .../confidential_transfer/instruction.rs | 12 +++ .../confidential_transfer/processor.rs | 81 +++++++++++-------- 7 files changed, 108 insertions(+), 42 deletions(-) diff --git a/token/client/Cargo.toml b/token/client/Cargo.toml index 00d4e1c33cd..e4fdd0dc146 100644 --- a/token/client/Cargo.toml +++ b/token/client/Cargo.toml @@ -24,3 +24,4 @@ thiserror = "1.0" [features] default = ["display"] display = ["dep:solana-cli-output"] +proof-program = [] diff --git a/token/client/src/token.rs b/token/client/src/token.rs index bd9c2ae0655..b37e89938ab 100644 --- a/token/client/src/token.rs +++ b/token/client/src/token.rs @@ -3,7 +3,6 @@ use { solana_program_test::tokio::time, solana_sdk::{ account::Account as BaseAccount, - epoch_info::EpochInfo, hash::Hash, instruction::Instruction, message::Message, @@ -26,21 +25,25 @@ use { }, instruction, pod::EncryptionPubkey, - solana_zk_token_sdk::{ - encryption::{auth_encryption::*, elgamal::*}, - errors::ProofError, - instruction::transfer_with_fee::FeeParameters, - }, + solana_zk_token_sdk::errors::ProofError, state::{Account, AccountState, Mint, Multisig}, }, std::{ - convert::TryInto, fmt, io, sync::{Arc, RwLock}, time::{Duration, Instant}, }, thiserror::Error, }; +#[cfg(feature = "proof-program")] +use { + solana_sdk::epoch_info::EpochInfo, + spl_token_2022::solana_zk_token_sdk::{ + encryption::{auth_encryption::*, elgamal::*}, + instruction::transfer_with_fee::FeeParameters, + }, + std::convert::TryInto, +}; #[derive(Error, Debug)] pub enum TokenError { @@ -1516,6 +1519,7 @@ where } /// Configures confidential transfers for a token account + #[cfg(feature = "proof-program")] pub async fn confidential_transfer_configure_token_account( &self, token_account: &Pubkey, @@ -1532,6 +1536,7 @@ where .await } + #[cfg(feature = "proof-program")] pub async fn confidential_transfer_configure_token_account_with_pending_counter( &self, token_account: &Pubkey, @@ -1554,6 +1559,7 @@ where .await } + #[cfg(feature = "proof-program")] pub async fn confidential_transfer_configure_token_account_with_pending_counter_and_keypair< S: Signer, >( @@ -1585,6 +1591,7 @@ where } /// Approves a token account for confidential transfers + #[cfg(feature = "proof-program")] pub async fn confidential_transfer_approve_account( &self, token_account: &Pubkey, @@ -1603,6 +1610,7 @@ where } /// Prepare a token account with the confidential transfer extension for closing + #[cfg(feature = "proof-program")] pub async fn confidential_transfer_empty_account( &self, token_account: &Pubkey, @@ -1618,6 +1626,7 @@ where .await } + #[cfg(feature = "proof-program")] pub async fn confidential_transfer_empty_account_with_keypair( &self, token_account: &Pubkey, @@ -1649,6 +1658,7 @@ where /// Fetch and decrypt the available balance of a confidential token account using the uniquely /// derived decryption key from a signer + #[cfg(feature = "proof-program")] pub async fn confidential_transfer_get_available_balance( &self, token_account: &Pubkey, @@ -1666,6 +1676,7 @@ where /// Fetch and decrypt the available balance of a confidential token account using a custom /// decryption key + #[cfg(feature = "proof-program")] pub async fn confidential_transfer_get_available_balance_with_key( &self, token_account: &Pubkey, @@ -1688,6 +1699,7 @@ where /// Fetch and decrypt the pending balance of a confidential token account using the uniquely /// derived decryption key from a signer + #[cfg(feature = "proof-program")] pub async fn confidential_transfer_get_pending_balance( &self, token_account: &Pubkey, @@ -1702,6 +1714,7 @@ where /// Fetch and decrypt the pending balance of a confidential token account using a custom /// decryption key + #[cfg(feature = "proof-program")] pub async fn confidential_transfer_get_pending_balance_with_key( &self, token_account: &Pubkey, @@ -1728,6 +1741,7 @@ where Ok(pending_balance) } + #[cfg(feature = "proof-program")] pub async fn confidential_transfer_get_withheld_amount( &self, withdraw_withheld_authority: &S, @@ -1744,6 +1758,7 @@ where .await } + #[cfg(feature = "proof-program")] pub async fn confidential_transfer_get_withheld_amount_with_key( &self, withdraw_withheld_authority_elgamal_keypair: &ElGamalKeypair, @@ -1770,6 +1785,7 @@ where } /// Fetch the ElGamal public key associated with a confidential token account + #[cfg(feature = "proof-program")] pub async fn confidential_transfer_get_encryption_pubkey( &self, token_account: &Pubkey, @@ -1786,6 +1802,7 @@ where } /// Fetch the ElGamal pubkey key of the auditor associated with a confidential token mint + #[cfg(feature = "proof-program")] pub async fn confidential_transfer_get_auditor_encryption_pubkey( &self, ) -> TokenResult> { @@ -1806,6 +1823,7 @@ where /// Fetch the ElGamal pubkey key of the withdraw withheld authority associated with a /// confidential token mint + #[cfg(feature = "proof-program")] pub async fn confidential_transfer_get_withdraw_withheld_authority_encryption_pubkey< S: Signer, >( @@ -1827,6 +1845,7 @@ where } /// Deposit SPL Tokens into the pending balance of a confidential token account + #[cfg(feature = "proof-program")] pub async fn confidential_transfer_deposit( &self, token_account: &Pubkey, @@ -1856,6 +1875,7 @@ where /// Withdraw SPL Tokens from the available balance of a confidential token account using the /// uniquely derived decryption key from a signer #[allow(clippy::too_many_arguments)] + #[cfg(feature = "proof-program")] pub async fn confidential_transfer_withdraw( &self, token_account: &Pubkey, @@ -1886,6 +1906,7 @@ where /// Withdraw SPL Tokens from the available balance of a confidential token account using custom /// keys #[allow(clippy::too_many_arguments)] + #[cfg(feature = "proof-program")] pub async fn confidential_transfer_withdraw_with_key( &self, token_account: &Pubkey, @@ -1930,6 +1951,7 @@ where /// Transfer tokens confidentially using the uniquely derived decryption keys from a signer #[allow(clippy::too_many_arguments)] + #[cfg(feature = "proof-program")] pub async fn confidential_transfer_transfer( &self, source_token_account: &Pubkey, @@ -1964,6 +1986,7 @@ where /// Transfer tokens confidentially using custom decryption keys #[allow(clippy::too_many_arguments)] + #[cfg(feature = "proof-program")] pub async fn confidential_transfer_transfer_with_key( &self, source_token_account: &Pubkey, @@ -2019,6 +2042,7 @@ where /// Transfer tokens confidentially with fee using the uniquely derived decryption keys from a /// signer #[allow(clippy::too_many_arguments)] + #[cfg(feature = "proof-program")] pub async fn confidential_transfer_transfer_with_fee( &self, source_token_account: &Pubkey, @@ -2057,6 +2081,7 @@ where /// Transfer tokens confidential with fee using custom decryption keys #[allow(clippy::too_many_arguments)] + #[cfg(feature = "proof-program")] pub async fn confidential_transfer_transfer_with_fee_with_key( &self, source_token_account: &Pubkey, @@ -2124,6 +2149,7 @@ where /// Applies the confidential transfer pending balance to the available balance using the /// uniquely derived decryption key + #[cfg(feature = "proof-program")] pub async fn confidential_transfer_apply_pending_balance( &self, token_account: &Pubkey, @@ -2148,6 +2174,7 @@ where /// Applies the confidential transfer pending balance to the available balance using a custom /// decryption key + #[cfg(feature = "proof-program")] pub async fn confidential_transfer_apply_pending_balance_with_key( &self, token_account: &Pubkey, @@ -2176,6 +2203,7 @@ where } /// Enable confidential transfer `Deposit` and `Transfer` instructions for a token account + #[cfg(feature = "proof-program")] pub async fn confidential_transfer_enable_confidential_credits( &self, token_account: &Pubkey, @@ -2196,6 +2224,7 @@ where } /// Disable confidential transfer `Deposit` and `Transfer` instructions for a token account + #[cfg(feature = "proof-program")] pub async fn confidential_transfer_disable_confidential_credits( &self, token_account: &Pubkey, @@ -2216,6 +2245,7 @@ where } /// Enable a confidential extension token account to receive non-confidential payments + #[cfg(feature = "proof-program")] pub async fn confidential_transfer_enable_non_confidential_credits( &self, token_account: &Pubkey, @@ -2236,6 +2266,7 @@ where } /// Disable non-confidential payments for a confidential extension token account + #[cfg(feature = "proof-program")] pub async fn confidential_transfer_disable_non_confidential_credits( &self, token_account: &Pubkey, @@ -2256,6 +2287,7 @@ where } /// Withdraw withheld confidential tokens from mint using the uniquely derived decryption key + #[cfg(feature = "proof-program")] pub async fn confidential_transfer_withdraw_withheld_tokens_from_mint( &self, withdraw_withheld_authority: &S, @@ -2281,6 +2313,7 @@ where } /// Withdraw withheld confidential tokens from mint using a custom decryption key + #[cfg(feature = "proof-program")] pub async fn confidential_transfer_withdraw_withheld_tokens_from_mint_with_key( &self, withdraw_withheld_authority: &S, @@ -2314,6 +2347,7 @@ where /// Withdraw withheld confidential tokens from accounts using the uniquely derived decryption /// key + #[cfg(feature = "proof-program")] pub async fn confidential_transfer_withdraw_withheld_tokens_from_accounts( &self, withdraw_withheld_authority: &S, @@ -2341,6 +2375,7 @@ where /// Withdraw withheld confidential tokens from accounts using a custom decryption key #[allow(clippy::too_many_arguments)] + #[cfg(feature = "proof-program")] pub async fn confidential_transfer_withdraw_withheld_tokens_from_accounts_with_key< S: Signer, >( @@ -2377,6 +2412,7 @@ where } /// Harvest withheld confidential tokens to mint + #[cfg(feature = "proof-program")] pub async fn confidential_transfer_harvest_withheld_tokens_to_mint( &self, sources: &[&Pubkey], diff --git a/token/program-2022-test/Cargo.toml b/token/program-2022-test/Cargo.toml index ed4de7d9ce9..87ecee57cd5 100644 --- a/token/program-2022-test/Cargo.toml +++ b/token/program-2022-test/Cargo.toml @@ -8,9 +8,10 @@ repository = "https://github.com/solana-labs/solana-program-library" version = "0.0.1" [features] -test-sbf = [] +test-sbf = ["zk-ops"] default = ["zk-ops"] zk-ops = [] +proof-program = [] [build-dependencies] walkdir = "2" diff --git a/token/program-2022-test/tests/confidential_transfer.rs b/token/program-2022-test/tests/confidential_transfer.rs index b5645f98644..53f2f5fd3c6 100644 --- a/token/program-2022-test/tests/confidential_transfer.rs +++ b/token/program-2022-test/tests/confidential_transfer.rs @@ -1,4 +1,4 @@ -#![cfg(feature = "test-sbf")] +#![cfg(all(feature = "test-sbf", feature = "proof-program"))] #![cfg(twoxtx)] mod program_test; diff --git a/token/program-2022/Cargo.toml b/token/program-2022/Cargo.toml index 0b3b59ea518..2ae7734eabf 100644 --- a/token/program-2022/Cargo.toml +++ b/token/program-2022/Cargo.toml @@ -15,6 +15,7 @@ serde-traits = ["serde", "serde_with"] # Remove these features once the underlying syscalls are released on all networks default = ["zk-ops"] zk-ops = [] +proof-program = [] [dependencies] arrayref = "0.3.6" diff --git a/token/program-2022/src/extension/confidential_transfer/instruction.rs b/token/program-2022/src/extension/confidential_transfer/instruction.rs index 2aed9820eb2..e955b150479 100644 --- a/token/program-2022/src/extension/confidential_transfer/instruction.rs +++ b/token/program-2022/src/extension/confidential_transfer/instruction.rs @@ -642,6 +642,7 @@ pub fn inner_configure_account( /// Create a `ConfigureAccount` instruction #[allow(clippy::too_many_arguments)] #[cfg(not(target_os = "solana"))] +#[cfg(feature = "proof-program")] pub fn configure_account( token_program_id: &Pubkey, token_account: &Pubkey, @@ -663,6 +664,7 @@ pub fn configure_account( multisig_signers, 1, )?, + #[cfg(feature = "proof-program")] verify_pubkey_validity(proof_data), ]) } @@ -722,6 +724,7 @@ pub fn inner_empty_account( } /// Create a `EmptyAccount` instruction +#[cfg(feature = "proof-program")] pub fn empty_account( token_program_id: &Pubkey, token_account: &Pubkey, @@ -737,6 +740,7 @@ pub fn empty_account( multisig_signers, 1, )?, // calls check_program_account + #[cfg(feature = "proof-program")] verify_close_account(proof_data), ]) } @@ -819,6 +823,7 @@ pub fn inner_withdraw( /// Create a `Withdraw` instruction #[allow(clippy::too_many_arguments)] #[cfg(not(target_os = "solana"))] +#[cfg(feature = "proof-program")] pub fn withdraw( token_program_id: &Pubkey, token_account: &Pubkey, @@ -842,6 +847,7 @@ pub fn withdraw( multisig_signers, 1, )?, // calls check_program_account + #[cfg(feature = "proof-program")] verify_withdraw(proof_data), ]) } @@ -888,6 +894,7 @@ pub fn inner_transfer( /// Create a `Transfer` instruction with regular (no-fee) proof #[allow(clippy::too_many_arguments)] #[cfg(not(target_os = "solana"))] +#[cfg(feature = "proof-program")] pub fn transfer( token_program_id: &Pubkey, source_token_account: &Pubkey, @@ -909,6 +916,7 @@ pub fn transfer( multisig_signers, 1, )?, // calls check_program_account + #[cfg(feature = "proof-program")] verify_transfer(proof_data), ]) } @@ -1119,6 +1127,7 @@ pub fn inner_withdraw_withheld_tokens_from_mint( } /// Create a `WithdrawWithheldTokensFromMint` instruction +#[cfg(feature = "proof-program")] pub fn withdraw_withheld_tokens_from_mint( token_program_id: &Pubkey, mint: &Pubkey, @@ -1136,6 +1145,7 @@ pub fn withdraw_withheld_tokens_from_mint( multisig_signers, 1, )?, + #[cfg(feature = "proof-program")] verify_withdraw_withheld_tokens(proof_data), ]) } @@ -1183,6 +1193,7 @@ pub fn inner_withdraw_withheld_tokens_from_accounts( } /// Create a `WithdrawWithheldTokensFromAccounts` instruction +#[cfg(feature = "proof-program")] pub fn withdraw_withheld_tokens_from_accounts( token_program_id: &Pubkey, mint: &Pubkey, @@ -1202,6 +1213,7 @@ pub fn withdraw_withheld_tokens_from_accounts( sources, 1, )?, + #[cfg(feature = "proof-program")] verify_withdraw_withheld_tokens(proof_data), ]) } diff --git a/token/program-2022/src/extension/confidential_transfer/processor.rs b/token/program-2022/src/extension/confidential_transfer/processor.rs index d2961a805b4..5688b154189 100644 --- a/token/program-2022/src/extension/confidential_transfer/processor.rs +++ b/token/program-2022/src/extension/confidential_transfer/processor.rs @@ -13,31 +13,33 @@ use { solana_program::{ account_info::{next_account_info, AccountInfo}, entrypoint::ProgramResult, - instruction::Instruction, msg, program_error::ProgramError, pubkey::Pubkey, - sysvar::instructions::get_instruction_relative, }, - solana_zk_token_sdk::zk_token_proof_program, }; // Remove feature once zk ops syscalls are enabled on all networks #[cfg(feature = "zk-ops")] use { - crate::extension::{ - memo_transfer::{check_previous_sibling_instruction_is_memo, memo_required}, - non_transferable::NonTransferable, - transfer_fee::TransferFeeConfig, - }, - solana_program::{clock::Clock, sysvar::Sysvar}, + crate::extension::{non_transferable::NonTransferable, transfer_fee::TransferFeeConfig}, solana_zk_token_sdk::zk_token_elgamal::ops as syscall, }; +#[cfg(feature = "proof-program")] +use { + crate::extension::memo_transfer::{check_previous_sibling_instruction_is_memo, memo_required}, + solana_program::instruction::Instruction, + solana_program::sysvar::instructions::get_instruction_relative, + solana_program::{clock::Clock, sysvar::Sysvar}, + solana_zk_token_sdk::zk_token_proof_program, +}; + /// Decodes the zero-knowledge proof instruction associated with the token instruction. /// /// `ConfigureAccount`, `EmptyAccount`, `Withdraw`, `Transfer`, `WithdrawWithheldTokensFromMint`, /// and `WithdrawWithheldTokensFromAccounts` instructions require corresponding zero-knowledge /// proof instructions. +#[cfg(feature = "proof-program")] fn decode_proof_instruction( expected: ProofInstruction, instruction: &Instruction, @@ -111,6 +113,7 @@ fn process_update_mint( } /// Processes a [ConfigureAccount] instruction. +#[cfg(feature = "proof-program")] fn process_configure_account( program_id: &Pubkey, accounts: &[AccountInfo], @@ -210,6 +213,7 @@ fn process_approve_account(accounts: &[AccountInfo]) -> ProgramResult { } /// Processes an [EmptyAccount] instruction. +#[cfg(feature = "proof-program")] fn process_empty_account( program_id: &Pubkey, accounts: &[AccountInfo], @@ -370,7 +374,7 @@ fn verify_and_split_deposit_amount(amount: u64) -> Result<(u64, u64), TokenError } /// Processes a [Withdraw] instruction. -#[cfg(feature = "zk-ops")] +#[cfg(all(feature = "zk-ops", feature = "proof-program"))] fn process_withdraw( program_id: &Pubkey, accounts: &[AccountInfo], @@ -463,7 +467,7 @@ fn process_withdraw( } /// Processes an [Transfer] instruction. -#[cfg(feature = "zk-ops")] +#[cfg(all(feature = "zk-ops", feature = "proof-program"))] fn process_transfer( program_id: &Pubkey, accounts: &[AccountInfo], @@ -646,7 +650,7 @@ fn process_transfer( } #[allow(clippy::too_many_arguments)] -#[cfg(feature = "zk-ops")] +#[cfg(all(feature = "zk-ops", feature = "proof-program"))] fn process_source_for_transfer( program_id: &Pubkey, source_account_info: &AccountInfo, @@ -710,7 +714,7 @@ fn process_source_for_transfer( Ok(()) } -#[cfg(feature = "zk-ops")] +#[cfg(all(feature = "zk-ops", feature = "proof-program"))] fn process_destination_for_transfer( destination_token_account_info: &AccountInfo, mint_info: &AccountInfo, @@ -922,7 +926,7 @@ fn process_allow_non_confidential_credits( } /// Processes an [WithdrawWithheldTokensFromMint] instruction. -#[cfg(feature = "zk-ops")] +#[cfg(all(feature = "zk-ops", feature = "proof-program"))] fn process_withdraw_withheld_tokens_from_mint( program_id: &Pubkey, accounts: &[AccountInfo], @@ -1018,7 +1022,8 @@ fn process_withdraw_withheld_tokens_from_mint( Ok(()) } -#[cfg(feature = "zk-ops")] +/// Processes an [WithdrawWithheldTokensFromAccounts] instruction. +#[cfg(all(feature = "zk-ops", feature = "proof-program"))] fn process_withdraw_withheld_tokens_from_accounts( program_id: &Pubkey, accounts: &[AccountInfo], @@ -1226,14 +1231,19 @@ pub(crate) fn process_instruction( } ConfidentialTransferInstruction::ConfigureAccount => { msg!("ConfidentialTransferInstruction::ConfigureAccount"); - let data = decode_instruction_data::(input)?; - process_configure_account( - program_id, - accounts, - &data.decryptable_zero_balance, - &data.maximum_pending_balance_credit_counter, - data.proof_instruction_offset as i64, - ) + #[cfg(feature = "proof-program")] + { + let data = decode_instruction_data::(input)?; + process_configure_account( + program_id, + accounts, + &data.decryptable_zero_balance, + &data.maximum_pending_balance_credit_counter, + data.proof_instruction_offset as i64, + ) + } + #[cfg(not(feature = "proof-program"))] + Err(ProgramError::InvalidInstructionData) } ConfidentialTransferInstruction::ApproveAccount => { msg!("ConfidentialTransferInstruction::ApproveAccount"); @@ -1241,8 +1251,13 @@ pub(crate) fn process_instruction( } ConfidentialTransferInstruction::EmptyAccount => { msg!("ConfidentialTransferInstruction::EmptyAccount"); - let data = decode_instruction_data::(input)?; - process_empty_account(program_id, accounts, data.proof_instruction_offset as i64) + #[cfg(feature = "proof-program")] + { + let data = decode_instruction_data::(input)?; + process_empty_account(program_id, accounts, data.proof_instruction_offset as i64) + } + #[cfg(not(feature = "proof-program"))] + Err(ProgramError::InvalidInstructionData) } ConfidentialTransferInstruction::Deposit => { msg!("ConfidentialTransferInstruction::Deposit"); @@ -1256,7 +1271,7 @@ pub(crate) fn process_instruction( } ConfidentialTransferInstruction::Withdraw => { msg!("ConfidentialTransferInstruction::Withdraw"); - #[cfg(feature = "zk-ops")] + #[cfg(all(feature = "zk-ops", feature = "proof-program"))] { let data = decode_instruction_data::(input)?; process_withdraw( @@ -1268,12 +1283,12 @@ pub(crate) fn process_instruction( data.proof_instruction_offset as i64, ) } - #[cfg(not(feature = "zk-ops"))] + #[cfg(not(all(feature = "zk-ops", feature = "proof-program")))] Err(ProgramError::InvalidInstructionData) } ConfidentialTransferInstruction::Transfer => { msg!("ConfidentialTransferInstruction::Transfer"); - #[cfg(feature = "zk-ops")] + #[cfg(all(feature = "zk-ops", feature = "proof-program"))] { let data = decode_instruction_data::(input)?; process_transfer( @@ -1283,7 +1298,7 @@ pub(crate) fn process_instruction( data.proof_instruction_offset as i64, ) } - #[cfg(not(feature = "zk-ops"))] + #[cfg(not(all(feature = "zk-ops", feature = "proof-program")))] Err(ProgramError::InvalidInstructionData) } ConfidentialTransferInstruction::ApplyPendingBalance => { @@ -1319,7 +1334,7 @@ pub(crate) fn process_instruction( } ConfidentialTransferInstruction::WithdrawWithheldTokensFromMint => { msg!("ConfidentialTransferInstruction::WithdrawWithheldTokensFromMint"); - #[cfg(feature = "zk-ops")] + #[cfg(all(feature = "zk-ops", feature = "proof-program"))] { let data = decode_instruction_data::(input)?; process_withdraw_withheld_tokens_from_mint( @@ -1328,12 +1343,12 @@ pub(crate) fn process_instruction( data.proof_instruction_offset as i64, ) } - #[cfg(not(feature = "zk-ops"))] + #[cfg(not(all(feature = "zk-ops", feature = "proof-program")))] Err(ProgramError::InvalidInstructionData) } ConfidentialTransferInstruction::WithdrawWithheldTokensFromAccounts => { msg!("ConfidentialTransferInstruction::WithdrawWithheldTokensFromAccounts"); - #[cfg(feature = "zk-ops")] + #[cfg(all(feature = "zk-ops", feature = "proof-program"))] { let data = decode_instruction_data::(input)?; @@ -1344,7 +1359,7 @@ pub(crate) fn process_instruction( data.proof_instruction_offset as i64, ) } - #[cfg(not(feature = "zk-ops"))] + #[cfg(not(all(feature = "zk-ops", feature = "proof-program")))] Err(ProgramError::InvalidInstructionData) } ConfidentialTransferInstruction::HarvestWithheldTokensToMint => {