Skip to content

Commit

Permalink
support resource group in vm-runtime
Browse files Browse the repository at this point in the history
  • Loading branch information
simonjiao committed Jan 15, 2025
1 parent 89ed235 commit 15da0be
Show file tree
Hide file tree
Showing 7 changed files with 262 additions and 178 deletions.
9 changes: 5 additions & 4 deletions vm/vm-runtime-types/src/resolver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,14 +89,15 @@ pub trait TResourceGroupView {
/// the parallel execution setting, as a wrong value will be (later) caught by validation.
/// Thus, R/W conflicts are avoided, as long as the estimates are correct (e.g. updating
/// struct members of a fixed size).
fn resource_group_size(&self, group_key: &Self::GroupKey) -> anyhow::Result<ResourceGroupSize>;
fn resource_group_size(&self, group_key: &Self::GroupKey)
-> PartialVMResult<ResourceGroupSize>;

fn get_resource_from_group(
&self,
group_key: &Self::GroupKey,
resource_tag: &Self::ResourceTag,
maybe_layout: Option<&Self::Layout>,
) -> anyhow::Result<Option<Bytes>>;
) -> PartialVMResult<Option<Bytes>>;

/// Needed for charging storage fees for a resource group write, as that requires knowing
/// the size of the resource group AFTER the changeset of the transaction is applied (while
Expand All @@ -107,7 +108,7 @@ pub trait TResourceGroupView {
&self,
group_key: &Self::GroupKey,
resource_tag: &Self::ResourceTag,
) -> anyhow::Result<usize> {
) -> PartialVMResult<usize> {
Ok(self
.get_resource_from_group(group_key, resource_tag, None)?
.map_or(0, |bytes| bytes.len()))
Expand All @@ -127,7 +128,7 @@ pub trait TResourceGroupView {
&self,
group_key: &Self::GroupKey,
resource_tag: &Self::ResourceTag,
) -> anyhow::Result<bool> {
) -> PartialVMResult<bool> {
self.get_resource_from_group(group_key, resource_tag, None)
.map(|maybe_bytes| maybe_bytes.is_some())
}
Expand Down
46 changes: 30 additions & 16 deletions vm/vm-runtime-types/src/resource_group_adapter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@
use crate::resolver::{
size_u32_as_uleb128, ResourceGroupSize, ResourceGroupView, TResourceGroupView, TResourceView,
};
use anyhow::Error;
use bytes::Bytes;
use move_core_types::vm_status::StatusCode;
use move_core_types::{language_storage::StructTag, value::MoveTypeLayout};
use serde::Serialize;
use starcoin_vm_types::errors::{PartialVMError, PartialVMResult};
use starcoin_vm_types::state_store::state_key::StateKey;
use std::{
cell::RefCell,
Expand Down Expand Up @@ -46,20 +47,24 @@ impl GroupSizeKind {
pub fn group_tagged_resource_size<T: Serialize + Clone + Debug>(
tag: &T,
value_byte_len: usize,
) -> anyhow::Result<u64> {
Ok((bcs::serialized_size(&tag)? + value_byte_len + size_u32_as_uleb128(value_byte_len)) as u64)
) -> PartialVMResult<u64> {
Ok((bcs::serialized_size(&tag).map_err(|e| {
PartialVMError::new(StatusCode::VALUE_SERIALIZATION_ERROR).with_message(format!(
"Tag serialization error for tag {:?}: {:?}",
tag, e
))
})? + value_byte_len
+ size_u32_as_uleb128(value_byte_len)) as u64)
}

/// Utility method to compute the size of the group as GroupSizeKind::AsSum.
pub fn group_size_as_sum<T: Serialize + Clone + Debug>(
mut group: impl Iterator<Item = (T, usize)>,
) -> anyhow::Result<ResourceGroupSize> {
let (count, len) = group
.try_fold((0, 0), |(count, len), (tag, value_byte_len)| {
let delta = group_tagged_resource_size(&tag, value_byte_len)?;
Ok((count + 1, len + delta))
})
.map_err(|_: Error| anyhow::Error::msg("Resource group member tag serialization error"))?;
) -> PartialVMResult<ResourceGroupSize> {
let (count, len) = group.try_fold((0, 0), |(count, len), (tag, value_byte_len)| {
let delta = group_tagged_resource_size(&tag, value_byte_len)?;
Ok::<(usize, u64), PartialVMError>((count + 1, len + delta))
})?;

Ok(ResourceGroupSize::Combined {
num_tagged_resources: count,
Expand Down Expand Up @@ -157,18 +162,24 @@ impl<'r> ResourceGroupAdapter<'r> {

// Ensures that the resource group at state_key is cached in self.group_cache. Ok(true)
// means the resource was already cached, while Ok(false) means it just got cached.
fn load_to_cache(&self, group_key: &StateKey) -> anyhow::Result<bool> {
fn load_to_cache(&self, group_key: &StateKey) -> PartialVMResult<bool> {
let already_cached = self.group_cache.borrow().contains_key(group_key);
if already_cached {
return Ok(true);
}

let group_data = self.resource_view.get_resource_bytes(group_key, None)?;
let (group_data, blob_len): (BTreeMap<StructTag, Bytes>, u64) = group_data.map_or_else(
|| Ok::<_, Error>((BTreeMap::new(), 0)),
|| Ok::<_, PartialVMError>((BTreeMap::new(), 0)),
|group_data_blob| {
let group_data = bcs::from_bytes(&group_data_blob)
.map_err(|_| anyhow::Error::msg("Resource group deserialization error"))?;
let group_data = bcs::from_bytes(&group_data_blob).map_err(|e| {
PartialVMError::new(StatusCode::UNEXPECTED_DESERIALIZATION_ERROR).with_message(
format!(
"Failed to deserialize the resource group at {:? }: {:?}",
group_key, e
),
)
})?;
Ok((group_data, group_data_blob.len() as u64))
},
)?;
Expand Down Expand Up @@ -199,7 +210,10 @@ impl TResourceGroupView for ResourceGroupAdapter<'_> {
self.group_size_kind == GroupSizeKind::AsSum
}

fn resource_group_size(&self, group_key: &Self::GroupKey) -> anyhow::Result<ResourceGroupSize> {
fn resource_group_size(
&self,
group_key: &Self::GroupKey,
) -> PartialVMResult<ResourceGroupSize> {
if self.group_size_kind == GroupSizeKind::None {
return Ok(ResourceGroupSize::zero_concrete());
}
Expand All @@ -222,7 +236,7 @@ impl TResourceGroupView for ResourceGroupAdapter<'_> {
group_key: &Self::GroupKey,
resource_tag: &Self::ResourceTag,
maybe_layout: Option<&MoveTypeLayout>,
) -> anyhow::Result<Option<Bytes>> {
) -> PartialVMResult<Option<Bytes>> {
if let Some(group_view) = self.maybe_resource_group_view {
return group_view.get_resource_from_group(group_key, resource_tag, maybe_layout);
}
Expand Down
69 changes: 65 additions & 4 deletions vm/vm-runtime/src/data_cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// SPDX-License-Identifier: Apache-2.0
//! Scratchpad for on chain values during the execution.
use crate::move_vm_ext::AsExecutorView;
use crate::move_vm_ext::{AsExecutorView, ResourceGroupResolver};
use bytes::Bytes;
use move_binary_format::deserializer::DeserializerConfig;
use move_binary_format::CompiledModule;
Expand All @@ -14,7 +14,7 @@ use move_table_extension::{TableHandle, TableResolver};
use starcoin_gas_schedule::LATEST_GAS_FEATURE_VERSION;
use starcoin_logger::prelude::*;
use starcoin_types::account_address::AccountAddress;
use starcoin_vm_runtime_types::resolver::ExecutorView;
use starcoin_vm_runtime_types::resolver::{ExecutorView, ResourceGroupSize, TResourceGroupView};
use starcoin_vm_runtime_types::resource_group_adapter::ResourceGroupAdapter;
use starcoin_vm_types::state_store::{
errors::StateviewError, state_key::StateKey, state_storage_usage::StateStorageUsage,
Expand All @@ -26,6 +26,7 @@ use starcoin_vm_types::{
vm_status::StatusCode,
write_set::{WriteOp, WriteSet},
};
use std::collections::HashMap;
use std::{
cell::RefCell,
collections::btree_map::BTreeMap,
Expand Down Expand Up @@ -53,7 +54,7 @@ pub fn get_resource_group_member_from_metadata(
pub struct StorageAdapter<'e, E> {
executor_view: &'e E,
_deserializer_config: DeserializerConfig,
_resource_group_view: ResourceGroupAdapter<'e>,
resource_group_view: ResourceGroupAdapter<'e>,
_accessed_groups: RefCell<HashSet<StateKey>>,
}

Expand Down Expand Up @@ -166,7 +167,7 @@ impl<'a, S: StateView> StorageAdapter<'a, S> {
Self {
executor_view: state_store,
_deserializer_config: DeserializerConfig::new(0, 0),
_resource_group_view: ResourceGroupAdapter::new(
resource_group_view: ResourceGroupAdapter::new(
None,
state_store,
LATEST_GAS_FEATURE_VERSION,
Expand Down Expand Up @@ -225,6 +226,36 @@ impl<'a, S: StateView> ResourceResolver for StorageAdapter<'a, S> {
}
}

impl<'a, S: StateView> ResourceGroupResolver for StorageAdapter<'a, S> {
fn release_resource_group_cache(
&self,
) -> Option<HashMap<StateKey, BTreeMap<StructTag, Bytes>>> {
self.resource_group_view.release_group_cache()
}

fn resource_group_size(&self, group_key: &StateKey) -> PartialVMResult<ResourceGroupSize> {
self.resource_group_view.resource_group_size(group_key)
}

fn resource_size_in_group(
&self,
group_key: &StateKey,
resource_tag: &StructTag,
) -> PartialVMResult<usize> {
self.resource_group_view
.resource_size_in_group(group_key, resource_tag)
}

fn resource_exists_in_group(
&self,
group_key: &StateKey,
resource_tag: &StructTag,
) -> PartialVMResult<bool> {
self.resource_group_view
.resource_exists_in_group(group_key, resource_tag)
}
}

impl<'a, S> Deref for StorageAdapter<'a, S> {
type Target = S;

Expand Down Expand Up @@ -321,6 +352,36 @@ impl<S: StateView> ResourceResolver for RemoteStorageOwned<S> {
}
}

impl<S: StateView> ResourceGroupResolver for RemoteStorageOwned<S> {
fn release_resource_group_cache(
&self,
) -> Option<HashMap<StateKey, BTreeMap<StructTag, Bytes>>> {
self.as_move_resolver().release_resource_group_cache()
}

fn resource_group_size(&self, group_key: &StateKey) -> PartialVMResult<ResourceGroupSize> {
self.as_move_resolver().resource_group_size(group_key)
}

fn resource_size_in_group(
&self,
group_key: &StateKey,
resource_tag: &StructTag,
) -> PartialVMResult<usize> {
self.as_move_resolver()
.resource_size_in_group(group_key, resource_tag)
}

fn resource_exists_in_group(
&self,
group_key: &StateKey,
resource_tag: &StructTag,
) -> PartialVMResult<bool> {
self.as_move_resolver()
.resource_exists_in_group(group_key, resource_tag)
}
}

impl<S: StateView> TableResolver for RemoteStorageOwned<S> {
fn resolve_table_entry_bytes_with_layout(
&self,
Expand Down
2 changes: 1 addition & 1 deletion vm/vm-runtime/src/move_vm_ext/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ mod warm_vm_cache;
pub(crate) mod write_op_converter;

pub use crate::move_vm_ext::{
resolver::{AsExecutorView, StarcoinMoveResolver},
resolver::{AsExecutorView, ResourceGroupResolver, StarcoinMoveResolver},
session::{SessionExt, SessionId},
vm::MoveVmExt,
};
Expand Down
50 changes: 29 additions & 21 deletions vm/vm-runtime/src/move_vm_ext/resolver.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
// Copyright (c) The Starcoin Core Contributors
// SPDX-License-Identifier: Apache-2.0

use move_binary_format::errors::PartialVMError;
use move_core_types::resolver::MoveResolver;
use bytes::Bytes;
use move_binary_format::errors::{PartialVMError, PartialVMResult};
use move_core_types::language_storage::StructTag;
use move_core_types::resolver::{MoveResolver, ResourceResolver};
use move_table_extension::TableResolver;
use starcoin_aggregator::resolver::{AggregatorV1Resolver, DelayedFieldResolver};
use starcoin_vm_runtime_types::resolver::ExecutorView;
use starcoin_vm_runtime_types::resolver::{ExecutorView, ResourceGroupSize};
use starcoin_vm_types::on_chain_config::ConfigStorage;
use starcoin_vm_types::state_store::state_key::StateKey;
use std::collections::{BTreeMap, HashMap};

/// A general resolver used by StarcoinVM. Allows to implement custom hooks on
/// top of storage, e.g. get resources from resource groups, etc.
Expand All @@ -16,6 +20,8 @@ pub trait StarcoinMoveResolver:
+ DelayedFieldResolver
+ ConfigStorage
+ MoveResolver<PartialVMError>
+ ResourceResolver
+ ResourceGroupResolver
+ TableResolver
+ AsExecutorView
{
Expand All @@ -26,30 +32,32 @@ impl<
+ ConfigStorage
+ DelayedFieldResolver
+ MoveResolver<PartialVMError>
+ ResourceResolver
+ ResourceGroupResolver
+ TableResolver
+ AsExecutorView,
> StarcoinMoveResolver for S
{
}

//pub trait ResourceGroupResolver {
// fn release_resource_group_cache(&self)
// -> Option<HashMap<StateKey, BTreeMap<StructTag, Bytes>>>;
//
// fn resource_group_size(&self, group_key: &StateKey) -> PartialVMResult<ResourceGroupSize>;
//
// fn resource_size_in_group(
// &self,
// group_key: &StateKey,
// resource_tag: &StructTag,
// ) -> PartialVMResult<usize>;
//
// fn resource_exists_in_group(
// &self,
// group_key: &StateKey,
// resource_tag: &StructTag,
// ) -> PartialVMResult<bool>;
//}
pub trait ResourceGroupResolver {
fn release_resource_group_cache(&self)
-> Option<HashMap<StateKey, BTreeMap<StructTag, Bytes>>>;

fn resource_group_size(&self, group_key: &StateKey) -> PartialVMResult<ResourceGroupSize>;

fn resource_size_in_group(
&self,
group_key: &StateKey,
resource_tag: &StructTag,
) -> PartialVMResult<usize>;

fn resource_exists_in_group(
&self,
group_key: &StateKey,
resource_tag: &StructTag,
) -> PartialVMResult<bool>;
}

pub trait AsExecutorView {
fn as_executor_view(&self) -> &dyn ExecutorView;
Expand Down
Loading

0 comments on commit 15da0be

Please sign in to comment.