near_vm_logic/dependencies.rs
1//! External dependencies of the near-vm-logic.
2
3use crate::types::{PublicKey, ReceiptIndex};
4use near_primitives_core::types::{AccountId, Balance, Gas};
5use near_vm_errors::VMLogicError;
6
7/// An abstraction over the memory of the smart contract.
8pub trait MemoryLike {
9 /// Returns whether the memory interval is completely inside the smart contract memory.
10 fn fits_memory(&self, offset: u64, len: u64) -> bool;
11
12 /// Reads the content of the given memory interval.
13 ///
14 /// # Panics
15 ///
16 /// If memory interval is outside the smart contract memory.
17 fn read_memory(&self, offset: u64, buffer: &mut [u8]);
18
19 /// Reads a single byte from the memory.
20 ///
21 /// # Panics
22 ///
23 /// If pointer is outside the smart contract memory.
24 fn read_memory_u8(&self, offset: u64) -> u8;
25
26 /// Writes the buffer into the smart contract memory.
27 ///
28 /// # Panics
29 ///
30 /// If `offset + buffer.len()` is outside the smart contract memory.
31 fn write_memory(&mut self, offset: u64, buffer: &[u8]);
32}
33
34pub type Result<T> = ::std::result::Result<T, VMLogicError>;
35
36/// Logical pointer to a value in storage.
37/// Allows getting value length before getting the value itself. This is needed so that runtime
38/// can charge gas before accessing a potentially large value.
39pub trait ValuePtr {
40 /// Returns the length of the value
41 fn len(&self) -> u32;
42
43 /// Dereferences the pointer.
44 /// Takes a box because currently runtime code uses dynamic dispatch.
45 /// # Errors
46 /// StorageError if reading from storage fails
47 fn deref(&self) -> Result<Vec<u8>>;
48}
49
50/// An external blockchain interface for the Runtime logic
51pub trait External {
52 /// Write to the storage trie of the current account
53 ///
54 /// # Arguments
55 ///
56 /// * `key` - a key for a new value
57 /// * `value` - a new value to be set
58 ///
59 /// # Errors
60 ///
61 /// This function could return HostErrorOrStorageError::StorageError on underlying DB failure
62 ///
63 /// # Example
64 /// ```
65 /// # use near_vm_logic::mocks::mock_external::MockedExternal;
66 /// # use near_vm_logic::External;
67 ///
68 /// # let mut external = MockedExternal::new();
69 /// assert_eq!(external.storage_set(b"key42", b"value1337"), Ok(()));
70 /// // Should return an old value if the key exists
71 /// assert_eq!(external.storage_set(b"key42", b"new_value"), Ok(()));
72 /// ```
73 fn storage_set(&mut self, key: &[u8], value: &[u8]) -> Result<()>;
74
75 /// Reads from the storage trie of the current account
76 ///
77 /// # Arguments
78 ///
79 /// * `key` - a key to read
80 ///
81 /// # Errors
82 ///
83 /// This function could return HostErrorOrStorageError::StorageError on underlying DB failure
84 ///
85 /// # Example
86 /// ```
87 /// # use near_vm_logic::mocks::mock_external::{MockedExternal};
88 /// # use near_vm_logic::{External, ValuePtr};
89 ///
90 /// # let mut external = MockedExternal::new();
91 /// external.storage_set(b"key42", b"value1337").unwrap();
92 /// assert_eq!(external.storage_get(b"key42").unwrap().map(|ptr| ptr.deref().unwrap()), Some(b"value1337".to_vec()));
93 /// // Returns Ok(None) if there is no value for a key
94 /// assert_eq!(external.storage_get(b"no_key").unwrap().map(|ptr| ptr.deref().unwrap()), None);
95 /// ```
96 fn storage_get<'a>(&'a self, key: &[u8]) -> Result<Option<Box<dyn ValuePtr + 'a>>>;
97
98 /// Removes the key from the storage
99 ///
100 /// # Arguments
101 ///
102 /// * `key` - a key to remove
103 ///
104 /// # Errors
105 ///
106 /// This function could return HostErrorOrStorageError::StorageError on underlying DB failure
107 ///
108 /// # Example
109 /// ```
110 /// # use near_vm_logic::mocks::mock_external::MockedExternal;
111 /// # use near_vm_logic::External;
112 ///
113 /// # let mut external = MockedExternal::new();
114 /// external.storage_set(b"key42", b"value1337").unwrap();
115 /// // Returns Ok if exists
116 /// assert_eq!(external.storage_remove(b"key42"), Ok(()));
117 /// // Returns Ok if there was no value
118 /// assert_eq!(external.storage_remove(b"no_value_key"), Ok(()));
119 /// ```
120 fn storage_remove(&mut self, key: &[u8]) -> Result<()>;
121
122 /// Removes all keys under given suffix in the storage.
123 ///
124 /// # Arguments
125 ///
126 /// * `prefix` - a prefix for all keys to remove
127 ///
128 /// # Errors
129 ///
130 /// This function could return HostErrorOrStorageError::StorageError on underlying DB failure
131 ///
132 /// # Example
133 /// ```
134 /// # use near_vm_logic::mocks::mock_external::MockedExternal;
135 /// # use near_vm_logic::External;
136 ///
137 /// # let mut external = MockedExternal::new();
138 /// external.storage_set(b"key1", b"value1337").unwrap();
139 /// external.storage_set(b"key2", b"value1337").unwrap();
140 /// assert_eq!(external.storage_remove_subtree(b"key"), Ok(()));
141 /// assert!(!external.storage_has_key(b"key1").unwrap());
142 /// assert!(!external.storage_has_key(b"key2").unwrap());
143 /// ```
144 fn storage_remove_subtree(&mut self, prefix: &[u8]) -> Result<()>;
145
146 /// Check whether key exists. Returns Ok(true) if key exists or Ok(false) otherwise
147 ///
148 /// # Arguments
149 ///
150 /// * `key` - a key to check
151 ///
152 /// # Errors
153 ///
154 /// This function could return HostErrorOrStorageError::StorageError on underlying DB failure
155 ///
156 /// # Example
157 /// ```
158 /// # use near_vm_logic::mocks::mock_external::MockedExternal;
159 /// # use near_vm_logic::External;
160 ///
161 /// # let mut external = MockedExternal::new();
162 /// external.storage_set(b"key42", b"value1337").unwrap();
163 /// // Returns value if exists
164 /// assert_eq!(external.storage_has_key(b"key42"), Ok(true));
165 /// // Returns None if there was no value
166 /// assert_eq!(external.storage_has_key(b"no_value_key"), Ok(false));
167 /// ```
168 fn storage_has_key(&mut self, key: &[u8]) -> Result<bool>;
169
170 /// Creates a receipt which will be executed after `receipt_indices`
171 ///
172 /// # Arguments
173 ///
174 /// * `receipt_indices` - a list of receipt indices the new receipt is depend on
175 ///
176 /// # Example
177 /// ```
178 /// # use near_vm_logic::mocks::mock_external::MockedExternal;
179 /// # use near_vm_logic::External;
180 ///
181 /// # let mut external = MockedExternal::new();
182 /// let receipt_index_one = external.create_receipt(vec![], "charli.near".to_owned()).unwrap();
183 /// let receipt_index_two = external.create_receipt(vec![receipt_index_one], "bob.near".to_owned());
184 ///
185 /// ```
186 ///
187 /// # Panics
188 /// Panics if one of `receipt_indices` is missing
189 fn create_receipt(
190 &mut self,
191 receipt_indices: Vec<ReceiptIndex>,
192 receiver_id: AccountId,
193 ) -> Result<ReceiptIndex>;
194
195 /// Attaches an `Action::CreateAccount` action to an existing receipt
196 ///
197 /// # Arguments
198 ///
199 /// * `receipt_index` - an index of Receipt to append an action
200 ///
201 /// # Example
202 /// ```
203 /// # use near_vm_logic::mocks::mock_external::MockedExternal;
204 /// # use near_vm_logic::External;
205 ///
206 /// # let mut external = MockedExternal::new();
207 /// let receipt_index = external.create_receipt(vec![], "charli.near".to_owned()).unwrap();
208 /// external.append_action_create_account(receipt_index).unwrap();
209 ///
210 /// ```
211 ///
212 /// # Panics
213 /// Panics if `receipt_index` is missing
214 fn append_action_create_account(&mut self, receipt_index: ReceiptIndex) -> Result<()>;
215
216 /// Attaches an `Action::DeployContract` action to an existing receipt
217 ///
218 /// # Arguments
219 ///
220 /// * `receipt_index` - an index of Receipt to append an action
221 /// * `code` - a Wasm code to attach
222 ///
223 /// # Example
224 /// ```
225 /// # use near_vm_logic::mocks::mock_external::MockedExternal;
226 /// # use near_vm_logic::External;
227 ///
228 /// # let mut external = MockedExternal::new();
229 /// let receipt_index = external.create_receipt(vec![], "charli.near".to_owned()).unwrap();
230 /// external.append_action_deploy_contract(receipt_index, b"some valid Wasm code".to_vec()).unwrap();
231 ///
232 /// ```
233 ///
234 /// # Panics
235 /// Panics if `receipt_index` is missing
236 fn append_action_deploy_contract(
237 &mut self,
238 receipt_index: ReceiptIndex,
239 code: Vec<u8>,
240 ) -> Result<()>;
241
242 /// Attaches an `Action::FunctionCall` action to an existing receipt
243 ///
244 /// # Arguments
245 ///
246 /// * `receipt_index` - an index of Receipt to append an action
247 /// * `method_name` - a name of the contract method to call
248 /// * `arguments` - a Wasm code to attach
249 /// * `attached_deposit` - amount of tokens to transfer with the call
250 /// * `prepaid_gas` - amount of prepaid gas to attach to the call
251 ///
252 /// # Example
253 /// ```
254 /// # use near_vm_logic::mocks::mock_external::MockedExternal;
255 /// # use near_vm_logic::External;
256 ///
257 /// # let mut external = MockedExternal::new();
258 /// let receipt_index = external.create_receipt(vec![], "charli.near".to_owned()).unwrap();
259 /// external.append_action_function_call(
260 /// receipt_index,
261 /// b"method_name".to_vec(),
262 /// b"{serialised: arguments}".to_vec(),
263 /// 100000u128,
264 /// 100u64
265 /// ).unwrap();
266 ///
267 /// ```
268 ///
269 /// # Panics
270 /// Panics if `receipt_index` is missing
271 fn append_action_function_call(
272 &mut self,
273 receipt_index: ReceiptIndex,
274 method_name: Vec<u8>,
275 arguments: Vec<u8>,
276 attached_deposit: Balance,
277 prepaid_gas: Gas,
278 ) -> Result<()>;
279
280 /// Attaches an `TransferAction` action to an existing receipt
281 ///
282 /// # Arguments
283 ///
284 /// * `receipt_index` - an index of Receipt to append an action
285 /// * `amount` - amount of tokens to transfer
286 ///
287 /// # Example
288 /// ```
289 /// # use near_vm_logic::mocks::mock_external::MockedExternal;
290 /// # use near_vm_logic::External;
291 ///
292 /// # let mut external = MockedExternal::new();
293 /// let receipt_index = external.create_receipt(vec![], "charli.near".to_owned()).unwrap();
294 /// external.append_action_transfer(
295 /// receipt_index,
296 /// 100000u128,
297 /// ).unwrap();
298 ///
299 /// ```
300 ///
301 /// # Panics
302 /// Panics if `receipt_index` is missing
303 fn append_action_transfer(
304 &mut self,
305 receipt_index: ReceiptIndex,
306 amount: Balance,
307 ) -> Result<()>;
308
309 /// Attaches an `StakeAction` action to an existing receipt
310 ///
311 /// # Arguments
312 ///
313 /// * `receipt_index` - an index of Receipt to append an action
314 /// * `stake` - amount of tokens to stake
315 /// * `public_key` - a validator public key
316 ///
317 /// # Example
318 /// ```
319 /// # use near_vm_logic::mocks::mock_external::MockedExternal;
320 /// # use near_vm_logic::External;
321 ///
322 /// # let mut external = MockedExternal::new();
323 /// let receipt_index = external.create_receipt(vec![], "charli.near".to_owned()).unwrap();
324 /// external.append_action_stake(
325 /// receipt_index,
326 /// 100000u128,
327 /// b"some public key".to_vec()
328 /// ).unwrap();
329 ///
330 /// ```
331 ///
332 /// # Panics
333 /// Panics if `receipt_index` is missing
334 fn append_action_stake(
335 &mut self,
336 receipt_index: ReceiptIndex,
337 stake: Balance,
338 public_key: PublicKey,
339 ) -> Result<()>;
340
341 /// Attaches an `AddKeyAction` action to an existing receipt
342 ///
343 /// # Arguments
344 ///
345 /// * `receipt_index` - an index of Receipt to append an action
346 /// * `public_key` - a public key for an access key
347 /// * `nonce` - a nonce
348 ///
349 /// # Example
350 /// ```
351 /// # use near_vm_logic::mocks::mock_external::MockedExternal;
352 /// # use near_vm_logic::External;
353 ///
354 /// # let mut external = MockedExternal::new();
355 /// let receipt_index = external.create_receipt(vec![], "charli.near".to_owned()).unwrap();
356 /// external.append_action_add_key_with_full_access(
357 /// receipt_index,
358 /// b"some public key".to_vec(),
359 /// 0u64
360 /// ).unwrap();
361 ///
362 /// ```
363 ///
364 /// # Panics
365 /// Panics if `receipt_index` is missing
366 fn append_action_add_key_with_full_access(
367 &mut self,
368 receipt_index: ReceiptIndex,
369 public_key: PublicKey,
370 nonce: u64,
371 ) -> Result<()>;
372
373 /// Attaches an `AddKeyAction` action to an existing receipt with `AccessKeyPermission::FunctionCall`
374 ///
375 /// # Arguments
376 ///
377 /// * `receipt_index` - an index of Receipt to append an action
378 /// * `public_key` - a public key for an access key
379 /// * `nonce` - a nonce
380 /// * `allowance` - amount of tokens allowed to spend by this access key
381 /// * `receiver_id` - a contract witch will be allowed to call with this access key
382 /// * `method_names` - a list of method names is allowed to call with this access key (empty = any method)
383 ///
384 /// # Example
385 /// ```
386 /// # use near_vm_logic::mocks::mock_external::MockedExternal;
387 /// # use near_vm_logic::External;
388 ///
389 /// # let mut external = MockedExternal::new();
390 /// let receipt_index = external.create_receipt(vec![], "charli.near".to_owned()).unwrap();
391 /// external.append_action_add_key_with_function_call(
392 /// receipt_index,
393 /// b"some public key".to_vec(),
394 /// 0u64,
395 /// None,
396 /// "bob.near".to_owned(),
397 /// vec![b"foo".to_vec(), b"bar".to_vec()]
398 /// ).unwrap();
399 ///
400 /// ```
401 ///
402 /// # Panics
403 /// Panics if `receipt_index` is missing
404 fn append_action_add_key_with_function_call(
405 &mut self,
406 receipt_index: ReceiptIndex,
407 public_key: PublicKey,
408 nonce: u64,
409 allowance: Option<Balance>,
410 receiver_id: AccountId,
411 method_names: Vec<Vec<u8>>,
412 ) -> Result<()>;
413
414 /// Attaches an `DeleteKeyAction` action to an existing receipt
415 ///
416 /// # Arguments
417 ///
418 /// * `receipt_index` - an index of Receipt to append an action
419 /// * `public_key` - a public key for an access key to delete
420 ///
421 /// # Example
422 /// ```
423 /// # use near_vm_logic::mocks::mock_external::MockedExternal;
424 /// # use near_vm_logic::External;
425 ///
426 /// # let mut external = MockedExternal::new();
427 /// let receipt_index = external.create_receipt(vec![], "charli.near".to_owned()).unwrap();
428 /// external.append_action_delete_key(
429 /// receipt_index,
430 /// b"some public key".to_vec()
431 /// ).unwrap();
432 ///
433 /// ```
434 ///
435 /// # Panics
436 /// Panics if `receipt_index` is missing
437 fn append_action_delete_key(
438 &mut self,
439 receipt_index: ReceiptIndex,
440 public_key: PublicKey,
441 ) -> Result<()>;
442
443 /// Attaches an `DeleteAccountAction` action to an existing receipt
444 ///
445 /// # Arguments
446 ///
447 /// * `receipt_index` - an index of Receipt to append an action
448 /// * `beneficiary_id` - an account id to which the rest of the funds of the removed account will be transferred
449 ///
450 /// # Example
451 /// ```
452 /// # use near_vm_logic::mocks::mock_external::MockedExternal;
453 /// # use near_vm_logic::External;
454 ///
455 /// # let mut external = MockedExternal::new();
456 /// let receipt_index = external.create_receipt(vec![], "charli.near".to_owned()).unwrap();
457 /// external.append_action_delete_account(
458 /// receipt_index,
459 /// "sam".to_owned()
460 /// ).unwrap();
461 ///
462 /// ```
463 ///
464 /// # Panics
465 /// Panics if `receipt_index` is missing
466 fn append_action_delete_account(
467 &mut self,
468 receipt_index: ReceiptIndex,
469 beneficiary_id: AccountId,
470 ) -> Result<()>;
471
472 /// Returns amount of touched trie nodes by storage operations
473 fn get_touched_nodes_count(&self) -> u64;
474
475 /// Resets amount of touched trie nodes by storage operations
476 fn reset_touched_nodes_counter(&mut self);
477
478 /// Returns the validator stake for given account in the current epoch.
479 /// If the account is not a validator, returns `None`.
480 fn validator_stake(&self, account_id: &AccountId) -> Result<Option<Balance>>;
481
482 /// Returns total stake of validators in the current epoch.
483 fn validator_total_stake(&self) -> Result<Balance>;
484}