From ae36347a597e13a565a3617f47cc48b66213d47b Mon Sep 17 00:00:00 2001 From: Todd Nowacki Date: Wed, 4 Jan 2023 14:33:59 -0800 Subject: [PATCH] Fix dynamic field indexer (#7131) Fix incorrect checking of object IDs for dynamic fields Co-authored-by: patrick --- crates/sui-core/src/authority.rs | 3 + .../src/unit_tests/authority_tests.rs | 4 +- crates/sui-open-rpc/spec/openrpc.json | 31 +---- crates/sui-types/src/dynamic_field.rs | 111 ++++++++++-------- 4 files changed, 72 insertions(+), 77 deletions(-) diff --git a/crates/sui-core/src/authority.rs b/crates/sui-core/src/authority.rs index b27b0528c85bb..369577599d33b 100644 --- a/crates/sui-core/src/authority.rs +++ b/crates/sui-core/src/authority.rs @@ -1675,6 +1675,9 @@ impl AuthorityState { let Some(index_store) = &self.indexes else{ return Ok(()) }; + if !index_store.is_empty() { + return Ok(()); + } let mut new_owners = vec![]; let mut new_dynamic_fields = vec![]; diff --git a/crates/sui-core/src/unit_tests/authority_tests.rs b/crates/sui-core/src/unit_tests/authority_tests.rs index fe8bfea15c7c7..30393215bc774 100644 --- a/crates/sui-core/src/unit_tests/authority_tests.rs +++ b/crates/sui-core/src/unit_tests/authority_tests.rs @@ -2963,9 +2963,7 @@ async fn test_store_get_dynamic_field() { .get_dynamic_fields(outer_v0.0, None, usize::MAX) .unwrap(); assert_eq!(fields.len(), 1); - assert!( - matches!(fields[0].type_, DynamicFieldType::DynamicField {wrapped_object_id} if wrapped_object_id == inner_v0.0) - ); + assert!(matches!(fields[0].type_, DynamicFieldType::DynamicField)); } #[tokio::test] diff --git a/crates/sui-open-rpc/spec/openrpc.json b/crates/sui-open-rpc/spec/openrpc.json index a9eaa0629eb3e..53a9762b08e41 100644 --- a/crates/sui-open-rpc/spec/openrpc.json +++ b/crates/sui-open-rpc/spec/openrpc.json @@ -2956,33 +2956,10 @@ } }, "DynamicFieldType": { - "oneOf": [ - { - "type": "string", - "enum": [ - "DynamicObject" - ] - }, - { - "type": "object", - "required": [ - "DynamicField" - ], - "properties": { - "DynamicField": { - "type": "object", - "required": [ - "wrappedObjectId" - ], - "properties": { - "wrappedObjectId": { - "$ref": "#/components/schemas/ObjectID" - } - } - } - }, - "additionalProperties": false - } + "type": "string", + "enum": [ + "DynamicField", + "DynamicObject" ] }, "Ed25519SuiSignature": { diff --git a/crates/sui-types/src/dynamic_field.rs b/crates/sui-types/src/dynamic_field.rs index ac0cb26708004..92e7bf4f59163 100644 --- a/crates/sui-types/src/dynamic_field.rs +++ b/crates/sui-types/src/dynamic_field.rs @@ -9,7 +9,6 @@ use serde::Serialize; use crate::base_types::ObjectDigest; use crate::error::{SuiError, SuiResult}; -use crate::id::ID; use crate::{ObjectID, SequenceNumber, SUI_FRAMEWORK_ADDRESS}; #[derive(Clone, Serialize, Deserialize, JsonSchema, Ord, PartialOrd, Eq, PartialEq, Debug)] @@ -26,9 +25,7 @@ pub struct DynamicFieldInfo { #[derive(Clone, Serialize, Deserialize, JsonSchema, Ord, PartialOrd, Eq, PartialEq, Debug)] pub enum DynamicFieldType { #[serde(rename_all = "camelCase")] - DynamicField { - wrapped_object_id: ObjectID, - }, + DynamicField, DynamicObject, } @@ -54,68 +51,88 @@ impl DynamicFieldInfo { } })?; - let object_id = - extract_object_id(&value).ok_or_else(|| SuiError::ObjectDeserializationError { - error: format!( - "Cannot extract dynamic object's object id from Field::value, {:?}", - value - ), - })?; - Ok(if is_dynamic_object(move_struct) { let name = match name { - MoveValue::Struct(s) => extract_field_from_move_struct(&s, "name"), + MoveValue::Struct(name_struct) => { + extract_field_from_move_struct(name_struct, "name") + } _ => None, } .ok_or_else(|| SuiError::ObjectDeserializationError { error: "Cannot extract [name] field from sui::dynamic_object_field::Wrapper." .to_string(), })?; - + // ID extracted from the wrapper object + let object_id = + extract_id_value(value).ok_or_else(|| SuiError::ObjectDeserializationError { + error: format!( + "Cannot extract dynamic object's object id from \ + sui::dynamic_field::Field, {value:?}" + ), + })?; (name.to_string(), DynamicFieldType::DynamicObject, object_id) } else { - ( - name.to_string(), - DynamicFieldType::DynamicField { - wrapped_object_id: object_id, - }, - object_id, - ) + // ID of the Field object + let object_id = extract_object_id(move_struct).ok_or_else(|| { + SuiError::ObjectDeserializationError { + error: format!( + "Cannot extract dynamic object's object id from \ + sui::dynamic_field::Field, {move_struct:?}", + ), + } + })?; + (name.to_string(), DynamicFieldType::DynamicField, object_id) }) } } -fn extract_field_from_move_struct(move_struct: &MoveStruct, field_name: &str) -> Option { +fn extract_field_from_move_struct<'a>( + move_struct: &'a MoveStruct, + field_name: &str, +) -> Option<&'a MoveValue> { match move_struct { - MoveStruct::WithTypes { fields, .. } => fields.iter().find_map(|(id, value)| { - if id.to_string() == field_name { - Some(value.clone()) - } else { - None - } - }), + MoveStruct::WithTypes { fields, .. } | MoveStruct::WithFields(fields) => { + fields.iter().find_map(|(id, value)| { + if id.to_string() == field_name { + Some(value) + } else { + None + } + }) + } _ => None, } } -fn extract_object_id(value: &MoveValue) -> Option { - match value { - MoveValue::Struct(MoveStruct::WithTypes { type_, fields }) => { - if type_ == &ID::type_() { - match fields.first() { - Some((_, MoveValue::Address(addr))) => Some(ObjectID::from(*addr)), - _ => None, - } - } else { - for (_, value) in fields { - let id = extract_object_id(value); - if id.is_some() { - return id; - } - } - None - } - } +fn extract_object_id(value: &MoveStruct) -> Option { + // id:UID is the first value in an object + let uid_value = match value { + MoveStruct::Runtime(fields) => fields.get(0)?, + MoveStruct::WithFields(fields) | MoveStruct::WithTypes { fields, .. } => &fields.get(0)?.1, + }; + // id is the first value in UID + let id_value = match uid_value { + MoveValue::Struct(MoveStruct::Runtime(fields)) => fields.get(0)?, + MoveValue::Struct( + MoveStruct::WithFields(fields) | MoveStruct::WithTypes { fields, .. }, + ) => &fields.get(0)?.1, + _ => return None, + }; + extract_id_value(id_value) +} + +fn extract_id_value(id_value: &MoveValue) -> Option { + // the id struct has a single bytes field + let id_bytes_value = match id_value { + MoveValue::Struct(MoveStruct::Runtime(fields)) => fields.get(0)?, + MoveValue::Struct( + MoveStruct::WithFields(fields) | MoveStruct::WithTypes { fields, .. }, + ) => &fields.get(0)?.1, + _ => return None, + }; + // the bytes field should be an address + match id_bytes_value { + MoveValue::Address(addr) => Some(ObjectID::from(*addr)), _ => None, } }