diff --git a/Cargo.lock b/Cargo.lock index 24d120c27908c..2610c2550fdd9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -288,6 +288,7 @@ dependencies = [ "aptos-db", "aptos-executor", "aptos-executor-types", + "aptos-framework", "aptos-genesis", "aptos-mempool", "aptos-mempool-notifications", @@ -297,6 +298,7 @@ dependencies = [ "aptos-types", "aptos-vm", "aptos-vm-validator", + "bcs 0.1.4 (git+https://github.com/aptos-labs/bcs.git?rev=d31fab9d81748e2594be5cd5cdf845786a30562d)", "bytes 1.2.1", "goldenfile", "hyper", diff --git a/api/src/tests/accounts_test.rs b/api/src/tests/accounts_test.rs index e8ba7dfa929c1..b958178fd209e 100644 --- a/api/src/tests/accounts_test.rs +++ b/api/src/tests/accounts_test.rs @@ -112,12 +112,12 @@ async fn test_account_modules_structs() { async fn test_get_account_resources_by_ledger_version() { let mut context = new_test_context(current_function_name!()); let account = context.gen_account(); - let txn = context.create_user_account(&account); + let txn = context.create_user_account(&account).await; context.commit_block(&vec![txn.clone()]).await; let ledger_version_1_resources = context .get(&account_resources( - &context.root_account().address().to_hex_literal(), + &context.root_account().await.address().to_hex_literal(), )) .await; let root_account = find_value(&ledger_version_1_resources, |f| { @@ -127,7 +127,7 @@ async fn test_get_account_resources_by_ledger_version() { let ledger_version_0_resources = context .get(&account_resources_with_ledger_version( - &context.root_account().address().to_hex_literal(), + &context.root_account().await.address().to_hex_literal(), 0, )) .await; @@ -143,7 +143,7 @@ async fn test_get_account_resources_by_too_large_ledger_version() { let resp = context .expect_status_code(404) .get(&account_resources_with_ledger_version( - &context.root_account().address().to_hex_literal(), + &context.root_account().await.address().to_hex_literal(), 1000000000000000000, )) .await; @@ -156,7 +156,7 @@ async fn test_get_account_resources_by_invalid_ledger_version() { let resp = context .expect_status_code(400) .get(&account_resources_with_ledger_version( - &context.root_account().address().to_hex_literal(), + &context.root_account().await.address().to_hex_literal(), -1, )) .await; @@ -169,7 +169,7 @@ async fn test_get_account_resources_by_invalid_ledger_version() { async fn test_get_account_modules_by_ledger_version() { let mut context = new_test_context(current_function_name!()); let code = "a11ceb0b0300000006010002030205050703070a0c0816100c260900000001000100000102084d794d6f64756c650269640000000000000000000000000b1e55ed00010000000231010200"; - let mut root_account = context.root_account(); + let mut root_account = context.root_account().await; let txn = root_account.sign_with_transaction_builder( context .transaction_factory() @@ -178,7 +178,7 @@ async fn test_get_account_modules_by_ledger_version() { context.commit_block(&vec![txn.clone()]).await; let modules = context .get(&account_modules( - &context.root_account().address().to_hex_literal(), + &context.root_account().await.address().to_hex_literal(), )) .await; @@ -186,7 +186,7 @@ async fn test_get_account_modules_by_ledger_version() { let modules = context .get(&account_modules_with_ledger_version( - &context.root_account().address().to_hex_literal(), + &context.root_account().await.address().to_hex_literal(), 0, )) .await; diff --git a/api/src/tests/modules.rs b/api/src/tests/modules.rs index c7da52fbf1704..c72956a822057 100644 --- a/api/src/tests/modules.rs +++ b/api/src/tests/modules.rs @@ -1,29 +1,25 @@ // Copyright © Aptos Foundation // SPDX-License-Identifier: Apache-2.0 -use super::{ - new_test_context, - resource_groups::{build_package, publish_package}, -}; -use aptos_api_test_context::current_function_name; +use super::new_test_context; +use aptos_api_test_context::{current_function_name, TestContext}; use std::path::PathBuf; #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_abi() { let mut context = new_test_context(current_function_name!()); - let mut root_account = context.root_account(); + let mut root_account = context.root_account().await; let mut account = context.gen_account(); let txn = context.create_user_account_by(&mut root_account, &account); context.commit_block(&vec![txn]).await; // Publish packages let named_addresses = vec![("abi".to_string(), account.address())]; - // TODO: Switch to build_package and publish_package in test_context once they're moved there. let txn = futures::executor::block_on(async move { let path = PathBuf::from(std::env!("CARGO_MANIFEST_DIR")).join("src/tests/move/pack_abi"); - build_package(path, named_addresses) + TestContext::build_package(path, named_addresses) }); - publish_package(&mut context, &mut account, txn).await; + context.publish_package(&mut account, txn).await; // Get abi. let modules = context diff --git a/api/src/tests/resource_groups.rs b/api/src/tests/resource_groups.rs index 0d54acd6e81ee..a2e1e4cbeb147 100644 --- a/api/src/tests/resource_groups.rs +++ b/api/src/tests/resource_groups.rs @@ -3,33 +3,28 @@ use super::new_test_context; use aptos_api_test_context::{current_function_name, TestContext}; -use aptos_cached_packages::aptos_stdlib; -use aptos_framework::BuiltPackage; -use aptos_sdk::types::LocalAccount; -use aptos_types::{account_address::AccountAddress, transaction::TransactionPayload}; -use serde_json::{json, Value}; +use serde_json::json; use std::path::PathBuf; // This test verifies that both READ APIs can seamlessly translate from resource group to resource // 1. Create accounts // 2. Publish a resource group package // 3. Verify default data exists -// 4. Read the resources from that resource group anad verify they don't exist +// 4. Read the resources from that resource group and verify they don't exist // 5. Init data for that resource group / member // 6. Read and ensure data is present // 7. Publish another resource group member -// 8. Read the resources from the new resource group anad verify they don't exist +// 8. Read the resources from the new resource group and verify they don't exist // 9. Init data for that resource group / member // 10. Read and ensure data is present #[tokio::test(flavor = "multi_thread", worker_threads = 2)] -async fn test_read_resoure_group() { +async fn test_gen_resource_group() { let mut context = new_test_context(current_function_name!()); // Prepare accounts - let mut root = context.root_account(); - let mut admin0 = create_account(&mut context, &mut root).await; - let mut admin1 = create_account(&mut context, &mut root).await; - let mut user = create_account(&mut context, &mut root).await; + let mut admin0 = context.create_account().await; + let mut admin1 = context.create_account().await; + let mut user = context.create_account().await; // Publish packages let named_addresses = vec![ @@ -41,171 +36,58 @@ async fn test_read_resoure_group() { let txn = futures::executor::block_on(async move { let path = PathBuf::from(std::env!("CARGO_MANIFEST_DIR")) .join("../aptos-move/move-examples/resource_groups/primary"); - build_package(path, named_addresses_clone) + TestContext::build_package(path, named_addresses_clone) }); - publish_package(&mut context, &mut admin0, txn).await; + context.publish_package(&mut admin0, txn).await; let named_addresses_clone = named_addresses.clone(); let txn = futures::executor::block_on(async move { let path = PathBuf::from(std::env!("CARGO_MANIFEST_DIR")) .join("../aptos-move/move-examples/resource_groups/secondary"); - build_package(path, named_addresses_clone) + TestContext::build_package(path, named_addresses_clone) }); - publish_package(&mut context, &mut admin1, txn).await; + context.publish_package(&mut admin1, txn).await; // Read default data let primary = format!("0x{}::{}::{}", admin0.address(), "primary", "Primary"); let secondary = format!("0x{}::{}::{}", admin1.address(), "secondary", "Secondary"); - let response = read_resource(&context, &admin0.address(), &primary).await; - assert_eq!(response["data"]["value"], "3"); - - let response = maybe_read_resource(&context, &admin0.address(), &primary).await; + let response = context.gen_resource(&admin0.address(), &primary).await; assert_eq!(response.unwrap()["data"]["value"], "3"); // Verify account is empty - let response = maybe_read_resource(&context, &user.address(), &primary).await; + let response = context.gen_resource(&user.address(), &primary).await; assert!(response.is_none()); - let response = maybe_read_resource(&context, &user.address(), &secondary).await; + let response = context.gen_resource(&user.address(), &secondary).await; assert!(response.is_none()); // Init secondary - execute_entry_function( - &mut context, - &mut user, - &format!("0x{}::secondary::init", admin1.address()), - json!([]), - json!([55]), - ) - .await; - let response = read_resource(&context, &user.address(), &secondary).await; - assert_eq!(response["data"]["value"], 55); - - let response = maybe_read_resource(&context, &user.address(), &secondary).await; + context + .api_execute_entry_function( + &mut user, + &format!("0x{}::secondary::init", admin1.address()), + json!([]), + json!([55]), + ) + .await; + let response = context.gen_resource(&user.address(), &secondary).await; assert_eq!(response.unwrap()["data"]["value"], 55); - let response = maybe_read_resource(&context, &user.address(), &primary).await; + let response = context.gen_resource(&user.address(), &primary).await; assert!(response.is_none()); // Init primary - execute_entry_function( - &mut context, - &mut user, - &format!("0x{}::primary::init", admin0.address()), - json!([]), - json!(["35"]), - ) - .await; - let response = read_resource(&context, &user.address(), &primary).await; - assert_eq!(response["data"]["value"], "35"); - - let response = maybe_read_resource(&context, &user.address(), &primary).await; - assert_eq!(response.unwrap()["data"]["value"], "35"); - - let response = read_resource(&context, &user.address(), &secondary).await; - assert_eq!(response["data"]["value"], 55); - - let response = maybe_read_resource(&context, &user.address(), &secondary).await; - assert_eq!(response.unwrap()["data"]["value"], 55); -} - -// TODO: The TestContext code is a bit of a mess, the following likely should be added and that -// code likely needs a good cleanup to merge to a common approach. - -async fn create_account(context: &mut TestContext, root: &mut LocalAccount) -> LocalAccount { - let account = context.gen_account(); - let factory = context.transaction_factory(); - let txn = root.sign_with_transaction_builder( - factory - .account_transfer(account.address(), 10_000_000) - .expiration_timestamp_secs(u64::MAX), - ); - - let bcs_txn = bcs::to_bytes(&txn).unwrap(); context - .expect_status_code(202) - .post_bcs_txn("/transactions", bcs_txn) - .await; - context.commit_mempool_txns(1).await; - account -} - -async fn maybe_read_resource( - context: &TestContext, - account_address: &AccountAddress, - resource: &str, -) -> Option { - let response = read_resources(context, account_address).await; - response - .as_array() - .unwrap() - .iter() - .find(|entry| entry["type"] == resource) - .cloned() -} - -async fn read_resources(context: &TestContext, account_address: &AccountAddress) -> Value { - let request = format!("/accounts/{}/resources", account_address); - context.get(&request).await -} - -async fn read_resource( - context: &TestContext, - account_address: &AccountAddress, - resource: &str, -) -> Value { - let request = format!("/accounts/{}/resource/{}", account_address, resource); - context.get(&request).await -} - -pub fn build_package( - path: PathBuf, - named_addresses: Vec<(String, AccountAddress)>, -) -> TransactionPayload { - let mut build_options = aptos_framework::BuildOptions::default(); - let _ = named_addresses - .into_iter() - .map(|(name, address)| build_options.named_addresses.insert(name, address)) - .collect::>(); - - let package = BuiltPackage::build(path, build_options).unwrap(); - let code = package.extract_code(); - let metadata = package.extract_metadata().unwrap(); - - aptos_stdlib::code_publish_package_txn(bcs::to_bytes(&metadata).unwrap(), code) -} - -pub async fn publish_package( - context: &mut TestContext, - publisher: &mut LocalAccount, - payload: TransactionPayload, -) { - let txn = - publisher.sign_with_transaction_builder(context.transaction_factory().payload(payload)); - let bcs_txn = bcs::to_bytes(&txn).unwrap(); - context - .expect_status_code(202) - .post_bcs_txn("/transactions", bcs_txn) - .await; - context.commit_mempool_txns(1).await; -} - -async fn execute_entry_function( - context: &mut TestContext, - account: &mut LocalAccount, - function: &str, - type_args: serde_json::Value, - args: serde_json::Value, -) { - context - .api_execute_txn( - account, - json!({ - "type": "entry_function_payload", - "function": function, - "type_arguments": type_args, - "arguments": args - }), + .api_execute_entry_function( + &mut user, + &format!("0x{}::primary::init", admin0.address()), + json!([]), + json!(["35"]), ) .await; + let response = context.gen_resource(&user.address(), &primary).await; + assert_eq!(response.unwrap()["data"]["value"], "35"); + + let response = context.gen_resource(&user.address(), &secondary).await; + assert_eq!(response.unwrap()["data"]["value"], 55); } diff --git a/api/src/tests/state_test.rs b/api/src/tests/state_test.rs index f49082c4724f0..b307da6d34ee0 100644 --- a/api/src/tests/state_test.rs +++ b/api/src/tests/state_test.rs @@ -129,7 +129,7 @@ async fn test_merkle_leaves_with_nft_transfer() { let ctx = &mut context; let creator = &mut ctx.gen_account(); let owner = &mut ctx.gen_account(); - let txn1 = ctx.mint_user_account(creator); + let txn1 = ctx.mint_user_account(creator).await; let txn2 = ctx.account_transfer(creator, owner, 100_000); let collection_name = "collection name".to_owned().into_bytes(); @@ -222,14 +222,14 @@ async fn test_get_table_item() { let ctx = &mut context; let mut account = ctx.gen_account(); let acc = &mut account; - let txn = ctx.create_user_account(acc); + let txn = ctx.create_user_account(acc).await; ctx.commit_block(&vec![txn.clone()]).await; make_test_tables(ctx, acc).await; // get the TestTables instance let tt = ctx .api_get_account_resource( - acc, + acc.address(), &acc.address().to_hex_literal(), "TableTestData", "TestTables", @@ -322,14 +322,8 @@ async fn make_test_tables(ctx: &mut TestContext, account: &mut LocalAccount) { ctx.api_publish_module(account, module.try_into().unwrap()) .await; - ctx.api_execute_entry_function( - account, - "TableTestData", - "make_test_tables", - json!([]), - json!([]), - ) - .await + ctx.api_execute_entry_function(account, "make_test_tables", json!([]), json!([])) + .await } async fn build_test_module(account: AccountAddress) -> Vec { diff --git a/api/src/tests/string_resource_test.rs b/api/src/tests/string_resource_test.rs index f199bada89d6d..4de58f0227f61 100644 --- a/api/src/tests/string_resource_test.rs +++ b/api/src/tests/string_resource_test.rs @@ -15,7 +15,7 @@ use std::convert::TryInto; async fn test_renders_move_acsii_string_into_utf8_string() { let mut context = new_test_context(current_function_name!()); let mut account = init_test_account(); - let txn = context.create_user_account(&account); + let txn = context.create_user_account(&account).await; context.commit_block(&vec![txn]).await; // module 0x87342d91af60c3a883a2812c9294c2f8::Message { @@ -38,7 +38,6 @@ async fn test_renders_move_acsii_string_into_utf8_string() { context .api_execute_entry_function( &mut account, - "Message", "set_message", json!([]), json!([hex::encode(b"hello world")]), @@ -47,7 +46,7 @@ async fn test_renders_move_acsii_string_into_utf8_string() { let message = context .api_get_account_resource( - &account, + account.address(), &account.address().to_hex_literal(), "Message", "MessageHolder", diff --git a/api/src/tests/transactions_test.rs b/api/src/tests/transactions_test.rs index e7aabed467324..8b74cd13856d4 100644 --- a/api/src/tests/transactions_test.rs +++ b/api/src/tests/transactions_test.rs @@ -25,6 +25,7 @@ use move_core_types::{ use poem_openapi::types::ParseFromJSON; use rand::{distributions::Alphanumeric, thread_rng, Rng}; use serde_json::json; +use std::path::PathBuf; #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_deserialize_genesis_transaction() { @@ -48,7 +49,7 @@ async fn test_get_transactions_output_genesis_transaction() { async fn test_get_transactions_returns_last_page_when_start_version_is_not_specified() { let mut context = new_test_context(current_function_name!()); - let mut root_account = context.root_account(); + let mut root_account = context.root_account().await; for _i in 0..20 { let account = context.gen_account(); let txn = context.create_user_account_by(&mut root_account, &account); @@ -112,7 +113,7 @@ async fn test_get_transactions_param_limit_exceeds_limit() { async fn test_get_transactions_output_user_transaction_with_entry_function_payload() { let mut context = new_test_context(current_function_name!()); let account = context.gen_account(); - let txn = context.create_user_account(&account); + let txn = context.create_user_account(&account).await; context.commit_block(&vec![txn.clone()]).await; let txns = context.get("/transactions?start=1").await; @@ -126,7 +127,7 @@ async fn test_get_transactions_output_user_transaction_with_entry_function_paylo async fn test_get_transactions_output_user_transaction_with_module_payload() { let mut context = new_test_context(current_function_name!()); let code = "a11ceb0b0300000006010002030205050703070a0c0816100c260900000001000100000102084d794d6f64756c650269640000000000000000000000000b1e55ed00010000000231010200"; - let mut root_account = context.root_account(); + let mut root_account = context.root_account().await; let txn = root_account.sign_with_transaction_builder( context .transaction_factory() @@ -172,7 +173,7 @@ async fn test_get_transactions_output_user_transaction_with_module_payload() { async fn test_post_bcs_format_transaction() { let mut context = new_test_context(current_function_name!()); let account = context.gen_account(); - let txn = context.create_user_account(&account); + let txn = context.create_user_account(&account).await; let body = bcs::to_bytes(&txn).unwrap(); let resp = context .expect_status_code(202) @@ -201,7 +202,7 @@ async fn test_post_invalid_bcs_format_transaction() { #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_post_invalid_signature_transaction() { let mut context = new_test_context(current_function_name!()); - let txn = context.create_invalid_signature_transaction(); + let txn = context.create_invalid_signature_transaction().await; let body = bcs::to_bytes(&txn).unwrap(); let resp = context .expect_status_code(400) @@ -215,8 +216,8 @@ async fn test_post_transaction_rejected_by_mempool() { let mut context = new_test_context(current_function_name!()); let account1 = context.gen_account(); let account2 = context.gen_account(); - let txn1 = context.create_user_account(&account1); - let txn2 = context.create_user_account(&account2); + let txn1 = context.create_user_account(&account1).await; + let txn2 = context.create_user_account(&account2).await; context .expect_status_code(202) @@ -236,7 +237,7 @@ async fn test_multi_agent_signed_transaction() { let account = context.gen_account(); let secondary = context.gen_account(); let factory = context.transaction_factory(); - let mut root_account = context.root_account(); + let mut root_account = context.root_account().await; // Create secondary signer account context @@ -305,7 +306,7 @@ async fn test_multi_ed25519_signed_transaction() { let auth_key = AuthenticationKey::multi_ed25519(&public_key); let factory = context.transaction_factory(); - let mut root_account = context.root_account(); + let mut root_account = context.root_account().await; // TODO: migrate once multi-ed25519 is supported let create_account_txn = root_account.sign_with_transaction_builder( factory.create_user_account(&Ed25519PrivateKey::generate_for_testing().public_key()), @@ -367,7 +368,7 @@ async fn test_multi_ed25519_signed_transaction() { async fn test_get_transaction_by_hash() { let mut context = new_test_context(current_function_name!()); let account = context.gen_account(); - let txn = context.create_user_account(&account); + let txn = context.create_user_account(&account).await; context.commit_block(&vec![txn.clone()]).await; let txns = context.get("/transactions?start=2&limit=1").await; @@ -419,7 +420,7 @@ async fn test_get_transaction_by_version_not_found() { async fn test_get_transaction_by_version() { let mut context = new_test_context(current_function_name!()); let account = context.gen_account(); - let txn = context.create_user_account(&account); + let txn = context.create_user_account(&account).await; context.commit_block(&vec![txn.clone()]).await; let txns = context.get("/transactions?start=2&limit=1").await; @@ -433,7 +434,7 @@ async fn test_get_transaction_by_version() { async fn test_get_pending_transaction_by_hash() { let mut context = new_test_context(current_function_name!()); let account = context.gen_account(); - let txn = context.create_user_account(&account); + let txn = context.create_user_account(&account).await; let body = bcs::to_bytes(&txn).unwrap(); let pending_txn = context .expect_status_code(202) @@ -468,7 +469,7 @@ async fn test_get_pending_transaction_by_hash() { async fn test_signing_message_with_entry_function_payload() { let mut context = new_test_context(current_function_name!()); let account = context.gen_account(); - let txn = context.create_user_account(&account); + let txn = context.create_user_account(&account).await; let payload = json!({ "type": "entry_function_payload", "function": "0x1::aptos_account::create_account", @@ -485,7 +486,7 @@ async fn test_signing_message_with_payload( txn: SignedTransaction, payload: serde_json::Value, ) { - let sender = context.root_account(); + let sender = context.root_account().await; let mut body = json!({ "sender": sender.address().to_hex_literal(), "sequence_number": sender.sequence_number().to_string(), @@ -517,6 +518,7 @@ async fn test_signing_message_with_payload( let sig = context .root_account() + .await .private_key() .sign_arbitrary_message(signing_msg.inner()); let expected_sig = match txn.authenticator() { @@ -550,14 +552,14 @@ async fn test_signing_message_with_payload( async fn test_get_account_transactions() { let mut context = new_test_context(current_function_name!()); let account = context.gen_account(); - let txn = context.create_user_account(&account); + let txn = context.create_user_account(&account).await; context.commit_block(&vec![txn]).await; let txns = context .get( format!( "/accounts/{}/transactions", - context.root_account().address() + context.root_account().await.address() ) .as_str(), ) @@ -571,14 +573,14 @@ async fn test_get_account_transactions() { async fn test_get_account_transactions_filter_transactions_by_start_sequence_number() { let mut context = new_test_context(current_function_name!()); let account = context.gen_account(); - let txn = context.create_user_account(&account); + let txn = context.create_user_account(&account).await; context.commit_block(&vec![txn]).await; let txns = context .get( format!( "/accounts/{}/transactions?start=1", - context.root_account().address() + context.root_account().await.address() ) .as_str(), ) @@ -590,14 +592,14 @@ async fn test_get_account_transactions_filter_transactions_by_start_sequence_num async fn test_get_account_transactions_filter_transactions_by_start_sequence_number_is_too_large() { let mut context = new_test_context(current_function_name!()); let account = context.gen_account(); - let txn = context.create_user_account(&account); + let txn = context.create_user_account(&account).await; context.commit_block(&vec![txn]).await; let txns = context .get( format!( "/accounts/{}/transactions?start=1000", - context.root_account().address() + context.root_account().await.address() ) .as_str(), ) @@ -608,7 +610,7 @@ async fn test_get_account_transactions_filter_transactions_by_start_sequence_num #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_get_account_transactions_filter_transactions_by_limit() { let mut context = new_test_context(current_function_name!()); - let mut root_account = context.root_account(); + let mut root_account = context.root_account().await; let account1 = context.gen_account(); let txn1 = context.create_user_account_by(&mut root_account, &account1); let account2 = context.gen_account(); @@ -619,7 +621,7 @@ async fn test_get_account_transactions_filter_transactions_by_limit() { .get( format!( "/accounts/{}/transactions?start=0&limit=1", - context.root_account().address() + context.root_account().await.address() ) .as_str(), ) @@ -630,7 +632,7 @@ async fn test_get_account_transactions_filter_transactions_by_limit() { .get( format!( "/accounts/{}/transactions?start=0&limit=2", - context.root_account().address() + context.root_account().await.address() ) .as_str(), ) @@ -641,7 +643,7 @@ async fn test_get_account_transactions_filter_transactions_by_limit() { #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_get_txn_execute_failed_by_invalid_script_payload_bytecode() { let context = new_test_context(current_function_name!()); - let mut root_account = context.root_account(); + let mut root_account = context.root_account().await; let invalid_bytecode = hex::decode("a11ceb0b030000").unwrap(); let txn = root_account.sign_with_transaction_builder( context @@ -655,7 +657,7 @@ async fn test_get_txn_execute_failed_by_invalid_script_payload_bytecode() { #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_get_txn_execute_failed_by_invalid_entry_function_address() { let context = new_test_context(current_function_name!()); - let account = context.root_account(); + let account = context.root_account().await; test_get_txn_execute_failed_by_invalid_entry_function( context, account, @@ -674,7 +676,7 @@ async fn test_get_txn_execute_failed_by_invalid_entry_function_address() { #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_get_txn_execute_failed_by_invalid_entry_function_module_name() { let context = new_test_context(current_function_name!()); - let account = context.root_account(); + let account = context.root_account().await; test_get_txn_execute_failed_by_invalid_entry_function( context, account, @@ -693,7 +695,7 @@ async fn test_get_txn_execute_failed_by_invalid_entry_function_module_name() { #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_get_txn_execute_failed_by_invalid_entry_function_name() { let context = new_test_context(current_function_name!()); - let account = context.root_account(); + let account = context.root_account().await; test_get_txn_execute_failed_by_invalid_entry_function( context, account, @@ -712,7 +714,7 @@ async fn test_get_txn_execute_failed_by_invalid_entry_function_name() { #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_get_txn_execute_failed_by_invalid_entry_function_arguments() { let context = new_test_context(current_function_name!()); - let account = context.root_account(); + let account = context.root_account().await; test_get_txn_execute_failed_by_invalid_entry_function( context, account, @@ -731,7 +733,7 @@ async fn test_get_txn_execute_failed_by_invalid_entry_function_arguments() { #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_get_txn_execute_failed_by_missing_entry_function_arguments() { let context = new_test_context(current_function_name!()); - let account = context.root_account(); + let account = context.root_account().await; test_get_txn_execute_failed_by_invalid_entry_function( context, account, @@ -752,7 +754,7 @@ async fn test_get_txn_execute_failed_by_entry_function_validation() { let mut context = new_test_context(current_function_name!()); let account = context.gen_account(); context - .commit_block(&vec![context.create_user_account(&account)]) + .commit_block(&vec![context.create_user_account(&account).await]) .await; test_get_txn_execute_failed_by_invalid_entry_function( @@ -775,7 +777,7 @@ async fn test_get_txn_execute_failed_by_entry_function_invalid_module_name() { let mut context = new_test_context(current_function_name!()); let account = context.gen_account(); context - .commit_block(&vec![context.create_user_account(&account)]) + .commit_block(&vec![context.create_user_account(&account).await]) .await; test_submit_entry_function_api_validation( @@ -798,7 +800,7 @@ async fn test_get_txn_execute_failed_by_entry_function_invalid_function_name() { let mut context = new_test_context(current_function_name!()); let account = context.gen_account(); context - .commit_block(&vec![context.create_user_account(&account)]) + .commit_block(&vec![context.create_user_account(&account).await]) .await; test_submit_entry_function_api_validation( @@ -816,38 +818,31 @@ async fn test_get_txn_execute_failed_by_entry_function_invalid_function_name() { .await; } -#[ignore] // Re-enable when change is moved to new publish flow #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_get_txn_execute_failed_by_entry_function_execution_failure() { let mut context = new_test_context(current_function_name!()); + let mut admin = context.create_account().await; - // address 0xA550C18 { - // module Hello { - // fun world() { - // 1/0; - // } - // public(script) fun hello() { - // world(); - // } - // } - // } - let hello_entry_fun = hex::decode("a11ceb0b030000000601000203020a050c01070d12081f100c2f24000000010000000002000000000548656c6c6f0568656c6c6f05776f726c640000000000000000000000000a550c180002000000021101020100000000050601000000000000000600000000000000001a010200").unwrap(); - let mut root_account = context.root_account(); - let module_txn = root_account - .sign_with_transaction_builder(context.transaction_factory().module(hello_entry_fun)); + let named_addresses = vec![("entry_func_fail".to_string(), admin.address())]; - context.commit_block(&vec![module_txn]).await; + let named_addresses_clone = named_addresses.clone(); + let txn = futures::executor::block_on(async move { + let path = PathBuf::from(std::env!("CARGO_MANIFEST_DIR")).join("test-context/move"); + TestContext::build_package(path, named_addresses_clone) + }); + let txn = context.publish_package(&mut admin, txn).await; - test_get_txn_execute_failed_by_invalid_entry_function( - context, - root_account, - "0xA550C18", - "Hello", - "hello", - vec![], - vec![], - ) - .await + let resp = context + .get( + format!( + "/transactions/by_hash/{}", + txn.committed_hash().to_hex_literal() + ) + .as_str(), + ) + .await; + + assert!(!resp["success"].as_bool().unwrap(), "{}", pretty(&resp)); } #[ignore] // re-enable after cleaning compiled code @@ -863,7 +858,7 @@ async fn test_get_txn_execute_failed_by_script_execution_failure() { let script = hex::decode("a11ceb0b030000000105000100000000050601000000000000000600000000000000001a0102") .unwrap(); - let mut root_account = context.root_account(); + let mut root_account = context.root_account().await; let txn = root_account.sign_with_transaction_builder( context .transaction_factory() diff --git a/api/src/tests/view_function.rs b/api/src/tests/view_function.rs index 9f7889bc5cfbd..7316bea302aea 100644 --- a/api/src/tests/view_function.rs +++ b/api/src/tests/view_function.rs @@ -10,7 +10,7 @@ async fn test_simple_view() { let mut context = new_test_context(current_function_name!()); let creator = &mut context.gen_account(); let owner = &mut context.gen_account(); - let txn1 = context.mint_user_account(creator); + let txn1 = context.mint_user_account(creator).await; let txn2 = context.account_transfer(creator, owner, 100_000); context.commit_block(&vec![txn1, txn2]).await; @@ -34,7 +34,7 @@ async fn test_simple_view_invalid() { let mut context = new_test_context(current_function_name!()); let creator = &mut context.gen_account(); let owner = &mut context.gen_account(); - let txn1 = context.mint_user_account(creator); + let txn1 = context.mint_user_account(creator).await; let txn2 = context.account_transfer(creator, owner, 100_000); context.commit_block(&vec![txn1, txn2]).await; @@ -60,7 +60,7 @@ async fn test_versioned_simple_view() { let mut context = new_test_context(current_function_name!()); let creator = &mut context.gen_account(); let owner = &mut context.gen_account(); - let txn1 = context.mint_user_account(creator); + let txn1 = context.mint_user_account(creator).await; let txn2 = context.account_transfer(creator, owner, 100_000); let txn3 = context.account_transfer(creator, owner, 100_000); @@ -94,7 +94,7 @@ async fn test_view_tuple() { // } // } let tuple_module = hex::decode("a11ceb0b0500000006010002030205050704070b1b0826200c461900000001000100000203030d5461626c6554657374446174610c72657475726e5f7475706c65000000000000000000000000000000000000000000000000000000000a550c180001000000030601000000000000000602000000000000000200").unwrap(); - let mut root_account = context.root_account(); + let mut root_account = context.root_account().await; let module_txn = root_account .sign_with_transaction_builder(context.transaction_factory().module(tuple_module)); diff --git a/api/test-context/Cargo.toml b/api/test-context/Cargo.toml index 0700fb34a5382..66e108dd848c2 100644 --- a/api/test-context/Cargo.toml +++ b/api/test-context/Cargo.toml @@ -22,6 +22,7 @@ aptos-crypto = { workspace = true } aptos-db = { workspace = true, features = ["fuzzing"] } aptos-executor = { workspace = true } aptos-executor-types = { workspace = true } +aptos-framework = { workspace = true } aptos-genesis = { workspace = true } aptos-mempool = { workspace = true, features = ["fuzzing"] } aptos-mempool-notifications = { workspace = true } @@ -31,6 +32,7 @@ aptos-temppath = { workspace = true } aptos-types = { workspace = true } aptos-vm = { workspace = true } aptos-vm-validator = { workspace = true } +bcs = { workspace = true } bytes = { workspace = true } goldenfile = { workspace = true } hyper = { workspace = true } diff --git a/api/test-context/move/Move.toml b/api/test-context/move/Move.toml new file mode 100644 index 0000000000000..bb81e10e4a519 --- /dev/null +++ b/api/test-context/move/Move.toml @@ -0,0 +1,9 @@ +[package] +name = "TransactationTests" +version = "0.0.0" + +[addresses] +entry_func_failed= "0x1" + +[dependencies] +AptosFramework = { local = "../../../aptos-move/framework/aptos-framework" } diff --git a/api/test-context/move/sources/entry_func_fail.move b/api/test-context/move/sources/entry_func_fail.move new file mode 100644 index 0000000000000..8c18096263e24 --- /dev/null +++ b/api/test-context/move/sources/entry_func_fail.move @@ -0,0 +1,6 @@ +module entry_func_failed::func { + public entry fun init() { + // invalid function with 0 as denominator + 1/0; + } +} diff --git a/api/test-context/src/test_context.rs b/api/test-context/src/test_context.rs index 3b4aa841befd9..e5de79ebaa964 100644 --- a/api/test-context/src/test_context.rs +++ b/api/test-context/src/test_context.rs @@ -7,6 +7,7 @@ use aptos_api_types::{ mime_types, HexEncodedBytes, TransactionOnChainData, X_APTOS_CHAIN_ID, X_APTOS_LEDGER_TIMESTAMP, X_APTOS_LEDGER_VERSION, }; +use aptos_cached_packages::aptos_stdlib; use aptos_config::{ config::{ NodeConfig, RocksdbConfigs, BUFFERED_STATE_TARGET_ITEMS, @@ -18,9 +19,11 @@ use aptos_crypto::{ed25519::Ed25519PrivateKey, hash::HashValue, SigningKey}; use aptos_db::AptosDB; use aptos_executor::{block_executor::BlockExecutor, db_bootstrapper}; use aptos_executor_types::BlockExecutorTrait; +use aptos_framework::BuiltPackage; use aptos_mempool::mocks::MockSharedMempool; use aptos_mempool_notifications::MempoolNotificationSender; use aptos_sdk::{ + bcs, transaction_builder::TransactionFactory, types::{ account_config::aptos_test_root_address, transaction::SignedTransaction, AccountKey, @@ -36,7 +39,7 @@ use aptos_types::{ block_metadata::BlockMetadata, chain_id::ChainId, ledger_info::{LedgerInfo, LedgerInfoWithSignatures}, - transaction::{Transaction, TransactionStatus}, + transaction::{Transaction, TransactionPayload, TransactionStatus}, }; use aptos_vm::AptosVM; use aptos_vm_validator::vm_validator::VMValidator; @@ -44,10 +47,12 @@ use bytes::Bytes; use hyper::{HeaderMap, Response}; use rand::SeedableRng; use serde_json::{json, Value}; -use std::{boxed::Box, iter::once, net::SocketAddr, sync::Arc, time::Duration}; +use std::{boxed::Box, iter::once, net::SocketAddr, path::PathBuf, sync::Arc, time::Duration}; use warp::{http::header::CONTENT_TYPE, Filter, Rejection, Reply}; use warp_reverse_proxy::reverse_proxy_filter; +const TRANSFER_AMOUNT: u64 = 10_000_000; + #[derive(Clone, Debug)] pub enum ApiSpecificConfig { // The SocketAddr is the address where the Poem backend is running. @@ -296,8 +301,15 @@ impl TestContext { TransactionFactory::new(self.context.chain_id()) } - pub fn root_account(&self) -> LocalAccount { - LocalAccount::new(aptos_test_root_address(), self.root_key.private_key(), 0) + pub async fn root_account(&self) -> LocalAccount { + // Fetch the actual root account's sequence number in case it has been used to sign + // transactions before. + let root_sequence_number = self.get_sequence_number(aptos_test_root_address()).await; + LocalAccount::new( + aptos_test_root_address(), + self.root_key.private_key(), + root_sequence_number, + ) } pub fn latest_state_view(&self) -> DbStateView { @@ -310,17 +322,35 @@ impl TestContext { LocalAccount::generate(self.rng()) } - pub fn create_user_account(&self, account: &LocalAccount) -> SignedTransaction { - let mut tc = self.root_account(); + pub async fn create_account(&mut self) -> LocalAccount { + let mut root = self.root_account().await; + let account = self.gen_account(); + let factory = self.transaction_factory(); + let txn = root.sign_with_transaction_builder( + factory + .account_transfer(account.address(), TRANSFER_AMOUNT) + .expiration_timestamp_secs(u64::MAX), + ); + + let bcs_txn = bcs::to_bytes(&txn).unwrap(); + self.expect_status_code(202) + .post_bcs_txn("/transactions", bcs_txn) + .await; + self.commit_mempool_txns(1).await; + account + } + + pub async fn create_user_account(&self, account: &LocalAccount) -> SignedTransaction { + let mut tc = self.root_account().await; self.create_user_account_by(&mut tc, account) } - pub fn mint_user_account(&self, account: &LocalAccount) -> SignedTransaction { - let mut tc = self.root_account(); + pub async fn mint_user_account(&self, account: &LocalAccount) -> SignedTransaction { + let mut tc = self.root_account().await; let factory = self.transaction_factory(); tc.sign_with_transaction_builder( factory - .account_transfer(account.address(), 10_000_000) + .account_transfer(account.address(), TRANSFER_AMOUNT) .expiration_timestamp_secs(u64::MAX), ) } @@ -352,9 +382,9 @@ impl TestContext { ) } - pub fn create_invalid_signature_transaction(&mut self) -> SignedTransaction { + pub async fn create_invalid_signature_transaction(&mut self) -> SignedTransaction { let factory = self.transaction_factory(); - let root_account = self.root_account(); + let root_account = self.root_account().await; let txn = factory .transfer(root_account.address(), 1) .sender(root_account.address()) @@ -382,6 +412,37 @@ impl TestContext { ret } + pub fn build_package( + path: PathBuf, + named_addresses: Vec<(String, AccountAddress)>, + ) -> TransactionPayload { + let mut build_options = aptos_framework::BuildOptions::default(); + named_addresses.into_iter().for_each(|(name, address)| { + build_options.named_addresses.insert(name, address); + }); + + let package = BuiltPackage::build(path, build_options).unwrap(); + let code = package.extract_code(); + let metadata = package.extract_metadata().unwrap(); + + aptos_stdlib::code_publish_package_txn(bcs::to_bytes(&metadata).unwrap(), code) + } + + pub async fn publish_package( + &mut self, + publisher: &mut LocalAccount, + payload: TransactionPayload, + ) -> SignedTransaction { + let txn = + publisher.sign_with_transaction_builder(self.transaction_factory().payload(payload)); + let bcs_txn = bcs::to_bytes(&txn).unwrap(); + self.expect_status_code(202) + .post_bcs_txn("/transactions", bcs_txn) + .await; + self.commit_mempool_txns(1).await; + txn + } + pub async fn commit_mempool_txns(&mut self, size: u64) { let txns = self.mempool.get_txns(size); self.commit_block(&txns).await; @@ -438,19 +499,50 @@ impl TestContext { .unwrap(); } + pub async fn get_sequence_number(&self, account: AccountAddress) -> u64 { + let account_resource = self + .gen_resource(&account, "0x1::account::Account") + .await + .unwrap(); + account_resource["data"]["sequence_number"] + .as_str() + .unwrap() + .parse::() + .unwrap() + } + + // return a specific resource for an account. None if not found. + pub async fn gen_resource( + &self, + account_address: &AccountAddress, + resource: &str, + ) -> Option { + let request = format!("/accounts/{}/resources", account_address); + let response = self.get(&request).await; + response + .as_array() + .unwrap() + .iter() + .find(|entry| entry["type"] == resource) + .cloned() + } + + // return all resources for an account + pub async fn gen_all_resources(&self, account_address: &AccountAddress) -> Value { + let request = format!("/accounts/{}/resources", account_address); + self.get(&request).await + } + // TODO: Add support for generic_type_params if necessary. pub async fn api_get_account_resource( &self, - account: &LocalAccount, + account: AccountAddress, resource_account_address: &str, module: &str, name: &str, ) -> serde_json::Value { let resources = self - .get(&format!( - "/accounts/{}/resources", - account.address().to_hex_literal() - )) + .get(&format!("/accounts/{}/resources", account.to_hex_literal())) .await; let vals: Vec = serde_json::from_value(resources).unwrap(); vals.into_iter() @@ -458,11 +550,24 @@ impl TestContext { .unwrap() } + // TODO: remove the helper function since we don't publish module directly anymore + pub async fn api_publish_module(&mut self, account: &mut LocalAccount, code: HexEncodedBytes) { + self.api_execute_txn( + account, + json!({ + "type": "module_bundle_payload", + "modules" : [ + {"bytecode": code}, + ], + }), + ) + .await; + } + pub async fn api_execute_entry_function( &mut self, account: &mut LocalAccount, - module: &str, - func: &str, + function: &str, type_args: serde_json::Value, args: serde_json::Value, ) { @@ -470,12 +575,7 @@ impl TestContext { account, json!({ "type": "entry_function_payload", - "function": format!( - "{}::{}::{}", - account.address().to_hex_literal(), - module, - func - ), + "function": function, "type_arguments": type_args, "arguments": args }), @@ -483,20 +583,7 @@ impl TestContext { .await; } - pub async fn api_publish_module(&mut self, account: &mut LocalAccount, code: HexEncodedBytes) { - self.api_execute_txn( - account, - json!({ - "type": "module_bundle_payload", - "modules" : [ - {"bytecode": code}, - ], - }), - ) - .await; - } - - pub async fn api_execute_txn(&mut self, account: &mut LocalAccount, payload: Value) { + async fn api_execute_txn(&mut self, account: &mut LocalAccount, payload: Value) { let mut request = json!({ "sender": account.address(), "sequence_number": account.sequence_number().to_string(),