use crate::{counters::CRITICAL_ERRORS, create_access_path, logging::AdapterLogSchema};
#[allow(unused_imports)]
use anyhow::format_err;
use anyhow::Error;
use aptos_logger::prelude::*;
use aptos_state_view::{StateView, StateViewId};
use aptos_types::{
access_path::AccessPath,
on_chain_config::ConfigStorage,
state_store::state_key::StateKey,
vm_status::StatusCode,
write_set::{WriteOp, WriteSet},
};
use fail::fail_point;
use move_deps::{
move_binary_format::errors::*,
move_core_types::{
account_address::AccountAddress,
language_storage::{ModuleId, StructTag},
resolver::{ModuleResolver, ResourceResolver},
},
move_table_extension::{TableHandle, TableOperation, TableResolver},
};
use std::{
collections::btree_map::BTreeMap,
ops::{Deref, DerefMut},
};
pub struct StateViewCache<'a, S> {
data_view: &'a S,
data_map: BTreeMap<StateKey, Option<Vec<u8>>>,
}
impl<'a, S: StateView> StateViewCache<'a, S> {
pub fn new(data_view: &'a S) -> Self {
StateViewCache {
data_view,
data_map: BTreeMap::new(),
}
}
pub(crate) fn push_write_set(&mut self, write_set: &WriteSet) {
for (ref ap, ref write_op) in write_set.iter() {
match write_op {
WriteOp::Value(blob) => {
self.data_map.insert(ap.clone(), Some(blob.clone()));
}
WriteOp::Deletion => {
self.data_map.remove(ap);
self.data_map.insert(ap.clone(), None);
}
}
}
}
}
impl<'block, S: StateView> StateView for StateViewCache<'block, S> {
fn get_state_value(&self, state_key: &StateKey) -> anyhow::Result<Option<Vec<u8>>> {
fail_point!("move_adapter::data_cache::get", |_| Err(format_err!(
"Injected failure in data_cache::get"
)));
match self.data_map.get(state_key) {
Some(opt_data) => Ok(opt_data.clone()),
None => match self.data_view.get_state_value(state_key) {
Ok(remote_data) => Ok(remote_data),
Err(e) => {
let log_context = AdapterLogSchema::new(self.data_view.id(), 0);
CRITICAL_ERRORS.inc();
error!(
log_context,
"[VM, StateView] Error getting data from storage for {:?}", state_key
);
Err(e)
}
},
}
}
fn is_genesis(&self) -> bool {
self.data_view.is_genesis()
}
fn id(&self) -> StateViewId {
self.data_view.id()
}
}
pub struct RemoteStorage<'a, S>(&'a S);
impl<'a, S: StateView> RemoteStorage<'a, S> {
pub fn new(state_store: &'a S) -> Self {
Self(state_store)
}
pub fn get(&self, access_path: &AccessPath) -> PartialVMResult<Option<Vec<u8>>> {
self.0
.get_state_value(&StateKey::AccessPath(access_path.clone()))
.map_err(|_| PartialVMError::new(StatusCode::STORAGE_ERROR))
}
}
impl<'a, S: StateView> ModuleResolver for RemoteStorage<'a, S> {
type Error = VMError;
fn get_module(&self, module_id: &ModuleId) -> Result<Option<Vec<u8>>, Self::Error> {
let ap = AccessPath::from(module_id);
self.get(&ap).map_err(|e| e.finish(Location::Undefined))
}
}
impl<'a, S: StateView> ResourceResolver for RemoteStorage<'a, S> {
type Error = VMError;
fn get_resource(
&self,
address: &AccountAddress,
struct_tag: &StructTag,
) -> Result<Option<Vec<u8>>, Self::Error> {
let ap = create_access_path(*address, struct_tag.clone());
self.get(&ap).map_err(|e| e.finish(Location::Undefined))
}
}
impl<'a, S: StateView> TableResolver for RemoteStorage<'a, S> {
fn resolve_table_entry(
&self,
handle: &TableHandle,
key: &[u8],
) -> Result<Option<Vec<u8>>, Error> {
self.get_state_value(&StateKey::table_item((*handle).into(), key.to_vec()))
}
fn operation_cost(&self, _op: TableOperation, _key_size: usize, _val_size: usize) -> u64 {
1
}
}
impl<'a, S: StateView> ConfigStorage for RemoteStorage<'a, S> {
fn fetch_config(&self, access_path: AccessPath) -> Option<Vec<u8>> {
self.get(&access_path).ok()?
}
}
impl<'a, S> Deref for RemoteStorage<'a, S> {
type Target = S;
fn deref(&self) -> &Self::Target {
self.0
}
}
pub trait AsMoveResolver<S> {
fn as_move_resolver(&self) -> RemoteStorage<S>;
}
impl<S: StateView> AsMoveResolver<S> for S {
fn as_move_resolver(&self) -> RemoteStorage<S> {
RemoteStorage::new(self)
}
}
pub struct RemoteStorageOwned<S> {
state_view: S,
}
impl<S> Deref for RemoteStorageOwned<S> {
type Target = S;
fn deref(&self) -> &Self::Target {
&self.state_view
}
}
impl<S> DerefMut for RemoteStorageOwned<S> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.state_view
}
}
impl<S: StateView> ModuleResolver for RemoteStorageOwned<S> {
type Error = VMError;
fn get_module(&self, module_id: &ModuleId) -> Result<Option<Vec<u8>>, Self::Error> {
self.as_move_resolver().get_module(module_id)
}
}
impl<S: StateView> ResourceResolver for RemoteStorageOwned<S> {
type Error = VMError;
fn get_resource(
&self,
address: &AccountAddress,
struct_tag: &StructTag,
) -> Result<Option<Vec<u8>>, Self::Error> {
self.as_move_resolver().get_resource(address, struct_tag)
}
}
impl<S: StateView> TableResolver for RemoteStorageOwned<S> {
fn resolve_table_entry(
&self,
handle: &TableHandle,
key: &[u8],
) -> Result<Option<Vec<u8>>, Error> {
self.as_move_resolver().resolve_table_entry(handle, key)
}
fn operation_cost(&self, op: TableOperation, key_size: usize, val_size: usize) -> u64 {
self.as_move_resolver()
.operation_cost(op, key_size, val_size)
}
}
impl<S: StateView> ConfigStorage for RemoteStorageOwned<S> {
fn fetch_config(&self, access_path: AccessPath) -> Option<Vec<u8>> {
self.as_move_resolver().fetch_config(access_path)
}
}
pub trait IntoMoveResolver<S> {
fn into_move_resolver(self) -> RemoteStorageOwned<S>;
}
impl<S: StateView> IntoMoveResolver<S> for S {
fn into_move_resolver(self) -> RemoteStorageOwned<S> {
RemoteStorageOwned { state_view: self }
}
}