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
use crate::errors::IntoVMError;
use crate::memory::WasmerMemory;
use crate::{cache, imports};
use near_runtime_fees::RuntimeFeesConfig;
use near_vm_errors::{FunctionCallError, MethodResolveError, VMError};
use near_vm_logic::types::PromiseResult;
use near_vm_logic::{External, VMConfig, VMContext, VMLogic, VMOutcome};
use wasmer_runtime::Module;
fn check_method(module: &Module, method_name: &str) -> Result<(), VMError> {
let info = module.info();
use wasmer_runtime_core::module::ExportIndex::Func;
if let Some(Func(index)) = info.exports.get(method_name) {
let func = info.func_assoc.get(index.clone()).unwrap();
let sig = info.signatures.get(func.clone()).unwrap();
if sig.params().is_empty() && sig.returns().is_empty() {
Ok(())
} else {
Err(VMError::FunctionCallError(FunctionCallError::MethodResolveError(
MethodResolveError::MethodInvalidSignature,
)))
}
} else {
Err(VMError::FunctionCallError(FunctionCallError::MethodResolveError(
MethodResolveError::MethodNotFound,
)))
}
}
pub fn run<'a>(
code_hash: Vec<u8>,
code: &[u8],
method_name: &[u8],
ext: &mut dyn External,
context: VMContext,
wasm_config: &'a VMConfig,
fees_config: &'a RuntimeFeesConfig,
promise_results: &'a [PromiseResult],
) -> (Option<VMOutcome>, Option<VMError>) {
if !cfg!(target_arch = "x86") && !cfg!(target_arch = "x86_64") {
panic!(
"Execution of smart contracts is only supported for x86 and x86_64 CPU architectures."
);
}
if method_name.is_empty() {
return (
None,
Some(VMError::FunctionCallError(FunctionCallError::MethodResolveError(
MethodResolveError::MethodEmptyName,
))),
);
}
let module = match cache::compile_module(code_hash, code, wasm_config) {
Ok(x) => x,
Err(err) => return (None, Some(err)),
};
let mut memory = match WasmerMemory::new(
wasm_config.limit_config.initial_memory_pages,
wasm_config.limit_config.max_memory_pages,
) {
Ok(x) => x,
Err(_err) => panic!("Cannot create memory for a contract call"),
};
let memory_copy = memory.clone();
let mut logic =
VMLogic::new(ext, context, wasm_config, fees_config, promise_results, &mut memory);
let import_object = imports::build(memory_copy, &mut logic);
let method_name = match std::str::from_utf8(method_name) {
Ok(x) => x,
Err(_) => {
return (
None,
Some(VMError::FunctionCallError(FunctionCallError::MethodResolveError(
MethodResolveError::MethodUTF8Error,
))),
)
}
};
if let Err(e) = check_method(&module, method_name) {
return (None, Some(e));
}
match module.instantiate(&import_object) {
Ok(instance) => match instance.call(&method_name, &[]) {
Ok(_) => (Some(logic.outcome()), None),
Err(err) => (Some(logic.outcome()), Some(err.into_vm_error())),
},
Err(err) => (Some(logic.outcome()), Some(err.into_vm_error())),
}
}