Skip to content

Commit

Permalink
[resource-group] Add execution layer code
Browse files Browse the repository at this point in the history
  • Loading branch information
welbon committed Jan 14, 2025
1 parent 89ed235 commit 06ec6e1
Show file tree
Hide file tree
Showing 8 changed files with 369 additions and 216 deletions.
1 change: 1 addition & 0 deletions state/statedb/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -671,6 +671,7 @@ impl ChainStateWriter for ChainStateDB {
}

fn apply_write_set(&self, write_set: WriteSet) -> Result<()> {
info!("ChainStateWriter::apply_write_set | write set: {:?}", write_set);
let mut lock_table_handle = self.updates_table_handle.write();
let mut locks = self.updates.write();
for (state_key, write_op) in write_set {
Expand Down
40 changes: 36 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,14 @@ 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 +107,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 +127,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 Expand Up @@ -249,6 +249,37 @@ where
}
}

impl<S> TResourceGroupView for S
where S: StateView {
type GroupKey = StateKey;
type ResourceTag = StructTag;
type Layout = MoveTypeLayout;

fn is_resource_group_split_in_change_set_capable(&self) -> bool {
todo!()
}

fn resource_group_size(&self, group_key: &Self::GroupKey) -> PartialVMResult<ResourceGroupSize> {
todo!()
}

fn get_resource_from_group(&self, group_key: &Self::GroupKey, resource_tag: &Self::ResourceTag, maybe_layout: Option<&Self::Layout>) -> PartialVMResult<Option<Bytes>> {
todo!()
}

fn resource_size_in_group(&self, group_key: &Self::GroupKey, resource_tag: &Self::ResourceTag) -> PartialVMResult<usize> {
todo!()
}

fn resource_exists_in_group(&self, group_key: &Self::GroupKey, resource_tag: &Self::ResourceTag) -> PartialVMResult<bool> {
todo!()
}

fn release_group_cache(&self) -> Option<HashMap<Self::GroupKey, BTreeMap<Self::ResourceTag, Bytes>>> {
todo!()
}
}

impl<S> TModuleView for S
where
S: StateView,
Expand All @@ -273,6 +304,7 @@ where
}
}


/// Allows to query storage metadata in the VM session. Needed for storage refunds.
/// - Result being Err means storage error or some incostistency (e.g. during speculation,
/// needing to abort/halt the transaction with an error status).
Expand Down
75 changes: 45 additions & 30 deletions vm/vm-runtime-types/src/resource_group_adapter.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,22 @@
// Copyright © Aptos Foundation
// SPDX-License-Identifier: Apache-2.0

use crate::resolver::{
size_u32_as_uleb128, ResourceGroupSize, ResourceGroupView, TResourceGroupView, TResourceView,
};
use anyhow::Error;
use bytes::Bytes;
use move_core_types::{language_storage::StructTag, value::MoveTypeLayout};
use serde::Serialize;
use starcoin_vm_types::state_store::state_key::StateKey;
use std::{
cell::RefCell,
collections::{BTreeMap, HashMap},
fmt::Debug,
};

use bytes::Bytes;
use move_core_types::{language_storage::StructTag, value::MoveTypeLayout, vm_status::StatusCode};
use serde::Serialize;

use starcoin_vm_types::{errors::{PartialVMError, PartialVMResult}, state_store::state_key::StateKey};

use crate::resolver::{
ResourceGroupSize, ResourceGroupView, size_u32_as_uleb128, TResourceGroupView, TResourceView,
};

/// Corresponding to different gas features, methods for counting the 'size' of a
/// resource group. None leads to 0, while AsBlob provides the group size as the
/// size of the serialized blob of the BTreeMap corresponding to the group.
Expand Down Expand Up @@ -46,27 +48,31 @@ 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,
all_tagged_resources_size: len,
})
}


#[test]
fn test_group_size_same_as_bcs() {
use move_core_types::identifier::Identifier;
Expand Down Expand Up @@ -157,18 +163,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 +211,7 @@ 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 +234,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 Expand Up @@ -262,17 +274,20 @@ impl TResourceGroupView for ResourceGroupAdapter<'_> {

#[cfg(test)]
mod tests {
use super::*;
use std::cmp::max;

use claims::{assert_gt, assert_none, assert_ok_eq, assert_some, assert_some_eq};
use move_core_types::account_address::AccountAddress;
use move_core_types::identifier::Identifier;
use move_core_types::language_storage::TypeTag;
use test_case::test_case;

use starcoin_vm_types::state_store::{
errors::StateviewError, state_storage_usage::StateStorageUsage, state_value::StateValue,
TStateView,
};
use std::cmp::max;
use test_case::test_case;

use super::*;

fn mock_tag_0() -> StructTag {
StructTag {
Expand Down Expand Up @@ -388,7 +403,7 @@ mod tests {
fn resource_group_size(
&self,
group_key: &Self::GroupKey,
) -> anyhow::Result<ResourceGroupSize> {
) -> PartialVMResult<ResourceGroupSize> {
Ok(self
.group
.get(group_key)
Expand All @@ -401,7 +416,7 @@ mod tests {
group_key: &Self::GroupKey,
resource_tag: &Self::ResourceTag,
_maybe_layout: Option<&Self::Layout>,
) -> anyhow::Result<Option<Bytes>> {
) -> PartialVMResult<Option<Bytes>> {
Ok(self
.group
.get(group_key)
Expand All @@ -412,15 +427,15 @@ mod tests {
&self,
_group_key: &Self::GroupKey,
_resource_tag: &Self::ResourceTag,
) -> anyhow::Result<usize> {
) -> PartialVMResult<usize> {
unimplemented!("Currently resolved by ResourceGroupAdapter");
}

fn resource_exists_in_group(
&self,
_group_key: &Self::GroupKey,
_resource_tag: &Self::ResourceTag,
) -> anyhow::Result<bool> {
) -> PartialVMResult<bool> {
unimplemented!("Currently resolved by ResourceGroupAdapter");
}

Expand Down
Loading

0 comments on commit 06ec6e1

Please sign in to comment.