multiversx_sc_scenario/facade/world_tx/
scenario_exec_call.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
152
153
154
155
use multiversx_sc::{
    tuple_util::NestedTupleFlatten,
    types::{
        heap::H256, Code, FunctionCall, ManagedAddress, ManagedBuffer, NotPayable, RHListExec, Tx,
        TxBaseWithEnv, TxEnv, TxEnvMockDeployAddress, TxEnvWithTxHash, TxFromSpecified, TxGas,
        TxPayment, TxToSpecified, UpgradeCall,
    },
};

use crate::{
    api::StaticApi,
    imports::MxscPath,
    scenario::tx_to_step::{address_annotated, TxToStep},
    scenario_model::{SetStateStep, TxExpect, TxResponse},
    ScenarioTxEnv, ScenarioTxRun, ScenarioWorld,
};

use super::ScenarioTxEnvData;

/// Environment for executing transactions.
pub struct ScenarioEnvExec<'w> {
    pub world: &'w mut ScenarioWorld,
    pub data: ScenarioTxEnvData,
}

impl TxEnv for ScenarioEnvExec<'_> {
    type Api = StaticApi;

    type RHExpect = TxExpect;

    fn resolve_sender_address(&self) -> ManagedAddress<Self::Api> {
        panic!("Explicit sender address expected")
    }

    fn default_gas_annotation(&self) -> ManagedBuffer<Self::Api> {
        self.data.default_gas_annotation()
    }

    fn default_gas_value(&self) -> u64 {
        self.data.default_gas_value()
    }
}

impl TxEnvMockDeployAddress for ScenarioEnvExec<'_> {
    fn mock_deploy_new_address<From, NA>(&mut self, from: &From, new_address: NA)
    where
        From: TxFromSpecified<Self>,
        NA: multiversx_sc::types::AnnotatedValue<Self, ManagedAddress<Self::Api>>,
    {
        let from_value = address_annotated(self, from);
        let sender_nonce = self
            .world
            .get_state()
            .accounts
            .get(&from_value.to_address())
            .expect("sender does not exist")
            .nonce;
        let new_address_value = address_annotated(self, &new_address);

        self.world.set_state_step(SetStateStep::new().new_address(
            from_value,
            sender_nonce,
            new_address_value,
        ));
    }
}

impl ScenarioTxEnv for ScenarioEnvExec<'_> {
    fn env_data(&self) -> &ScenarioTxEnvData {
        &self.data
    }
}

impl<'w, From, To, Payment, Gas, RH> ScenarioTxRun
    for Tx<ScenarioEnvExec<'w>, From, To, Payment, Gas, FunctionCall<StaticApi>, RH>
where
    From: TxFromSpecified<ScenarioEnvExec<'w>>,
    To: TxToSpecified<ScenarioEnvExec<'w>>,
    Payment: TxPayment<ScenarioEnvExec<'w>>,
    Gas: TxGas<ScenarioEnvExec<'w>>,
    RH: RHListExec<TxResponse, ScenarioEnvExec<'w>>,
    RH::ListReturns: NestedTupleFlatten,
{
    type Returns = <RH::ListReturns as NestedTupleFlatten>::Unpacked;

    fn run(self) -> Self::Returns {
        let mut step_wrapper = self.tx_to_step();
        step_wrapper.env.world.sc_call(&mut step_wrapper.step);
        step_wrapper.process_result()
    }
}

impl<'w, From, To, RH> ScenarioTxRun
    for Tx<
        ScenarioEnvExec<'w>,
        From,
        To,
        NotPayable,
        (),
        UpgradeCall<ScenarioEnvExec<'w>, Code<MxscPath<'w>>>,
        RH,
    >
where
    From: TxFromSpecified<ScenarioEnvExec<'w>>,
    To: TxToSpecified<ScenarioEnvExec<'w>>,
    RH: RHListExec<TxResponse, ScenarioEnvExec<'w>>,
    RH::ListReturns: NestedTupleFlatten,
{
    type Returns = <RH::ListReturns as NestedTupleFlatten>::Unpacked;

    fn run(self) -> Self::Returns {
        let mut step_wrapper = self.tx_to_step();
        step_wrapper.env.world.sc_call(&mut step_wrapper.step);
        step_wrapper.process_result()
    }
}

impl TxEnvWithTxHash for ScenarioEnvExec<'_> {
    fn set_tx_hash(&mut self, tx_hash: H256) {
        self.data.set_tx_hash(tx_hash);
    }

    fn take_tx_hash(&mut self) -> Option<H256> {
        self.data.take_tx_hash()
    }
}

impl ScenarioWorld {
    pub fn tx(&mut self) -> TxBaseWithEnv<ScenarioEnvExec<'_>> {
        let data = self.new_env_data();
        let env = ScenarioEnvExec { world: self, data };
        Tx::new_with_env(env)
    }

    pub fn chain_call<From, To, Payment, Gas, RH, F>(&mut self, f: F) -> &mut Self
    where
        From: TxFromSpecified<ScenarioTxEnvData>,
        To: TxToSpecified<ScenarioTxEnvData>,
        Payment: TxPayment<ScenarioTxEnvData>,
        Gas: TxGas<ScenarioTxEnvData>,
        RH: RHListExec<TxResponse, ScenarioTxEnvData, ListReturns = ()>,
        F: FnOnce(
            TxBaseWithEnv<ScenarioTxEnvData>,
        )
            -> Tx<ScenarioTxEnvData, From, To, Payment, Gas, FunctionCall<StaticApi>, RH>,
    {
        let env = self.new_env_data();
        let tx_base = TxBaseWithEnv::new_with_env(env);
        let tx = f(tx_base);
        let mut step_wrapper = tx.tx_to_step();
        self.sc_call(&mut step_wrapper.step);
        step_wrapper.process_result();
        self
    }
}