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 {}. Do we generate enough gas objects during genesis?",
49            txn_count,
50            txns.len(),
51        );
52
53        let fullnode = ctx.get_fullnode_client();
54
55        info!("Test execution with WaitForEffectsCert");
56        let txn = txns.swap_remove(0);
57        let txn_digest = *txn.digest();
58
59        let response = fullnode
60            .quorum_driver_api()
61            .execute_transaction_block(
62                txn,
63                IotaTransactionBlockResponseOptions::new().with_effects(),
64                Some(ExecuteTransactionRequestType::WaitForEffectsCert),
65            )
66            .await?;
67
68        assert!(!response.confirmed_local_execution.unwrap());
69        assert_eq!(txn_digest, response.digest);
70        let effects = response.effects.unwrap();
71        if !matches!(effects.status(), IotaExecutionStatus::Success) {
72            panic!(
73                "Failed to execute transfer transaction {:?}: {:?}",
74                txn_digest,
75                effects.status()
76            )
77        }
78        // Verify fullnode observes the txn
79        ctx.let_fullnode_sync(vec![txn_digest], 5).await;
80        Self::verify_transaction(fullnode, txn_digest).await;
81
82        info!("Test execution with WaitForLocalExecution");
83        let txn = txns.swap_remove(0);
84        let txn_digest = *txn.digest();
85
86        let response = fullnode
87            .quorum_driver_api()
88            .execute_transaction_block(
89                txn,
90                IotaTransactionBlockResponseOptions::new().with_effects(),
91                Some(ExecuteTransactionRequestType::WaitForLocalExecution),
92            )
93            .await?;
94        assert!(response.confirmed_local_execution.unwrap());
95        assert_eq!(txn_digest, response.digest);
96        let effects = response.effects.unwrap();
97        if !matches!(effects.status(), IotaExecutionStatus::Success) {
98            panic!(
99                "Failed to execute transfer transaction {:?}: {:?}",
100                txn_digest,
101                effects.status()
102            )
103        }
104        // Unlike in other execution modes, there's no need to wait for the node to sync
105        Self::verify_transaction(fullnode, txn_digest).await;
106
107        Ok(())
108    }
109}