Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[JSON RPC API] - New APIs for getting object's dynamic field #5882

Merged
merged 13 commits into from
Dec 16, 2022

Conversation

patrickkuo
Copy link
Contributor

@patrickkuo patrickkuo commented Nov 5, 2022

Summary

This PR adds dynamic field support to Sui's JSON-RPC APIs.

Notable changes

  • added dynamic_field_index and owner_index to IndexStore storing all object owned dynamic field object info
  • owner_index in AuthorityPerpetualTables is deprecated and will be removed in subsequence PR
  • new get_dynamic_field_object method for retrieving object using parent object id and dynamic field name.

Examples

the first object is nfts::marketplace::Marketplace, second object is nfts::geniteam::Player
Requests

curl --location --request POST '127.0.0.1:9000' \
--header 'Content-Type: application/json' \
--data-raw '[
    {
        "jsonrpc": "2.0",
        "id": 1,
        "method": "sui_getDynamicFields",
        "params": [
            "0xc404264ae29f8f5d5a9e0da0213cddb64228575f"
        ]
    },
    {
        "jsonrpc": "2.0",
        "id": 2,
        "method": "sui_getDynamicFields",
        "params": [
            "0x1f6a5b789f31c0511ff3f0cbe7e2d9fda0ea10da"
        ]
    }
]'

Response

[
    {
        "jsonrpc": "2.0",
        "result": {
            "data": [
                {
                    "name": "0x2::object::ID {bytes: 0xbbbb096cc9145afb1df64546d3b64b1160ba284f}",
                    "type": {
                        "DynamicField": {
                            "wrappedObjectId": "0xbbbb096cc9145afb1df64546d3b64b1160ba284f"
                        }
                    },
                    "objectType": "0x2d5da76aaa9ea52407ba16a1c22c443f53d19963::marketplace::Listing<0x2::coin::Coin<0x2::sui::SUI>, 0x2::sui::SUI>",
                    "objectId": "0x16632ab5a8f7455d01c32507ba2ce0fc86dd3625",
                    "version": 1,
                    "digest": "1m9qSQd9zwSpEU50qV4UqOVyUfHcUUgsztfAwfKPLfQ="
                }
            ],
            "nextCursor": null
        },
        "id": 1
    },
    {
        "jsonrpc": "2.0",
        "result": {
            "data": [
                {
                    "name": "0x2::typed_id::TypedID<0x2d5da76aaa9ea52407ba16a1c22c443f53d19963::geniteam::Farm> {id: 0x2::object::ID {bytes: 0xa2811c9063490d8bb2535917f4585fe8294863e0}}",
                    "type": "DynamicObject",
                    "objectType": "0x2d5da76aaa9ea52407ba16a1c22c443f53d19963::geniteam::Farm",
                    "objectId": "0xa2811c9063490d8bb2535917f4585fe8294863e0",
                    "version": 1,
                    "digest": "B63S7la6PzJFDfzf024k/bYof6YoDMN2gCHMY8ZqRWY="
                }
            ],
            "nextCursor": null
        },
        "id": 2
    }
]

Remaining Tasks:

  • Testing
  • Docs
  • Migration guide

TODOs:

@patrickkuo patrickkuo changed the title Replace get_object_owned_by_object with get_dynamid_fields Replace get_object_owned_by_object with get_dynamic_fields Nov 5, 2022
@patrickkuo patrickkuo force-pushed the pat/dynamic_fields_rpc branch 4 times, most recently from 33c3dea to 65c7427 Compare November 23, 2022 17:44
@patrickkuo patrickkuo marked this pull request as ready for review November 24, 2022 12:12
@patrickkuo patrickkuo self-assigned this Nov 24, 2022
@patrickkuo patrickkuo requested a review from gegaowp November 24, 2022 12:13
@@ -97,6 +131,21 @@ impl RpcReadApiServer for ReadApi {
.try_into()?)
}

