Skip to content

Commit

Permalink
[CLI] Support object query (#1931)
Browse files Browse the repository at this point in the history
* [CLI] Support object query

* [CLI] object query
  • Loading branch information
vegetabledogdog authored Jun 22, 2024
1 parent fd3fb1a commit dc8afb3
Show file tree
Hide file tree
Showing 5 changed files with 110 additions and 43 deletions.
2 changes: 1 addition & 1 deletion crates/rooch-rpc-api/src/jsonrpc_types/move_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ impl std::fmt::Display for ObjectIDVecView {
.map(|id| format!("{:?}", id))
.collect::<Vec<_>>()
.join(",");
write!(f, "{:?}", concated_str)
write!(f, "{}", concated_str)
}
}

Expand Down
16 changes: 16 additions & 0 deletions crates/rooch-rpc-client/src/rooch_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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<IndexerStateID>,
limit: Option<usize>,
query_options: Option<QueryOptions>,
) -> Result<IndexerObjectStatePageView> {
Ok(self
.http
.query_object_states(filter, cursor, limit.map(Into::into), query_options)
.await?)
}
}
6 changes: 3 additions & 3 deletions crates/rooch/src/commands/move_cli/commands/prove.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 .. -- <options>` to pass on options to the prover.
#[derive(Parser)]
#[clap(name = "coverage")]
#[clap(name = "prove")]
pub struct ProveCommand {
#[clap(flatten)]
pub prove: Prove,
Expand Down
109 changes: 80 additions & 29 deletions crates/rooch/src/commands/object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Vec<ParsedObjectID>>,

/// Struct name as `ADDRESS::MODULE_NAME::STRUCT_NAME<TypeParam1?, TypeParam2?>`
#[clap(short = 't', long, value_parser=ParsedStructType::parse)]
object_type: Option<ParsedStructType>,

/// The address of the object's owner.
#[clap(short = 'o', long, value_parser=ParsedAddress::parse)]
owner: Option<ParsedAddress>,

/// Max number of items returned per page
#[clap(long)]
pub id: ParsedObjectID,
limit: Option<usize>,

#[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<Option<StateView>> for ObjectCommand {
async fn execute(self) -> RoochResult<Option<StateView>> {
impl CommandAction<IndexerObjectStatePageView> for ObjectCommand {
async fn execute(self) -> RoochResult<IndexerObjectStatePageView> {
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<ObjectStateFilterView> = 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::<Result<Vec<_>>>()?;
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?)
}
}
20 changes: 10 additions & 10 deletions crates/testsuite/features/cmd.feature
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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"
Expand Down Expand Up @@ -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"
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit dc8afb3

Please sign in to comment.