diff --git a/crates/rooch-rpc-api/src/jsonrpc_types/move_types.rs b/crates/rooch-rpc-api/src/jsonrpc_types/move_types.rs index d3c3d8060a..7899c8453c 100644 --- a/crates/rooch-rpc-api/src/jsonrpc_types/move_types.rs +++ b/crates/rooch-rpc-api/src/jsonrpc_types/move_types.rs @@ -76,7 +76,7 @@ impl std::fmt::Display for ObjectIDVecView { .map(|id| format!("{:?}", id)) .collect::>() .join(","); - write!(f, "{:?}", concated_str) + write!(f, "{}", concated_str) } } diff --git a/crates/rooch-rpc-client/src/rooch_client.rs b/crates/rooch-rpc-client/src/rooch_client.rs index bf5f16ba44..a9073568c6 100644 --- a/crates/rooch-rpc-client/src/rooch_client.rs +++ b/crates/rooch-rpc-client/src/rooch_client.rs @@ -15,6 +15,9 @@ use rooch_rpc_api::jsonrpc_types::{ RoochAddressView, StateOptions, StatePageView, StructTagView, }; use rooch_rpc_api::jsonrpc_types::{ExecuteTransactionResponseView, StateView}; +use rooch_rpc_api::jsonrpc_types::{ + IndexerObjectStatePageView, ObjectStateFilterView, QueryOptions, +}; use rooch_rpc_api::jsonrpc_types::{TransactionWithInfoPageView, TxOptions}; use rooch_types::indexer::state::IndexerStateID; use rooch_types::{address::RoochAddress, transaction::rooch::RoochTransaction}; @@ -203,4 +206,17 @@ impl RoochRpcClient { .get_balances(account_addr.into(), cursor, limit.map(Into::into)) .await?) } + + pub async fn query_object_states( + &self, + filter: ObjectStateFilterView, + cursor: Option, + limit: Option, + query_options: Option, + ) -> Result { + Ok(self + .http + .query_object_states(filter, cursor, limit.map(Into::into), query_options) + .await?) + } } diff --git a/crates/rooch/src/commands/move_cli/commands/prove.rs b/crates/rooch/src/commands/move_cli/commands/prove.rs index eb3534571e..9664fc103c 100644 --- a/crates/rooch/src/commands/move_cli/commands/prove.rs +++ b/crates/rooch/src/commands/move_cli/commands/prove.rs @@ -12,10 +12,10 @@ use move_cli::{base::prove::Prove, Move}; use rooch_types::error::RoochResult; use serde_json::Value; -/// Inspect test coverage for this package. A previous test run with the `--coverage` flag must -/// have previously been run. +/// Run the Move Prover on the package at `path`. If no path is provided defaults to current +/// directory. Use `.. prove .. -- ` to pass on options to the prover. #[derive(Parser)] -#[clap(name = "coverage")] +#[clap(name = "prove")] pub struct ProveCommand { #[clap(flatten)] pub prove: Prove, diff --git a/crates/rooch/src/commands/object.rs b/crates/rooch/src/commands/object.rs index ab2c3603fc..0a786ab98f 100644 --- a/crates/rooch/src/commands/object.rs +++ b/crates/rooch/src/commands/object.rs @@ -2,49 +2,100 @@ // SPDX-License-Identifier: Apache-2.0 use crate::cli_types::{CommandAction, WalletContextOptions}; +use anyhow::Result; use async_trait::async_trait; use clap::Parser; -use moveos_types::access_path::AccessPath; -use rooch_rpc_api::jsonrpc_types::StateView; -use rooch_types::{error::RoochResult, function_arg::ParsedObjectID}; +use move_command_line_common::types::ParsedStructType; +use rooch_rpc_api::jsonrpc_types::{ + IndexerObjectStatePageView, ObjectStateFilterView, QueryOptions, RoochAddressView, +}; +use rooch_types::address::ParsedAddress; +use rooch_types::{ + error::{RoochError, RoochResult}, + function_arg::ParsedObjectID, +}; -/// Get object by object id -#[derive(Debug, Parser)] +#[derive(Parser)] pub struct ObjectCommand { - /// Object id. + /// Object ids. Separate multiple IDs with a space. + #[clap(short = 'i', long, value_delimiter = ' ', num_args = 1..)] + object_ids: Option>, + + /// Struct name as `ADDRESS::MODULE_NAME::STRUCT_NAME` + #[clap(short = 't', long, value_parser=ParsedStructType::parse)] + object_type: Option, + + /// The address of the object's owner. + #[clap(short = 'o', long, value_parser=ParsedAddress::parse)] + owner: Option, + + /// Max number of items returned per page #[clap(long)] - pub id: ParsedObjectID, + limit: Option, - #[clap(flatten)] - pub(crate) context_options: WalletContextOptions, + /// descending order + #[clap(short = 'd', long, default_value = "false")] + descending_order: bool, /// Render and return display fields. - #[clap(long)] + #[clap(long, default_value = "false")] pub show_display: bool, + + #[clap(flatten)] + pub(crate) context_options: WalletContextOptions, } #[async_trait] -impl CommandAction> for ObjectCommand { - async fn execute(self) -> RoochResult> { +impl CommandAction for ObjectCommand { + async fn execute(self) -> RoochResult { let context = self.context_options.build()?; - let mapping = context.address_mapping(); - let id = self.id.into_object_id(&mapping)?; + let address_mapping = context.address_mapping(); let client = context.get_client().await?; - let resp = if self.show_display { - client - .rooch - .get_decoded_states_with_display(AccessPath::object(id)) - .await? - .pop() - .flatten() - } else { - client - .rooch - .get_decoded_states(AccessPath::object(id)) - .await? - .pop() - .flatten() + + let mut filter: Option = None; + if self.object_ids.is_some() { + let object_ids = self.object_ids.clone().unwrap(); + + let obj_ids = object_ids + .into_iter() + .map(|id| id.into_object_id(&address_mapping)) + .collect::>>()?; + filter = Some(ObjectStateFilterView::ObjectId(obj_ids.into())); + } else if self.owner.is_some() && self.object_type.is_some() { + let owner = self.owner.clone().unwrap(); + let object_type = self.object_type.clone().unwrap(); + + let obj_type = object_type.into_struct_tag(&address_mapping)?; + let owner_addr: RoochAddressView = owner.into_rooch_address(&address_mapping)?.into(); + filter = Some(ObjectStateFilterView::ObjectTypeWithOwner { + object_type: obj_type.into(), + owner: owner_addr.into(), + }); + } else if self.owner.is_some() { + let owner = self.owner.clone().unwrap(); + + let owner_addr: RoochAddressView = owner.into_rooch_address(&address_mapping)?.into(); + filter = Some(ObjectStateFilterView::Owner(owner_addr.into())); + } else if self.object_type.is_some() { + let object_type = self.object_type.clone().unwrap(); + + let obj_type = object_type.into_struct_tag(&address_mapping)?; + filter = Some(ObjectStateFilterView::ObjectType(obj_type.into())); + } + + let query_options = QueryOptions { + descending: self.descending_order, + decode: true, + show_display: self.show_display, }; - Ok(resp) + + if filter.is_none() { + return Err(RoochError::from(anyhow::anyhow!("No filter provided"))); + } + + Ok(client + .rooch + .query_object_states(filter.unwrap(), None, self.limit, Some(query_options)) + .await?) } } diff --git a/crates/testsuite/features/cmd.feature b/crates/testsuite/features/cmd.feature index fb58142cc5..cb885c271f 100644 --- a/crates/testsuite/features/cmd.feature +++ b/crates/testsuite/features/cmd.feature @@ -70,8 +70,8 @@ Feature: Rooch CLI integration tests @serial Scenario: state Given a server for state - Then cmd: "object --id 0x3" - Then cmd: "object --id 0x2::object::Timestamp" + Then cmd: "object -i 0x3" + Then cmd: "object -i 0x2::object::Timestamp" Then cmd: "state --access-path /object/0x2::object::Timestamp" Then assert: "{{$.state[-1][0].value_type}} == '0x2::object::ObjectEntity<0x2::object::Timestamp>'" Then cmd: "state --access-path /object/0x3::chain_id::ChainID" @@ -137,10 +137,10 @@ Feature: Rooch CLI integration tests Then assert: "{{$.rpc[-1].has_next_page}} == false" # Sync states - Then cmd: "rpc request --method rooch_queryObjectStates --params '[{"object_type":"0x3::coin::CoinInfo"}, null, "10", {"descending": true,"showDisplay":false}]' --json" - Then assert: "{{$.rpc[-1].data[0].tx_order}} == 1" - Then assert: "{{$.rpc[-1].data[0].object_type}} == 0x3::coin::CoinInfo<0x3::gas_coin::GasCoin>" - Then assert: "{{$.rpc[-1].has_next_page}} == false" + Then cmd: "object -t 0x3::coin::CoinInfo --limit 10 -d" + Then assert: "{{$.object[-1].data[0].tx_order}} == 1" + Then assert: "{{$.object[-1].data[0].object_type}} == 0x3::coin::CoinInfo<0x3::gas_coin::GasCoin>" + Then assert: "{{$.object[-1].has_next_page}} == false" Then cmd: "rpc request --method rooch_listFieldStates --params '["{{$.address_mapping.default}}", null, "10", {"descending": true,"showDisplay":false}]' --json" Then assert: "{{$.rpc[-1].has_next_page}} == false" @@ -303,8 +303,8 @@ Feature: Rooch CLI integration tests # because the indexer is async update, so sleep 2 seconds to wait indexer update. Then sleep: "2" - Then cmd: "rpc request --method rooch_queryObjectStates --params '[{"object_type":"{{$.address_mapping.default}}::child_object::Child"}, null, "10", {"descending": true,"showDisplay":false}]' --json" - Then assert: "{{$.rpc[-1].data[0].object_id}} == {{$.event[-1].data[0].decoded_event_data.value.id}}" + Then cmd: "object -t {{$.address_mapping.default}}::child_object::Child --limit 10 -d" + Then assert: "{{$.object[-1].data[0].object_id}} == {{$.event[-1].data[0].decoded_event_data.value.id}}" Then cmd: "move run --function default::third_party_module_for_child_object::update_child_age --args object:{{$.event[-1].data[0].decoded_event_data.value.id}} --args u64:10" Then assert: "{{$.move[-1].execution_info.status.type}} == executed" @@ -392,8 +392,8 @@ Feature: Rooch CLI integration tests Then sleep: "10" # wait rooch sync and index # query utxos - Then cmd: "rpc request --method rooch_queryObjectStates --params '[{"object_type_with_owner":{"object_type":"0x4::utxo::UTXO","owner":"{{$.account[-1].default.bitcoin_address}}"}},null, null, null]' --json" - Then assert: "{{$.rpc[-1].data[0].owner}} == {{$.account[-1].default.address}}" + Then cmd: "object -t 0x4::utxo::UTXO -o {{$.account[-1].default.bitcoin_address}}" + Then assert: "{{$.object[-1].data[0].owner}} == {{$.account[-1].default.address}}" # release servers Then stop the server