near_vm_logic/mocks/
mock_external.rs

1use crate::{External, ValuePtr};
2use near_primitives_core::types::{AccountId, Balance, Gas};
3use near_vm_errors::HostError;
4use serde::{Deserialize, Serialize};
5use std::collections::HashMap;
6
7#[derive(Default, Clone)]
8/// Emulates the trie and the mock handling code.
9pub struct MockedExternal {
10    pub fake_trie: HashMap<Vec<u8>, Vec<u8>>,
11    receipts: Vec<Receipt>,
12    pub validators: HashMap<AccountId, Balance>,
13}
14
15pub struct MockedValuePtr {
16    value: Vec<u8>,
17}
18
19impl MockedValuePtr {
20    pub fn new<T>(value: T) -> Self
21    where
22        T: AsRef<[u8]>,
23    {
24        MockedValuePtr { value: value.as_ref().to_vec() }
25    }
26}
27
28impl ValuePtr for MockedValuePtr {
29    fn len(&self) -> u32 {
30        self.value.len() as u32
31    }
32
33    fn deref(&self) -> crate::dependencies::Result<Vec<u8>> {
34        Ok(self.value.clone())
35    }
36}
37
38impl MockedExternal {
39    pub fn new() -> Self {
40        Self::default()
41    }
42
43    /// Get calls to receipt create that were performed during contract call.
44    pub fn get_receipt_create_calls(&self) -> &Vec<Receipt> {
45        &self.receipts
46    }
47}
48
49use crate::dependencies::Result;
50use crate::types::PublicKey;
51
52impl External for MockedExternal {
53    fn storage_set(&mut self, key: &[u8], value: &[u8]) -> Result<()> {
54        self.fake_trie.insert(key.to_vec(), value.to_vec());
55        Ok(())
56    }
57
58    fn storage_get(&self, key: &[u8]) -> Result<Option<Box<dyn ValuePtr>>> {
59        Ok(self
60            .fake_trie
61            .get(key)
62            .map(|value| Box::new(MockedValuePtr { value: value.clone() }) as Box<_>))
63    }
64
65    fn storage_remove(&mut self, key: &[u8]) -> Result<()> {
66        self.fake_trie.remove(key);
67        Ok(())
68    }
69
70    fn storage_remove_subtree(&mut self, prefix: &[u8]) -> Result<()> {
71        let keys: Vec<_> = self
72            .fake_trie
73            .iter()
74            .filter_map(|(key, _)| if key.starts_with(prefix) { Some(key.clone()) } else { None })
75            .collect();
76        for key in keys {
77            self.fake_trie.remove(&key);
78        }
79        Ok(())
80    }
81
82    fn storage_has_key(&mut self, key: &[u8]) -> Result<bool> {
83        Ok(self.fake_trie.contains_key(key))
84    }
85
86    fn create_receipt(&mut self, receipt_indices: Vec<u64>, receiver_id: String) -> Result<u64> {
87        if let Some(index) = receipt_indices.iter().find(|&&el| el >= self.receipts.len() as u64) {
88            return Err(HostError::InvalidReceiptIndex { receipt_index: *index }.into());
89        }
90        let res = self.receipts.len() as u64;
91        self.receipts.push(Receipt { receipt_indices, receiver_id, actions: vec![] });
92        Ok(res)
93    }
94
95    fn append_action_create_account(&mut self, receipt_index: u64) -> Result<()> {
96        self.receipts.get_mut(receipt_index as usize).unwrap().actions.push(Action::CreateAccount);
97        Ok(())
98    }
99
100    fn append_action_deploy_contract(&mut self, receipt_index: u64, code: Vec<u8>) -> Result<()> {
101        self.receipts
102            .get_mut(receipt_index as usize)
103            .unwrap()
104            .actions
105            .push(Action::DeployContract(DeployContractAction { code }));
106        Ok(())
107    }
108
109    fn append_action_function_call(
110        &mut self,
111        receipt_index: u64,
112        method_name: Vec<u8>,
113        arguments: Vec<u8>,
114        attached_deposit: u128,
115        prepaid_gas: u64,
116    ) -> Result<()> {
117        self.receipts.get_mut(receipt_index as usize).unwrap().actions.push(Action::FunctionCall(
118            FunctionCallAction {
119                method_name,
120                args: arguments,
121                deposit: attached_deposit,
122                gas: prepaid_gas,
123            },
124        ));
125        Ok(())
126    }
127
128    fn append_action_transfer(&mut self, receipt_index: u64, amount: u128) -> Result<()> {
129        self.receipts
130            .get_mut(receipt_index as usize)
131            .unwrap()
132            .actions
133            .push(Action::Transfer(TransferAction { deposit: amount }));
134        Ok(())
135    }
136
137    fn append_action_stake(
138        &mut self,
139        receipt_index: u64,
140        stake: u128,
141        public_key: Vec<u8>,
142    ) -> Result<()> {
143        self.receipts
144            .get_mut(receipt_index as usize)
145            .unwrap()
146            .actions
147            .push(Action::Stake(StakeAction { stake, public_key }));
148        Ok(())
149    }
150
151    fn append_action_add_key_with_full_access(
152        &mut self,
153        receipt_index: u64,
154        public_key: Vec<u8>,
155        nonce: u64,
156    ) -> Result<()> {
157        self.receipts
158            .get_mut(receipt_index as usize)
159            .unwrap()
160            .actions
161            .push(Action::AddKeyWithFullAccess(AddKeyWithFullAccessAction { public_key, nonce }));
162        Ok(())
163    }
164
165    fn append_action_add_key_with_function_call(
166        &mut self,
167        receipt_index: u64,
168        public_key: Vec<u8>,
169        nonce: u64,
170        allowance: Option<u128>,
171        receiver_id: String,
172        method_names: Vec<Vec<u8>>,
173    ) -> Result<()> {
174        self.receipts.get_mut(receipt_index as usize).unwrap().actions.push(
175            Action::AddKeyWithFunctionCall(AddKeyWithFunctionCallAction {
176                public_key,
177                nonce,
178                allowance,
179                receiver_id,
180                method_names,
181            }),
182        );
183        Ok(())
184    }
185
186    fn append_action_delete_key(&mut self, receipt_index: u64, public_key: Vec<u8>) -> Result<()> {
187        self.receipts
188            .get_mut(receipt_index as usize)
189            .unwrap()
190            .actions
191            .push(Action::DeleteKey(DeleteKeyAction { public_key }));
192        Ok(())
193    }
194
195    fn append_action_delete_account(
196        &mut self,
197        receipt_index: u64,
198        beneficiary_id: String,
199    ) -> Result<()> {
200        self.receipts
201            .get_mut(receipt_index as usize)
202            .unwrap()
203            .actions
204            .push(Action::DeleteAccount(DeleteAccountAction { beneficiary_id }));
205        Ok(())
206    }
207
208    fn get_touched_nodes_count(&self) -> u64 {
209        0
210    }
211
212    fn reset_touched_nodes_counter(&mut self) {}
213
214    fn validator_stake(&self, account_id: &AccountId) -> Result<Option<Balance>> {
215        Ok(self.validators.get(account_id).cloned())
216    }
217
218    fn validator_total_stake(&self) -> Result<Balance> {
219        Ok(self.validators.values().sum())
220    }
221}
222
223#[derive(Serialize, Deserialize, Clone, Debug)]
224pub struct Receipt {
225    receipt_indices: Vec<u64>,
226    receiver_id: String,
227    actions: Vec<Action>,
228}
229
230#[derive(Serialize, Deserialize, Clone, Debug)]
231pub enum Action {
232    CreateAccount,
233    DeployContract(DeployContractAction),
234    FunctionCall(FunctionCallAction),
235    Transfer(TransferAction),
236    Stake(StakeAction),
237    AddKeyWithFullAccess(AddKeyWithFullAccessAction),
238    AddKeyWithFunctionCall(AddKeyWithFunctionCallAction),
239    DeleteKey(DeleteKeyAction),
240    DeleteAccount(DeleteAccountAction),
241}
242
243#[derive(Serialize, Deserialize, Clone, Debug)]
244pub struct DeployContractAction {
245    pub code: Vec<u8>,
246}
247
248#[derive(Serialize, Deserialize, Clone, Debug)]
249pub struct FunctionCallAction {
250    #[serde(with = "crate::serde_with::bytes_as_str")]
251    method_name: Vec<u8>,
252    /// Most function calls still take JSON as input, so we'll keep it there as a string.
253    /// Once we switch to borsh, we'll have to switch to base64 encoding.
254    /// Right now, it is only used with standalone runtime when passing in Receipts or expecting
255    /// receipts. The workaround for input is to use a VMContext input.
256    #[serde(with = "crate::serde_with::bytes_as_str")]
257    args: Vec<u8>,
258    gas: Gas,
259    deposit: Balance,
260}
261
262#[derive(Serialize, Deserialize, Clone, Debug)]
263pub struct TransferAction {
264    deposit: Balance,
265}
266
267#[derive(Serialize, Deserialize, Clone, Debug)]
268pub struct StakeAction {
269    stake: Balance,
270    #[serde(with = "crate::serde_with::bytes_as_base58")]
271    public_key: PublicKey,
272}
273
274#[derive(Serialize, Deserialize, Clone, Debug)]
275pub struct AddKeyWithFullAccessAction {
276    #[serde(with = "crate::serde_with::bytes_as_base58")]
277    public_key: PublicKey,
278    nonce: u64,
279}
280
281#[derive(Serialize, Deserialize, Clone, Debug)]
282pub struct AddKeyWithFunctionCallAction {
283    #[serde(with = "crate::serde_with::bytes_as_base58")]
284    public_key: PublicKey,
285    nonce: u64,
286    allowance: Option<Balance>,
287    receiver_id: AccountId,
288    #[serde(with = "crate::serde_with::vec_bytes_as_str")]
289    method_names: Vec<Vec<u8>>,
290}
291
292#[derive(Serialize, Deserialize, Clone, Debug)]
293pub struct DeleteKeyAction {
294    #[serde(with = "crate::serde_with::bytes_as_base58")]
295    public_key: PublicKey,
296}
297
298#[derive(Serialize, Deserialize, Clone, Debug)]
299pub struct DeleteAccountAction {
300    beneficiary_id: AccountId,
301}