Skip to content

Commit

Permalink
Fix dynamic field indexer (#7131)
Browse files Browse the repository at this point in the history
Fix incorrect checking of object IDs for dynamic fields

Co-authored-by: patrick <patrickkuo@me.com>
  • Loading branch information
tnowacki and patrickkuo committed Jan 4, 2023
1 parent e2276ea commit 54b65af
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 77 deletions.
3 changes: 3 additions & 0 deletions crates/sui-core/src/authority.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1655,6 +1655,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![];
Expand Down
4 changes: 1 addition & 3 deletions crates/sui-core/src/unit_tests/authority_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2945,9 +2945,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]
Expand Down
31 changes: 4 additions & 27 deletions crates/sui-open-rpc/spec/openrpc.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": {
Expand Down
111 changes: 64 additions & 47 deletions crates/sui-types/src/dynamic_field.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand All @@ -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,
}

Expand All @@ -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<MoveValue> {
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<ObjectID> {
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<ObjectID> {
// 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<ObjectID> {
// 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,
}
}
Expand Down

0 comments on commit 54b65af

Please sign in to comment.