From 25db7451e04b5f1af435c3edf7bfbe80993aaa5c Mon Sep 17 00:00:00 2001 From: jolestar Date: Sun, 7 Jul 2024 01:11:28 +0800 Subject: [PATCH] [object] Parse the account dynamic field --- moveos/moveos-types/src/access_path.rs | 1 - moveos/moveos-types/src/moveos_std/object.rs | 2 +- .../src/moveos_std/object/dynamic_field.rs | 121 +++++++++++++++++- moveos/moveos-types/src/state.rs | 12 +- moveos/moveos-types/src/state_resolver.rs | 5 +- 5 files changed, 133 insertions(+), 8 deletions(-) diff --git a/moveos/moveos-types/src/access_path.rs b/moveos/moveos-types/src/access_path.rs index 4dfde80550..5a858523ee 100644 --- a/moveos/moveos-types/src/access_path.rs +++ b/moveos/moveos-types/src/access_path.rs @@ -393,7 +393,6 @@ impl<'de> Deserialize<'de> for AccessPath { #[cfg(test)] mod tests { use super::*; - use crate::move_std::string::MoveString; fn test_path_roundtrip(path: &str) { let path = path.parse::().unwrap(); diff --git a/moveos/moveos-types/src/moveos_std/object.rs b/moveos/moveos-types/src/moveos_std/object.rs index 15dfe0d3de..b86ae9a633 100644 --- a/moveos/moveos-types/src/moveos_std/object.rs +++ b/moveos/moveos-types/src/moveos_std/object.rs @@ -37,7 +37,7 @@ use std::str::FromStr; pub use dynamic_field::{ construct_dynamic_field_struct_tag, is_dynamic_field_type, is_field_struct_tag, DynamicField, - DYNAMIC_FIELD_STRUCT_NAME, + RawField, DYNAMIC_FIELD_STRUCT_NAME, }; mod dynamic_field; diff --git a/moveos/moveos-types/src/moveos_std/object/dynamic_field.rs b/moveos/moveos-types/src/moveos_std/object/dynamic_field.rs index 244d0d4893..7353b41c8b 100644 --- a/moveos/moveos-types/src/moveos_std/object/dynamic_field.rs +++ b/moveos/moveos-types/src/moveos_std/object/dynamic_field.rs @@ -3,8 +3,10 @@ use crate::{ addresses::MOVEOS_STD_ADDRESS, - state::{MoveState, MoveStructState, MoveStructType}, + move_std::string::MoveString, + state::{MoveState, MoveStructState, MoveStructType, MoveType}, }; +use anyhow::{anyhow, bail, Result}; use move_core_types::{ ident_str, identifier::IdentStr, @@ -30,6 +32,85 @@ impl DynamicField { } } +#[derive(Debug, Clone)] +pub struct RawField { + pub name: Vec, + pub name_type: TypeTag, + pub value: Vec, + pub value_type: TypeTag, +} + +impl RawField { + pub fn new(name: Vec, name_type: TypeTag, value: Vec, value_type: TypeTag) -> Self { + Self { + name, + name_type, + value, + value_type, + } + } + + pub fn from_dynamic_field(field: &DynamicField) -> Self + where + N: MoveState, + V: MoveState, + { + Self { + name: field.name.to_bytes(), + name_type: N::type_tag(), + value: field.value.to_bytes(), + value_type: V::type_tag(), + } + } + + //This function is from bcs module, + //find a better way to parse the vec. + fn parse_length(bytes: &[u8]) -> Result<(usize, usize)> { + let mut value: u64 = 0; + let mut iter = bytes.iter(); + let mut used_bytes: usize = 0; + for shift in (0..32).step_by(7) { + let byte = *iter + .next() + .ok_or_else(|| anyhow!("Invalid bytes, NonCanonicalUleb128Encoding"))?; + used_bytes += 1; + let digit = byte & 0x7f; + value |= u64::from(digit) << shift; + // If the highest bit of `byte` is 0, return the final value. + if digit == byte { + if shift > 0 && digit == 0 { + // We only accept canonical ULEB128 encodings, therefore the + // heaviest (and last) base-128 digit must be non-zero. + bail!("Invalid bytes, NonCanonicalUleb128Encoding"); + } + // Decoded integer must not overflow. + return Ok(( + used_bytes, + u32::try_from(value).map_err(|_| { + anyhow!("Invalid bytes, IntegerOverflowDuringUleb128Decoding") + })? as usize, + )); + } + } + // Decoded integer must not overflow. + bail!("Invalid bytes, IntegerOverflowDuringUleb128Decoding") + } + + /// Parse bcs serialized `DynamicField` bytes to `RawField` + pub fn parse_resource_field(bytes: &[u8], value_type: TypeTag) -> anyhow::Result { + let (used_bytes, name_length) = Self::parse_length(bytes)?; + let name_bytes_length = used_bytes + name_length; + let name = &bytes[..name_bytes_length]; + let value = &bytes[name_bytes_length..]; + Ok(Self { + name: name.to_vec(), + name_type: MoveString::type_tag(), + value: value.to_vec(), + value_type, + }) + } +} + impl MoveStructType for DynamicField where N: MoveState, @@ -94,3 +175,41 @@ pub fn construct_dynamic_field_struct_tag(name_tag: TypeTag, value_tag: TypeTag) type_params: vec![name_tag, value_tag], } } + +#[cfg(test)] +mod tests { + use super::*; + use crate::{move_std::string::MoveString, state::MoveType}; + use move_core_types::account_address::AccountAddress; + + #[derive(Eq, PartialEq, Debug, Clone, Deserialize, Serialize)] + struct TestStruct { + count: u64, + } + + impl MoveStructType for TestStruct { + const ADDRESS: AccountAddress = MOVEOS_STD_ADDRESS; + const MODULE_NAME: &'static IdentStr = ident_str!("object"); + const STRUCT_NAME: &'static IdentStr = ident_str!("TestStruct"); + } + + impl MoveStructState for TestStruct { + fn struct_layout() -> MoveStructLayout { + MoveStructLayout::new(vec![MoveTypeLayout::U64]) + } + } + + #[test] + fn test_dynamic_field() { + let field = DynamicField::new( + MoveString::from(TestStruct::struct_tag().to_canonical_string()), + TestStruct { count: 10 }, + ); + let raw_field_bytes = bcs::to_bytes(&field).unwrap(); + let raw_field = RawField::from_dynamic_field(&field); + let parsed_raw_field = + RawField::parse_resource_field(&raw_field_bytes, TestStruct::type_tag()).unwrap(); + assert_eq!(raw_field.name, parsed_raw_field.name); + assert_eq!(raw_field.value, parsed_raw_field.value); + } +} diff --git a/moveos/moveos-types/src/state.rs b/moveos/moveos-types/src/state.rs index 008e67f62d..77fc68e262 100644 --- a/moveos/moveos-types/src/state.rs +++ b/moveos/moveos-types/src/state.rs @@ -576,9 +576,15 @@ where } } -impl MoveType for String { - fn type_tag() -> TypeTag { - MoveString::type_tag() +impl MoveStructType for String { + const ADDRESS: AccountAddress = MoveString::ADDRESS; + const MODULE_NAME: &'static IdentStr = MoveString::MODULE_NAME; + const STRUCT_NAME: &'static IdentStr = MoveString::STRUCT_NAME; +} + +impl MoveStructState for String { + fn struct_layout() -> MoveStructLayout { + MoveString::struct_layout() } } diff --git a/moveos/moveos-types/src/state_resolver.rs b/moveos/moveos-types/src/state_resolver.rs index 61109574f4..5411e65084 100644 --- a/moveos/moveos-types/src/state_resolver.rs +++ b/moveos/moveos-types/src/state_resolver.rs @@ -5,7 +5,7 @@ use crate::move_std::string::MoveString; use crate::moveos_std::account::Account; use crate::moveos_std::module_store::Package; use crate::moveos_std::move_module::MoveModuleDynamicField; -use crate::moveos_std::object::{ObjectEntity, ObjectID}; +use crate::moveos_std::object::{ObjectEntity, ObjectID, RawField}; use crate::state::{FieldKey, MoveType, ObjectState}; use crate::{ access_path::AccessPath, h256::H256, moveos_std::object::AnnotatedObject, state::AnnotatedState, @@ -161,7 +161,8 @@ where resource_tag, s.value_type() ); - Ok(s.value) + let field = RawField::parse_resource_field(&s.value, resource_tag.clone().into())?; + Ok(field.value) }) .transpose();