From 127c17a1216a09883e087721435429d96d6e60fa Mon Sep 17 00:00:00 2001 From: patrick Date: Wed, 11 Jan 2023 01:01:51 +0000 Subject: [PATCH 01/11] use MoveValue type + parsed json value for DynamicFieldName instead of MoveValue::to_string --- crates/sui-core/src/authority.rs | 11 ++- crates/sui-core/src/event_handler.rs | 6 +- .../src/unit_tests/event_handler_tests.rs | 2 +- crates/sui-json-rpc-types/src/lib.rs | 90 +++++++++++++------ crates/sui-json-rpc/src/api.rs | 3 +- crates/sui-json-rpc/src/read_api.rs | 6 +- crates/sui-storage/src/indexes.rs | 10 ++- crates/sui-types/src/dynamic_field.rs | 38 ++++++-- 8 files changed, 116 insertions(+), 50 deletions(-) diff --git a/crates/sui-core/src/authority.rs b/crates/sui-core/src/authority.rs index 1e8170597d263..03ab79a3a8db7 100644 --- a/crates/sui-core/src/authority.rs +++ b/crates/sui-core/src/authority.rs @@ -46,7 +46,7 @@ use narwhal_config::{ use sui_adapter::{adapter, execution_mode}; use sui_config::genesis::Genesis; use sui_json_rpc_types::{ - type_and_fields_from_move_struct, DevInspectResults, SuiEvent, SuiEventEnvelope, + type_and_fields_from_move_struct, DevInspectResults, SuiEvent, SuiEventEnvelope, SuiMoveValue, SuiTransactionEffects, }; use sui_macros::nondeterministic; @@ -60,7 +60,7 @@ use sui_storage::{ }; use sui_types::committee::{EpochId, ProtocolVersion}; use sui_types::crypto::{sha3_hash, AuthorityKeyPair, NetworkKeyPair, Signer}; -use sui_types::dynamic_field::{DynamicFieldInfo, DynamicFieldType}; +use sui_types::dynamic_field::{DynamicFieldInfo, DynamicFieldName, DynamicFieldType}; use sui_types::event::{Event, EventID}; use sui_types::gas::{GasCostSummary, GasPrice, SuiCostTable, SuiGasStatus}; use sui_types::messages_checkpoint::{ @@ -1276,6 +1276,11 @@ impl AuthorityState { let (name, type_, object_id) = DynamicFieldInfo::parse_move_object(&move_struct).tap_err(|e| warn!("{e}"))?; + let name = DynamicFieldName { + type_: SuiMoveValue::parse_move_value_type(&name), + value: SuiMoveValue::from(name).to_json_value(), + }; + Ok(Some(match type_ { DynamicFieldType::DynamicObject => { // Find the actual object from storage using the object id obtained from the wrapper. @@ -2019,7 +2024,7 @@ impl AuthorityState { pub fn get_dynamic_field_object_id( &self, owner: ObjectID, - name: &str, + name: &DynamicFieldName, ) -> SuiResult> { if let Some(indexes) = &self.indexes { indexes.get_dynamic_field_object_id(owner, name) diff --git a/crates/sui-core/src/event_handler.rs b/crates/sui-core/src/event_handler.rs index 3e5db4d27f345..d22d955ced227 100644 --- a/crates/sui-core/src/event_handler.rs +++ b/crates/sui-core/src/event_handler.rs @@ -128,11 +128,7 @@ impl EventHandler { Event::move_event_to_move_struct(type_, contents, self.module_cache.as_ref())?; // Convert into `SuiMoveStruct` which is a mirror of MoveStruct but with additional type supports, (e.g. ascii::String). let sui_move_struct = SuiMoveStruct::from(move_struct); - Some(sui_move_struct.to_json_value().map_err(|e| { - SuiError::ObjectSerializationError { - error: e.to_string(), - } - })?) + Some(sui_move_struct.to_json_value()) } _ => None, }; diff --git a/crates/sui-core/src/unit_tests/event_handler_tests.rs b/crates/sui-core/src/unit_tests/event_handler_tests.rs index 2747a2fbd6473..0632b75e9eef7 100644 --- a/crates/sui-core/src/unit_tests/event_handler_tests.rs +++ b/crates/sui-core/src/unit_tests/event_handler_tests.rs @@ -37,7 +37,7 @@ fn test_to_json_value() { MoveStruct::simple_deserialize(&event_bytes, &TestEvent::layout()) .unwrap() .into(); - let json_value = sui_move_struct.to_json_value().unwrap(); + let json_value = sui_move_struct.to_json_value(); assert_eq!( Some(&json!("1000000")), json_value.pointer("/coins/0/balance") diff --git a/crates/sui-json-rpc-types/src/lib.rs b/crates/sui-json-rpc-types/src/lib.rs index 6274a6c0be5c1..f3a67af7b495e 100644 --- a/crates/sui-json-rpc-types/src/lib.rs +++ b/crates/sui-json-rpc-types/src/lib.rs @@ -26,7 +26,7 @@ use schemars::JsonSchema; use serde::ser::Error; use serde::Deserialize; use serde::Serialize; -use serde_json::Value; +use serde_json::{json, Value}; use serde_with::serde_as; use sui_json::SuiJsonValue; use sui_protocol_config::ProtocolConfig; @@ -1185,6 +1185,60 @@ pub enum SuiMoveValue { Option(Box>), } +impl SuiMoveValue { + pub fn to_json_value(self) -> Value { + match self { + SuiMoveValue::Struct(move_struct) => move_struct.to_json_value(), + SuiMoveValue::Vector(values) => SuiMoveStruct::Runtime(values).to_json_value(), + SuiMoveValue::Number(v) => json!(v), + SuiMoveValue::Bool(v) => json!(v), + SuiMoveValue::Address(v) => json!(v), + SuiMoveValue::String(v) => json!(v), + SuiMoveValue::UID { id } => json!({ "id": id }), + SuiMoveValue::Option(v) => json!(v), + } + } + + pub fn parse_move_value_type(value: &MoveValue) -> String { + match value { + MoveValue::U8(_) => "u8".into(), + MoveValue::U16(_) => "u16".into(), + MoveValue::U32(_) => "u32".into(), + MoveValue::U64(_) => "u64".into(), + MoveValue::U128(_) => "u128".into(), + MoveValue::U256(_) => "u256".into(), + MoveValue::Bool(_) => "bool".into(), + MoveValue::Address(_) => "Address".into(), + MoveValue::Signer(_) => "Signer".into(), + MoveValue::Vector(v) => { + let inner_type = v + .first() + .map(Self::parse_move_value_type) + .unwrap_or_else(|| "?".into()); + format!("Vec<{inner_type}>") + } + MoveValue::Struct(s) => match s { + MoveStruct::Runtime(v) => { + let inner_type = v + .first() + .map(Self::parse_move_value_type) + .unwrap_or_else(|| "?".into()); + format!("Vec<{inner_type}>") + } + // Treat this like tuple + MoveStruct::WithFields(f) => { + let types = f + .iter() + .map(|(_, v)| Self::parse_move_value_type(v)) + .join(","); + format!("({types})") + } + MoveStruct::WithTypes { type_, .. } => type_.to_string(), + }, + } + } +} + impl Display for SuiMoveValue { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { let mut writer = String::new(); @@ -1268,41 +1322,25 @@ pub enum SuiMoveStruct { } impl SuiMoveStruct { - pub fn to_json_value(self) -> Result { + pub fn to_json_value(self) -> Value { // Unwrap MoveStructs - let unwrapped = match self { + match self { SuiMoveStruct::Runtime(values) => { let values = values .into_iter() - .map(|value| match value { - SuiMoveValue::Struct(move_struct) => move_struct.to_json_value(), - SuiMoveValue::Vector(values) => { - SuiMoveStruct::Runtime(values).to_json_value() - } - _ => serde_json::to_value(&value), - }) - .collect::, _>>()?; - serde_json::to_value(&values) + .map(|value| value.to_json_value()) + .collect::>(); + json!(values) } // We only care about values here, assuming struct type information is known at the client side. SuiMoveStruct::WithTypes { type_: _, fields } | SuiMoveStruct::WithFields(fields) => { let fields = fields .into_iter() - .map(|(key, value)| { - let value = match value { - SuiMoveValue::Struct(move_struct) => move_struct.to_json_value(), - SuiMoveValue::Vector(values) => { - SuiMoveStruct::Runtime(values).to_json_value() - } - _ => serde_json::to_value(&value), - }; - value.map(|value| (key, value)) - }) - .collect::, _>>()?; - serde_json::to_value(&fields) + .map(|(key, value)| (key, value.to_json_value())) + .collect::>(); + json!(fields) } - }?; - serde_json::to_value(&unwrapped) + } } } diff --git a/crates/sui-json-rpc/src/api.rs b/crates/sui-json-rpc/src/api.rs index 6d8f319294ff8..7369a2b57238f 100644 --- a/crates/sui-json-rpc/src/api.rs +++ b/crates/sui-json-rpc/src/api.rs @@ -23,6 +23,7 @@ use sui_types::base_types::{ ObjectID, SequenceNumber, SuiAddress, TransactionDigest, TxSequenceNumber, }; use sui_types::committee::EpochId; +use sui_types::dynamic_field::DynamicFieldName; use sui_types::event::EventID; use sui_types::governance::DelegatedStake; use sui_types::messages::CommitteeInfoResponse; @@ -164,7 +165,7 @@ pub trait RpcReadApi { /// The ID of the queried parent object parent_object_id: ObjectID, /// The Name of the dynamic field - name: String, + name: DynamicFieldName, ) -> RpcResult; } diff --git a/crates/sui-json-rpc/src/read_api.rs b/crates/sui-json-rpc/src/read_api.rs index 45d24aa410057..d5d854825f791 100644 --- a/crates/sui-json-rpc/src/read_api.rs +++ b/crates/sui-json-rpc/src/read_api.rs @@ -34,6 +34,8 @@ use sui_types::move_package::normalize_modules; use sui_types::object::{Data, ObjectRead}; use sui_types::query::TransactionQuery; +use sui_adapter::execution_mode::DevInspect; +use sui_types::dynamic_field::DynamicFieldName; use tracing::debug; use crate::api::RpcFullNodeReadApiServer; @@ -132,14 +134,14 @@ impl RpcReadApiServer for ReadApi { async fn get_dynamic_field_object( &self, parent_object_id: ObjectID, - name: String, + name: DynamicFieldName, ) -> RpcResult { let id = self .state .get_dynamic_field_object_id(parent_object_id, &name) .map_err(|e| anyhow!("{e}"))? .ok_or_else(|| { - anyhow!("Cannot find dynamic field [{name}] for object [{parent_object_id}].") + anyhow!("Cannot find dynamic field [{name:?}] for object [{parent_object_id}].") })?; self.get_object(id).await } diff --git a/crates/sui-storage/src/indexes.rs b/crates/sui-storage/src/indexes.rs index 05caeb6d5092b..a79e7f6386261 100644 --- a/crates/sui-storage/src/indexes.rs +++ b/crates/sui-storage/src/indexes.rs @@ -19,7 +19,7 @@ use typed_store_derive::DBMapUtils; use sui_types::base_types::{ObjectID, SuiAddress, TransactionDigest, TxSequenceNumber}; use sui_types::base_types::{ObjectInfo, ObjectRef}; -use sui_types::dynamic_field::DynamicFieldInfo; +use sui_types::dynamic_field::{DynamicFieldInfo, DynamicFieldName}; use sui_types::error::{SuiError, SuiResult}; use sui_types::fp_ensure; use sui_types::object::Owner; @@ -554,7 +554,7 @@ impl IndexStore { pub fn get_dynamic_field_object_id( &self, object: ObjectID, - name: &str, + name: &DynamicFieldName, ) -> SuiResult> { debug!(?object, "get_dynamic_field_object_id"); Ok(self @@ -563,7 +563,11 @@ impl IndexStore { .iter() // The object id 0 is the smallest possible .skip_to(&(object, ObjectID::ZERO))? - .find(|((object_owner, _), info)| (object_owner == &object && info.name == name)) + .find(|((object_owner, _), info)| { + object_owner == &object + && info.name.type_ == name.type_ + && info.name.value == name.value + }) .map(|(_, object_info)| object_info.object_id)) } diff --git a/crates/sui-types/src/dynamic_field.rs b/crates/sui-types/src/dynamic_field.rs index 92e7bf4f59163..fa91090124132 100644 --- a/crates/sui-types/src/dynamic_field.rs +++ b/crates/sui-types/src/dynamic_field.rs @@ -1,20 +1,23 @@ // Copyright (c) Mysten Labs, Inc. // SPDX-License-Identifier: Apache-2.0 +use crate::base_types::ObjectDigest; +use crate::error::{SuiError, SuiResult}; +use crate::{ObjectID, SequenceNumber, SUI_FRAMEWORK_ADDRESS}; use move_core_types::language_storage::{StructTag, TypeTag}; use move_core_types::value::{MoveStruct, MoveValue}; use schemars::JsonSchema; use serde::Deserialize; use serde::Serialize; +use serde_json::Value; +use serde_with::serde_as; +use serde_with::DisplayFromStr; +use std::fmt::{Display, Formatter}; -use crate::base_types::ObjectDigest; -use crate::error::{SuiError, SuiResult}; -use crate::{ObjectID, SequenceNumber, SUI_FRAMEWORK_ADDRESS}; - -#[derive(Clone, Serialize, Deserialize, JsonSchema, Ord, PartialOrd, Eq, PartialEq, Debug)] +#[derive(Clone, Serialize, Deserialize, JsonSchema, Debug)] #[serde(rename_all = "camelCase")] pub struct DynamicFieldInfo { - pub name: String, + pub name: DynamicFieldName, pub type_: DynamicFieldType, pub object_type: String, pub object_id: ObjectID, @@ -22,6 +25,23 @@ pub struct DynamicFieldInfo { pub digest: ObjectDigest, } +#[serde_as] +#[derive(Clone, Serialize, Deserialize, JsonSchema, Debug)] +#[serde(rename_all = "camelCase")] +pub struct DynamicFieldName { + pub type_: String, + // Bincode does not like serde_json::Value, rocksdb will not insert the value without this hack. + #[schemars(with = "Value")] + #[serde_as(as = "DisplayFromStr")] + pub value: Value, +} + +impl Display for DynamicFieldName { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "{}: {}", self.type_, self.value) + } +} + #[derive(Clone, Serialize, Deserialize, JsonSchema, Ord, PartialOrd, Eq, PartialEq, Debug)] pub enum DynamicFieldType { #[serde(rename_all = "camelCase")] @@ -38,7 +58,7 @@ impl DynamicFieldInfo { pub fn parse_move_object( move_struct: &MoveStruct, - ) -> SuiResult<(String, DynamicFieldType, ObjectID)> { + ) -> SuiResult<(MoveValue, DynamicFieldType, ObjectID)> { let name = extract_field_from_move_struct(move_struct, "name").ok_or_else(|| { SuiError::ObjectDeserializationError { error: "Cannot extract [name] field from sui::dynamic_field::Field".to_string(), @@ -70,7 +90,7 @@ impl DynamicFieldInfo { sui::dynamic_field::Field, {value:?}" ), })?; - (name.to_string(), DynamicFieldType::DynamicObject, object_id) + (name.clone(), DynamicFieldType::DynamicObject, object_id) } else { // ID of the Field object let object_id = extract_object_id(move_struct).ok_or_else(|| { @@ -81,7 +101,7 @@ impl DynamicFieldInfo { ), } })?; - (name.to_string(), DynamicFieldType::DynamicField, object_id) + (name.clone(), DynamicFieldType::DynamicField, object_id) }) } } From e6f1931db038aa9e5ddc326d4e27ffea1d783861 Mon Sep 17 00:00:00 2001 From: patrick Date: Wed, 11 Jan 2023 16:29:50 +0000 Subject: [PATCH 02/11] add more name parsing test --- .../src/unit_tests/authority_tests.rs | 116 ++++++++---------- .../object_basics/sources/object_basics.move | 16 +++ crates/sui-open-rpc/spec/openrpc.json | 17 ++- 3 files changed, 79 insertions(+), 70 deletions(-) diff --git a/crates/sui-core/src/unit_tests/authority_tests.rs b/crates/sui-core/src/unit_tests/authority_tests.rs index 0884faab56aa6..ddb419c5aa909 100644 --- a/crates/sui-core/src/unit_tests/authority_tests.rs +++ b/crates/sui-core/src/unit_tests/authority_tests.rs @@ -17,6 +17,7 @@ use move_binary_format::{ file_format::{self, AddressIdentifierIndex, IdentifierIndex, ModuleHandle}, CompiledModule, }; +use move_core_types::identifier::IdentStr; use move_core_types::{ account_address::AccountAddress, ident_str, identifier::Identifier, language_storage::TypeTag, }; @@ -25,6 +26,7 @@ use rand::{ prelude::StdRng, Rng, SeedableRng, }; +use serde_json::json; use std::collections::HashSet; use std::fs; use std::future::Future; @@ -3183,13 +3185,29 @@ async fn test_store_revert_unwrap_move_call() { } #[tokio::test] async fn test_store_get_dynamic_object() { + let (_, fields) = create_and_retrieve_df_info(ident_str!("add_ofield")).await; + assert_eq!(fields.len(), 1); + assert_eq!(fields[0].type_, DynamicFieldType::DynamicObject); +} + +#[tokio::test] +async fn test_store_get_dynamic_field() { + let (_, fields) = create_and_retrieve_df_info(ident_str!("add_field")).await; + + assert_eq!(fields.len(), 1); + assert!(matches!(fields[0].type_, DynamicFieldType::DynamicField)); + assert_eq!(json!(true), fields[0].name.value); + assert_eq!("bool", fields[0].name.type_) +} + +async fn create_and_retrieve_df_info(function: &IdentStr) -> (SuiAddress, Vec) { let (sender, sender_key): (_, AccountKeyPair) = get_key_pair(); let gas_object_id = ObjectID::random(); let (authority_state, object_basics) = init_state_with_ids_and_object_basics(vec![(sender, gas_object_id)]).await; let create_outer_effects = create_move_object( - &object_basics.0, + &object_basics, &authority_state, &gas_object_id, &sender, @@ -3222,7 +3240,7 @@ async fn test_store_get_dynamic_object() { sender, object_basics.0, ident_str!("object_basics").to_owned(), - ident_str!("add_ofield").to_owned(), + function.to_owned(), vec![], create_inner_effects.gas_object.0, vec![ @@ -3245,82 +3263,44 @@ async fn test_store_get_dynamic_object() { assert!(add_effects.status.is_ok()); assert_eq!(add_effects.created.len(), 1); - let fields = authority_state - .get_dynamic_fields(outer_v0.0, None, usize::MAX) - .unwrap(); - assert_eq!(fields.len(), 1); - assert_eq!(fields[0].type_, DynamicFieldType::DynamicObject); + ( + sender, + authority_state + .get_dynamic_fields(outer_v0.0, None, usize::MAX) + .unwrap(), + ) } #[tokio::test] -async fn test_store_get_dynamic_field() { - let (sender, sender_key): (_, AccountKeyPair) = get_key_pair(); - let gas_object_id = ObjectID::random(); - let (authority_state, object_basics) = - init_state_with_ids_and_object_basics(vec![(sender, gas_object_id)]).await; - - let create_outer_effects = create_move_object( - &object_basics.0, - &authority_state, - &gas_object_id, - &sender, - &sender_key, - ) - .await - .unwrap(); - - assert!(create_outer_effects.status.is_ok()); - assert_eq!(create_outer_effects.created.len(), 1); +async fn test_dynamic_field_struct_name_parsing() { + let (_, fields) = create_and_retrieve_df_info(ident_str!("add_field_with_struct_name")).await; - let create_inner_effects = create_move_object( - &object_basics.0, - &authority_state, - &gas_object_id, - &sender, - &sender_key, - ) - .await - .unwrap(); - - assert!(create_inner_effects.status.is_ok()); - assert_eq!(create_inner_effects.created.len(), 1); - - let outer_v0 = create_outer_effects.created[0].0; - let inner_v0 = create_inner_effects.created[0].0; - - let add_txn = to_sender_signed_transaction( - TransactionData::new_move_call_with_dummy_gas_price( - sender, - object_basics.0, - ident_str!("object_basics").to_owned(), - ident_str!("add_field").to_owned(), - vec![], - create_inner_effects.gas_object.0, - vec![ - CallArg::Object(ObjectArg::ImmOrOwnedObject(outer_v0)), - CallArg::Object(ObjectArg::ImmOrOwnedObject(inner_v0)), - ], - MAX_GAS, - ), - &sender_key, - ); + assert_eq!(fields.len(), 1); + assert!(matches!(fields[0].type_, DynamicFieldType::DynamicField)); + assert_eq!(json!({"name_str": "Test Name"}), fields[0].name.value); + assert_eq!("0x0::object_basics::Name", fields[0].name.type_) +} - let add_cert = init_certified_transaction(add_txn, &authority_state); +#[tokio::test] +async fn test_dynamic_field_bytearray_name_parsing() { + let (_, fields) = + create_and_retrieve_df_info(ident_str!("add_field_with_bytearray_name")).await; - let add_effects = authority_state - .try_execute_for_test(&add_cert) - .await - .unwrap() - .into_message(); + assert_eq!(fields.len(), 1); + assert!(matches!(fields[0].type_, DynamicFieldType::DynamicField)); + assert_eq!("Vec", fields[0].name.type_); + assert_eq!(json!("Test Name".as_bytes()), fields[0].name.value); +} - assert!(add_effects.status.is_ok()); - assert_eq!(add_effects.created.len(), 1); +#[tokio::test] +async fn test_dynamic_field_address_name_parsing() { + let (sender, fields) = + create_and_retrieve_df_info(ident_str!("add_field_with_address_name")).await; - let fields = authority_state - .get_dynamic_fields(outer_v0.0, None, usize::MAX) - .unwrap(); assert_eq!(fields.len(), 1); assert!(matches!(fields[0].type_, DynamicFieldType::DynamicField)); + assert_eq!("Address", fields[0].name.type_); + assert_eq!(json!(sender), fields[0].name.value); } #[tokio::test] diff --git a/crates/sui-core/src/unit_tests/data/object_basics/sources/object_basics.move b/crates/sui-core/src/unit_tests/data/object_basics/sources/object_basics.move index 9b485f7dd8741..d6f8f72ebd4fa 100644 --- a/crates/sui-core/src/unit_tests/data/object_basics/sources/object_basics.move +++ b/crates/sui-core/src/unit_tests/data/object_basics/sources/object_basics.move @@ -107,6 +107,22 @@ module examples::object_basics { ); } + struct Name has copy, drop, store { + name_str: std::string::String + } + + public entry fun add_field_with_struct_name(o: &mut Object, v: Object) { + sui::dynamic_field::add(&mut o.id, Name {name_str: std::string::utf8(b"Test Name")}, v); + } + + public entry fun add_field_with_bytearray_name(o: &mut Object, v: Object) { + sui::dynamic_field::add(&mut o.id,b"Test Name", v); + } + + public entry fun add_field_with_address_name(o: &mut Object, v: Object, ctx: &mut TxContext) { + sui::dynamic_field::add(&mut o.id,tx_context::sender(ctx), v); + } + public entry fun generic_test() {} public entry fun use_clock(_clock: &Clock) {} diff --git a/crates/sui-open-rpc/spec/openrpc.json b/crates/sui-open-rpc/spec/openrpc.json index d03b4710782fe..23195ea89bcdf 100644 --- a/crates/sui-open-rpc/spec/openrpc.json +++ b/crates/sui-open-rpc/spec/openrpc.json @@ -844,7 +844,7 @@ "description": "The Name of the dynamic field", "required": true, "schema": { - "type": "string" + "$ref": "#/components/schemas/DynamicFieldName" } } ], @@ -3475,7 +3475,7 @@ "$ref": "#/components/schemas/ObjectDigest" }, "name": { - "type": "string" + "$ref": "#/components/schemas/DynamicFieldName" }, "objectId": { "$ref": "#/components/schemas/ObjectID" @@ -3491,6 +3491,19 @@ } } }, + "DynamicFieldName": { + "type": "object", + "required": [ + "type", + "value" + ], + "properties": { + "type": { + "type": "string" + }, + "value": true + } + }, "DynamicFieldType": { "type": "string", "enum": [ From 250acd54324ce5a88b89c418c965979fe2aab010 Mon Sep 17 00:00:00 2001 From: patrick Date: Thu, 12 Jan 2023 01:40:50 +0000 Subject: [PATCH 03/11] make `Readable` generic added serde adaptors to make fastcrypto's Hex, Base64 and Base58 work with array and TryFrom> types. --- crates/sui-types/src/base_types.rs | 16 +- crates/sui-types/src/crypto.rs | 9 +- crates/sui-types/src/dynamic_field.rs | 6 +- crates/sui-types/src/messages_checkpoint.rs | 1 + crates/sui-types/src/sui_serde.rs | 154 +++++++++++++------- 5 files changed, 123 insertions(+), 63 deletions(-) diff --git a/crates/sui-types/src/base_types.rs b/crates/sui-types/src/base_types.rs index 92809d1b54ccf..9aa128370f3a0 100644 --- a/crates/sui-types/src/base_types.rs +++ b/crates/sui-types/src/base_types.rs @@ -2,6 +2,18 @@ // Copyright (c) Mysten Labs, Inc. // SPDX-License-Identifier: Apache-2.0 +pub use crate::committee::EpochId; +use crate::crypto::{ + AuthorityPublicKey, AuthorityPublicKeyBytes, KeypairTraits, PublicKey, SuiPublicKey, +}; +use crate::error::ExecutionError; +use crate::error::ExecutionErrorKind; +use crate::error::SuiError; +use crate::gas_coin::GasCoin; +use crate::object::{Object, Owner}; +use crate::sui_serde::HexObjectId; +use crate::sui_serde::Readable; +use crate::sui_serde::ToArray; use anyhow::anyhow; use fastcrypto::encoding::decode_bytes_hex; use move_core_types::account_address::AccountAddress; @@ -74,7 +86,7 @@ pub type AuthorityName = AuthorityPublicKeyBytes; #[derive(Eq, PartialEq, Clone, Copy, PartialOrd, Ord, Hash, Serialize, Deserialize, JsonSchema)] pub struct ObjectID( #[schemars(with = "Hex")] - #[serde_as(as = "Readable")] + #[serde_as(as = "Readable")] AccountAddress, ); @@ -155,7 +167,7 @@ pub const SUI_ADDRESS_LENGTH: usize = ObjectID::LENGTH; )] pub struct SuiAddress( #[schemars(with = "Hex")] - #[serde_as(as = "Readable")] + #[serde_as(as = "Readable, _>")] [u8; SUI_ADDRESS_LENGTH], ); diff --git a/crates/sui-types/src/crypto.rs b/crates/sui-types/src/crypto.rs index 28445f6dc371f..328edb4e5acf2 100644 --- a/crates/sui-types/src/crypto.rs +++ b/crates/sui-types/src/crypto.rs @@ -1,5 +1,6 @@ // Copyright (c) Mysten Labs, Inc. // SPDX-License-Identifier: Apache-2.0 +use crate::sui_serde::ToArray; use anyhow::{anyhow, Error}; use derive_more::From; use eyre::eyre; @@ -323,7 +324,7 @@ impl PublicKey { )] pub struct AuthorityPublicKeyBytes( #[schemars(with = "Base64")] - #[serde_as(as = "Readable")] + #[serde_as(as = "Readable, Bytes>")] [u8; AuthorityPublicKey::LENGTH], ); @@ -814,7 +815,7 @@ impl SuiPublicKey for BLS12381PublicKey { #[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash)] pub struct Ed25519SuiSignature( #[schemars(with = "Base64")] - #[serde_as(as = "Readable")] + #[serde_as(as = "Readable, Bytes>")] [u8; Ed25519PublicKey::LENGTH + Ed25519Signature::LENGTH + 1], ); @@ -872,7 +873,7 @@ impl Signer for Ed25519KeyPair { #[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash)] pub struct Secp256k1SuiSignature( #[schemars(with = "Base64")] - #[serde_as(as = "Readable")] + #[serde_as(as = "Readable, Bytes>")] [u8; Secp256k1PublicKey::LENGTH + Secp256k1Signature::LENGTH + 1], ); @@ -923,7 +924,7 @@ impl Signer for Secp256k1KeyPair { #[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash)] pub struct Secp256r1SuiSignature( #[schemars(with = "Base64")] - #[serde_as(as = "Readable")] + #[serde_as(as = "Readable, Bytes>")] [u8; Secp256r1PublicKey::LENGTH + Secp256r1Signature::LENGTH + 1], ); diff --git a/crates/sui-types/src/dynamic_field.rs b/crates/sui-types/src/dynamic_field.rs index fa91090124132..690778114417f 100644 --- a/crates/sui-types/src/dynamic_field.rs +++ b/crates/sui-types/src/dynamic_field.rs @@ -3,6 +3,7 @@ use crate::base_types::ObjectDigest; use crate::error::{SuiError, SuiResult}; +use crate::sui_serde::Readable; use crate::{ObjectID, SequenceNumber, SUI_FRAMEWORK_ADDRESS}; use move_core_types::language_storage::{StructTag, TypeTag}; use move_core_types::value::{MoveStruct, MoveValue}; @@ -13,7 +14,6 @@ use serde_json::Value; use serde_with::serde_as; use serde_with::DisplayFromStr; use std::fmt::{Display, Formatter}; - #[derive(Clone, Serialize, Deserialize, JsonSchema, Debug)] #[serde(rename_all = "camelCase")] pub struct DynamicFieldInfo { @@ -30,9 +30,9 @@ pub struct DynamicFieldInfo { #[serde(rename_all = "camelCase")] pub struct DynamicFieldName { pub type_: String, - // Bincode does not like serde_json::Value, rocksdb will not insert the value without this hack. + // Bincode does not like serde_json::Value, rocksdb will not insert the value without serializing value as string. #[schemars(with = "Value")] - #[serde_as(as = "DisplayFromStr")] + #[serde_as(as = "Readable<_, DisplayFromStr>")] pub value: Value, } diff --git a/crates/sui-types/src/messages_checkpoint.rs b/crates/sui-types/src/messages_checkpoint.rs index b37c845d3c920..5908add738964 100644 --- a/crates/sui-types/src/messages_checkpoint.rs +++ b/crates/sui-types/src/messages_checkpoint.rs @@ -17,6 +17,7 @@ use crate::{ crypto::{sha3_hash, AuthoritySignature, VerificationObligation}, error::SuiError, }; +use fastcrypto::encoding::{Base58, Encoding, Hex}; use fastcrypto::traits::Signer; use schemars::JsonSchema; use serde::de::DeserializeOwned; diff --git a/crates/sui-types/src/sui_serde.rs b/crates/sui-types/src/sui_serde.rs index dfd64d35f1c6e..8b4590af4c8f5 100644 --- a/crates/sui-types/src/sui_serde.rs +++ b/crates/sui-types/src/sui_serde.rs @@ -5,7 +5,8 @@ use std::fmt::Debug; use std::marker::PhantomData; use anyhow::anyhow; -use fastcrypto::encoding::Encoding; +use fastcrypto::encoding::{Base64, Encoding, Hex}; +use fastcrypto::traits::ToFromBytes; use move_core_types::account_address::AccountAddress; use serde; use serde::de::{Deserializer, Error}; @@ -31,108 +32,153 @@ where S::Error::custom(format!("byte serialization failed, cause by: {:?}", e)) } -/// Use with serde_as to encode/decode bytes to/from Base64/Hex for human-readable serializer and deserializer -/// E : Encoding of the human readable output -/// R : serde_as SerializeAs/DeserializeAs delegation +/// Use with serde_as to control serde for human-readable serialization and deserialization +/// `H` : serde_as SerializeAs/DeserializeAs delegation for human readable in/output +/// `R` : serde_as SerializeAs/DeserializeAs delegation for non-human readable in/output /// /// # Example: /// /// ```text /// #[serde_as] /// #[derive(Deserialize, Serialize)] -/// struct Example(#[serde_as(as = "Readable(Hex, _)")] [u8; 20]); +/// struct Example(#[serde_as(as = "Readable")] [u8; 20]); /// ``` /// -/// The above example will encode the byte array to Hex string for human-readable serializer +/// The above example will delegate human-readable serde to `DisplayFromStr` /// and array tuple (default) for non-human-readable serializer. -pub struct Readable { - element: PhantomData, - encoding: PhantomData, +pub struct Readable { + human_readable: PhantomData, + non_human_readable: PhantomData, } -impl SerializeAs for Readable +impl SerializeAs for Readable where - T: AsRef<[u8]>, + H: SerializeAs, R: SerializeAs, - E: SerializeAs, { fn serialize_as(value: &T, serializer: S) -> Result where S: Serializer, { if serializer.is_human_readable() { - E::serialize_as(value, serializer) + H::serialize_as(value, serializer) } else { R::serialize_as(value, serializer) } } } -/// DeserializeAs support for Arrays -impl<'de, R, E, const N: usize> DeserializeAs<'de, [u8; N]> for Readable + +impl<'de, R, H, T> DeserializeAs<'de, T> for Readable where - R: DeserializeAs<'de, [u8; N]>, - E: DeserializeAs<'de, Vec>, + H: DeserializeAs<'de, T>, + R: DeserializeAs<'de, T>, { - fn deserialize_as(deserializer: D) -> Result<[u8; N], D::Error> + fn deserialize_as(deserializer: D) -> Result where D: Deserializer<'de>, { if deserializer.is_human_readable() { - let value = E::deserialize_as(deserializer)?; - if value.len() != N { - return Err(Error::custom(anyhow!( - "invalid array length {}, expecting {}", - value.len(), - N - ))); - } - let mut array = [0u8; N]; - array.copy_from_slice(&value[..N]); - Ok(array) + H::deserialize_as(deserializer) } else { R::deserialize_as(deserializer) } } } -/// DeserializeAs support for Vec -impl<'de, R, E> DeserializeAs<'de, Vec> for Readable -where - R: DeserializeAs<'de, Vec>, - E: DeserializeAs<'de, Vec>, -{ - fn deserialize_as(deserializer: D) -> Result, D::Error> + +/// custom serde for AccountAddress +pub struct HexObjectId; + +impl SerializeAs for HexObjectId { + fn serialize_as(value: &AccountAddress, serializer: S) -> Result + where + S: Serializer, + { + Hex::serialize_as(value, serializer) + } +} + +impl<'de> DeserializeAs<'de, AccountAddress> for HexObjectId { + fn deserialize_as(deserializer: D) -> Result where D: Deserializer<'de>, { - if deserializer.is_human_readable() { - E::deserialize_as(deserializer) + let s = String::deserialize(deserializer)?; + if s.starts_with("0x") { + AccountAddress::from_hex_literal(&s) } else { - R::deserialize_as(deserializer) + AccountAddress::from_hex(&s) } + .map_err(to_custom_error::<'de, D, _>) } } -/// DeserializeAs support for AccountAddress -impl<'de, R, E> DeserializeAs<'de, AccountAddress> for Readable +/// DeserializeAs adaptor for `Vec` <> `TryFrom>` +pub struct TryFromVec { + vec: PhantomData, +} + +impl SerializeAs for TryFromVec where - R: DeserializeAs<'de, AccountAddress>, - E: Encoding, + V: SerializeAs, { - fn deserialize_as(deserializer: D) -> Result + fn serialize_as(value: &T, serializer: S) -> Result + where + S: Serializer, + { + V::serialize_as(value, serializer) + } +} + +impl<'de, V, T> DeserializeAs<'de, T> for TryFromVec +where + V: DeserializeAs<'de, Vec>, + T: TryFrom>, + >>::Error: std::fmt::Display, +{ + fn deserialize_as(deserializer: D) -> Result where D: Deserializer<'de>, { - if deserializer.is_human_readable() { - let s = String::deserialize(deserializer)?; - if s.starts_with("0x") { - AccountAddress::from_hex_literal(&s) - } else { - AccountAddress::from_hex(&s) - } - .map_err(to_custom_error::<'de, D, _>) - } else { - R::deserialize_as(deserializer) + T::try_from(V::deserialize_as(deserializer)?).map_err(Error::custom) + } +} + +/// DeserializeAs adaptor for `Vec` <> `[u8;N]` +pub struct ToArray { + vec: PhantomData, +} + +impl SerializeAs for ToArray +where + V: SerializeAs, +{ + fn serialize_as(value: &T, serializer: S) -> Result + where + S: Serializer, + { + V::serialize_as(value, serializer) + } +} + +impl<'de, V, const N: usize> DeserializeAs<'de, [u8; N]> for ToArray +where + V: DeserializeAs<'de, Vec>, +{ + fn deserialize_as(deserializer: D) -> Result<[u8; N], D::Error> + where + D: Deserializer<'de>, + { + let value = V::deserialize_as(deserializer)?; + if value.len() != N { + return Err(Error::custom(anyhow!( + "invalid array length {}, expecting {}", + value.len(), + N + ))); } + let mut array = [0u8; N]; + array.copy_from_slice(&value[..N]); + Ok(array) } } From ae01de7725c5d28299ddf5442ae6d4e67f92a311 Mon Sep 17 00:00:00 2001 From: patrick Date: Thu, 12 Jan 2023 12:08:07 +0000 Subject: [PATCH 04/11] use TypeTag instead of String --- crates/sui-core/src/authority.rs | 9 ++-- .../src/unit_tests/authority_tests.rs | 12 ++++-- crates/sui-json-rpc-types/src/lib.rs | 41 +------------------ crates/sui-types/src/dynamic_field.rs | 4 +- 4 files changed, 19 insertions(+), 47 deletions(-) diff --git a/crates/sui-core/src/authority.rs b/crates/sui-core/src/authority.rs index 03ab79a3a8db7..b18afa8c24915 100644 --- a/crates/sui-core/src/authority.rs +++ b/crates/sui-core/src/authority.rs @@ -1273,12 +1273,15 @@ impl AuthorityState { self.module_cache.as_ref(), )?; - let (name, type_, object_id) = + let (name_value, type_, object_id) = DynamicFieldInfo::parse_move_object(&move_struct).tap_err(|e| warn!("{e}"))?; + // Safe to unwrap, we checked this is a dynamic field object, it must have type parameters. + let name_type = move_object.type_.type_params.first().unwrap().clone(); + let name = DynamicFieldName { - type_: SuiMoveValue::parse_move_value_type(&name), - value: SuiMoveValue::from(name).to_json_value(), + type_: name_type, + value: SuiMoveValue::from(name_value).to_json_value(), }; Ok(Some(match type_ { diff --git a/crates/sui-core/src/unit_tests/authority_tests.rs b/crates/sui-core/src/unit_tests/authority_tests.rs index ddb419c5aa909..2a943f8f7e957 100644 --- a/crates/sui-core/src/unit_tests/authority_tests.rs +++ b/crates/sui-core/src/unit_tests/authority_tests.rs @@ -40,6 +40,7 @@ use sui_types::utils::{ use sui_types::{SUI_CLOCK_OBJECT_ID, SUI_CLOCK_OBJECT_SHARED_VERSION, SUI_FRAMEWORK_OBJECT_ID}; use crate::epoch::epoch_metrics::EpochMetrics; +use move_core_types::parser::parse_type_tag; use std::{convert::TryInto, env}; use sui_macros::sim_test; use sui_protocol_config::{ProtocolConfig, SupportedProtocolVersions}; @@ -3197,7 +3198,7 @@ async fn test_store_get_dynamic_field() { assert_eq!(fields.len(), 1); assert!(matches!(fields[0].type_, DynamicFieldType::DynamicField)); assert_eq!(json!(true), fields[0].name.value); - assert_eq!("bool", fields[0].name.type_) + assert_eq!(TypeTag::Bool, fields[0].name.type_) } async fn create_and_retrieve_df_info(function: &IdentStr) -> (SuiAddress, Vec) { @@ -3278,7 +3279,10 @@ async fn test_dynamic_field_struct_name_parsing() { assert_eq!(fields.len(), 1); assert!(matches!(fields[0].type_, DynamicFieldType::DynamicField)); assert_eq!(json!({"name_str": "Test Name"}), fields[0].name.value); - assert_eq!("0x0::object_basics::Name", fields[0].name.type_) + assert_eq!( + parse_type_tag("0x0::object_basics::Name").unwrap(), + fields[0].name.type_ + ) } #[tokio::test] @@ -3288,7 +3292,7 @@ async fn test_dynamic_field_bytearray_name_parsing() { assert_eq!(fields.len(), 1); assert!(matches!(fields[0].type_, DynamicFieldType::DynamicField)); - assert_eq!("Vec", fields[0].name.type_); + assert_eq!(parse_type_tag("vector").unwrap(), fields[0].name.type_); assert_eq!(json!("Test Name".as_bytes()), fields[0].name.value); } @@ -3299,7 +3303,7 @@ async fn test_dynamic_field_address_name_parsing() { assert_eq!(fields.len(), 1); assert!(matches!(fields[0].type_, DynamicFieldType::DynamicField)); - assert_eq!("Address", fields[0].name.type_); + assert_eq!(parse_type_tag("address").unwrap(), fields[0].name.type_); assert_eq!(json!(sender), fields[0].name.value); } diff --git a/crates/sui-json-rpc-types/src/lib.rs b/crates/sui-json-rpc-types/src/lib.rs index f3a67af7b495e..597120113e1cf 100644 --- a/crates/sui-json-rpc-types/src/lib.rs +++ b/crates/sui-json-rpc-types/src/lib.rs @@ -1186,6 +1186,7 @@ pub enum SuiMoveValue { } impl SuiMoveValue { + /// Extract values from MoveValue without type information in json format pub fn to_json_value(self) -> Value { match self { SuiMoveValue::Struct(move_struct) => move_struct.to_json_value(), @@ -1198,45 +1199,6 @@ impl SuiMoveValue { SuiMoveValue::Option(v) => json!(v), } } - - pub fn parse_move_value_type(value: &MoveValue) -> String { - match value { - MoveValue::U8(_) => "u8".into(), - MoveValue::U16(_) => "u16".into(), - MoveValue::U32(_) => "u32".into(), - MoveValue::U64(_) => "u64".into(), - MoveValue::U128(_) => "u128".into(), - MoveValue::U256(_) => "u256".into(), - MoveValue::Bool(_) => "bool".into(), - MoveValue::Address(_) => "Address".into(), - MoveValue::Signer(_) => "Signer".into(), - MoveValue::Vector(v) => { - let inner_type = v - .first() - .map(Self::parse_move_value_type) - .unwrap_or_else(|| "?".into()); - format!("Vec<{inner_type}>") - } - MoveValue::Struct(s) => match s { - MoveStruct::Runtime(v) => { - let inner_type = v - .first() - .map(Self::parse_move_value_type) - .unwrap_or_else(|| "?".into()); - format!("Vec<{inner_type}>") - } - // Treat this like tuple - MoveStruct::WithFields(f) => { - let types = f - .iter() - .map(|(_, v)| Self::parse_move_value_type(v)) - .join(","); - format!("({types})") - } - MoveStruct::WithTypes { type_, .. } => type_.to_string(), - }, - } - } } impl Display for SuiMoveValue { @@ -1322,6 +1284,7 @@ pub enum SuiMoveStruct { } impl SuiMoveStruct { + /// Extract values from MoveStruct without type information in json format pub fn to_json_value(self) -> Value { // Unwrap MoveStructs match self { diff --git a/crates/sui-types/src/dynamic_field.rs b/crates/sui-types/src/dynamic_field.rs index 690778114417f..e400e5dfe0a9d 100644 --- a/crates/sui-types/src/dynamic_field.rs +++ b/crates/sui-types/src/dynamic_field.rs @@ -29,7 +29,9 @@ pub struct DynamicFieldInfo { #[derive(Clone, Serialize, Deserialize, JsonSchema, Debug)] #[serde(rename_all = "camelCase")] pub struct DynamicFieldName { - pub type_: String, + #[schemars(with = "String")] + #[serde_as(as = "Readable")] + pub type_: TypeTag, // Bincode does not like serde_json::Value, rocksdb will not insert the value without serializing value as string. #[schemars(with = "Value")] #[serde_as(as = "Readable<_, DisplayFromStr>")] From 247f380bf942c7de1b688850cecf12dd30030846 Mon Sep 17 00:00:00 2001 From: patrick Date: Mon, 23 Jan 2023 12:06:46 +0000 Subject: [PATCH 05/11] add test for dynamic_object_field and bug fix --- crates/sui-core/src/authority.rs | 3 +- .../src/unit_tests/authority_tests.rs | 37 ++++++++++++++++++- .../object_basics/sources/object_basics.move | 12 ++++++ crates/sui-json-rpc/src/read_api.rs | 1 - crates/sui-types/src/dynamic_field.rs | 16 ++++++++ 5 files changed, 65 insertions(+), 4 deletions(-) diff --git a/crates/sui-core/src/authority.rs b/crates/sui-core/src/authority.rs index b18afa8c24915..7d96717e1efe2 100644 --- a/crates/sui-core/src/authority.rs +++ b/crates/sui-core/src/authority.rs @@ -1276,8 +1276,7 @@ impl AuthorityState { let (name_value, type_, object_id) = DynamicFieldInfo::parse_move_object(&move_struct).tap_err(|e| warn!("{e}"))?; - // Safe to unwrap, we checked this is a dynamic field object, it must have type parameters. - let name_type = move_object.type_.type_params.first().unwrap().clone(); + let name_type = DynamicFieldInfo::try_extract_field_name(&move_object.type_, &type_)?; let name = DynamicFieldName { type_: name_type, diff --git a/crates/sui-core/src/unit_tests/authority_tests.rs b/crates/sui-core/src/unit_tests/authority_tests.rs index 2a943f8f7e957..97508a80741e0 100644 --- a/crates/sui-core/src/unit_tests/authority_tests.rs +++ b/crates/sui-core/src/unit_tests/authority_tests.rs @@ -3208,7 +3208,7 @@ async fn create_and_retrieve_df_info(function: &IdentStr) -> (SuiAddress, Vec").unwrap(), fields[0].name.type_); + assert_eq!(json!("Test Name".as_bytes()), fields[0].name.value); +} + +#[tokio::test] +async fn test_dynamic_object_field_address_name_parsing() { + let (sender, fields) = + create_and_retrieve_df_info(ident_str!("add_ofield_with_address_name")).await; + + assert_eq!(fields.len(), 1); + assert!(matches!(fields[0].type_, DynamicFieldType::DynamicObject)); + assert_eq!(parse_type_tag("address").unwrap(), fields[0].name.type_); + assert_eq!(json!(sender), fields[0].name.value); +} + #[tokio::test] async fn test_store_revert_add_ofield() { let (sender, sender_key): (_, AccountKeyPair) = get_key_pair(); diff --git a/crates/sui-core/src/unit_tests/data/object_basics/sources/object_basics.move b/crates/sui-core/src/unit_tests/data/object_basics/sources/object_basics.move index d6f8f72ebd4fa..e074e161447cf 100644 --- a/crates/sui-core/src/unit_tests/data/object_basics/sources/object_basics.move +++ b/crates/sui-core/src/unit_tests/data/object_basics/sources/object_basics.move @@ -115,14 +115,26 @@ module examples::object_basics { sui::dynamic_field::add(&mut o.id, Name {name_str: std::string::utf8(b"Test Name")}, v); } + public entry fun add_ofield_with_struct_name(o: &mut Object, v: Object) { + ofield::add(&mut o.id, Name {name_str: std::string::utf8(b"Test Name")}, v); + } + public entry fun add_field_with_bytearray_name(o: &mut Object, v: Object) { sui::dynamic_field::add(&mut o.id,b"Test Name", v); } + public entry fun add_ofield_with_bytearray_name(o: &mut Object, v: Object) { + ofield::add(&mut o.id,b"Test Name", v); + } + public entry fun add_field_with_address_name(o: &mut Object, v: Object, ctx: &mut TxContext) { sui::dynamic_field::add(&mut o.id,tx_context::sender(ctx), v); } + public entry fun add_ofield_with_address_name(o: &mut Object, v: Object, ctx: &mut TxContext) { + ofield::add(&mut o.id,tx_context::sender(ctx), v); + } + public entry fun generic_test() {} public entry fun use_clock(_clock: &Clock) {} diff --git a/crates/sui-json-rpc/src/read_api.rs b/crates/sui-json-rpc/src/read_api.rs index d5d854825f791..558d352b331b0 100644 --- a/crates/sui-json-rpc/src/read_api.rs +++ b/crates/sui-json-rpc/src/read_api.rs @@ -34,7 +34,6 @@ use sui_types::move_package::normalize_modules; use sui_types::object::{Data, ObjectRead}; use sui_types::query::TransactionQuery; -use sui_adapter::execution_mode::DevInspect; use sui_types::dynamic_field::DynamicFieldName; use tracing::debug; diff --git a/crates/sui-types/src/dynamic_field.rs b/crates/sui-types/src/dynamic_field.rs index e400e5dfe0a9d..e62de570e01bc 100644 --- a/crates/sui-types/src/dynamic_field.rs +++ b/crates/sui-types/src/dynamic_field.rs @@ -58,6 +58,22 @@ impl DynamicFieldInfo { && tag.name.as_str() == "Field" } + pub fn try_extract_field_name(tag: &StructTag, type_: &DynamicFieldType) -> SuiResult { + match (type_, tag.type_params.first()) { + (DynamicFieldType::DynamicField, Some(name_type)) => Ok(name_type.clone()), + (DynamicFieldType::DynamicObject, Some(TypeTag::Struct(s))) => Ok(s + .type_params + .first() + .ok_or_else(|| SuiError::ObjectDeserializationError { + error: format!("Error extracting dynamic object name from object: {tag}"), + })? + .clone()), + _ => Err(SuiError::ObjectDeserializationError { + error: format!("Error extracting dynamic object name from object: {tag}"), + }), + } + } + pub fn parse_move_object( move_struct: &MoveStruct, ) -> SuiResult<(MoveValue, DynamicFieldType, ObjectID)> { From d34a522e1288b933edc53407b9eb4ab9fdb7b9cc Mon Sep 17 00:00:00 2001 From: patrick Date: Tue, 31 Jan 2023 12:31:09 +0000 Subject: [PATCH 06/11] add DynamicFieldName to TS SDK --- .changeset/witty-bananas-yell.md | 5 ++++ crates/sui-types/src/base_types.rs | 25 +++++-------------- crates/sui-types/src/digests.rs | 6 ++--- crates/sui-types/src/messages_checkpoint.rs | 1 - .../src/providers/json-rpc-provider.ts | 4 +-- sdk/typescript/src/providers/provider.ts | 4 +-- sdk/typescript/src/providers/void-provider.ts | 4 +-- sdk/typescript/src/types/dynamic_fields.ts | 8 +++++- 8 files changed, 27 insertions(+), 30 deletions(-) create mode 100644 .changeset/witty-bananas-yell.md diff --git a/.changeset/witty-bananas-yell.md b/.changeset/witty-bananas-yell.md new file mode 100644 index 0000000000000..81f0ec7a0b57c --- /dev/null +++ b/.changeset/witty-bananas-yell.md @@ -0,0 +1,5 @@ +--- +"@mysten/sui.js": minor +--- + +Use DynamicFieldName struct instead of string for dynamic field's name diff --git a/crates/sui-types/src/base_types.rs b/crates/sui-types/src/base_types.rs index 9aa128370f3a0..cf1d67ebf2fcf 100644 --- a/crates/sui-types/src/base_types.rs +++ b/crates/sui-types/src/base_types.rs @@ -4,18 +4,23 @@ pub use crate::committee::EpochId; use crate::crypto::{ - AuthorityPublicKey, AuthorityPublicKeyBytes, KeypairTraits, PublicKey, SuiPublicKey, + AuthorityPublicKey, AuthorityPublicKeyBytes, KeypairTraits, PublicKey, SignatureScheme, + SuiPublicKey, }; +pub use crate::digests::{ObjectDigest, TransactionDigest, TransactionEffectsDigest}; use crate::error::ExecutionError; use crate::error::ExecutionErrorKind; use crate::error::SuiError; use crate::gas_coin::GasCoin; +use crate::multisig::MultiSigPublicKey; use crate::object::{Object, Owner}; use crate::sui_serde::HexObjectId; use crate::sui_serde::Readable; use crate::sui_serde::ToArray; use anyhow::anyhow; use fastcrypto::encoding::decode_bytes_hex; +use fastcrypto::encoding::{Encoding, Hex}; +use fastcrypto::hash::{HashFunction, Sha3_256}; use move_core_types::account_address::AccountAddress; use move_core_types::ident_str; use move_core_types::identifier::IdentStr; @@ -29,24 +34,6 @@ use std::convert::{TryFrom, TryInto}; use std::fmt; use std::str::FromStr; -pub use crate::committee::EpochId; -use crate::crypto::{ - AuthorityPublicKey, AuthorityPublicKeyBytes, KeypairTraits, PublicKey, SignatureScheme, - SuiPublicKey, SuiSignature, -}; -pub use crate::digests::{ObjectDigest, TransactionDigest, TransactionEffectsDigest}; -use crate::epoch_data::EpochData; -use crate::error::ExecutionErrorKind; -use crate::error::SuiError; -use crate::error::{ExecutionError, SuiResult}; -use crate::gas_coin::GasCoin; -use crate::multisig::MultiSigPublicKey; -use crate::object::{Object, Owner}; -use crate::signature::GenericSignature; -use crate::sui_serde::Readable; -use fastcrypto::encoding::{Encoding, Hex}; -use fastcrypto::hash::{HashFunction, Sha3_256}; - #[cfg(test)] #[path = "unit_tests/base_types_tests.rs"] mod base_types_tests; diff --git a/crates/sui-types/src/digests.rs b/crates/sui-types/src/digests.rs index 383add21f888a..3e9bc3ca86a69 100644 --- a/crates/sui-types/src/digests.rs +++ b/crates/sui-types/src/digests.rs @@ -4,11 +4,11 @@ use std::fmt; use crate::sui_serde::Readable; +use crate::sui_serde::ToArray; use fastcrypto::encoding::{Base58, Base64, Encoding}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use serde_with::{serde_as, Bytes}; - /// A representation of a SHA3-256 Digest #[serde_as] #[derive( @@ -16,7 +16,7 @@ use serde_with::{serde_as, Bytes}; )] pub struct Sha3Digest( #[schemars(with = "Base58")] - #[serde_as(as = "Readable")] + #[serde_as(as = "Readable, Bytes>")] [u8; 32], ); @@ -464,7 +464,7 @@ impl fmt::UpperHex for TransactionEffectsDigest { #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, JsonSchema)] pub struct ObjectDigest( #[schemars(with = "Base64")] - #[serde_as(as = "Readable")] + #[serde_as(as = "Readable, Bytes>")] [u8; 32], // Sha3Digest, ); diff --git a/crates/sui-types/src/messages_checkpoint.rs b/crates/sui-types/src/messages_checkpoint.rs index 5908add738964..b37c845d3c920 100644 --- a/crates/sui-types/src/messages_checkpoint.rs +++ b/crates/sui-types/src/messages_checkpoint.rs @@ -17,7 +17,6 @@ use crate::{ crypto::{sha3_hash, AuthoritySignature, VerificationObligation}, error::SuiError, }; -use fastcrypto::encoding::{Base58, Encoding, Hex}; use fastcrypto::traits::Signer; use schemars::JsonSchema; use serde::de::DeserializeOwned; diff --git a/sdk/typescript/src/providers/json-rpc-provider.ts b/sdk/typescript/src/providers/json-rpc-provider.ts index 3f91dc721008b..f1b20373fa2ad 100644 --- a/sdk/typescript/src/providers/json-rpc-provider.ts +++ b/sdk/typescript/src/providers/json-rpc-provider.ts @@ -61,7 +61,7 @@ import { versionToString, } from '../types'; import { lt } from '@suchipi/femver'; -import { DynamicFieldPage } from '../types/dynamic_fields'; +import { DynamicFieldName, DynamicFieldPage } from '../types/dynamic_fields'; import { DEFAULT_CLIENT_OPTIONS, WebsocketClient, @@ -930,7 +930,7 @@ export class JsonRpcProvider extends Provider { async getDynamicFieldObject( parent_object_id: ObjectId, - name: string, + name: DynamicFieldName, ): Promise { try { const resp = await this.client.requestWithType( diff --git a/sdk/typescript/src/providers/provider.ts b/sdk/typescript/src/providers/provider.ts index f353c7403f505..de2856d7e4282 100644 --- a/sdk/typescript/src/providers/provider.ts +++ b/sdk/typescript/src/providers/provider.ts @@ -47,7 +47,7 @@ import { CommitteeInfo, } from '../types'; -import { DynamicFieldPage } from '../types/dynamic_fields'; +import { DynamicFieldName, DynamicFieldPage } from '../types/dynamic_fields'; /////////////////////////////// // Exported Abstracts @@ -356,7 +356,7 @@ export abstract class Provider { */ abstract getDynamicFieldObject( parent_object_id: ObjectId, - name: string, + name: DynamicFieldName, ): Promise; /** diff --git a/sdk/typescript/src/providers/void-provider.ts b/sdk/typescript/src/providers/void-provider.ts index acc42fc1805af..c36fef5c9cc83 100644 --- a/sdk/typescript/src/providers/void-provider.ts +++ b/sdk/typescript/src/providers/void-provider.ts @@ -48,7 +48,7 @@ import { } from '../types'; import { Provider } from './provider'; -import { DynamicFieldPage } from '../types/dynamic_fields'; +import { DynamicFieldName, DynamicFieldPage } from '../types/dynamic_fields'; import { SerializedSignature } from '../cryptography/signature'; export class VoidProvider extends Provider { @@ -209,7 +209,7 @@ export class VoidProvider extends Provider { getDynamicFieldObject( _parent_object_id: ObjectId, - _name: string, + _name: DynamicFieldName, ): Promise { throw this.newError('getDynamicFieldObject'); } diff --git a/sdk/typescript/src/types/dynamic_fields.ts b/sdk/typescript/src/types/dynamic_fields.ts index d02c8ae96bc54..6c60bdd392bc0 100644 --- a/sdk/typescript/src/types/dynamic_fields.ts +++ b/sdk/typescript/src/types/dynamic_fields.ts @@ -18,8 +18,14 @@ export const DynamicFieldType = union([ ]); export type DynamicFieldType = Infer; +export const DynamicFieldName = object({ + type: string(), + value: object(), +}); +export type DynamicFieldName = Infer; + export const DynamicFieldInfo = object({ - name: string(), + name: DynamicFieldName, type: DynamicFieldType, objectType: string(), objectId: ObjectId, From c324680ab4d28a2bec81e1ca2f56ae8ead54b7b3 Mon Sep 17 00:00:00 2001 From: patrick Date: Wed, 15 Feb 2023 12:53:03 +0000 Subject: [PATCH 07/11] move Hex deserialize as array to fastcrypto --- Cargo.lock | 4 +- crates/sui-types/Cargo.toml | 2 +- crates/sui-types/src/base_types.rs | 8 +-- crates/sui-types/src/crypto.rs | 9 ++-- crates/sui-types/src/digests.rs | 5 +- crates/sui-types/src/sui_serde.rs | 80 ++---------------------------- narwhal/crypto/Cargo.toml | 2 +- 7 files changed, 18 insertions(+), 92 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e7c1bf6880513..dd59ee756797f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7652,9 +7652,9 @@ dependencies = [ [[package]] name = "serde_bytes" -version = "0.11.8" +version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "718dc5fff5b36f99093fc49b280cfc96ce6fc824317783bff5a1fed0c7a64819" +checksum = "416bda436f9aab92e02c8e10d49a15ddd339cea90b6e340fe51ed97abb548294" dependencies = [ "serde 1.0.152", ] diff --git a/crates/sui-types/Cargo.toml b/crates/sui-types/Cargo.toml index da58d71206141..08033e84a12fa 100644 --- a/crates/sui-types/Cargo.toml +++ b/crates/sui-types/Cargo.toml @@ -18,7 +18,7 @@ serde = { version = "1.0.144", features = ["derive"] } serde-name = "0.2.1" thiserror = "1.0.34" tracing = "0.1" -serde_bytes = "0.11.7" +serde_bytes = "0.11.9" serde_json = "1.0.88" serde_with = "2.1.0" serde_repr = "0.1" diff --git a/crates/sui-types/src/base_types.rs b/crates/sui-types/src/base_types.rs index cf1d67ebf2fcf..8f3728fd1504c 100644 --- a/crates/sui-types/src/base_types.rs +++ b/crates/sui-types/src/base_types.rs @@ -8,15 +8,15 @@ use crate::crypto::{ SuiPublicKey, }; pub use crate::digests::{ObjectDigest, TransactionDigest, TransactionEffectsDigest}; +use crate::epoch_data::EpochData; use crate::error::ExecutionError; use crate::error::ExecutionErrorKind; use crate::error::SuiError; use crate::gas_coin::GasCoin; use crate::multisig::MultiSigPublicKey; use crate::object::{Object, Owner}; -use crate::sui_serde::HexObjectId; +use crate::sui_serde::HexAccountAddress; use crate::sui_serde::Readable; -use crate::sui_serde::ToArray; use anyhow::anyhow; use fastcrypto::encoding::decode_bytes_hex; use fastcrypto::encoding::{Encoding, Hex}; @@ -73,7 +73,7 @@ pub type AuthorityName = AuthorityPublicKeyBytes; #[derive(Eq, PartialEq, Clone, Copy, PartialOrd, Ord, Hash, Serialize, Deserialize, JsonSchema)] pub struct ObjectID( #[schemars(with = "Hex")] - #[serde_as(as = "Readable")] + #[serde_as(as = "Readable")] AccountAddress, ); @@ -154,7 +154,7 @@ pub const SUI_ADDRESS_LENGTH: usize = ObjectID::LENGTH; )] pub struct SuiAddress( #[schemars(with = "Hex")] - #[serde_as(as = "Readable, _>")] + #[serde_as(as = "Readable")] [u8; SUI_ADDRESS_LENGTH], ); diff --git a/crates/sui-types/src/crypto.rs b/crates/sui-types/src/crypto.rs index 328edb4e5acf2..28445f6dc371f 100644 --- a/crates/sui-types/src/crypto.rs +++ b/crates/sui-types/src/crypto.rs @@ -1,6 +1,5 @@ // Copyright (c) Mysten Labs, Inc. // SPDX-License-Identifier: Apache-2.0 -use crate::sui_serde::ToArray; use anyhow::{anyhow, Error}; use derive_more::From; use eyre::eyre; @@ -324,7 +323,7 @@ impl PublicKey { )] pub struct AuthorityPublicKeyBytes( #[schemars(with = "Base64")] - #[serde_as(as = "Readable, Bytes>")] + #[serde_as(as = "Readable")] [u8; AuthorityPublicKey::LENGTH], ); @@ -815,7 +814,7 @@ impl SuiPublicKey for BLS12381PublicKey { #[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash)] pub struct Ed25519SuiSignature( #[schemars(with = "Base64")] - #[serde_as(as = "Readable, Bytes>")] + #[serde_as(as = "Readable")] [u8; Ed25519PublicKey::LENGTH + Ed25519Signature::LENGTH + 1], ); @@ -873,7 +872,7 @@ impl Signer for Ed25519KeyPair { #[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash)] pub struct Secp256k1SuiSignature( #[schemars(with = "Base64")] - #[serde_as(as = "Readable, Bytes>")] + #[serde_as(as = "Readable")] [u8; Secp256k1PublicKey::LENGTH + Secp256k1Signature::LENGTH + 1], ); @@ -924,7 +923,7 @@ impl Signer for Secp256k1KeyPair { #[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash)] pub struct Secp256r1SuiSignature( #[schemars(with = "Base64")] - #[serde_as(as = "Readable, Bytes>")] + #[serde_as(as = "Readable")] [u8; Secp256r1PublicKey::LENGTH + Secp256r1Signature::LENGTH + 1], ); diff --git a/crates/sui-types/src/digests.rs b/crates/sui-types/src/digests.rs index 3e9bc3ca86a69..9da9291dd523f 100644 --- a/crates/sui-types/src/digests.rs +++ b/crates/sui-types/src/digests.rs @@ -4,7 +4,6 @@ use std::fmt; use crate::sui_serde::Readable; -use crate::sui_serde::ToArray; use fastcrypto::encoding::{Base58, Base64, Encoding}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; @@ -16,7 +15,7 @@ use serde_with::{serde_as, Bytes}; )] pub struct Sha3Digest( #[schemars(with = "Base58")] - #[serde_as(as = "Readable, Bytes>")] + #[serde_as(as = "Readable")] [u8; 32], ); @@ -464,7 +463,7 @@ impl fmt::UpperHex for TransactionEffectsDigest { #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, JsonSchema)] pub struct ObjectDigest( #[schemars(with = "Base64")] - #[serde_as(as = "Readable, Bytes>")] + #[serde_as(as = "Readable")] [u8; 32], // Sha3Digest, ); diff --git a/crates/sui-types/src/sui_serde.rs b/crates/sui-types/src/sui_serde.rs index 8b4590af4c8f5..b648b65058340 100644 --- a/crates/sui-types/src/sui_serde.rs +++ b/crates/sui-types/src/sui_serde.rs @@ -4,9 +4,7 @@ use std::fmt::Debug; use std::marker::PhantomData; -use anyhow::anyhow; -use fastcrypto::encoding::{Base64, Encoding, Hex}; -use fastcrypto::traits::ToFromBytes; +use fastcrypto::encoding::Hex; use move_core_types::account_address::AccountAddress; use serde; use serde::de::{Deserializer, Error}; @@ -86,9 +84,9 @@ where } /// custom serde for AccountAddress -pub struct HexObjectId; +pub struct HexAccountAddress; -impl SerializeAs for HexObjectId { +impl SerializeAs for HexAccountAddress { fn serialize_as(value: &AccountAddress, serializer: S) -> Result where S: Serializer, @@ -97,7 +95,7 @@ impl SerializeAs for HexObjectId { } } -impl<'de> DeserializeAs<'de, AccountAddress> for HexObjectId { +impl<'de> DeserializeAs<'de, AccountAddress> for HexAccountAddress { fn deserialize_as(deserializer: D) -> Result where D: Deserializer<'de>, @@ -112,76 +110,6 @@ impl<'de> DeserializeAs<'de, AccountAddress> for HexObjectId { } } -/// DeserializeAs adaptor for `Vec` <> `TryFrom>` -pub struct TryFromVec { - vec: PhantomData, -} - -impl SerializeAs for TryFromVec -where - V: SerializeAs, -{ - fn serialize_as(value: &T, serializer: S) -> Result - where - S: Serializer, - { - V::serialize_as(value, serializer) - } -} - -impl<'de, V, T> DeserializeAs<'de, T> for TryFromVec -where - V: DeserializeAs<'de, Vec>, - T: TryFrom>, - >>::Error: std::fmt::Display, -{ - fn deserialize_as(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - T::try_from(V::deserialize_as(deserializer)?).map_err(Error::custom) - } -} - -/// DeserializeAs adaptor for `Vec` <> `[u8;N]` -pub struct ToArray { - vec: PhantomData, -} - -impl SerializeAs for ToArray -where - V: SerializeAs, -{ - fn serialize_as(value: &T, serializer: S) -> Result - where - S: Serializer, - { - V::serialize_as(value, serializer) - } -} - -impl<'de, V, const N: usize> DeserializeAs<'de, [u8; N]> for ToArray -where - V: DeserializeAs<'de, Vec>, -{ - fn deserialize_as(deserializer: D) -> Result<[u8; N], D::Error> - where - D: Deserializer<'de>, - { - let value = V::deserialize_as(deserializer)?; - if value.len() != N { - return Err(Error::custom(anyhow!( - "invalid array length {}, expecting {}", - value.len(), - N - ))); - } - let mut array = [0u8; N]; - array.copy_from_slice(&value[..N]); - Ok(array) - } -} - /// Serializes a bitmap according to the roaring bitmap on-disk standard. /// pub struct SuiBitmap; diff --git a/narwhal/crypto/Cargo.toml b/narwhal/crypto/Cargo.toml index ce1e8bcf9815b..caa04b18fb1df 100644 --- a/narwhal/crypto/Cargo.toml +++ b/narwhal/crypto/Cargo.toml @@ -13,7 +13,7 @@ ark-bls12-377 = { version = "0.3.0", features = ["std"], optional = true } eyre = "0.6.8" rand = { version = "0.8.5", features = ["std"] } serde = { version = "1.0.144", features = ["derive"] } -serde_bytes = "0.11.7" +serde_bytes = "0.11.9" serde_with = "2.1.0" tokio = { workspace = true, features = ["sync", "rt", "macros"] } zeroize = "1.5.7" From 1a8de24dd61ecf3e95d6020cd21fb81cd41913c2 Mon Sep 17 00:00:00 2001 From: patrick Date: Tue, 21 Feb 2023 12:09:55 +0000 Subject: [PATCH 08/11] fixup after rebase --- crates/sui-types/src/base_types.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/crates/sui-types/src/base_types.rs b/crates/sui-types/src/base_types.rs index 8f3728fd1504c..c520c0cf5ef91 100644 --- a/crates/sui-types/src/base_types.rs +++ b/crates/sui-types/src/base_types.rs @@ -5,16 +5,17 @@ pub use crate::committee::EpochId; use crate::crypto::{ AuthorityPublicKey, AuthorityPublicKeyBytes, KeypairTraits, PublicKey, SignatureScheme, - SuiPublicKey, + SuiPublicKey, SuiSignature, }; pub use crate::digests::{ObjectDigest, TransactionDigest, TransactionEffectsDigest}; use crate::epoch_data::EpochData; -use crate::error::ExecutionError; use crate::error::ExecutionErrorKind; use crate::error::SuiError; +use crate::error::{ExecutionError, SuiResult}; use crate::gas_coin::GasCoin; use crate::multisig::MultiSigPublicKey; use crate::object::{Object, Owner}; +use crate::signature::GenericSignature; use crate::sui_serde::HexAccountAddress; use crate::sui_serde::Readable; use anyhow::anyhow; From b48e50d1a0ee540efc8bed6394a16b8ab88ef497 Mon Sep 17 00:00:00 2001 From: patrick Date: Tue, 21 Feb 2023 13:06:32 +0000 Subject: [PATCH 09/11] add backward compatibility --- sdk/typescript/src/types/dynamic_fields.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/typescript/src/types/dynamic_fields.ts b/sdk/typescript/src/types/dynamic_fields.ts index 6c60bdd392bc0..35d4558cd9dd3 100644 --- a/sdk/typescript/src/types/dynamic_fields.ts +++ b/sdk/typescript/src/types/dynamic_fields.ts @@ -25,7 +25,7 @@ export const DynamicFieldName = object({ export type DynamicFieldName = Infer; export const DynamicFieldInfo = object({ - name: DynamicFieldName, + name: union([DynamicFieldName, string()]), type: DynamicFieldType, objectType: string(), objectId: ObjectId, From 2d6d9dadcca8613b6beb80521c10a1f5b8de6ba2 Mon Sep 17 00:00:00 2001 From: patrick Date: Tue, 21 Feb 2023 13:57:38 +0000 Subject: [PATCH 10/11] fix ts --- sdk/typescript/src/types/dynamic_fields.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sdk/typescript/src/types/dynamic_fields.ts b/sdk/typescript/src/types/dynamic_fields.ts index 35d4558cd9dd3..591f8ba63fd66 100644 --- a/sdk/typescript/src/types/dynamic_fields.ts +++ b/sdk/typescript/src/types/dynamic_fields.ts @@ -2,6 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 import { + any, array, Infer, literal, @@ -20,7 +21,7 @@ export type DynamicFieldType = Infer; export const DynamicFieldName = object({ type: string(), - value: object(), + value: any(), }); export type DynamicFieldName = Infer; From 271452b6e99e0319e469771f18f2c5cebe4b65b5 Mon Sep 17 00:00:00 2001 From: patrick Date: Wed, 22 Feb 2023 11:56:50 +0000 Subject: [PATCH 11/11] fix TS failing test --- sdk/typescript/src/providers/json-rpc-provider.ts | 2 +- sdk/typescript/src/providers/provider.ts | 2 +- sdk/typescript/src/providers/void-provider.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sdk/typescript/src/providers/json-rpc-provider.ts b/sdk/typescript/src/providers/json-rpc-provider.ts index f1b20373fa2ad..296decd2e9742 100644 --- a/sdk/typescript/src/providers/json-rpc-provider.ts +++ b/sdk/typescript/src/providers/json-rpc-provider.ts @@ -930,7 +930,7 @@ export class JsonRpcProvider extends Provider { async getDynamicFieldObject( parent_object_id: ObjectId, - name: DynamicFieldName, + name: string | DynamicFieldName, ): Promise { try { const resp = await this.client.requestWithType( diff --git a/sdk/typescript/src/providers/provider.ts b/sdk/typescript/src/providers/provider.ts index de2856d7e4282..c4f890afef410 100644 --- a/sdk/typescript/src/providers/provider.ts +++ b/sdk/typescript/src/providers/provider.ts @@ -356,7 +356,7 @@ export abstract class Provider { */ abstract getDynamicFieldObject( parent_object_id: ObjectId, - name: DynamicFieldName, + name: string | DynamicFieldName, ): Promise; /** diff --git a/sdk/typescript/src/providers/void-provider.ts b/sdk/typescript/src/providers/void-provider.ts index c36fef5c9cc83..89e972902675f 100644 --- a/sdk/typescript/src/providers/void-provider.ts +++ b/sdk/typescript/src/providers/void-provider.ts @@ -209,7 +209,7 @@ export class VoidProvider extends Provider { getDynamicFieldObject( _parent_object_id: ObjectId, - _name: DynamicFieldName, + _name: string | DynamicFieldName, ): Promise { throw this.newError('getDynamicFieldObject'); }