Skip to main content

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