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}