multiversx_chain_vm/host/
runtime.rs1mod runtime_instance_call;
2mod runtime_instance_call_default;
3
4pub use runtime_instance_call::{RuntimeInstanceCall, RuntimeInstanceCallLambda};
5pub use runtime_instance_call_default::RuntimeInstanceCallLambdaDefault;
6
7use std::{
8 ops::Deref,
9 sync::{Arc, RwLock, Weak},
10};
11
12use multiversx_chain_vm_executor::{CompilationOptions, Executor};
13
14use crate::{
15 blockchain::VMConfigRef,
16 display_util::address_hex,
17 host::context::{TxContext, TxContextRef},
18};
19
20pub struct Runtime {
21 pub vm_ref: VMConfigRef,
22 executor: Box<dyn Executor + Send + Sync>,
23 context_cell: RwLock<Option<TxContextRef>>,
24}
25
26#[derive(Clone)]
27pub struct RuntimeRef(Arc<Runtime>);
28
29#[derive(Clone)]
30pub struct RuntimeWeakRef(Weak<Runtime>);
31
32impl Runtime {
33 pub fn new(vm_ref: VMConfigRef, executor: Box<dyn Executor + Send + Sync>) -> Self {
34 Runtime {
35 vm_ref,
36 executor,
37 context_cell: RwLock::new(None),
38 }
39 }
40
41 pub fn get_executor_context(&self) -> TxContextRef {
42 self.context_cell
43 .read()
44 .unwrap()
45 .clone()
46 .expect("no executor context configured")
47 }
48
49 fn set_executor_context(&self, value: Option<TxContextRef>) {
50 let mut cell_ref = self.context_cell.write().unwrap();
51 *cell_ref = value;
52 }
53}
54
55impl RuntimeRef {
56 pub fn new(vm_ref: VMConfigRef, executor: Box<dyn Executor + Send + Sync>) -> Self {
57 RuntimeRef(Arc::new(Runtime::new(vm_ref, executor)))
58 }
59
60 pub fn downgrade(&self) -> RuntimeWeakRef {
61 RuntimeWeakRef(Arc::downgrade(&self.0))
62 }
63
64 pub fn get_mut(&mut self) -> &mut Runtime {
65 Arc::get_mut(&mut self.0).expect(
66 "RuntimeRef cannot grant mutable access, because more than one strong reference exists",
67 )
68 }
69
70 pub fn new_cyclic<F>(init_fn: F) -> RuntimeRef
76 where
77 F: FnOnce(RuntimeWeakRef) -> Runtime,
78 {
79 let runtime_arc = Arc::new_cyclic(|weak| init_fn(RuntimeWeakRef(weak.clone())));
80 RuntimeRef(runtime_arc)
81 }
82}
83
84impl Deref for RuntimeRef {
85 type Target = Runtime;
86
87 fn deref(&self) -> &Self::Target {
88 self.0.deref()
89 }
90}
91
92impl RuntimeWeakRef {
93 pub fn upgrade(&self) -> RuntimeRef {
94 RuntimeRef(
95 self.0
96 .upgrade()
97 .expect("RuntimeWeakRef points to a dropped reference"),
98 )
99 }
100}
101
102impl RuntimeRef {
103 pub fn execute<F>(&self, tx_context: TxContext, call_lambda: F) -> TxContext
108 where
109 F: RuntimeInstanceCallLambda,
110 {
111 let func_name = tx_context.tx_input_box.func_name.clone();
112 let contract_code = get_contract_identifier(&tx_context);
113 let gas_limit = tx_context.input_ref().gas_limit;
114
115 let tx_context_ref = TxContextRef::new(Arc::new(tx_context));
116
117 self.set_executor_context(Some(tx_context_ref.clone()));
118
119 let compilation_options = CompilationOptions {
120 unmetered_locals: 0,
121 max_memory_grow: 0,
122 max_memory_grow_delta: 0,
123 opcode_trace: false,
124 };
125
126 let mut instance = self
127 .executor
128 .new_instance(contract_code.as_slice(), &compilation_options)
129 .expect("error instantiating executor instance");
130
131 self.set_executor_context(None);
132
133 call_lambda.call(RuntimeInstanceCall {
134 instance: &mut *instance,
135 func_name: func_name.as_str(),
136 gas_limit,
137 tx_context_ref: &tx_context_ref,
138 });
139
140 std::mem::drop(instance);
141
142 Arc::into_inner(tx_context_ref.0)
143 .expect("cannot extract final TxContext from stack because of lingering references")
144 }
145}
146
147fn get_contract_identifier(tx_context: &TxContext) -> Vec<u8> {
148 tx_context
149 .tx_cache
150 .with_account(&tx_context.tx_input_box.to, |account| {
151 account.contract_path.clone().unwrap_or_else(|| {
152 panic!(
153 "Recipient account is not a smart contract {}",
154 address_hex(&tx_context.tx_input_box.to)
155 )
156 })
157 })
158}