use super::{Receipt, VmAction};
use crate::types::Balance;
use near_vm_logic::{External, HostError, ValuePtr};
use std::collections::HashMap;
type Result<T> = ::core::result::Result<T, near_vm_logic::VMLogicError>;
#[derive(Default, Clone)]
pub(crate) struct SdkExternal {
pub fake_trie: HashMap<Vec<u8>, Vec<u8>>,
pub receipts: Vec<Receipt>,
pub validators: HashMap<String, Balance>,
}
pub struct MockedValuePtr {
value: Vec<u8>,
}
impl ValuePtr for MockedValuePtr {
fn len(&self) -> u32 {
self.value.len() as u32
}
fn deref(&self) -> Result<Vec<u8>> {
Ok(self.value.clone())
}
}
impl SdkExternal {
pub fn new() -> Self {
Self::default()
}
}
impl External for SdkExternal {
fn storage_set(&mut self, key: &[u8], value: &[u8]) -> Result<()> {
self.fake_trie.insert(key.to_vec(), value.to_vec());
Ok(())
}
fn storage_get(&self, key: &[u8]) -> Result<Option<Box<dyn ValuePtr>>> {
Ok(self.fake_trie.get(key).map(|value| {
Box::new(MockedValuePtr {
value: value.clone(),
}) as Box<_>
}))
}
fn storage_remove(&mut self, key: &[u8]) -> Result<()> {
self.fake_trie.remove(key);
Ok(())
}
fn storage_remove_subtree(&mut self, prefix: &[u8]) -> Result<()> {
self.fake_trie.retain(|key, _| !key.starts_with(prefix));
Ok(())
}
fn storage_has_key(&mut self, key: &[u8]) -> Result<bool> {
Ok(self.fake_trie.contains_key(key))
}
fn create_receipt(&mut self, receipt_indices: Vec<u64>, receiver_id: String) -> Result<u64> {
if let Some(index) = receipt_indices
.iter()
.find(|&&el| el >= self.receipts.len() as u64)
{
return Err(HostError::InvalidReceiptIndex {
receipt_index: *index,
}
.into());
}
let res = self.receipts.len() as u64;
self.receipts.push(Receipt {
receipt_indices,
receiver_id,
actions: vec![],
});
Ok(res)
}
fn append_action_create_account(&mut self, receipt_index: u64) -> Result<()> {
self.receipts
.get_mut(receipt_index as usize)
.unwrap()
.actions
.push(VmAction::CreateAccount);
Ok(())
}
fn append_action_deploy_contract(&mut self, receipt_index: u64, code: Vec<u8>) -> Result<()> {
self.receipts
.get_mut(receipt_index as usize)
.unwrap()
.actions
.push(VmAction::DeployContract { code });
Ok(())
}
fn append_action_function_call(
&mut self,
receipt_index: u64,
method_name: Vec<u8>,
arguments: Vec<u8>,
attached_deposit: u128,
prepaid_gas: u64,
) -> Result<()> {
self.receipts
.get_mut(receipt_index as usize)
.unwrap()
.actions
.push(VmAction::FunctionCall {
method_name: String::from_utf8(method_name).unwrap(),
args: arguments,
deposit: attached_deposit,
gas: prepaid_gas,
});
Ok(())
}
fn append_action_transfer(&mut self, receipt_index: u64, amount: u128) -> Result<()> {
self.receipts
.get_mut(receipt_index as usize)
.unwrap()
.actions
.push(VmAction::Transfer { deposit: amount });
Ok(())
}
fn append_action_stake(
&mut self,
receipt_index: u64,
stake: u128,
public_key: Vec<u8>,
) -> Result<()> {
self.receipts
.get_mut(receipt_index as usize)
.unwrap()
.actions
.push(VmAction::Stake { stake, public_key });
Ok(())
}
fn append_action_add_key_with_full_access(
&mut self,
receipt_index: u64,
public_key: Vec<u8>,
nonce: u64,
) -> Result<()> {
self.receipts
.get_mut(receipt_index as usize)
.unwrap()
.actions
.push(VmAction::AddKeyWithFullAccess { public_key, nonce });
Ok(())
}
fn append_action_add_key_with_function_call(
&mut self,
receipt_index: u64,
public_key: Vec<u8>,
nonce: u64,
allowance: Option<u128>,
receiver_id: String,
method_names: Vec<Vec<u8>>,
) -> Result<()> {
let method_names = method_names
.into_iter()
.map(|s| String::from_utf8(s).unwrap())
.collect();
self.receipts
.get_mut(receipt_index as usize)
.unwrap()
.actions
.push(VmAction::AddKeyWithFunctionCall {
public_key,
nonce,
allowance,
receiver_id,
method_names,
});
Ok(())
}
fn append_action_delete_key(&mut self, receipt_index: u64, public_key: Vec<u8>) -> Result<()> {
self.receipts
.get_mut(receipt_index as usize)
.unwrap()
.actions
.push(VmAction::DeleteKey { public_key });
Ok(())
}
fn append_action_delete_account(
&mut self,
receipt_index: u64,
beneficiary_id: String,
) -> Result<()> {
self.receipts
.get_mut(receipt_index as usize)
.unwrap()
.actions
.push(VmAction::DeleteAccount { beneficiary_id });
Ok(())
}
fn get_touched_nodes_count(&self) -> u64 {
0
}
fn reset_touched_nodes_counter(&mut self) {}
fn validator_stake(&self, account_id: &String) -> Result<Option<Balance>> {
Ok(self.validators.get(account_id).cloned())
}
fn validator_total_stake(&self) -> Result<Balance> {
Ok(self.validators.values().sum())
}
}