From 3c377e74ff6fd282076363f8d85e0e53a9df11ff Mon Sep 17 00:00:00 2001 From: Emma Zhong Date: Thu, 2 Nov 2023 16:56:21 -0700 Subject: [PATCH] [indexer] add ability to use struct type filter for get_owned_objects (#14639) ## Description This PR enables struct type and `MatchAny` struct type filters for get_owned_objects method. ## Test Plan Tested locally. --- If your changes are not user-facing and not a breaking change, you can skip the following section. Otherwise, please indicate what changed, and then add to the Release Notes section as highlighted during the release process. ### Type of Change (Check all that apply) - [ ] protocol change - [ ] user-visible impact - [ ] breaking change for a client SDKs - [ ] breaking change for FNs (FN binary must upgrade) - [ ] breaking change for validators or node operators (must upgrade binaries) - [ ] breaking change for on-chain data layout - [ ] necessitate either a data wipe or data migration ### Release notes --- .../2023-08-19-044023_objects/up.sql | 1 + .../sui-indexer/src/apis/governance_api_v2.rs | 8 +++- crates/sui-indexer/src/apis/indexer_api_v2.rs | 9 +---- .../src/apis/transaction_builder_api_v2.rs | 4 +- crates/sui-indexer/src/indexer_reader.rs | 37 ++++++++++++++++--- 5 files changed, 41 insertions(+), 18 deletions(-) diff --git a/crates/sui-indexer/migrations_v2/2023-08-19-044023_objects/up.sql b/crates/sui-indexer/migrations_v2/2023-08-19-044023_objects/up.sql index 57be2affcb536..abf91fc483332 100644 --- a/crates/sui-indexer/migrations_v2/2023-08-19-044023_objects/up.sql +++ b/crates/sui-indexer/migrations_v2/2023-08-19-044023_objects/up.sql @@ -33,3 +33,4 @@ CREATE TABLE objects ( CREATE INDEX objects_owner ON objects (owner_type, owner_id) WHERE owner_type BETWEEN 1 AND 2 AND owner_id IS NOT NULL; CREATE INDEX objects_coin ON objects (owner_id, coin_type) WHERE coin_type IS NOT NULL AND owner_type = 1; CREATE INDEX objects_checkpoint_sequence_number ON objects (checkpoint_sequence_number); +CREATE INDEX objects_type ON objects (object_type); diff --git a/crates/sui-indexer/src/apis/governance_api_v2.rs b/crates/sui-indexer/src/apis/governance_api_v2.rs index f8cd132f5ebfd..1c588adcaf84a 100644 --- a/crates/sui-indexer/src/apis/governance_api_v2.rs +++ b/crates/sui-indexer/src/apis/governance_api_v2.rs @@ -11,7 +11,9 @@ use cached::{proc_macro::cached, SizedCache}; use sui_json_rpc::{ api::GovernanceReadApiServer, governance_api::ValidatorExchangeRates, SuiRpcModule, }; -use sui_json_rpc_types::{DelegatedStake, EpochInfo, StakeStatus, SuiCommittee, ValidatorApys}; +use sui_json_rpc_types::{ + DelegatedStake, EpochInfo, StakeStatus, SuiCommittee, SuiObjectDataFilter, ValidatorApys, +}; use sui_open_rpc::Module; use sui_types::{ base_types::{MoveObjectType, ObjectID, SuiAddress}, @@ -74,7 +76,9 @@ impl GovernanceReadApiV2 { .inner .get_owned_objects_in_blocking_task( owner, - Some(MoveObjectType::staked_sui().to_string()), + Some(SuiObjectDataFilter::StructType( + MoveObjectType::staked_sui().into(), + )), None, // Allow querying for up to 1000 staked objects 1000, diff --git a/crates/sui-indexer/src/apis/indexer_api_v2.rs b/crates/sui-indexer/src/apis/indexer_api_v2.rs index af6876f5b2e78..5496fa1338b10 100644 --- a/crates/sui-indexer/src/apis/indexer_api_v2.rs +++ b/crates/sui-indexer/src/apis/indexer_api_v2.rs @@ -45,17 +45,10 @@ impl IndexerApiV2 { limit: usize, ) -> RpcResult { let SuiObjectResponseQuery { filter, options } = query.unwrap_or_default(); - if filter.is_some() { - // TODO: do we want to support this? - return Err(IndexerError::NotSupportedError( - "Indexer does not support querying owned objects with filters".into(), - ) - .into()); - } let options = options.unwrap_or_default(); let objects = self .inner - .get_owned_objects_in_blocking_task(address, None, cursor, limit + 1) + .get_owned_objects_in_blocking_task(address, filter, cursor, limit + 1) .await?; let mut objects = self .inner diff --git a/crates/sui-indexer/src/apis/transaction_builder_api_v2.rs b/crates/sui-indexer/src/apis/transaction_builder_api_v2.rs index 874a2cb8500a1..49ae10175d72e 100644 --- a/crates/sui-indexer/src/apis/transaction_builder_api_v2.rs +++ b/crates/sui-indexer/src/apis/transaction_builder_api_v2.rs @@ -6,7 +6,7 @@ use crate::indexer_reader::IndexerReader; use async_trait::async_trait; use move_core_types::language_storage::StructTag; use sui_json_rpc::transaction_builder_api::TransactionBuilderApi; -use sui_json_rpc_types::{SuiObjectDataOptions, SuiObjectResponse}; +use sui_json_rpc_types::{SuiObjectDataFilter, SuiObjectDataOptions, SuiObjectResponse}; use sui_transaction_builder::DataReader; use sui_types::base_types::{ObjectID, ObjectInfo, SuiAddress}; use sui_types::object::Object; @@ -33,7 +33,7 @@ impl DataReader for TransactionBuilderApiV2 { .inner .get_owned_objects_in_blocking_task( address, - Some(object_type.to_canonical_string()), + Some(SuiObjectDataFilter::StructType(object_type)), None, 50, // Limit the number of objects returned to 50 ) diff --git a/crates/sui-indexer/src/indexer_reader.rs b/crates/sui-indexer/src/indexer_reader.rs index b0f6fb44a518f..e6e4b5c5274a3 100644 --- a/crates/sui-indexer/src/indexer_reader.rs +++ b/crates/sui-indexer/src/indexer_reader.rs @@ -41,7 +41,7 @@ use std::{ }; use sui_json_rpc_types::{ AddressMetrics, CheckpointId, EpochInfo, EventFilter, MoveCallMetrics, MoveFunctionName, - NetworkMetrics, SuiEvent, SuiTransactionBlockResponse, TransactionFilter, + NetworkMetrics, SuiEvent, SuiObjectDataFilter, SuiTransactionBlockResponse, TransactionFilter, }; use sui_json_rpc_types::{ Balance, Coin as SuiCoin, SuiCoinMetadata, SuiTransactionBlockEffects, @@ -555,20 +555,45 @@ impl IndexerReader { pub async fn get_owned_objects_in_blocking_task( &self, address: SuiAddress, - object_type: Option, + filter: Option, cursor: Option, limit: usize, ) -> Result, IndexerError> { + let object_types = Self::extract_struct_filters(filter)?; self.spawn_blocking(move |this| { - this.get_owned_objects_impl(address, object_type, cursor, limit) + this.get_owned_objects_impl(address, object_types, cursor, limit) }) .await } + fn extract_struct_filters( + filter: Option, + ) -> Result>, IndexerError> { + if filter.is_none() { + return Ok(None); + } + match filter.unwrap() { + SuiObjectDataFilter::StructType (struct_tag ) => Ok(Some(vec![struct_tag.to_string()])), + SuiObjectDataFilter::MatchAny(filters) => { + filters.iter().map(|filter| { + match filter { + SuiObjectDataFilter::StructType (struct_tag ) => Ok(struct_tag.to_string()), + _ => Err(IndexerError::InvalidArgumentError( + "Invalid filter type. Only struct filters and MatchAny of struct filters are supported.".into(), + )), + } + }).collect::, _>>().map(Some) + } + _ => Err(IndexerError::InvalidArgumentError( + "Invalid filter type. Only struct filters and MatchAny of struct filters are supported.".into(), + )), + } + } + fn get_owned_objects_impl( &self, address: SuiAddress, - object_type: Option, + object_types: Option>, cursor: Option, limit: usize, ) -> Result, IndexerError> { @@ -578,8 +603,8 @@ impl IndexerReader { .filter(objects::dsl::owner_id.eq(address.to_vec())) .limit(limit as i64) .into_boxed(); - if let Some(object_type) = object_type { - query = query.filter(objects::dsl::object_type.eq(object_type)); + if let Some(object_types) = object_types { + query = query.filter(objects::dsl::object_type.eq_any(object_types)); } if let Some(object_cursor) = cursor {