drt_sc_scenario/debug_executor/
contract_container.rs

1use drt_chain_vm::tx_mock::{TxContextRef, TxFunctionName, TxPanic};
2use drt_chain_vm_executor::{BreakpointValue, ExecutorError, Instance, MemLength, MemPtr};
3use drt_sc::contract_base::CallableContract;
4use std::sync::Arc;
5
6use super::{catch_tx_panic, StaticVarStack};
7
8/// Contains a reference to a contract implementation.
9///
10/// It can optionally also contain an allowed endpoint whitelist, to simulate multi-contract.
11pub struct ContractContainer {
12    callable: Box<dyn CallableContract>,
13    function_whitelist: Option<Vec<String>>,
14    pub panic_message: bool,
15}
16
17impl ContractContainer {
18    pub fn new(
19        callable: Box<dyn CallableContract>,
20        function_whitelist: Option<Vec<String>>,
21        panic_message: bool,
22    ) -> Self {
23        ContractContainer {
24            callable,
25            function_whitelist,
26            panic_message,
27        }
28    }
29
30    fn validate_function_name(&self, function_name: &TxFunctionName) -> bool {
31        if let Some(function_whitelist) = &self.function_whitelist {
32            function_whitelist
33                .iter()
34                .any(|whitelisted_endpoint| whitelisted_endpoint.as_str() == function_name.as_str())
35        } else {
36            true
37        }
38    }
39
40    pub fn call(&self, function_name: &TxFunctionName) -> bool {
41        if self.validate_function_name(function_name) {
42            self.callable.call(function_name.as_str())
43        } else {
44            false
45        }
46    }
47}
48
49/// Prepares the StaticVarStack and catches panics.
50/// The result of the panics is written to the top of the TxContext stack.
51pub fn contract_instance_wrapped_execution<F>(panic_message: bool, f: F)
52where
53    F: FnOnce() -> Result<(), TxPanic>,
54{
55    StaticVarStack::static_push();
56
57    let result = catch_tx_panic(panic_message, f);
58
59    if let Err(tx_panic) = result {
60        TxContextRef::new_from_static().replace_tx_result_with_error(tx_panic);
61    }
62
63    StaticVarStack::static_pop();
64}
65
66#[derive(Clone)]
67pub struct ContractContainerRef(pub(crate) Arc<ContractContainer>);
68
69impl ContractContainerRef {
70    pub fn new(contract_container: ContractContainer) -> Self {
71        ContractContainerRef(Arc::new(contract_container))
72    }
73}
74
75impl Instance for ContractContainerRef {
76    fn call(&self, func_name: &str) -> Result<(), String> {
77        let tx_func_name = TxFunctionName::from(func_name);
78
79        contract_instance_wrapped_execution(self.0.panic_message, || {
80            let call_successful = self.0.call(&tx_func_name);
81            if call_successful {
82                Ok(())
83            } else {
84                Err(TxPanic::new(1, "invalid function (not found)"))
85            }
86        });
87
88        Ok(())
89    }
90
91    fn check_signatures(&self) -> bool {
92        true
93    }
94
95    fn has_function(&self, func_name: &str) -> bool {
96        let tx_func_name = TxFunctionName::from(func_name);
97        self.0.validate_function_name(&tx_func_name)
98    }
99
100    fn get_exported_function_names(&self) -> Vec<String> {
101        panic!("ContractContainer get_exported_function_names not yet supported")
102    }
103
104    fn set_points_limit(&self, _limit: u64) -> Result<(), String> {
105        panic!("ContractContainerRef set_points_limit not supported")
106    }
107
108    fn set_points_used(&self, _points: u64) -> Result<(), String> {
109        panic!("ContractContainerRef set_points_used not supported")
110    }
111
112    fn get_points_used(&self) -> Result<u64, String> {
113        panic!("ContractContainerRef get_points_used not supported")
114    }
115
116    fn memory_length(&self) -> Result<u64, String> {
117        panic!("ContractContainerRef memory_length not supported")
118    }
119
120    fn memory_ptr(&self) -> Result<*mut u8, String> {
121        panic!("ContractContainerRef memory_ptr not supported")
122    }
123
124    fn memory_load(
125        &self,
126        _mem_ptr: MemPtr,
127        _mem_length: MemLength,
128    ) -> Result<&[u8], ExecutorError> {
129        panic!("ContractContainerRef memory_load not supported")
130    }
131
132    fn memory_store(&self, _mem_ptr: MemPtr, _data: &[u8]) -> Result<(), ExecutorError> {
133        panic!("ContractContainerRef memory_store not supported")
134    }
135
136    fn memory_grow(&self, _by_num_pages: u32) -> Result<u32, ExecutorError> {
137        panic!("ContractContainerRef memory_grow not supported")
138    }
139
140    fn set_breakpoint_value(&self, _value: BreakpointValue) -> Result<(), String> {
141        panic!("ContractContainerRef set_breakpoint_value not supported")
142    }
143
144    fn get_breakpoint_value(&self) -> Result<BreakpointValue, String> {
145        panic!("ContractContainerRef get_breakpoint_value not supported")
146    }
147
148    fn reset(&self) -> Result<(), String> {
149        panic!("ContractContainerRef reset not supported")
150    }
151
152    fn cache(&self) -> Result<Vec<u8>, String> {
153        panic!("ContractContainerRef cache not supported")
154    }
155}