From c2489a6220de94112f1df8a740d3201c9fd361e7 Mon Sep 17 00:00:00 2001 From: Oliver He Date: Thu, 7 Nov 2024 16:32:06 -0500 Subject: [PATCH] Add SDK support for prover and pepper use with keyless (#15191) * Add sdk support for prover and pepper use with keyless * update * update * fix --- Cargo.lock | 1 + .../aptos-rest-client/src/client_builder.rs | 10 +- crates/aptos-rest-client/src/lib.rs | 196 ++++++++++++++++- crates/aptos/src/account/key_rotation.rs | 56 +---- .../src/emitter/transaction_executor.rs | 10 +- sdk/Cargo.toml | 1 + sdk/src/coin_client.rs | 35 ++- sdk/src/types.rs | 200 +++++++++++++++++- testsuite/smoke-test/src/keyless.rs | 38 ++-- 9 files changed, 438 insertions(+), 109 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a38bd0ab3a12f..7589eaac35db0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3747,6 +3747,7 @@ dependencies = [ "once_cell", "rand 0.7.3", "rand_core 0.5.1", + "reqwest 0.11.23", "serde", "serde_json", "tiny-bip39", diff --git a/crates/aptos-rest-client/src/client_builder.rs b/crates/aptos-rest-client/src/client_builder.rs index 9f7bc81cb16df..777fa7815695a 100644 --- a/crates/aptos-rest-client/src/client_builder.rs +++ b/crates/aptos-rest-client/src/client_builder.rs @@ -23,13 +23,9 @@ pub enum AptosBaseUrl { impl AptosBaseUrl { pub fn to_url(&self) -> Url { match self { - AptosBaseUrl::Mainnet => { - Url::from_str("https://fullnode.mainnet.aptoslabs.com").unwrap() - }, - AptosBaseUrl::Devnet => Url::from_str("https://fullnode.devnet.aptoslabs.com").unwrap(), - AptosBaseUrl::Testnet => { - Url::from_str("https://fullnode.testnet.aptoslabs.com").unwrap() - }, + AptosBaseUrl::Mainnet => Url::from_str("https://api.mainnet.aptoslabs.com").unwrap(), + AptosBaseUrl::Devnet => Url::from_str("https://api.devnet.aptoslabs.com").unwrap(), + AptosBaseUrl::Testnet => Url::from_str("https://api.testnet.aptoslabs.com").unwrap(), AptosBaseUrl::Custom(url) => url.to_owned(), } } diff --git a/crates/aptos-rest-client/src/lib.rs b/crates/aptos-rest-client/src/lib.rs index 30b8542c70d05..0a2e76274f8bc 100644 --- a/crates/aptos-rest-client/src/lib.rs +++ b/crates/aptos-rest-client/src/lib.rs @@ -7,6 +7,7 @@ extern crate core; pub mod aptos; pub mod error; pub mod faucet; +use error::AptosErrorResponse; pub use faucet::FaucetClient; pub mod response; pub use response::Response; @@ -23,9 +24,9 @@ pub use aptos_api_types::{ use aptos_api_types::{ deserialize_from_string, mime_types::{BCS, BCS_SIGNED_TRANSACTION, BCS_VIEW_FUNCTION, JSON}, - AptosError, BcsBlock, Block, GasEstimation, HexEncodedBytes, IndexResponse, MoveModuleId, - TransactionData, TransactionOnChainData, TransactionsBatchSubmissionResult, UserTransaction, - VersionedEvent, ViewFunction, ViewRequest, + AptosError, AptosErrorCode, BcsBlock, Block, GasEstimation, HexEncodedBytes, IndexResponse, + MoveModuleId, TransactionData, TransactionOnChainData, TransactionsBatchSubmissionResult, + UserTransaction, VersionedEvent, ViewFunction, ViewRequest, }; use aptos_crypto::HashValue; use aptos_logger::{debug, info, sample, sample::SampleRate}; @@ -33,8 +34,9 @@ use aptos_types::{ account_address::AccountAddress, account_config::{AccountResource, NewBlockEvent, CORE_CODE_ADDRESS}, contract_event::EventWithVersion, + keyless::{Groth16Proof, Pepper, ZeroKnowledgeSig, ZKP}, state_store::state_key::StateKey, - transaction::SignedTransaction, + transaction::{authenticator::EphemeralSignature, SignedTransaction}, }; use move_core_types::{ ident_str, @@ -64,6 +66,16 @@ const X_APTOS_SDK_HEADER_VALUE: &str = concat!("aptos-rust-sdk/", env!("CARGO_PK type AptosResult = Result; +#[derive(Deserialize)] +pub struct Table { + pub handle: AccountAddress, +} + +#[derive(Deserialize)] +pub struct OriginatingAddress { + pub address_map: Table, +} + #[derive(Clone, Debug)] pub struct Client { inner: ReqwestClient, @@ -71,6 +83,48 @@ pub struct Client { version_path_base: String, } +// TODO: Dedupe the pepper/prover request/response types with the ones defined in the service. +#[derive(Clone, Debug, serde::Serialize)] +pub struct PepperRequest { + pub jwt_b64: String, + #[serde(with = "hex")] + pub epk: Vec, + #[serde(with = "hex")] + pub epk_blinder: Vec, + pub exp_date_secs: u64, + pub uid_key: String, +} + +#[derive(Debug, serde::Deserialize)] +struct PepperResponse { + #[serde(with = "hex")] + pub pepper: Vec, +} + +#[derive(Clone, Debug, serde::Serialize)] +pub struct ProverRequest { + pub jwt_b64: String, + #[serde(with = "hex")] + pub epk: Vec, + #[serde(with = "hex")] + pub epk_blinder: Vec, + pub exp_date_secs: u64, + pub exp_horizon_secs: u64, + #[serde(with = "hex")] + pub pepper: Vec, + pub uid_key: String, +} + +#[derive(Debug, serde::Deserialize)] +struct ProverResponse { + proof: Groth16Proof, + #[serde(with = "hex")] + #[allow(dead_code)] + public_inputs_hash: [u8; 32], + #[serde(with = "hex")] + training_wheels_signature: Vec, +} + impl Client { pub fn builder(aptos_base_url: AptosBaseUrl) -> ClientBuilder { ClientBuilder::new(aptos_base_url) @@ -101,6 +155,14 @@ impl Client { Ok(self.base_url.join(&self.version_path_base)?.join(path)?) } + pub fn get_prover_url(&self) -> Url { + self.base_url.join("keyless/prover/v0/prove").unwrap() + } + + pub fn get_pepper_url(&self) -> Url { + self.base_url.join("keyless/pepper/v0/fetch").unwrap() + } + pub async fn get_aptos_version(&self) -> AptosResult> { self.get_resource::(CORE_CODE_ADDRESS, "0x1::version::Version") .await @@ -204,6 +266,54 @@ impl Client { Ok(response.and_then(|inner| bcs::from_bytes(&inner))?) } + pub async fn lookup_address( + &self, + address_key: AccountAddress, + must_exist: bool, + ) -> AptosResult> { + let originating_address_table: Response = self + .get_account_resource_bcs(CORE_CODE_ADDRESS, "0x1::account::OriginatingAddress") + .await?; + + let table_handle = originating_address_table.inner().address_map.handle; + + // The derived address that can be used to look up the original address + match self + .get_table_item_bcs( + table_handle, + "address", + "address", + address_key.to_hex_literal(), + ) + .await + { + Ok(inner) => Ok(inner), + Err(RestError::Api(AptosErrorResponse { + error: + AptosError { + error_code: AptosErrorCode::TableItemNotFound, + .. + }, + .. + })) => { + // If the table item wasn't found, we may check if the account exists + if !must_exist { + Ok(Response::new( + address_key, + originating_address_table.state().clone(), + )) + } else { + self.get_account_bcs(address_key) + .await + .map(|account_resource| { + Response::new(address_key, account_resource.state().clone()) + }) + } + }, + Err(err) => Err(err), + } + } + async fn view_account_balance_bcs_impl( &self, address: AccountAddress, @@ -454,7 +564,10 @@ impl Client { self.json::(response).await } - pub async fn submit_without_serializing_response(&self, txn: &SignedTransaction) -> Result<()> { + pub async fn submit_without_deserializing_response( + &self, + txn: &SignedTransaction, + ) -> Result<()> { let txn_payload = bcs::to_bytes(txn)?; let url = self.build_path("transactions")?; @@ -1227,6 +1340,32 @@ impl Client { self.json(response).await } + pub async fn get_account_sequence_number( + &self, + address: AccountAddress, + ) -> AptosResult> { + let res = self.get_account_bcs(address).await; + + match res { + Ok(account) => account.and_then(|account| Ok(account.sequence_number())), + Err(error) => match error { + RestError::Api(error) => { + if matches!(error.error.error_code, AptosErrorCode::AccountNotFound) { + if let Some(state) = error.state { + Ok(Response::new(0, state)) + } else { + let ledger_info = self.get_ledger_information().await?; + Ok(Response::new(0, ledger_info.state().clone())) + } + } else { + Err(error::RestError::Api(error)) + } + }, + _ => Err(error), + }, + } + } + pub async fn get_account_events_bcs( &self, address: AccountAddress, @@ -1499,6 +1638,53 @@ impl Client { self.check_and_parse_bcs_response(response).await } + pub async fn make_prover_request(&self, req: ProverRequest) -> AptosResult { + let response: ProverResponse = self + .post_json_no_state(self.get_prover_url(), serde_json::to_value(req.clone())?) + .await?; + let proof = response.proof; + let ephem_sig = Some( + EphemeralSignature::try_from(response.training_wheels_signature.as_slice()) + .map_err(anyhow::Error::from)?, + ); + Ok(ZeroKnowledgeSig { + proof: ZKP::Groth16(proof), + exp_horizon_secs: req.exp_horizon_secs, + extra_field: None, + override_aud_val: None, + training_wheels_signature: ephem_sig, + }) + } + + pub async fn make_pepper_request(&self, req: PepperRequest) -> AptosResult { + let response: PepperResponse = self + .post_json_no_state(self.get_pepper_url(), serde_json::to_value(req.clone())?) + .await?; + let pepper = response.pepper; + Ok(Pepper::new( + pepper.as_slice().try_into().map_err(anyhow::Error::from)?, + )) + } + + async fn post_json_no_state( + &self, + url: Url, + data: serde_json::Value, + ) -> AptosResult { + let response = self + .inner + .post(url) + .header(ACCEPT, JSON) + .json(&data) + .send() + .await?; + if !response.status().is_success() { + Err(parse_error(response).await) + } else { + Ok(response.json().await.map_err(anyhow::Error::from)?) + } + } + async fn post_bcs( &self, url: Url, diff --git a/crates/aptos/src/account/key_rotation.rs b/crates/aptos/src/account/key_rotation.rs index 0d26e85a97856..0cbf9f9805aa1 100644 --- a/crates/aptos/src/account/key_rotation.rs +++ b/crates/aptos/src/account/key_rotation.rs @@ -14,11 +14,7 @@ use aptos_crypto::{ PrivateKey, SigningKey, }; use aptos_ledger; -use aptos_rest_client::{ - aptos_api_types::{AptosError, AptosErrorCode}, - error::{AptosErrorResponse, RestError}, - Client, -}; +use aptos_rest_client::{error::RestError, Client}; use aptos_types::{ account_address::AccountAddress, account_config::{RotationProofChallenge, CORE_CODE_ADDRESS}, @@ -391,52 +387,8 @@ pub async fn lookup_address( address_key: AccountAddress, must_exist: bool, ) -> Result { - let originating_resource: OriginatingResource = rest_client - .get_account_resource_bcs(CORE_CODE_ADDRESS, "0x1::account::OriginatingAddress") + Ok(rest_client + .lookup_address(address_key, must_exist) .await? - .into_inner(); - - let table_handle = originating_resource.address_map.handle; - - // The derived address that can be used to look up the original address - match rest_client - .get_table_item_bcs( - table_handle, - "address", - "address", - address_key.to_hex_literal(), - ) - .await - { - Ok(inner) => Ok(inner.into_inner()), - Err(RestError::Api(AptosErrorResponse { - error: - AptosError { - error_code: AptosErrorCode::TableItemNotFound, - .. - }, - .. - })) => { - // If the table item wasn't found, we may check if the account exists - if !must_exist { - Ok(address_key) - } else { - rest_client - .get_account_bcs(address_key) - .await - .map(|_| address_key) - } - }, - Err(err) => Err(err), - } -} - -#[derive(Deserialize)] -pub struct OriginatingResource { - pub address_map: Table, -} - -#[derive(Deserialize)] -pub struct Table { - pub handle: AccountAddress, + .into_inner()) } diff --git a/crates/transaction-emitter-lib/src/emitter/transaction_executor.rs b/crates/transaction-emitter-lib/src/emitter/transaction_executor.rs index 55713307dd45c..27d87d6d1cd68 100644 --- a/crates/transaction-emitter-lib/src/emitter/transaction_executor.rs +++ b/crates/transaction-emitter-lib/src/emitter/transaction_executor.rs @@ -277,17 +277,11 @@ pub async fn query_sequence_number_with_client( ) -> Result { let result = FETCH_ACCOUNT_RETRY_POLICY .retry_if( - move || rest_client.get_account_bcs(account_address), + move || rest_client.get_account_sequence_number(account_address), |error: &RestError| !is_account_not_found(error), ) .await; - match result { - Ok(account) => Ok(account.into_inner().sequence_number()), - Err(error) => match is_account_not_found(&error) { - true => Ok(0), - false => Err(error.into()), - }, - } + Ok(*result?.inner()) } fn is_account_not_found(error: &RestError) -> bool { diff --git a/sdk/Cargo.toml b/sdk/Cargo.toml index ed87ebb322a59..26e12125ab42b 100644 --- a/sdk/Cargo.toml +++ b/sdk/Cargo.toml @@ -26,6 +26,7 @@ ed25519-dalek-bip32 = { workspace = true } hex = { workspace = true } move-core-types = { workspace = true } rand_core = { workspace = true } +reqwest = { workspace = true } serde = { workspace = true } serde_json = { workspace = true } tiny-bip39 = { workspace = true } diff --git a/sdk/src/coin_client.rs b/sdk/src/coin_client.rs index 6f136522e85e9..8e521c3bf0ace 100644 --- a/sdk/src/coin_client.rs +++ b/sdk/src/coin_client.rs @@ -17,6 +17,7 @@ use crate::{ }, }; use anyhow::{Context, Result}; +use aptos_types::transaction::SignedTransaction; use std::{ str::FromStr, time::{SystemTime, UNIX_EPOCH}, @@ -39,6 +40,25 @@ impl<'a> CoinClient<'a> { amount: u64, options: Option>, ) -> Result { + let signed_txn = self + .get_signed_transfer_txn(from_account, to_account, amount, options) + .await?; + Ok(self + .api_client + .submit(&signed_txn) + .await + .context("Failed to submit transfer transaction")? + .into_inner()) + // <:!:section_1 + } + + pub async fn get_signed_transfer_txn( + &self, + from_account: &mut LocalAccount, + to_account: AccountAddress, + amount: u64, + options: Option>, + ) -> Result { let options = options.unwrap_or_default(); // :!:>section_1 @@ -51,8 +71,11 @@ impl<'a> CoinClient<'a> { .chain_id; let transaction_builder = TransactionBuilder::new( TransactionPayload::EntryFunction(EntryFunction::new( - ModuleId::new(AccountAddress::ONE, Identifier::new("coin").unwrap()), - Identifier::new("transfer").unwrap(), + ModuleId::new( + AccountAddress::ONE, + Identifier::new("aptos_account").unwrap(), + ), + Identifier::new("transfer_coins").unwrap(), vec![TypeTag::from_str(options.coin_type).unwrap()], vec![ bcs::to_bytes(&to_account).unwrap(), @@ -71,13 +94,7 @@ impl<'a> CoinClient<'a> { .max_gas_amount(options.max_gas_amount) .gas_unit_price(options.gas_unit_price); let signed_txn = from_account.sign_with_transaction_builder(transaction_builder); - Ok(self - .api_client - .submit(&signed_txn) - .await - .context("Failed to submit transfer transaction")? - .into_inner()) - // <:!:section_1 + Ok(signed_txn) } pub async fn get_account_balance(&self, account: &AccountAddress) -> Result { diff --git a/sdk/src/types.rs b/sdk/src/types.rs index 8bf98ac47f441..941cdf0a4c55e 100644 --- a/sdk/src/types.rs +++ b/sdk/src/types.rs @@ -18,6 +18,7 @@ use crate::{ use anyhow::{Context, Result}; use aptos_crypto::{ed25519::Ed25519Signature, secp256r1_ecdsa, PrivateKey, SigningKey}; use aptos_ledger::AptosLedgerError; +use aptos_rest_client::{Client, PepperRequest, ProverRequest}; pub use aptos_types::*; use aptos_types::{ event::EventKey, @@ -557,7 +558,6 @@ pub struct EphemeralKeyPair { #[allow(dead_code)] nonce: String, expiry_date_secs: u64, - #[allow(dead_code)] blinder: Vec, } @@ -583,6 +583,17 @@ impl EphemeralKeyPair { blinder, }) } + + pub fn new_ed25519( + private_key: Ed25519PrivateKey, + expiry_date_secs: u64, + blinder: Vec, + ) -> Result { + let esk = EphemeralPrivateKey::Ed25519 { + inner_private_key: private_key, + }; + Self::new(esk, expiry_date_secs, blinder) + } } #[derive(Debug)] @@ -628,8 +639,8 @@ impl KeylessAccount { jwt: &str, ephemeral_key_pair: EphemeralKeyPair, uid_key: Option<&str>, - pepper: Option, - zk_sig: Option, + pepper: Pepper, + zk_sig: ZeroKnowledgeSig, ) -> Result { let claims = extract_claims_from_jwt(jwt)?; let uid_key = uid_key.unwrap_or("sub").to_string(); @@ -643,8 +654,8 @@ impl KeylessAccount { &uid_val, &extract_header_json_from_jwt(jwt)?, ephemeral_key_pair, - pepper.expect("pepper fetch not implemented"), - zk_sig.expect("proof fetch not implemented"), + pepper, + zk_sig, )?; account.jwt = Some(jwt.to_string()); Ok(account) @@ -687,8 +698,8 @@ impl FederatedKeylessAccount { ephemeral_key_pair: EphemeralKeyPair, jwk_addr: AccountAddress, uid_key: Option<&str>, - pepper: Option, - zk_sig: Option, + pepper: Pepper, + zk_sig: ZeroKnowledgeSig, ) -> Result { let claims = extract_claims_from_jwt(jwt)?; let uid_key = uid_key.unwrap_or("sub").to_string(); @@ -702,8 +713,8 @@ impl FederatedKeylessAccount { &uid_val, &extract_header_json_from_jwt(jwt)?, ephemeral_key_pair, - pepper.expect("pepper fetch not implemented"), - zk_sig.expect("proof fetch not implemented"), + pepper, + zk_sig, jwk_addr, )?; account.jwt = Some(jwt.to_string()); @@ -751,6 +762,73 @@ fn create_federated_public_key( }) } +pub async fn derive_keyless_account( + rest_client: &Client, + jwt: &str, + ephemeral_key_pair: EphemeralKeyPair, + jwk_addr: Option, +) -> Result { + let pepper = get_pepper_from_jwt(rest_client, jwt, &ephemeral_key_pair).await?; + let zksig = get_proof_from_jwt(rest_client, jwt, &ephemeral_key_pair, &pepper).await?; + + let account = match jwk_addr { + Some(jwk_addr) => { + let federated_account = FederatedKeylessAccount::new_from_jwt( + jwt, + ephemeral_key_pair, + jwk_addr, + Some("sub"), + pepper.clone(), + zksig, + )?; + LocalAccount::new_federated_keyless( + federated_account.authentication_key().account_address(), + federated_account, + 0, // We'll update this with the actual sequence number below + ) + }, + None => { + let keyless_account = KeylessAccount::new_from_jwt( + jwt, + ephemeral_key_pair, + Some("sub"), + pepper.clone(), + zksig, + )?; + LocalAccount::new_keyless( + keyless_account.authentication_key().account_address(), + keyless_account, + 0, // We'll update this with the actual sequence number below + ) + }, + }; + + // Look up the on-chain address and sequence number + let address = rest_client + .lookup_address(account.authentication_key().account_address(), false) + .await?; + let sequence_number = rest_client + .get_account_sequence_number(account.authentication_key().account_address()) + .await?; + + // Create the final account with the correct address and sequence number + Ok(match account.auth { + LocalAccountAuthenticator::Keyless(keyless_account) => LocalAccount::new_keyless( + address.into_inner(), + keyless_account, + sequence_number.into_inner(), + ), + LocalAccountAuthenticator::FederatedKeyless(federated_keyless_account) => { + LocalAccount::new_federated_keyless( + address.into_inner(), + federated_keyless_account, + sequence_number.into_inner(), + ) + }, + _ => unreachable!("We only create keyless or federated keyless accounts here"), + }) +} + pub fn extract_claims_from_jwt(jwt: &str) -> Result { let parts: Vec<&str> = jwt.split('.').collect(); let jwt_payload_json = @@ -818,9 +896,49 @@ impl CommonKeylessAccount for &FederatedKeylessAccount { } } +async fn get_proof_from_jwt( + rest_client: &Client, + jwt: &str, + ephemeral_key_pair: &EphemeralKeyPair, + pepper: &Pepper, +) -> Result { + let default_config = Configuration::new_for_devnet(); + let prover_request = ProverRequest { + jwt_b64: jwt.to_string(), + epk: bcs::to_bytes(&ephemeral_key_pair.public_key)?, + epk_blinder: ephemeral_key_pair.blinder.clone(), + exp_date_secs: ephemeral_key_pair.expiry_date_secs, + exp_horizon_secs: default_config.max_exp_horizon_secs, + pepper: pepper.to_bytes().to_vec(), + uid_key: "sub".to_string(), + }; + let response = rest_client.make_prover_request(prover_request).await?; + Ok(response) +} + +async fn get_pepper_from_jwt( + rest_client: &Client, + jwt: &str, + ephemeral_key_pair: &EphemeralKeyPair, +) -> Result { + let pepper_request = PepperRequest { + jwt_b64: jwt.to_string(), + epk: bcs::to_bytes(&ephemeral_key_pair.public_key)?, + epk_blinder: ephemeral_key_pair.blinder.clone(), + exp_date_secs: ephemeral_key_pair.expiry_date_secs, + uid_key: "sub".to_string(), + }; + let response = rest_client.make_pepper_request(pepper_request).await?; + Ok(response) +} + #[cfg(test)] mod tests { use super::*; + use crate::coin_client::CoinClient; + use aptos_crypto::ed25519::Ed25519PrivateKey; + use aptos_rest_client::{AptosBaseUrl, FaucetClient}; + use reqwest::Url; #[test] fn test_recover_account_from_derive_path() { @@ -862,4 +980,68 @@ mod tests { // Test invalid private key hex literal. assert!(LocalAccount::from_private_key("invalid_private_key", 0).is_err()); } + + #[ignore] + #[tokio::test] + async fn test_derive_keyless_account() { + let aptos_rest_client = Client::builder(AptosBaseUrl::Devnet).build(); + // This JWT is taken from https://github.com/aptos-labs/aptos-ts-sdk/blob/f644e61beb70e69dfd489e75287c67b527385135/tests/e2e/api/keyless.test.ts#L11 + // As is the ephemeralKeyPair + // This ephemeralKeyPair expires December 29, 2024. + let jwt = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6InRlc3QtcnNhIn0.eyJpc3MiOiJ0ZXN0Lm9pZGMucHJvdmlkZXIiLCJhdWQiOiJ0ZXN0LWtleWxlc3MtZGFwcCIsInN1YiI6InRlc3QtdXNlci0wIiwiZW1haWwiOiJ0ZXN0QGFwdG9zbGFicy5jb20iLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwiaWF0IjoxNzI1NDc1MTEyLCJleHAiOjI3MDAwMDAwMDAsIm5vbmNlIjoiNzA5NTI0MjMzMzk2NDQ1NzI2NzkzNDcyMzc2ODA4MDMwMzMyNDQ2MjgyMTE5MTc1NjQwOTQ1MDA5OTUxOTc4MTA1MTkxMDE4NzExOCJ9.eHqJLdje0FRD3UPmSw8sFHRYe9lwqSydAMcfHcpxkFwew2OTy6bWFsLQTdJp-eCZPhNzlfBXwNxaAJZksCWFWkzCz2913a5b88XRT9Im7JBDtA1e1IBXrnfXG0MDpsVRAuRNzLWqDi_4Fl1OELvoEOK-Tl4cmIwOhBr943S-b14PRVhrQ1XBD5MXaHWcJyxMaEtZfu_xxCQ-jjR---iguD243Ze98JlcOIV8VmEBg3YiSyVdMDZ8cgRia0DI8DwFn7rIxaV2H5FXb9JcehLgNP82-gsfEGV0iAXuBk7ZvRzMVA-srE9JvxVOyq5UkYu0Ss9LjKzX0KVojl7Au_OxGA"; + let sk_bytes = + hex::decode("1111111111111111111111111111111111111111111111111111111111111111") + .unwrap(); + let esk = Ed25519PrivateKey::try_from(sk_bytes.as_slice()).unwrap(); + let ephemeral_key_pair = + EphemeralKeyPair::new_ed25519(esk, 1735475012, vec![0; 31]).unwrap(); + let mut account = derive_keyless_account(&aptos_rest_client, jwt, ephemeral_key_pair, None) + .await + .unwrap(); + println!("Address: {}", account.address().to_hex_literal()); + let balance = aptos_rest_client + .view_apt_account_balance(account.address()) + .await + .unwrap() + .into_inner(); + if balance < 10000000 { + println!("Funding account"); + let faucet_client = FaucetClient::new_from_rest_client( + Url::from_str("https://faucet.devnet.aptoslabs.com").unwrap(), + aptos_rest_client.clone(), + ); + faucet_client + .fund(account.address(), 10000000) + .await + .unwrap(); + } + println!( + "Balance: {}", + aptos_rest_client + .view_apt_account_balance(account.address()) + .await + .unwrap() + .into_inner() + ); + let coin_client = CoinClient::new(&aptos_rest_client); + let signed_txn = coin_client + .get_signed_transfer_txn( + &mut account, + AccountAddress::from_hex_literal( + "0x7968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30", + ) + .unwrap(), + 1111111, + None, + ) + .await + .unwrap(); + println!( + "Sent 1111111 to 0x7968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30" + ); + aptos_rest_client + .submit_without_deserializing_response(&signed_txn) + .await + .unwrap(); + } } diff --git a/testsuite/smoke-test/src/keyless.rs b/testsuite/smoke-test/src/keyless.rs index 6e847afbc5dc5..f128c6aef9eca 100644 --- a/testsuite/smoke-test/src/keyless.rs +++ b/testsuite/smoke-test/src/keyless.rs @@ -55,7 +55,7 @@ async fn test_keyless_oidc_txn_verifies() { let result = swarm .aptos_public_info() .client() - .submit_without_serializing_response(&signed_txn) + .submit_without_deserializing_response(&signed_txn) .await; if let Err(e) = result { @@ -83,7 +83,7 @@ async fn test_keyless_rotate_vk() { info!("Submitting keyless Groth16 transaction w.r.t. to initial VK; should succeed"); let result = info .client() - .submit_without_serializing_response(&signed_txn) + .submit_without_deserializing_response(&signed_txn) .await; if let Err(e) = result { @@ -104,7 +104,7 @@ async fn test_keyless_rotate_vk() { info!("Submitting keyless Groth16 transaction w.r.t. to upgraded VK; should fail"); let result = info .client() - .submit_without_serializing_response(&signed_txn) + .submit_without_deserializing_response(&signed_txn) .await; if result.is_ok() { @@ -121,7 +121,7 @@ async fn test_keyless_rotate_vk() { info!("Submitting keyless Groth16 transaction w.r.t. to old VK; should fail"); let result = info .client() - .submit_without_serializing_response(&signed_txn) + .submit_without_deserializing_response(&signed_txn) .await; if result.is_ok() { @@ -133,7 +133,7 @@ async fn test_keyless_rotate_vk() { info!("Submitting keyless Groth16 transaction w.r.t. to upgraded VK; should succeed"); let result = info .client() - .submit_without_serializing_response(&signed_txn) + .submit_without_deserializing_response(&signed_txn) .await; if let Err(e) = result { @@ -184,7 +184,7 @@ async fn test_keyless_oidc_txn_with_bad_jwt_sig() { info!("Submit OpenID transaction with bad JWT signature"); let result = info .client() - .submit_without_serializing_response(&signed_txn) + .submit_without_deserializing_response(&signed_txn) .await; if result.is_ok() { @@ -205,7 +205,7 @@ async fn test_keyless_oidc_txn_with_expired_epk() { info!("Submit OpenID transaction with expired EPK"); let result = info .client() - .submit_without_serializing_response(&signed_txn) + .submit_without_deserializing_response(&signed_txn) .await; if result.is_ok() { @@ -221,7 +221,7 @@ async fn test_keyless_groth16_verifies() { let result = swarm .aptos_public_info() .client() - .submit_without_serializing_response(&signed_txn) + .submit_without_deserializing_response(&signed_txn) .await; if let Err(e) = result { @@ -331,8 +331,8 @@ script {{ ephemeral_key_pair, root_addr, None, - Some(get_sample_pepper()), - Some(get_sample_zk_sig()), + get_sample_pepper(), + get_sample_zk_sig(), ) .unwrap(); @@ -380,7 +380,7 @@ script {{ let result = swarm .aptos_public_info() .client() - .submit_without_serializing_response(&signed_txn) + .submit_without_deserializing_response(&signed_txn) .await; debug!("result={:?}", result); assert_eq!(expect_txn_succeed, result.is_ok()); @@ -395,7 +395,7 @@ async fn test_keyless_no_extra_field_groth16_verifies() { let result = swarm .aptos_public_info() .client() - .submit_without_serializing_response(&signed_txn) + .submit_without_deserializing_response(&signed_txn) .await; if let Err(e) = result { @@ -418,7 +418,7 @@ async fn test_keyless_no_training_wheels_groth16_verifies() { info!("Submit keyless Groth16 transaction"); let result = info .client() - .submit_without_serializing_response(&signed_txn) + .submit_without_deserializing_response(&signed_txn) .await; if let Err(e) = result { @@ -478,7 +478,7 @@ async fn test_keyless_groth16_verifies_using_rust_sdk() { let result = swarm .aptos_public_info() .client() - .submit_without_serializing_response(&signed_txn) + .submit_without_deserializing_response(&signed_txn) .await; if let Err(e) = result { @@ -501,8 +501,8 @@ async fn test_keyless_groth16_verifies_using_rust_sdk_from_jwt() { &get_sample_jwt_token(), ephemeral_key_pair, None, - Some(get_sample_pepper()), - Some(get_sample_zk_sig()), + get_sample_pepper(), + get_sample_zk_sig(), ) .unwrap(); let addr = info @@ -535,7 +535,7 @@ async fn test_keyless_groth16_verifies_using_rust_sdk_from_jwt() { let result = swarm .aptos_public_info() .client() - .submit_without_serializing_response(&signed_txn) + .submit_without_deserializing_response(&signed_txn) .await; if let Err(e) = result { @@ -555,7 +555,7 @@ async fn test_keyless_groth16_with_mauled_proof() { info!("Submit keyless Groth16 transaction"); let result = info .client() - .submit_without_serializing_response(&signed_txn) + .submit_without_deserializing_response(&signed_txn) .await; if result.is_ok() { @@ -585,7 +585,7 @@ async fn test_keyless_groth16_with_bad_tw_signature() { info!("Submit keyless Groth16 transaction"); let result = info .client() - .submit_without_serializing_response(&signed_txn) + .submit_without_deserializing_response(&signed_txn) .await; if result.is_ok() {