wasmer_runtime_core_near/
cache.rs1use crate::{module::ModuleInfo, sys::Memory};
6use borsh::{BorshDeserialize, BorshSerialize};
7use std::{io, mem, slice};
8
9#[derive(Debug)]
11pub enum InvalidFileType {
12 InvalidSize,
14 InvalidMagic,
16}
17
18#[derive(Debug)]
20pub enum Error {
21 IoError(io::Error),
23 DeserializeError(String),
25 SerializeError(String),
27 Unknown(String),
29 InvalidFile(InvalidFileType),
31 InvalidatedCache,
33 UnsupportedBackend(String),
35}
36
37impl From<io::Error> for Error {
38 fn from(io_err: io::Error) -> Self {
39 Error::IoError(io_err)
40 }
41}
42
43#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
49pub struct WasmHash([u8; 32]);
51
52impl WasmHash {
53 pub fn generate(wasm: &[u8]) -> Self {
59 let hash = blake3::hash(wasm);
60 WasmHash(hash.into())
61 }
62
63 pub fn encode(self) -> String {
66 hex::encode(&self.into_array() as &[u8])
67 }
68
69 pub fn decode(hex_str: &str) -> Result<Self, Error> {
71 let bytes = hex::decode(hex_str).map_err(|e| {
72 Error::DeserializeError(format!(
73 "Could not decode prehashed key as hexadecimal: {}",
74 e
75 ))
76 })?;
77 if bytes.len() != 32 {
78 return Err(Error::DeserializeError(
79 "Prehashed keys must deserialze into exactly 32 bytes".to_string(),
80 ));
81 }
82 use std::convert::TryInto;
83 Ok(WasmHash(bytes[0..32].try_into().map_err(|e| {
84 Error::DeserializeError(format!("Could not get first 32 bytes: {}", e))
85 })?))
86 }
87
88 pub(crate) fn into_array(self) -> [u8; 32] {
89 let mut total = [0u8; 32];
90 total[0..32].copy_from_slice(&self.0);
91 total
92 }
93}
94
95const CURRENT_CACHE_VERSION: u64 = 0;
96static WASMER_CACHE_MAGIC: [u8; 8] = *b"WASMER\0\0";
97
98#[repr(C, packed)]
100struct ArtifactHeader {
101 magic: [u8; 8], version: u64,
103 data_len: u64,
104}
105
106impl ArtifactHeader {
107 pub fn read_from_slice(buffer: &[u8]) -> Result<(&Self, &[u8]), Error> {
108 if buffer.len() >= mem::size_of::<ArtifactHeader>() {
109 if &buffer[..8] == &WASMER_CACHE_MAGIC {
110 let (header_slice, body_slice) = buffer.split_at(mem::size_of::<ArtifactHeader>());
111 let header = unsafe { &*(header_slice.as_ptr() as *const ArtifactHeader) };
112
113 if header.version == CURRENT_CACHE_VERSION {
114 Ok((header, body_slice))
115 } else {
116 Err(Error::InvalidatedCache)
117 }
118 } else {
119 Err(Error::InvalidFile(InvalidFileType::InvalidMagic))
120 }
121 } else {
122 Err(Error::InvalidFile(InvalidFileType::InvalidSize))
123 }
124 }
125
126 pub fn read_from_slice_mut(buffer: &mut [u8]) -> Result<(&mut Self, &mut [u8]), Error> {
127 if buffer.len() >= mem::size_of::<ArtifactHeader>() {
128 if &buffer[..8] == &WASMER_CACHE_MAGIC {
129 let (header_slice, body_slice) =
130 buffer.split_at_mut(mem::size_of::<ArtifactHeader>());
131 let header = unsafe { &mut *(header_slice.as_ptr() as *mut ArtifactHeader) };
132
133 if header.version == CURRENT_CACHE_VERSION {
134 Ok((header, body_slice))
135 } else {
136 Err(Error::InvalidatedCache)
137 }
138 } else {
139 Err(Error::InvalidFile(InvalidFileType::InvalidMagic))
140 }
141 } else {
142 Err(Error::InvalidFile(InvalidFileType::InvalidSize))
143 }
144 }
145
146 pub fn as_slice(&self) -> &[u8] {
147 let ptr = self as *const ArtifactHeader as *const u8;
148 unsafe { slice::from_raw_parts(ptr, mem::size_of::<ArtifactHeader>()) }
149 }
150}
151
152#[derive(Serialize, Deserialize, BorshSerialize, BorshDeserialize)]
153struct ArtifactInner {
154 info: Box<ModuleInfo>,
155 #[serde(with = "serde_bytes")]
156 backend_metadata: Box<[u8]>,
157 compiled_code: Memory,
158}
159
160pub struct Artifact {
163 inner: ArtifactInner,
164}
165
166impl Artifact {
167 pub(crate) fn from_parts(
168 info: Box<ModuleInfo>,
169 backend_metadata: Box<[u8]>,
170 compiled_code: Memory,
171 ) -> Self {
172 Self {
173 inner: ArtifactInner {
174 info,
175 backend_metadata,
176 compiled_code,
177 },
178 }
179 }
180
181 pub fn deserialize(bytes: &[u8]) -> Result<Self, Error> {
183 let (_, body_slice) = ArtifactHeader::read_from_slice(bytes)?;
184
185 let inner = ArtifactInner::try_from_slice(body_slice)
186 .map_err(|e| Error::DeserializeError(format!("{:#?}", e)))?;
187
188 Ok(Artifact { inner })
189 }
190
191 pub fn info(&self) -> &ModuleInfo {
193 &self.inner.info
194 }
195
196 #[doc(hidden)]
197 pub fn consume(self) -> (ModuleInfo, Box<[u8]>, Memory) {
198 (
199 *self.inner.info,
200 self.inner.backend_metadata,
201 self.inner.compiled_code,
202 )
203 }
204
205 pub fn serialize(&self) -> Result<Vec<u8>, Error> {
207 let cache_header = ArtifactHeader {
208 magic: WASMER_CACHE_MAGIC,
209 version: CURRENT_CACHE_VERSION,
210 data_len: 0,
211 };
212
213 let mut buffer = cache_header.as_slice().to_vec();
214
215 let mut encoded =
216 borsh::to_vec(&self.inner).map_err(|e| Error::SerializeError(e.to_string()))?;
217 buffer.append(&mut encoded);
218
219 let data_len = (buffer.len() - mem::size_of::<ArtifactHeader>()) as u64;
220
221 let (header, _) = ArtifactHeader::read_from_slice_mut(&mut buffer)?;
222 header.data_len = data_len;
223
224 Ok(buffer)
225 }
226}
227
228pub const WASMER_VERSION_HASH: &'static str =
230 include_str!(concat!(env!("OUT_DIR"), "/wasmer_version_hash.txt"));