Skip to content

Commit 28b0158

Browse files
committed
refactor lib.rs to compile.rs & calls.rs
1 parent ce32c51 commit 28b0158

File tree

4 files changed

+734
-704
lines changed

4 files changed

+734
-704
lines changed

packages/vm/Cargo.toml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,6 @@ readme = "README.md"
1111
[dependencies]
1212
assert_matches = "1.3.0"
1313
hex = "0.4"
14-
# parity-wasm = "0.45"
15-
pwasm-utils = "0.12"
1614
wasm-instrument = "0.2.0"
1715
wasmer = { version = "2.3.0", default-features = false, features = ["singlepass", "compiler", "universal"] }
1816
wasmer-middlewares = "2.3.0"

packages/vm/src/calls.rs

Lines changed: 337 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,337 @@
1+
use crate::cache::Cache;
2+
use crate::vm::{self, Environment};
3+
4+
pub use crate::error::Error;
5+
pub use std::ptr::NonNull;
6+
use std::sync::Arc;
7+
use wasmer::Universal;
8+
use wasmer_middlewares::metering::{get_remaining_points, MeteringPoints};
9+
10+
use wasmer::Singlepass;
11+
12+
use wasmer::{imports, wasmparser::Operator, CompilerConfig, Function, Store};
13+
use wasmer_middlewares::Metering;
14+
15+
// use owasm_crypto::ecvrf;
16+
17+
fn require_mem_range(max_range: usize, require_range: usize) -> Result<(), Error> {
18+
if max_range < require_range {
19+
return Err(Error::MemoryOutOfBoundError);
20+
}
21+
Ok(())
22+
}
23+
24+
fn cost(_operator: &Operator) -> u64 {
25+
// A flat fee for each operation
26+
1
27+
}
28+
29+
pub fn run<E>(
30+
cache: &mut Cache,
31+
code: &[u8],
32+
gas: u64,
33+
is_prepare: bool,
34+
env: E,
35+
) -> Result<u64, Error>
36+
where
37+
E: vm::Env + 'static,
38+
{
39+
let owasm_env = Environment::new(env);
40+
41+
let mut compiler = Singlepass::new();
42+
let metering = Arc::new(Metering::new(0, cost));
43+
compiler.push_middleware(metering);
44+
let engine = Universal::new(compiler).engine();
45+
let store = Store::new(&engine);
46+
47+
let import_object = imports! {
48+
"env" => {
49+
"gas" => Function::new_native_with_env(&store, owasm_env.clone(), |env: &Environment<E>, _gas: u32| {
50+
env.decrease_gas_left(1)
51+
}),
52+
"get_span_size" => Function::new_native_with_env(&store, owasm_env.clone(), |env: &Environment<E>| {
53+
env.with_vm(|vm| {
54+
vm.env.get_span_size()
55+
})
56+
}),
57+
"read_calldata" => Function::new_native_with_env(&store, owasm_env.clone(), |env: &Environment<E>, ptr: i64| {
58+
env.with_mut_vm(|vm| -> Result<i64, Error>{
59+
let span_size = vm.env.get_span_size();
60+
// consume gas equal size of span when read calldata
61+
env.decrease_gas_left(span_size as u64)?;
62+
63+
let memory = env.memory()?;
64+
require_mem_range(memory.size().bytes().0, (ptr + span_size) as usize)?;
65+
66+
let data = vm.env.get_calldata()?;
67+
68+
for (idx, byte) in data.iter().enumerate() {
69+
memory.view()[ptr as usize + idx].set(*byte);
70+
}
71+
72+
Ok(data.len() as i64)
73+
})
74+
}),
75+
"set_return_data" => Function::new_native_with_env(&store, owasm_env.clone(), |env: &Environment<E>, ptr: i64, len: i64| {
76+
env.with_mut_vm(|vm| {
77+
let span_size = vm.env.get_span_size();
78+
79+
if len > span_size {
80+
return Err(Error::SpanTooSmallError);
81+
}
82+
83+
// consume gas equal size of span when save data to memory
84+
env.decrease_gas_left(span_size as u64)?;
85+
86+
let memory = env.memory()?;
87+
require_mem_range(memory.size().bytes().0, (ptr + span_size) as usize)?;
88+
89+
let data: Vec<u8> = memory.view()[ptr as usize..(ptr + len) as usize].iter().map(|cell| cell.get()).collect();
90+
vm.env.set_return_data(&data)
91+
})
92+
}),
93+
"get_ask_count" => Function::new_native_with_env(&store, owasm_env.clone(), |env: &Environment<E>| {
94+
env.with_vm(|vm| {
95+
vm.env.get_ask_count()
96+
})
97+
}),
98+
"get_min_count" => Function::new_native_with_env(&store, owasm_env.clone(), |env: &Environment<E>| {
99+
env.with_vm(|vm| {
100+
vm.env.get_min_count()
101+
})
102+
}),
103+
"get_prepare_time" => Function::new_native_with_env(&store, owasm_env.clone(), |env: &Environment<E>| {
104+
env.with_vm(|vm| {
105+
vm.env.get_prepare_time()
106+
})
107+
}),
108+
"get_execute_time" => Function::new_native_with_env(&store, owasm_env.clone(), |env: &Environment<E>| {
109+
env.with_vm(|vm| {
110+
vm.env.get_execute_time()
111+
})
112+
}),
113+
"get_ans_count" => Function::new_native_with_env(&store, owasm_env.clone(), |env: &Environment<E>| {
114+
env.with_vm(|vm| {
115+
vm.env.get_ans_count()
116+
})
117+
}),
118+
"ask_external_data" => Function::new_native_with_env(&store, owasm_env.clone(), |env: &Environment<E>, eid: i64, did: i64, ptr: i64, len: i64| {
119+
env.with_mut_vm(|vm| {
120+
let span_size = vm.env.get_span_size();
121+
122+
if len > span_size {
123+
return Err(Error::SpanTooSmallError);
124+
}
125+
126+
// consume gas equal size of span when write calldata for raw request
127+
env.decrease_gas_left(span_size as u64)?;
128+
129+
let memory = env.memory()?;
130+
require_mem_range(memory.size().bytes().0, (ptr + span_size) as usize)?;
131+
132+
let data: Vec<u8> = memory.view()[ptr as usize..(ptr + len) as usize].iter().map(|cell| cell.get()).collect();
133+
vm.env.ask_external_data(eid, did, &data)
134+
})
135+
}),
136+
"get_external_data_status" => Function::new_native_with_env(&store, owasm_env.clone(), |env: &Environment<E>, eid: i64, vid: i64| {
137+
env.with_vm(|vm| {
138+
vm.env.get_external_data_status(eid, vid)
139+
})
140+
}),
141+
"read_external_data" => Function::new_native_with_env(&store, owasm_env.clone(), |env: &Environment<E>, eid: i64, vid: i64, ptr: i64| {
142+
env.with_mut_vm(|vm| -> Result<i64, Error>{
143+
let span_size = vm.env.get_span_size();
144+
// consume gas equal size of span when read data from report
145+
env.decrease_gas_left(span_size as u64)?;
146+
147+
let memory = env.memory()?;
148+
require_mem_range(memory.size().bytes().0, (ptr + span_size) as usize)?;
149+
150+
let data = vm.env.get_external_data(eid, vid)?;
151+
152+
for (idx, byte) in data.iter().enumerate() {
153+
memory.view()[ptr as usize + idx].set(*byte);
154+
}
155+
156+
Ok(data.len() as i64)
157+
})
158+
}),
159+
// "ecvrf_verify" => Function::new_native_with_env(&store, owasm_env.clone(), |env: &Environment<E>, y_ptr: i64, y_len: i64, pi_ptr: i64, pi_len: i64, alpha_ptr: i64, alpha_len: i64| {
160+
// env.with_mut_vm(|vm| -> Result<u32, Error>{
161+
// // consume gas relatively to the function running time (~12ms)
162+
// vm.consume_gas(500000)?;
163+
// env.decrease_gas_left(500000)?;
164+
165+
// let y: Vec<u8> = get_from_mem(env, y_ptr, y_len)?;
166+
// let pi: Vec<u8>= get_from_mem(env, pi_ptr, pi_len)?;
167+
// let alpha: Vec<u8> = get_from_mem(env, alpha_ptr, alpha_len)?;
168+
// Ok(ecvrf::ecvrf_verify(&y, &pi, &alpha) as u32)
169+
// })
170+
// }),
171+
},
172+
};
173+
174+
let instance = cache.get_instance(code, &store, &import_object)?;
175+
let instance_ptr = NonNull::from(&instance);
176+
owasm_env.set_wasmer_instance(Some(instance_ptr));
177+
owasm_env.set_gas_left(gas);
178+
179+
// get function and exec
180+
let entry = if is_prepare { "prepare" } else { "execute" };
181+
let function = instance
182+
.exports
183+
.get_function(entry)
184+
.unwrap()
185+
.native::<(), ()>()
186+
.map_err(|_| Error::BadEntrySignatureError)?;
187+
188+
function.call().map_err(|runtime_err| {
189+
if let Ok(err) = runtime_err.downcast::<Error>() {
190+
return err.clone();
191+
}
192+
193+
match get_remaining_points(&instance) {
194+
MeteringPoints::Remaining(_) => Error::RuntimeError,
195+
MeteringPoints::Exhausted => Error::OutOfGasError,
196+
}
197+
})?;
198+
199+
match get_remaining_points(&instance) {
200+
MeteringPoints::Remaining(count) => Ok(gas.saturating_sub(count)),
201+
MeteringPoints::Exhausted => Err(Error::OutOfGasError),
202+
}
203+
}
204+
205+
#[cfg(test)]
206+
mod test {
207+
use crate::cache::CacheOptions;
208+
209+
use super::*;
210+
use crate::compile::compile;
211+
use std::io::{Read, Write};
212+
use std::process::Command;
213+
use tempfile::NamedTempFile;
214+
215+
pub struct MockEnv {}
216+
217+
impl vm::Env for MockEnv {
218+
fn get_span_size(&self) -> i64 {
219+
30000
220+
}
221+
fn get_calldata(&self) -> Result<Vec<u8>, Error> {
222+
Ok(vec![1])
223+
}
224+
fn set_return_data(&self, _: &[u8]) -> Result<(), Error> {
225+
Ok(())
226+
}
227+
fn get_ask_count(&self) -> i64 {
228+
10
229+
}
230+
fn get_min_count(&self) -> i64 {
231+
8
232+
}
233+
fn get_prepare_time(&self) -> i64 {
234+
100_000
235+
}
236+
fn get_execute_time(&self) -> Result<i64, Error> {
237+
Ok(100_000)
238+
}
239+
fn get_ans_count(&self) -> Result<i64, Error> {
240+
Ok(8)
241+
}
242+
fn ask_external_data(&self, _: i64, _: i64, _: &[u8]) -> Result<(), Error> {
243+
Ok(())
244+
}
245+
fn get_external_data_status(&self, _: i64, _: i64) -> Result<i64, Error> {
246+
Ok(1)
247+
}
248+
fn get_external_data(&self, _: i64, _: i64) -> Result<Vec<u8>, Error> {
249+
Ok(vec![1])
250+
}
251+
}
252+
253+
fn wat2wasm(wat: impl AsRef<[u8]>) -> Vec<u8> {
254+
let mut input_file = NamedTempFile::new().unwrap();
255+
let mut output_file = NamedTempFile::new().unwrap();
256+
input_file.write_all(wat.as_ref()).unwrap();
257+
Command::new("wat2wasm")
258+
.args(&[
259+
input_file.path().to_str().unwrap(),
260+
"-o",
261+
output_file.path().to_str().unwrap(),
262+
])
263+
.output()
264+
.unwrap();
265+
let mut wasm = Vec::new();
266+
output_file.read_to_end(&mut wasm).unwrap();
267+
wasm
268+
}
269+
270+
#[test]
271+
fn test_simple_gas_used() {
272+
let wasm = wat2wasm(
273+
r#"(module
274+
(type (func (param i64 i64 i64 i64) (result)))
275+
(func
276+
(local $idx i32)
277+
(local.set $idx (i32.const 0))
278+
(block
279+
(loop
280+
(local.set $idx (local.get $idx) (i32.const 1) (i32.add) )
281+
(br_if 0 (i32.lt_u (local.get $idx) (i32.const 100000)))
282+
)
283+
)
284+
)
285+
(func (;"execute": Resolves with result "beeb";)
286+
)
287+
(memory 17)
288+
(data (i32.const 1048576) "beeb") (;str = "beeb";)
289+
(export "prepare" (func 0))
290+
(export "execute" (func 1)))
291+
"#,
292+
);
293+
let code = compile(&wasm).unwrap();
294+
let mut cache = Cache::new(CacheOptions { cache_size: 10000 });
295+
let env = MockEnv {};
296+
let gas_used = run(&mut cache, &code, 4294967290, true, env).unwrap();
297+
assert_eq!(gas_used, 800013 as u64);
298+
}
299+
300+
#[test]
301+
fn test_ask_count_gas_used() {
302+
let wasm = wat2wasm(
303+
r#"(module
304+
(type (func (param i64 i64 i64 i64) (result)))
305+
(import "env" "ask_external_data" (func (type 0)))
306+
(func
307+
(local $idx i32)
308+
309+
(i64.const 1)
310+
(i64.const 1)
311+
(i64.const 1048576)
312+
(i64.const 4)
313+
call 0
314+
315+
(local.set $idx (i32.const 0))
316+
(block
317+
(loop
318+
(local.set $idx (local.get $idx) (i32.const 1) (i32.add) )
319+
(br_if 0 (i32.lt_u (local.get $idx) (i32.const 100000)))
320+
)
321+
)
322+
)
323+
(func (;"execute": Resolves with result "beeb";))
324+
(memory (export "memory") 17)
325+
(data (i32.const 1048576) "beeb")
326+
(export "prepare" (func 1))
327+
(export "execute" (func 2)))
328+
"#,
329+
);
330+
331+
let code = compile(&wasm).unwrap();
332+
let mut cache = Cache::new(CacheOptions { cache_size: 10000 });
333+
let env = MockEnv {};
334+
let gas_used = run(&mut cache, &code, 4294967290, true, env).unwrap();
335+
assert_eq!(gas_used, 830018 as u64);
336+
}
337+
}

0 commit comments

Comments
 (0)