From 8d74379e083b9a3158bf3ea992884e16f96da2ef Mon Sep 17 00:00:00 2001 From: Tomasz Pastusiak Date: Tue, 29 Oct 2024 13:20:53 +0100 Subject: [PATCH] iota-indexer: Add tests for TransactionBuilder api --- crates/iota-indexer/tests/rpc-tests/main.rs | 3 + .../tests/rpc-tests/transaction_builder.rs | 277 ++++++++++++++++++ 2 files changed, 280 insertions(+) create mode 100644 crates/iota-indexer/tests/rpc-tests/transaction_builder.rs diff --git a/crates/iota-indexer/tests/rpc-tests/main.rs b/crates/iota-indexer/tests/rpc-tests/main.rs index bd1a3788c89..da7e6b631b6 100644 --- a/crates/iota-indexer/tests/rpc-tests/main.rs +++ b/crates/iota-indexer/tests/rpc-tests/main.rs @@ -16,5 +16,8 @@ mod move_utils; #[cfg(feature = "shared_test_runtime")] mod read_api; +#[cfg(feature = "shared_test_runtime")] +mod transaction_builder; + #[cfg(feature = "shared_test_runtime")] mod write_api; diff --git a/crates/iota-indexer/tests/rpc-tests/transaction_builder.rs b/crates/iota-indexer/tests/rpc-tests/transaction_builder.rs new file mode 100644 index 00000000000..214b276633e --- /dev/null +++ b/crates/iota-indexer/tests/rpc-tests/transaction_builder.rs @@ -0,0 +1,277 @@ +// Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use iota_json_rpc_api::{ + CoinReadApiClient, GovernanceReadApiClient, IndexerApiClient, ReadApiClient, + TransactionBuilderClient, WriteApiClient, +}; +use iota_json_rpc_types::{ + CoinPage, DelegatedStake, IotaObjectDataOptions, IotaObjectResponseQuery, + IotaTransactionBlockResponseOptions, ObjectsPage, StakeStatus, TransactionBlockBytes, +}; +use iota_test_transaction_builder::TestTransactionBuilder; +use iota_types::{ + balance::Balance, + base_types::{IotaAddress, ObjectID, ObjectRef}, + crypto::{AccountKeyPair, get_key_pair}, + object::Owner, + programmable_transaction_builder::ProgrammableTransactionBuilder, + utils::to_sender_signed_transaction, +}; +use jsonrpsee::http_client::HttpClient; +use test_cluster::TestCluster; + +use crate::common::{ + ApiTestSetup, indexer_wait_for_checkpoint, indexer_wait_for_object, + indexer_wait_for_transaction, +}; + +const FUNDED_BALANCE_PER_COIN: u64 = 10_000_000_000; + +#[test] +fn transfer_object() { + let ApiTestSetup { + runtime, + store, + client, + cluster, + } = ApiTestSetup::get_or_init(); + + runtime.block_on(async move { + indexer_wait_for_checkpoint(store, 1).await; + + let (sender, keypair): (_, AccountKeyPair) = get_key_pair(); + let (receiver, _): (_, AccountKeyPair) = get_key_pair(); + + let sender_coins = create_coins_for_addr(cluster, client, sender, 2).await; + let gas = sender_coins[0]; + let object_to_send = sender_coins[1]; + + let tx_bytes = client + .transfer_object( + sender, + object_to_send, + Some(gas), + 100_000_000.into(), + receiver, + ) + .await + .unwrap(); + + let txn = to_sender_signed_transaction(tx_bytes.to_data().unwrap(), &keypair); + let res = cluster.wallet.execute_transaction_must_succeed(txn).await; + indexer_wait_for_transaction(res.digest, store, client).await; + + let transferred_object = client + .get_object(object_to_send, Some(IotaObjectDataOptions::full_content())) + .await + .unwrap(); + + assert_eq!( + transferred_object.owner(), + Some(Owner::AddressOwner(receiver)) + ); + }); +} + +#[test] +fn transfer_iota() { + let ApiTestSetup { + runtime, + store, + client, + cluster, + } = ApiTestSetup::get_or_init(); + + runtime.block_on(async move { + indexer_wait_for_checkpoint(store, 1).await; + + let (sender, keypair): (_, AccountKeyPair) = get_key_pair(); + let (receiver, _): (_, AccountKeyPair) = get_key_pair(); + + let sender_coins = create_coins_for_addr(cluster, client, sender, 1).await; + let gas = sender_coins[0]; + let transferred_balance = 100_000; + + let tx_bytes = client + .transfer_iota( + sender, + gas, + 100_000_000.into(), + receiver, + Some(transferred_balance.into()), + ) + .await + .unwrap(); + + let txn = to_sender_signed_transaction(tx_bytes.to_data().unwrap(), &keypair); + let res = cluster.wallet.execute_transaction_must_succeed(txn).await; + indexer_wait_for_transaction(res.digest, store, client).await; + + let receiver_balances = get_address_balances(client, receiver).await; + + assert_eq!(receiver_balances, [transferred_balance]); + }); +} + +#[test] +fn pay() { + let ApiTestSetup { + runtime, + store, + client, + cluster, + } = ApiTestSetup::get_or_init(); + + runtime.block_on(async move { + indexer_wait_for_checkpoint(store, 1).await; + + let (sender, keypair): (_, AccountKeyPair) = get_key_pair(); + let (receiver_1, _): (_, AccountKeyPair) = get_key_pair(); + let (receiver_2, _): (_, AccountKeyPair) = get_key_pair(); + + let input_coins: u64 = 3; + let sender_coins = + create_coins_for_addr(cluster, client, sender, input_coins as u32 + 1).await; + let total_input_coins_balance = FUNDED_BALANCE_PER_COIN * input_coins; + let transferred_balance_1 = total_input_coins_balance / 2 - 100; + let transferred_balance_2 = total_input_coins_balance / 2 - 700; + + let tx_bytes = client + .pay( + sender, + sender_coins[0..input_coins as usize].into(), + [receiver_1, receiver_2].into(), + [transferred_balance_1.into(), transferred_balance_2.into()].into(), + None, // let node find the gas automatically + 100_000_000.into(), + ) + .await + .unwrap(); + + let txn = to_sender_signed_transaction(tx_bytes.to_data().unwrap(), &keypair); + let res = cluster.wallet.execute_transaction_must_succeed(txn).await; + indexer_wait_for_transaction(res.digest, store, client).await; + + let receiver_1_balances = get_address_balances(client, receiver_1).await; + let receiver_2_balances = get_address_balances(client, receiver_2).await; + + assert_eq!(receiver_1_balances, [transferred_balance_1]); + assert_eq!(receiver_2_balances, [transferred_balance_2]); + }); +} + +#[test] +fn pay_iota() { + let ApiTestSetup { + runtime, + store, + client, + cluster, + } = ApiTestSetup::get_or_init(); + + runtime.block_on(async move { + indexer_wait_for_checkpoint(store, 1).await; + + let (sender, keypair): (_, AccountKeyPair) = get_key_pair(); + let (receiver_1, _): (_, AccountKeyPair) = get_key_pair(); + let (receiver_2, _): (_, AccountKeyPair) = get_key_pair(); + + let input_coins: u64 = 3; + let sender_coins = create_coins_for_addr(cluster, client, sender, input_coins as u32).await; + let gas_budget = 100_000_000; + let total_available_input_coins_balance: u64 = + FUNDED_BALANCE_PER_COIN * input_coins - gas_budget; + let transferred_balance_1 = total_available_input_coins_balance / 2 - 100; + let transferred_balance_2 = total_available_input_coins_balance / 2 - 700; + + let tx_bytes = client + .pay_iota( + sender, + sender_coins.into(), + [receiver_1, receiver_2].into(), + [transferred_balance_1.into(), transferred_balance_2.into()].into(), + gas_budget.into(), + ) + .await + .unwrap(); + + let txn = to_sender_signed_transaction(tx_bytes.to_data().unwrap(), &keypair); + let res = cluster.wallet.execute_transaction_must_succeed(txn).await; + indexer_wait_for_transaction(res.digest, store, client).await; + + let receiver_1_balances = get_address_balances(client, receiver_1).await; + let receiver_2_balances = get_address_balances(client, receiver_2).await; + + assert_eq!(receiver_1_balances, [transferred_balance_1]); + assert_eq!(receiver_2_balances, [transferred_balance_2]); + }); +} + +#[test] +fn pay_all_iota() { + let ApiTestSetup { + runtime, + store, + client, + cluster, + } = ApiTestSetup::get_or_init(); + + runtime.block_on(async move { + indexer_wait_for_checkpoint(store, 1).await; + + let (sender, keypair): (_, AccountKeyPair) = get_key_pair(); + let (receiver, _): (_, AccountKeyPair) = get_key_pair(); + + let input_coins: u64 = 3; + let sender_coins = create_coins_for_addr(cluster, client, sender, input_coins as u32).await; + let gas_budget = 100_000_000; + + let tx_bytes = client + .pay_all_iota(sender, sender_coins.into(), receiver, gas_budget.into()) + .await + .unwrap(); + + let txn = to_sender_signed_transaction(tx_bytes.to_data().unwrap(), &keypair); + let res = cluster.wallet.execute_transaction_must_succeed(txn).await; + indexer_wait_for_transaction(res.digest, store, client).await; + + let receiver_balances = get_address_balances(client, receiver).await; + let expected_minimum_reciver_balance = FUNDED_BALANCE_PER_COIN * input_coins - gas_budget; + + assert_eq!(receiver_balances.len(), 1); + assert!(receiver_balances[0] >= expected_minimum_reciver_balance); + }); +} + +async fn get_address_balances(indexer_client: &HttpClient, address: IotaAddress) -> Vec { + indexer_client + .get_coins(address, None, None, None) + .await + .unwrap() + .data + .iter() + .map(|coin| coin.balance) + .collect() +} + +async fn create_coins_for_addr( + cluster: &TestCluster, + indexer_client: &HttpClient, + address: IotaAddress, + objects_count: u32, +) -> Vec { + let mut coins: Vec = Vec::new(); + for _ in 0..objects_count { + let coin = cluster + .fund_address_and_return_gas( + cluster.get_reference_gas_price().await, + Some(FUNDED_BALANCE_PER_COIN), + address, + ) + .await; + indexer_wait_for_object(indexer_client, coin.0, coin.1).await; + coins.push(coin.0); + } + coins +}