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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
use crate::{
api::types::GearPages,
metadata::{
env,
ext::Ext,
result::{Error, Result},
StoreData,
},
};
use wasmtime::{
AsContext, AsContextMut, Config, Engine, Extern, Func, Instance, Linker, Memory, Module, Store,
Val,
};
const PAGE_SIZE: usize = 4096;
const META_STATE: &str = "meta_state";
pub fn execute<R>(wasm: &[u8], f: impl Fn(Reader) -> Result<R>) -> Result<R> {
let engine = Engine::default();
let module = Module::new(&engine, &mut &wasm[..])?;
let mut store = Store::new(&engine, Default::default());
let mut linker = <Linker<StoreData>>::new(&engine);
env::apply(&mut store, &mut linker)?;
let instance = linker.instantiate(&mut store, &module)?;
f(Reader {
instance,
linker,
store,
})
}
pub struct Reader {
instance: Instance,
linker: Linker<StoreData>,
pub store: Store<StoreData>,
}
impl Reader {
pub fn func(&mut self, name: impl AsRef<str>) -> Result<Func> {
let meta = name.as_ref();
self.instance
.get_func(self.store.as_context_mut(), meta)
.ok_or_else(|| Error::MetadataNotExists(meta.into()))
}
pub fn memory(&mut self) -> Result<Memory> {
if let Some(Extern::Memory(mem)) =
self.linker
.get(self.store.as_context_mut(), "env", "memory")
{
Ok(mem)
} else {
Err(Error::MemoryNotExists)
}
}
pub fn meta(&mut self, memory: &Memory, meta: &str) -> Result<Vec<u8>> {
let mut res = [Val::null()];
self.func(meta)?.call(&mut self.store, &[], &mut res)?;
let at = if let Val::I32(at) = res[0] {
at as usize
} else {
return Err(Error::ReadMetadataFailed(meta.into()));
};
let mem = memory.data(&self.store);
let mut ptr_bytes = [0; 4];
ptr_bytes.copy_from_slice(&mem[at..(at + 4)]);
let ptr = i32::from_le_bytes(ptr_bytes) as usize;
let mut len_bytes = [0; 4];
len_bytes.copy_from_slice(&mem[(at + 4)..(at + 8)]);
let len = i32::from_le_bytes(len_bytes) as usize;
Ok(mem[ptr..(ptr + len)].into())
}
pub fn state(
&mut self,
initial_size: u64,
pages: GearPages,
msg: Vec<u8>,
timestamp: u64,
height: u64,
) -> Result<Vec<u8>> {
let mem = self.memory()?;
let mem_size = mem.size(&self.store);
if mem_size < initial_size {
mem.grow(self.store.as_context_mut(), initial_size - mem_size)?;
}
let data = self.store.data_mut();
data.msg = msg;
data.timestamp = timestamp;
data.height = height;
let mem_mut = mem.data_mut(self.store.as_context_mut());
for (idx, page) in pages {
let start = (idx as usize) * PAGE_SIZE;
let end = start + PAGE_SIZE;
mem_mut[start..end].copy_from_slice(&page);
}
self.meta(&mem, META_STATE)
}
}