-
Notifications
You must be signed in to change notification settings - Fork 99
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1136 from multiversx/exec-exec
Executor interface in VM
- Loading branch information
Showing
32 changed files
with
415 additions
and
217 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
mod catch_tx_panic; | ||
mod contract_container; | ||
mod contract_map; | ||
mod static_var_stack; | ||
mod tx_static_vars; | ||
|
||
pub use catch_tx_panic::catch_tx_panic; | ||
pub use contract_container::{ContractContainer, ContractContainerRef}; | ||
pub use contract_map::{ContractMap, ContractMapRef}; | ||
pub use static_var_stack::{StaticVarData, StaticVarStack}; | ||
pub use tx_static_vars::TxStaticVars; |
3 changes: 1 addition & 2 deletions
3
vm/src/tx_execution/catch_tx_panic.rs → ...ario/src/debug_executor/catch_tx_panic.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
146 changes: 146 additions & 0 deletions
146
framework/scenario/src/debug_executor/contract_container.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,146 @@ | ||
use std::rc::Rc; | ||
|
||
use multiversx_chain_vm::tx_mock::{TxContextRef, TxFunctionName, TxPanic}; | ||
use multiversx_chain_vm_executor::{BreakpointValue, ExecutorError, Instance, MemLength, MemPtr}; | ||
use multiversx_sc::contract_base::CallableContract; | ||
|
||
use super::{catch_tx_panic, StaticVarStack}; | ||
|
||
/// Contains a reference to a contract implementation. | ||
/// | ||
/// It can optionally also contain an allowed endpoint whitelist, to simulate multi-contract. | ||
pub struct ContractContainer { | ||
callable: Box<dyn CallableContract>, | ||
function_whitelist: Option<Vec<String>>, | ||
pub panic_message: bool, | ||
} | ||
|
||
impl ContractContainer { | ||
pub fn new( | ||
callable: Box<dyn CallableContract>, | ||
function_whitelist: Option<Vec<String>>, | ||
panic_message: bool, | ||
) -> Self { | ||
ContractContainer { | ||
callable, | ||
function_whitelist, | ||
panic_message, | ||
} | ||
} | ||
|
||
fn validate_function_name(&self, function_name: &TxFunctionName) -> bool { | ||
if let Some(function_whitelist) = &self.function_whitelist { | ||
function_whitelist | ||
.iter() | ||
.any(|whitelisted_endpoint| whitelisted_endpoint.as_str() == function_name.as_str()) | ||
} else { | ||
true | ||
} | ||
} | ||
|
||
pub fn call(&self, function_name: &TxFunctionName) -> bool { | ||
if self.validate_function_name(function_name) { | ||
self.callable.call(function_name.as_str()) | ||
} else { | ||
false | ||
} | ||
} | ||
} | ||
|
||
#[derive(Clone)] | ||
pub struct ContractContainerRef(pub(crate) Rc<ContractContainer>); | ||
|
||
impl ContractContainerRef { | ||
pub fn new(contract_container: ContractContainer) -> Self { | ||
ContractContainerRef(Rc::new(contract_container)) | ||
} | ||
} | ||
|
||
impl Instance for ContractContainerRef { | ||
fn call(&self, func_name: &str) -> Result<(), String> { | ||
let tx_func_name = TxFunctionName::from(func_name); | ||
StaticVarStack::static_push(); | ||
|
||
let result = catch_tx_panic(self.0.panic_message, || { | ||
let call_successful = self.0.call(&tx_func_name); | ||
if call_successful { | ||
Ok(()) | ||
} else { | ||
Err(TxPanic::new(1, "invalid function (not found)")) | ||
} | ||
}); | ||
|
||
if let Err(tx_panic) = result { | ||
TxContextRef::new_from_static().replace_tx_result_with_error(tx_panic); | ||
} | ||
|
||
StaticVarStack::static_pop(); | ||
|
||
Ok(()) | ||
} | ||
|
||
fn check_signatures(&self) -> bool { | ||
true | ||
} | ||
|
||
fn has_function(&self, func_name: &str) -> bool { | ||
let tx_func_name = TxFunctionName::from(func_name); | ||
self.0.validate_function_name(&tx_func_name) | ||
} | ||
|
||
fn get_exported_function_names(&self) -> Vec<String> { | ||
panic!("ContractContainer get_exported_function_names not yet supported") | ||
} | ||
|
||
fn set_points_limit(&self, _limit: u64) -> Result<(), String> { | ||
panic!("ContractContainerRef set_points_limit not supported") | ||
} | ||
|
||
fn set_points_used(&self, _points: u64) -> Result<(), String> { | ||
panic!("ContractContainerRef set_points_used not supported") | ||
} | ||
|
||
fn get_points_used(&self) -> Result<u64, String> { | ||
panic!("ContractContainerRef get_points_used not supported") | ||
} | ||
|
||
fn memory_length(&self) -> Result<u64, String> { | ||
panic!("ContractContainerRef memory_length not supported") | ||
} | ||
|
||
fn memory_ptr(&self) -> Result<*mut u8, String> { | ||
panic!("ContractContainerRef memory_ptr not supported") | ||
} | ||
|
||
fn memory_load( | ||
&self, | ||
_mem_ptr: MemPtr, | ||
_mem_length: MemLength, | ||
) -> Result<&[u8], ExecutorError> { | ||
panic!("ContractContainerRef memory_load not supported") | ||
} | ||
|
||
fn memory_store(&self, _mem_ptr: MemPtr, _data: &[u8]) -> Result<(), ExecutorError> { | ||
panic!("ContractContainerRef memory_store not supported") | ||
} | ||
|
||
fn memory_grow(&self, _by_num_pages: u32) -> Result<u32, ExecutorError> { | ||
panic!("ContractContainerRef memory_grow not supported") | ||
} | ||
|
||
fn set_breakpoint_value(&self, _value: BreakpointValue) -> Result<(), String> { | ||
panic!("ContractContainerRef set_breakpoint_value not supported") | ||
} | ||
|
||
fn get_breakpoint_value(&self) -> Result<BreakpointValue, String> { | ||
panic!("ContractContainerRef get_breakpoint_value not supported") | ||
} | ||
|
||
fn reset(&self) -> Result<(), String> { | ||
panic!("ContractContainerRef reset not supported") | ||
} | ||
|
||
fn cache(&self) -> Result<Vec<u8>, String> { | ||
panic!("ContractContainerRef cache not supported") | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
use super::*; | ||
|
||
use multiversx_chain_vm_executor::{ | ||
CompilationOptions, Executor, ExecutorError, Instance, OpcodeCost, | ||
}; | ||
use std::{ | ||
cell::{Ref, RefCell, RefMut}, | ||
collections::HashMap, | ||
fmt, | ||
rc::Rc, | ||
}; | ||
|
||
pub struct ContractMap { | ||
contract_objs: HashMap<Vec<u8>, ContractContainerRef>, | ||
} | ||
|
||
impl fmt::Debug for ContractMap { | ||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
f.debug_struct("ContractMap").finish() | ||
} | ||
} | ||
|
||
impl ContractMap { | ||
pub fn new() -> Self { | ||
ContractMap { | ||
contract_objs: HashMap::new(), | ||
} | ||
} | ||
|
||
pub fn get_contract(&self, contract_identifier: &[u8]) -> ContractContainerRef { | ||
if let Some(contract_contatiner) = self.contract_objs.get(contract_identifier) { | ||
contract_contatiner.clone() | ||
} else { | ||
unknown_contract_panic(contract_identifier) | ||
} | ||
} | ||
|
||
pub fn register_contract( | ||
&mut self, | ||
contract_bytes: Vec<u8>, | ||
contract_container: ContractContainer, | ||
) { | ||
let previous_entry = self.contract_objs.insert( | ||
contract_bytes, | ||
ContractContainerRef::new(contract_container), | ||
); | ||
assert!(previous_entry.is_none(), "contract inserted twice"); | ||
} | ||
|
||
pub fn contains_contract(&self, contract_bytes: &[u8]) -> bool { | ||
self.contract_objs.contains_key(contract_bytes) | ||
} | ||
} | ||
|
||
fn unknown_contract_panic(contract_identifier: &[u8]) -> ! { | ||
if let Ok(s) = std::str::from_utf8(contract_identifier) { | ||
panic!("Unknown contract: {s}") | ||
} else { | ||
panic!( | ||
"Unknown contract of length {} bytes", | ||
contract_identifier.len() | ||
) | ||
} | ||
} | ||
|
||
impl Default for ContractMap { | ||
fn default() -> Self { | ||
Self::new() | ||
} | ||
} | ||
|
||
#[derive(Default, Clone, Debug)] | ||
pub struct ContractMapRef(Rc<RefCell<ContractMap>>); | ||
|
||
impl ContractMapRef { | ||
pub fn new() -> Self { | ||
ContractMapRef(Rc::new(RefCell::new(ContractMap::new()))) | ||
} | ||
|
||
pub fn borrow(&self) -> Ref<ContractMap> { | ||
self.0.borrow() | ||
} | ||
|
||
pub fn borrow_mut(&self) -> RefMut<ContractMap> { | ||
self.0.borrow_mut() | ||
} | ||
} | ||
|
||
impl Executor for ContractMapRef { | ||
fn set_vm_hooks_ptr( | ||
&mut self, | ||
_vm_hooks_ptr: *mut std::ffi::c_void, | ||
) -> Result<(), ExecutorError> { | ||
todo!() | ||
} | ||
|
||
fn set_opcode_cost(&mut self, _opcode_cost: &OpcodeCost) -> Result<(), ExecutorError> { | ||
Ok(()) | ||
} | ||
|
||
fn new_instance( | ||
&self, | ||
wasm_bytes: &[u8], | ||
_compilation_options: &CompilationOptions, | ||
) -> Result<Box<dyn Instance>, ExecutorError> { | ||
Ok(Box::new(self.borrow().get_contract(wasm_bytes))) | ||
} | ||
|
||
fn new_instance_from_cache( | ||
&self, | ||
_cache_bytes: &[u8], | ||
_compilation_options: &CompilationOptions, | ||
) -> Result<Box<dyn Instance>, ExecutorError> { | ||
panic!("ContractMap new_instance_from_cache not supported") | ||
} | ||
} |
File renamed without changes.
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.