iota_cluster_test/test_case/
fullnode_execute_transaction_test.rs

1// Copyright (c) Mysten Labs, Inc.
2// Modifications Copyright (c) 2024 IOTA Stiftung
3// SPDX-License-Identifier: Apache-2.0
4
5use async_trait::async_trait;
6use iota_json_rpc_types::{
7    IotaExecutionStatus, IotaTransactionBlockEffectsAPI, IotaTransactionBlockResponseOptions,
8};
9use iota_sdk::IotaClient;
10use iota_types::{
11    base_types::TransactionDigest, quorum_driver_types::ExecuteTransactionRequestType,
12};
13use tracing::info;
14
15use crate::{TestCaseImpl, TestContext};
16
17pub struct FullNodeExecuteTransactionTest;
18
19impl FullNodeExecuteTransactionTest {
20    async fn verify_transaction(fullnode: &IotaClient, tx_digest: TransactionDigest) {
21        fullnode
22            .read_api()
23            .get_transaction_with_options(tx_digest, IotaTransactionBlockResponseOptions::new())
24            .await
25            .unwrap_or_else(|e| {
26                panic!("failed get transaction {tx_digest:?} from fullnode: {e:?}")
27            });
28    }
29}
30
31#[async_trait]
32impl TestCaseImpl for FullNodeExecuteTransactionTest {
33    fn name(&self) -> &'static str {
34        "FullNodeExecuteTransaction"
35    }
36
37    fn description(&self) -> &'static str {
38        "Test executing transaction via Fullnode Quorum Driver"
39    }
40
41    async fn run(&self, ctx: &mut TestContext) -> Result<(), anyhow::Error> {
42        let txn_count = 4;
43        ctx.get_iota_from_faucet(Some(1)).await;
44
45        let mut txns = ctx.make_transactions(txn_count).await;
46        assert!(
47            txns.len() >= txn_count,
48            "expect at least {} txns, but only got {txn_count}. Do we generate enough gas objects during genesis?",
49            txns.len(),
50        );
51
52        let fullnode = ctx.get_fullnode_client();
53
54        info!("Test execution with WaitForEffectsCert");
55        let txn = txns.swap_remove(0);
56        let txn_digest = *txn.digest();
57
58        let response = fullnode
59            .quorum_driver_api()
60            .execute_transaction_block(
61                txn,
62                IotaTransactionBlockResponseOptions::new().with_effects(),
63                Some(ExecuteTransactionRequestType::WaitForEffectsCert),
64            )
65            .await?;
66
67        assert!(!response.confirmed_local_execution.unwrap());
68        assert_eq!(txn_digest, response.digest);
69        let effects = response.effects.unwrap();
70        if !matches!(effects.status(), IotaExecutionStatus::Success) {
71            panic!(
72                "failed to execute transfer transaction {txn_digest:?}: {:?}",
73                effects.status()
74            )
75        }
76        // Verify fullnode observes the txn
77        ctx.let_fullnode_sync(vec![txn_digest], 5).await;
78        Self::verify_transaction(fullnode, txn_digest).await;
79
80        info!("Test execution with WaitForLocalExecution");
81        let txn = txns.swap_remove(0);
82        let txn_digest = *txn.digest();
83
84        let response = fullnode
85            .quorum_driver_api()
86            .execute_transaction_block(
87                txn,
88                IotaTransactionBlockResponseOptions::new().with_effects(),
89                Some(ExecuteTransactionRequestType::WaitForLocalExecution),
90            )
91            .await?;
92        assert!(response.confirmed_local_execution.unwrap());
93        assert_eq!(txn_digest, response.digest);
94        let effects = response.effects.unwrap();
95        if !matches!(effects.status(), IotaExecutionStatus::Success) {
96            panic!(
97                "failed to execute transfer transaction {txn_digest:?}: {:?}",
98                effects.status()
99            )
100        }
101        // Unlike in other execution modes, there's no need to wait for the node to sync
102        Self::verify_transaction(fullnode, txn_digest).await;
103
104        Ok(())
105    }
106}