transaction_fuzzer/
executor.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
// Copyright (c) Mysten Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

use std::{fmt::Debug, path::PathBuf, sync::Arc};

use sui_core::authority::test_authority_builder::TestAuthorityBuilder;
use sui_core::{authority::AuthorityState, test_utils::send_and_confirm_transaction};
use sui_move_build::BuildConfig;
use sui_types::base_types::ObjectID;
use sui_types::effects::{TransactionEffects, TransactionEffectsAPI};
use sui_types::error::SuiError;
use sui_types::execution_status::{ExecutionFailureStatus, ExecutionStatus};
use sui_types::object::Object;
use sui_types::transaction::{Transaction, TransactionData};
use sui_types::utils::to_sender_signed_transaction;
use tokio::runtime::Runtime;

use crate::account_universe::{AccountCurrent, PUBLISH_BUDGET};

pub type ExecutionResult = Result<ExecutionStatus, SuiError>;

fn build_test_modules(test_dir: &str) -> (Vec<u8>, Vec<Vec<u8>>) {
    let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
    path.extend(["data", test_dir]);
    let with_unpublished_deps = false;
    let config = BuildConfig::new_for_testing();
    let package = config.build(&path).unwrap();
    (
        package.get_package_digest(with_unpublished_deps).to_vec(),
        package.get_package_bytes(with_unpublished_deps),
    )
}

// We want to look for either panics (in which case we won't hit this) or invariant violations in
// which case we want to panic.
pub fn assert_is_acceptable_result(result: &ExecutionResult) {
    if let Ok(
        e @ ExecutionStatus::Failure {
            error: ExecutionFailureStatus::InvariantViolation,
            command: _,
        },
    ) = result
    {
        panic!("Invariant violation: {e:#?}")
    }
}

#[derive(Clone)]
pub struct Executor {
    pub state: Arc<AuthorityState>,
    pub rt: Arc<Runtime>,
}

impl Debug for Executor {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("Executor").finish()
    }
}

impl Default for Executor {
    fn default() -> Self {
        Self::new()
    }
}

impl Executor {
    pub fn new() -> Self {
        let rt = Runtime::new().unwrap();
        let state = rt.block_on(TestAuthorityBuilder::new().build());
        Self {
            state,
            rt: Arc::new(rt),
        }
    }

    pub fn new_with_rgp(rgp: u64) -> Self {
        let rt = Runtime::new().unwrap();
        let state = rt.block_on(
            TestAuthorityBuilder::new()
                .with_reference_gas_price(rgp)
                .build(),
        );
        Self {
            state,
            rt: Arc::new(rt),
        }
    }

    pub fn get_reference_gas_price(&self) -> u64 {
        self.state.reference_gas_price_for_testing().unwrap()
    }

    pub fn add_object(&mut self, object: Object) {
        self.rt.block_on(self.state.insert_genesis_object(object));
    }

    pub fn add_objects(&mut self, objects: &[Object]) {
        self.rt.block_on(self.state.insert_genesis_objects(objects));
    }

    pub fn execute_transaction(&mut self, txn: Transaction) -> ExecutionResult {
        self.rt
            .block_on(send_and_confirm_transaction(&self.state, None, txn))
            .map(|(_, effects)| effects.into_data().status().clone())
    }

    pub fn publish(
        &mut self,
        package_name: &str,
        dep_ids: Vec<ObjectID>,
        account: &mut AccountCurrent,
    ) -> TransactionEffects {
        let (_, modules) = build_test_modules(package_name);
        // let gas_obj_ref = account.current_coins.last().unwrap().compute_object_reference();
        let gas_object = account.new_gas_object(self);
        let data = TransactionData::new_module(
            account.initial_data.account.address,
            gas_object.compute_object_reference(),
            modules,
            dep_ids,
            PUBLISH_BUDGET,
            1000,
        );
        let txn = to_sender_signed_transaction(data, &account.initial_data.account.key);
        let effects = self
            .rt
            .block_on(send_and_confirm_transaction(&self.state, None, txn))
            .unwrap()
            .1
            .into_data();

        assert!(
            matches!(effects.status(), ExecutionStatus::Success { .. }),
            "{:?}",
            effects.status()
        );
        effects
    }

    pub fn execute_transactions(
        &mut self,
        txn: impl IntoIterator<Item = Transaction>,
    ) -> Vec<ExecutionResult> {
        txn.into_iter()
            .map(|txn| self.execute_transaction(txn))
            .collect()
    }
}