async fn get_dynamic_field_object(
Copy link
Contributor

@666lcz 666lcz Nov 28, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In https://docs.sui.io/devnet/build/programming-with-objects/ch5-dynamic-fields, we use dynamic field and dynamic object field to refer to two different types of dynamic fields and mentioned that an object stored in this kind of field will be considered wrapped and will not be accessible via its ID by external tools (explorers, wallets, etc) accessing storage.. Does this endpoint support both types?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes both are supported.

pub type_: DynamicFieldType,

pub enum DynamicFieldType {
#[serde(rename_all = "camelCase")]
DynamicField {
wrapped_object_id: ObjectID,
},
DynamicObject,
}

The DynamicFieldType enum is used to indicate whether it is dynamic field or dynamic field object.

@patrickkuo
Copy link
Contributor Author

One question I have is do we still support object owning objects in Move? i.e. transferring ownership to an object without using dynamic field. This PR assumes an object can only own another object using DF, is this the right assumption? @tnowacki ?

@patrickkuo patrickkuo force-pushed the pat/dynamic_fields_rpc branch from 3735554 to 76fd4c0 Compare November 28, 2022 09:53
Copy link
Contributor

@ronny-mysten ronny-mysten left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Noted a few things in what I believe is the output to documentation. Ignore me if I'm wrong.

crates/sui-core/src/authority/authority_store_tables.rs Outdated Show resolved Hide resolved
crates/sui-json-rpc/src/api.rs Outdated Show resolved Hide resolved
crates/sui-json-rpc/src/api.rs Outdated Show resolved Hide resolved
crates/sui-json-rpc/src/api.rs Outdated Show resolved Hide resolved
Copy link
Contributor

@longbowlu longbowlu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm thinking we should move owner indexer and the new dynamic field tables into indexes.rs.

It does not seem the owner info has to be in the critical path, or even live in validator's storage. After some quick look, the only place that validators may look at the owner table is make_account_info which will be called by handle_account_info_request. Today the only callsite is get_all_owned_objects and sync_all_owned_objects, which iiuc, is now deprecated with gateway gone. @lxfind wdyt?

The long term plan is to move all indices to indexer. cc @mystenmark

@patrickkuo patrickkuo force-pushed the pat/dynamic_fields_rpc branch from 8470c07 to 4ce6a8e Compare November 30, 2022 14:00
@patrickkuo
Copy link
Contributor Author

@ronny-mysten thanks for all the doc fixes!

@patrickkuo
Copy link
Contributor Author

I'm thinking we should move owner indexer and the new dynamic field tables into indexes.rs.

It does not seem the owner info has to be in the critical path, or even live in validator's storage. After some quick look, the only place that validators may look at the owner table is make_account_info which will be called by handle_account_info_request. Today the only callsite is get_all_owned_objects and sync_all_owned_objects, which iiuc, is now deprecated with gateway gone. @lxfind wdyt?

The long term plan is to move all indices to indexer. cc @mystenmark

I think we will still need owner_index for make_account_info, however dynamic_field_index should definitely move to the index storage.

I will make that changes.

@lxfind
Copy link
Contributor

lxfind commented Nov 30, 2022

Correct. owner_index should not belong to validator store.

@patrickkuo patrickkuo force-pushed the pat/dynamic_fields_rpc branch 2 times, most recently from d90a602 to 89b9fd9 Compare December 1, 2022 11:21
@tnowacki
Copy link
Contributor

tnowacki commented Dec 2, 2022

Sorry for the late reply!

One question I have is do we still support object owning objects in Move? i.e. transferring ownership to an object without using dynamic field. This PR assumes an object can only own another object using DF, is this the right assumption?

Correct. Within Move, you can only make an object own another object through dynamic fields (in particular dynamic object fields)

@longbowlu
Copy link
Contributor

I'm thinking we should move owner indexer and the new dynamic field tables into indexes.rs.
It does not seem the owner info has to be in the critical path, or even live in validator's storage. After some quick look, the only place that validators may look at the owner table is make_account_info which will be called by handle_account_info_request. Today the only callsite is get_all_owned_objects and sync_all_owned_objects, which iiuc, is now deprecated with gateway gone. @lxfind wdyt?
The long term plan is to move all indices to indexer. cc @mystenmark

I think we will still need owner_index for make_account_info, however dynamic_field_index should definitely move to the index storage.

I will make that changes.

Iiuc, make_account_info is obsolete after gateway deprecation

@patrickkuo patrickkuo force-pushed the pat/dynamic_fields_rpc branch from 89b9fd9 to 1d64f8e Compare December 6, 2022 13:17
@vercel
Copy link

vercel bot commented Dec 6, 2022

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated
wallet-adapter ✅ Ready (Inspect) Visit Preview 💬 Add your feedback Dec 16, 2022 at 0:01AM (UTC)
1 Ignored Deployment
Name Status Preview Comments Updated
explorer ⬜️ Ignored (Inspect) Dec 16, 2022 at 0:01AM (UTC)

Copy link
Contributor

@tnowacki tnowacki left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still going through things! But wanted to leave the first set of comments I had so far (I will continue to look more later today)

};
match self.get_owner_at_version(id, *old_version)? {
Owner::AddressOwner(addr) => deleted_owners.push((addr, *id)),
Owner::ObjectOwner(object_id) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You probably want to filter for the type here too. I don't think you want this event/index for the secondary object in the dynamic object field case.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In other words, we need to check that the object's type is sui::dynamic_field::Field, otherwise it could be some other object being used with sui::dynamic_object_field

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still reviewing but leaving these comments here as I go: Do we need a type filter here if we are filtering on creation?

Copy link
Contributor Author

@patrickkuo patrickkuo Dec 12, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good catch! this will remove unnecessary seek and delete ops on db

Copy link
Contributor Author

@patrickkuo patrickkuo Dec 12, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually after looking at the code (this was done quite a while ago 😅), it will require an extra DB read to retrieve the object type because TransactionEffects only contains ObjectRef, which will be more expensive because it will deserialise the whole Object from storage. We could do this without the db read after this PR which adds ObjectType to the effects.

I will add a TODO for now.

deleted_owners.push((addr, *id));
}
Owner::ObjectOwner(object_id) => {
deleted_dynamic_fields.push((ObjectID::from(object_id), *id))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same type filtering issue as above

@@ -1209,6 +1211,10 @@ impl AuthorityState {
effects: &SignedTransactionEffects,
timestamp_ms: u64,
) -> SuiResult {
let changes = self
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm just learning here, when does index_tx get run? This is some separate service or something right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently this runs in fullnode (@gegaowp 's indexer work will probably move this to the indexer), there are 2 code path leading to this method, one is from the node_sync when the fullnode receive new transactions; another path is from the TransactiondOrchestrator which updates the local store after successful tx execution.

)),
Owner::ObjectOwner(object_id) => {
let id = o.id();
let Some(info) = self.try_create_dynamic_field_info(o)? else{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not important, but I've been noticing on my PRs too, it doesn't seem like rustfmt likes let-else. There isn't a space in else{

Just noting and summoning my normal person for Rust questions, @bmwill. Do we need to do something else to configure rustfmt to handle let-else?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nope, unfortunately the let-else feature was stabilized without the corresponding formatting being added to rustfmt

Copy link
Contributor

@gegaowp gegaowp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I reviewed the RPC, Rust SDK and sui-storage parts, which LGTM.

I do not enough knowledge to review files below and will leave it to other folks

  • authority.rs
  • object_basics.move
  • sui-types/src/dynamic_field.rs

parent_object_id: ObjectID,
/// Optional paging cursor
cursor: Option<ObjectID>,
/// Maximum item returned per page
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: looks like otherwise QUERY_MAX_RESULT_LIMIT will be returned, let's add a comment for that?

Err(anyhow!("Page result limit must be larger then 0."))?;
}
Ok(if limit > QUERY_MAX_RESULT_LIMIT {
pub fn cap_page_limit(limit: Option<usize>) -> usize {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good move!

@patrickkuo
Copy link
Contributor Author

Anyone still reviewing this PR? I would like to merge soon.

@patrickkuo patrickkuo force-pushed the pat/dynamic_fields_rpc branch from 527a78a to 6013e6f Compare December 15, 2022 23:59
@vercel vercel bot temporarily deployed to Preview – explorer-storybook December 16, 2022 00:00 Inactive
@vercel vercel bot temporarily deployed to Preview – wallet-adapter December 16, 2022 00:01 Inactive
@patrickkuo patrickkuo merged commit 3da2953 into main Dec 16, 2022
@patrickkuo patrickkuo deleted the pat/dynamic_fields_rpc branch December 16, 2022 00:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants