sui_cluster_test/test_case/
fullnode_execute_transaction_test.rs

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