[token-2022] Create proof-program feature (#4040)

This commit is contained in:
samkim-crypto 2023-03-12 10:22:03 +09:00 committed by GitHub
parent ecd5c45726
commit 95a079a6e0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 108 additions and 42 deletions

View File

@ -24,3 +24,4 @@ thiserror = "1.0"
[features]
default = ["display"]
display = ["dep:solana-cli-output"]
proof-program = []

View File

@ -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<S: Signer>(
&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<S: Signer>(
&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<S: Signer>(
&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<S: Signer>(
&self,
token_account: &Pubkey,
@ -1618,6 +1626,7 @@ where
.await
}
#[cfg(feature = "proof-program")]
pub async fn confidential_transfer_empty_account_with_keypair<S: Signer>(
&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<S: Signer>(
&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<S: Signer>(
&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<S: Signer>(
&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<S: Signer>(
&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<S: Signer>(
&self,
) -> TokenResult<Option<ElGamalPubkey>> {
@ -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<S: Signer>(
&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<S: Signer>(
&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<S: Signer>(
&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<S: Signer>(
&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<S: Signer>(
&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<S: Signer>(
&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<S: Signer>(
&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<S: Signer>(
&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<S: Signer>(
&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<S: Signer>(
&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<S: Signer>(
&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<S: Signer>(
&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<S: Signer>(
&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<S: Signer>(
&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<S: Signer>(
&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<S: Signer>(
&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],

View File

@ -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"

View File

@ -1,4 +1,4 @@
#![cfg(feature = "test-sbf")]
#![cfg(all(feature = "test-sbf", feature = "proof-program"))]
#![cfg(twoxtx)]
mod program_test;

View File

@ -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"

View File

@ -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),
])
}

View File

@ -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<T: Pod>(
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::<ConfigureAccountInstructionData>(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::<ConfigureAccountInstructionData>(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::<EmptyAccountInstructionData>(input)?;
process_empty_account(program_id, accounts, data.proof_instruction_offset as i64)
#[cfg(feature = "proof-program")]
{
let data = decode_instruction_data::<EmptyAccountInstructionData>(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::<WithdrawInstructionData>(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::<TransferInstructionData>(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::<WithdrawWithheldTokensFromMintData>(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::<WithdrawWithheldTokensFromAccountsData>(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 => {