diff --git a/api/src/transactions.rs b/api/src/transactions.rs index 62b5a07159966..78547389760e0 100644 --- a/api/src/transactions.rs +++ b/api/src/transactions.rs @@ -1294,6 +1294,13 @@ impl TransactionsApi { } }, }, + TransactionPayload::EncryptedPayload(_) => { + return Err(SubmitTransactionError::bad_request_with_code( + "Encrypted Transaction is not supported yet", + AptosErrorCode::InvalidInput, + ledger_info, + )); + }, } // TODO: Verify script args? @@ -1580,6 +1587,18 @@ impl TransactionsApi { )); } + if txn + .raw_transaction_ref() + .payload_ref() + .is_encrypted_variant() + { + return Err(SubmitTransactionError::bad_request_with_code( + "Encrypted transactions cannot be simulated", + AptosErrorCode::InvalidInput, + &ledger_info, + )); + } + // Simulate transaction let state_view = self.context.latest_state_view_poem(&ledger_info)?; let (vm_status, output) = @@ -1639,6 +1658,9 @@ impl TransactionsApi { }; stats_key }, + TransactionPayload::EncryptedPayload(_) => { + unreachable!("Encrypted transactions must not be simulated") + }, }; self.context .simulate_txn_stats() diff --git a/api/types/src/convert.rs b/api/types/src/convert.rs index 44978f4422cfd..ecfc688514a80 100644 --- a/api/types/src/convert.rs +++ b/api/types/src/convert.rs @@ -403,6 +403,9 @@ impl<'a, S: StateView> MoveConverter<'a, S> { }, // Deprecated. ModuleBundle(_) => bail!("Module bundle payload has been removed"), + EncryptedPayload(_) => { + bail!("Encrypted payload isn't supported yet") + }, }; Ok(ret) } diff --git a/aptos-move/aptos-transaction-simulation-session/src/session.rs b/aptos-move/aptos-transaction-simulation-session/src/session.rs index 3ccfee6395b5a..703da15199796 100644 --- a/aptos-move/aptos-transaction-simulation-session/src/session.rs +++ b/aptos-move/aptos-transaction-simulation-session/src/session.rs @@ -326,6 +326,7 @@ impl Session { name_from_executable(executable) }, TransactionPayload::ModuleBundle(_) => unreachable!(), + TransactionPayload::EncryptedPayload(_) => "encrypted".to_string(), }; let output_path = self diff --git a/aptos-move/aptos-vm/src/aptos_vm.rs b/aptos-move/aptos-vm/src/aptos_vm.rs index 84785e117d619..64e92617e1b50 100644 --- a/aptos-move/aptos-vm/src/aptos_vm.rs +++ b/aptos-move/aptos-vm/src/aptos_vm.rs @@ -3198,6 +3198,10 @@ impl VMValidator for AptosVM { } } + if transaction.payload().is_encrypted_variant() { + return VMValidatorResult::error(StatusCode::FEATURE_UNDER_GATING); + } + let txn = match transaction.check_signature() { Ok(t) => t, _ => { diff --git a/consensus/src/quorum_store/types.rs b/consensus/src/quorum_store/types.rs index 490690114cd41..3254305b6d8f5 100644 --- a/consensus/src/quorum_store/types.rs +++ b/consensus/src/quorum_store/types.rs @@ -177,7 +177,11 @@ impl Batch { ensure!( txn.gas_unit_price() >= self.gas_bucket_start(), "Payload gas unit price doesn't match batch info" - ) + ); + ensure!( + !txn.payload().is_encrypted_variant(), + "Encrypted transaction is not supported yet" + ); } Ok(()) } diff --git a/crates/aptos-transaction-filters/src/transaction_filter.rs b/crates/aptos-transaction-filters/src/transaction_filter.rs index 18bfcbb3f7029..81e95d3c7dca0 100644 --- a/crates/aptos-transaction-filters/src/transaction_filter.rs +++ b/crates/aptos-transaction-filters/src/transaction_filter.rs @@ -4,6 +4,7 @@ use aptos_crypto::{ed25519::Ed25519PublicKey, HashValue}; use aptos_types::transaction::{ authenticator::{AccountAuthenticator, AnyPublicKey, TransactionAuthenticator}, + encrypted_payload::EncryptedPayload, EntryFunction, MultisigTransactionPayload, Script, SignedTransaction, TransactionExecutableRef, TransactionExtraConfig, TransactionPayload, TransactionPayloadInner, }; @@ -343,6 +344,18 @@ fn matches_entry_function( }, } }, + TransactionPayload::EncryptedPayload(EncryptedPayload::V1(payload)) => { + if let Ok(executable) = payload.executable_ref() { + match executable { + TransactionExecutableRef::Script(_) | TransactionExecutableRef::Empty => false, + TransactionExecutableRef::EntryFunction(entry_function) => { + compare_entry_function(entry_function, address, module_name, function) + }, + } + } else { + false + } + }, } } @@ -374,6 +387,18 @@ fn matches_entry_function_module_address( }, } }, + TransactionPayload::EncryptedPayload(EncryptedPayload::V1(payload)) => { + if let Ok(executable) = payload.executable_ref() { + match executable { + TransactionExecutableRef::Script(_) | TransactionExecutableRef::Empty => false, + TransactionExecutableRef::EntryFunction(entry_function) => { + compare_entry_function_module_address(entry_function, module_address) + }, + } + } else { + false + } + }, } } @@ -397,6 +422,15 @@ fn matches_multisig_address( .unwrap_or(false), } }, + TransactionPayload::EncryptedPayload(EncryptedPayload::V1(payload)) => { + match payload.extra_config() { + TransactionExtraConfig::V1 { + multisig_address, .. + } => multisig_address + .map(|multisig_address| multisig_address == *address) + .unwrap_or(false), + } + }, } } @@ -421,6 +455,19 @@ fn matches_script_argument_address( }, } }, + TransactionPayload::EncryptedPayload(EncryptedPayload::V1(payload)) => { + if let Ok(executable) = payload.executable_ref() { + match executable { + TransactionExecutableRef::EntryFunction(_) + | TransactionExecutableRef::Empty => false, + TransactionExecutableRef::Script(script) => { + compare_script_argument_address(script, address) + }, + } + } else { + false + } + }, } } diff --git a/types/src/transaction/encrypted_payload.rs b/types/src/transaction/encrypted_payload.rs new file mode 100644 index 0000000000000..91cf0732c5df0 --- /dev/null +++ b/types/src/transaction/encrypted_payload.rs @@ -0,0 +1,64 @@ +// Copyright (c) Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 + +use crate::transaction::{TransactionExecutable, TransactionExecutableRef, TransactionExtraConfig}; +use anyhow::{bail, Result}; +use aptos_crypto::HashValue; +use serde::{Deserialize, Serialize}; + +pub type CipherText = Vec; +pub type EvalProof = Vec; + +#[derive(Clone, Debug, Hash, Eq, PartialEq, Serialize, Deserialize)] +pub enum EncryptedPayload { + Encrypted { + ciphertext: CipherText, + extra_config: TransactionExtraConfig, + payload_hash: HashValue, + }, + FailedDecryption { + ciphertext: CipherText, + extra_config: TransactionExtraConfig, + payload_hash: HashValue, + + eval_proof: EvalProof, + }, + Decrypted { + ciphertext: CipherText, + extra_config: TransactionExtraConfig, + payload_hash: HashValue, + eval_proof: EvalProof, + + // decrypted things + executable: TransactionExecutable, + decryption_nonce: u64, + }, +} + +impl EncryptedPayload { + pub fn executable(&self) -> Result { + let Self::Decrypted { executable, .. } = self else { + bail!("Transaction is encrypted"); + }; + Ok(executable.clone()) + } + + pub fn executable_ref(&self) -> Result> { + let Self::Decrypted { executable, .. } = self else { + bail!("Transaction is encrypted"); + }; + Ok(executable.as_ref()) + } + + pub fn extra_config(&self) -> &TransactionExtraConfig { + match self { + EncryptedPayload::Encrypted { extra_config, .. } => extra_config, + EncryptedPayload::FailedDecryption { extra_config, .. } => extra_config, + EncryptedPayload::Decrypted { extra_config, .. } => extra_config, + } + } + + pub fn is_encrypted(&self) -> bool { + matches!(self, Self::Encrypted { .. }) + } +} diff --git a/types/src/transaction/mod.rs b/types/src/transaction/mod.rs index c830d25501cfe..772ae5ce11fdd 100644 --- a/types/src/transaction/mod.rs +++ b/types/src/transaction/mod.rs @@ -12,9 +12,12 @@ use crate::{ keyless::{KeylessPublicKey, KeylessSignature}, ledger_info::LedgerInfo, proof::{TransactionInfoListWithProof, TransactionInfoWithProof}, - transaction::authenticator::{ - AASigningData, AccountAuthenticator, AnyPublicKey, AnySignature, SingleKeyAuthenticator, - TransactionAuthenticator, + transaction::{ + authenticator::{ + AASigningData, AccountAuthenticator, AnyPublicKey, AnySignature, + SingleKeyAuthenticator, TransactionAuthenticator, + }, + encrypted_payload::EncryptedPayload, }, vm_status::{DiscardedVMStatus, KeptVMStatus, StatusCode, StatusType, VMStatus}, write_set::{HotStateOp, WriteSet}, @@ -46,6 +49,7 @@ pub mod authenticator; pub mod block_epilogue; mod block_output; mod change_set; +pub mod encrypted_payload; mod module; mod multisig; mod script; @@ -546,6 +550,10 @@ impl RawTransaction { self.payload } + pub fn payload_ref(&self) -> &TransactionPayload { + &self.payload + } + pub fn executable_ref(&self) -> Result> { self.payload.executable_ref() } @@ -679,6 +687,8 @@ pub enum TransactionPayload { /// Contains an executable (script/entry function) along with extra configuration. /// Once this new format is fully rolled out, above payload variants will be deprecated. Payload(TransactionPayloadInner), + /// Represents an encrypted transaction payload + EncryptedPayload(EncryptedPayload), } #[derive(Clone, Debug, Hash, Eq, PartialEq, Serialize, Deserialize)] @@ -761,6 +771,9 @@ impl TransactionPayload { TransactionPayload::Payload(TransactionPayloadInner::V1 { extra_config, .. }) => { extra_config.is_multisig() }, + TransactionPayload::EncryptedPayload(encrypted_payload) => { + encrypted_payload.extra_config().is_multisig() + }, } } @@ -793,6 +806,9 @@ impl TransactionPayload { TransactionPayload::ModuleBundle(_) => { Err(format_err!("ModuleBundle variant is deprecated")) }, + TransactionPayload::EncryptedPayload(encrypted_payload) => { + encrypted_payload.executable() + }, } } @@ -809,6 +825,9 @@ impl TransactionPayload { TransactionPayload::ModuleBundle(_) => { Err(format_err!("ModuleBundle variant is deprecated")) }, + TransactionPayload::EncryptedPayload(encrypted_payload) => { + encrypted_payload.executable_ref() + }, } } @@ -827,6 +846,9 @@ impl TransactionPayload { TransactionPayload::Payload(TransactionPayloadInner::V1 { extra_config, .. }) => { extra_config.clone() }, + TransactionPayload::EncryptedPayload(encrypted_payload) => { + encrypted_payload.extra_config().clone() + }, } } @@ -919,6 +941,10 @@ impl TransactionPayload { extra_config, }) } + + pub fn is_encrypted_variant(&self) -> bool { + matches!(self, Self::EncryptedPayload(_)) + } } impl TransactionExtraConfig { diff --git a/types/src/transaction/use_case.rs b/types/src/transaction/use_case.rs index e22fb0194ecb3..2efded33174a5 100644 --- a/types/src/transaction/use_case.rs +++ b/types/src/transaction/use_case.rs @@ -41,6 +41,15 @@ fn parse_use_case(payload: &TransactionPayload) -> UseCaseKey { None } }, + EncryptedPayload(encrypted_payload) => { + if let Ok(TransactionExecutableRef::EntryFunction(entry_fun)) = + encrypted_payload.executable_ref() + { + Some(entry_fun) + } else { + None + } + }, }; match maybe_entry_func {