Skip to content

Commit 4a04a88

Browse files
authored
[txn sim session] add view_resource and view_resource_group (#17729)
1 parent 21aa34a commit 4a04a88

File tree

3 files changed

+206
-20
lines changed

3 files changed

+206
-20
lines changed

aptos-move/aptos-transaction-simulation-session/examples/local.sh

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,9 @@ cargo run -p aptos -- move run --session sess --function-id 0x1::aptos_account::
1515

1616
# view account sequence number
1717
cargo run -p aptos -- move view --session sess --function-id 0x1::account::get_sequence_number --args address:default
18+
19+
# view resource
20+
cargo run -p aptos -- move sim view-resource --session sess --account default --resource 0x1::account::Account
21+
22+
# view resource group
23+
cargo run -p aptos -- move sim view-resource-group --session sess --account default --resource-group 0x1::object::ObjectGroup --derived-object-address 0xA

aptos-move/aptos-transaction-simulation-session/src/session.rs

Lines changed: 128 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,15 @@ use crate::{
77
txn_output::{save_events, save_write_set},
88
};
99
use anyhow::Result;
10-
use aptos_resource_viewer::AptosValueAnnotator;
10+
use aptos_resource_viewer::{AnnotatedMoveValue, AptosValueAnnotator};
1111
use aptos_rest_client::{AptosBaseUrl, Client};
1212
use aptos_transaction_simulation::{
1313
DeltaStateStore, EitherStateView, EmptyStateView, SimulationStateStore, GENESIS_CHANGE_SET_HEAD,
1414
};
1515
use aptos_types::{
16-
account_address::AccountAddress,
16+
account_address::{create_derived_object_address, AccountAddress},
1717
fee_statement::FeeStatement,
18+
state_store::{state_key::StateKey, TStateView},
1819
transaction::{
1920
AuxiliaryInfo, PersistedAuxiliaryInfo, SignedTransaction, TransactionExecutable,
2021
TransactionOutput, TransactionPayload, TransactionPayloadInner, TransactionStatus,
@@ -25,38 +26,38 @@ use aptos_validator_interface::{DebuggerStateView, RestDebuggerInterface};
2526
use aptos_vm::{data_cache::AsMoveResolver, AptosVM};
2627
use aptos_vm_environment::environment::AptosEnvironment;
2728
use aptos_vm_logging::log_schema::AdapterLogSchema;
28-
use aptos_vm_types::{module_and_script_storage::AsAptosCodeStorage, resolver::StateStorageView};
29+
use aptos_vm_types::module_and_script_storage::AsAptosCodeStorage;
2930
use move_core_types::{
3031
identifier::Identifier,
31-
language_storage::{ModuleId, TypeTag},
32+
language_storage::{ModuleId, StructTag, TypeTag},
3233
};
3334
use serde::{Deserialize, Serialize};
35+
use serde_json::json;
3436
use std::{
35-
collections::HashMap,
37+
collections::{BTreeMap, HashMap},
3638
path::{Path, PathBuf},
3739
sync::Arc,
3840
};
3941
use url::Url;
4042

4143
type SessionStateStore = DeltaStateStore<EitherStateView<EmptyStateView, DebuggerStateView>>;
4244

45+
/// Formats an account address for display.
46+
/// Truncates the address if it's more than 4 digits.
47+
fn format_address(address: &AccountAddress) -> String {
48+
let address_str = address.to_hex_literal();
49+
if address_str.len() > 6 {
50+
format!("{}...", &address_str[..6])
51+
} else {
52+
address_str
53+
}
54+
}
55+
4356
/// Formats a module ID for display by adjusting the address for better readability.
4457
fn format_module_id(module_id: &ModuleId) -> String {
4558
let address = module_id.address();
4659
let name = module_id.name();
47-
48-
// Format address: add 0x prefix, trim leading zeros, limit to 4 digits
49-
let address_str = format!("{:x}", address);
50-
let trimmed = address_str.trim_start_matches('0');
51-
let display_address = if trimmed.is_empty() {
52-
"0".to_string()
53-
} else if trimmed.len() > 4 {
54-
format!("{}...", &trimmed[..4])
55-
} else {
56-
trimmed.to_string()
57-
};
58-
59-
format!("0x{}::{}", display_address, name)
60+
format!("{}::{}", format_address(address), name)
6061
}
6162

6263
#[derive(Debug, Serialize, Deserialize)]
@@ -85,6 +86,14 @@ enum Summary {
8586
result: ViewResult,
8687
gas_used: u64,
8788
},
89+
ViewResource {
90+
resource_type: String,
91+
resource_value: Option<serde_json::Value>,
92+
},
93+
ViewResourceGroup {
94+
group_type: String,
95+
group_value: Option<serde_json::Value>,
96+
},
8897
}
8998

9099
/// A session for simulating transactions, with data being persisted to a directory, allowing the session
@@ -414,7 +423,107 @@ impl Session {
414423
res
415424
}
416425

417-
// TODO: view resource
426+
/// Views a Move resource.
427+
pub fn view_resource(
428+
&mut self,
429+
account_addr: AccountAddress,
430+
resource_tag: &StructTag,
431+
) -> Result<Option<serde_json::Value>> {
432+
let state_key = StateKey::resource(&account_addr, resource_tag)?;
433+
434+
let json_val = match self.state_store.get_state_value_bytes(&state_key)? {
435+
Some(bytes) => {
436+
let annotator = AptosValueAnnotator::new(&self.state_store);
437+
let annotated =
438+
AnnotatedMoveValue::Struct(annotator.view_resource(resource_tag, &bytes)?);
439+
Some(aptos_api_types::MoveValue::try_from(annotated)?.json()?)
440+
},
441+
None => None,
442+
};
443+
444+
let summary = Summary::ViewResource {
445+
resource_type: resource_tag.to_canonical_string(),
446+
resource_value: json_val.clone(),
447+
};
448+
449+
let summary_path = self
450+
.path
451+
.join(format!(
452+
"[{}] view resource {}::{}::{}::{}",
453+
self.config.ops,
454+
format_address(&account_addr),
455+
format_address(&resource_tag.address),
456+
resource_tag.module,
457+
resource_tag.name,
458+
))
459+
.join("summary.json");
460+
std::fs::create_dir_all(summary_path.parent().unwrap())?;
461+
std::fs::write(summary_path, serde_json::to_string_pretty(&summary)?)?;
462+
463+
self.config.ops += 1;
464+
self.config.save_to_file(&self.path.join("config.json"))?;
465+
466+
Ok(json_val)
467+
}
468+
469+
pub fn view_resource_group(
470+
&mut self,
471+
account_addr: AccountAddress,
472+
resource_group_tag: &StructTag,
473+
derived_object_address: Option<AccountAddress>,
474+
) -> Result<Option<serde_json::Value>> {
475+
let account_addr = match derived_object_address {
476+
Some(addr) => create_derived_object_address(account_addr, addr),
477+
None => account_addr,
478+
};
479+
480+
let state_key = StateKey::resource_group(&account_addr, resource_group_tag);
481+
482+
let json_val = match self.state_store.get_state_value_bytes(&state_key)? {
483+
Some(bytes) => {
484+
let group: BTreeMap<StructTag, Vec<u8>> = bcs::from_bytes(&bytes)?;
485+
486+
let annotator = AptosValueAnnotator::new(&self.state_store);
487+
488+
let mut group_deserialized = BTreeMap::new();
489+
for (resource_tag, bytes) in group {
490+
let annotated =
491+
AnnotatedMoveValue::Struct(annotator.view_resource(&resource_tag, &bytes)?);
492+
group_deserialized.insert(
493+
resource_tag.to_canonical_string(),
494+
aptos_api_types::MoveValue::try_from(annotated)?.json()?,
495+
);
496+
}
497+
498+
Some(json!(group_deserialized))
499+
},
500+
None => None,
501+
};
502+
503+
let summary = Summary::ViewResourceGroup {
504+
group_type: resource_group_tag.to_canonical_string(),
505+
group_value: json_val.clone(),
506+
};
507+
508+
let summary_path = self
509+
.path
510+
.join(format!(
511+
"[{}] view resource group {}::{}::{}::{}",
512+
self.config.ops,
513+
format_address(&account_addr),
514+
format_address(&resource_group_tag.address),
515+
resource_group_tag.module,
516+
resource_group_tag.name,
517+
))
518+
.join("summary.json");
519+
std::fs::create_dir_all(summary_path.parent().unwrap())?;
520+
std::fs::write(summary_path, serde_json::to_string_pretty(&summary)?)?;
521+
522+
self.config.ops += 1;
523+
self.config.save_to_file(&self.path.join("config.json"))?;
524+
525+
Ok(json_val)
526+
}
418527
}
419528

420529
#[test]

crates/aptos/src/move_tool/sim.rs

Lines changed: 72 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use aptos_rest_client::Client;
99
use aptos_transaction_simulation_session::Session;
1010
use async_trait::async_trait;
1111
use clap::{Parser, Subcommand};
12-
use move_core_types::account_address::AccountAddress;
12+
use move_core_types::{account_address::AccountAddress, language_storage::StructTag};
1313
use std::path::PathBuf;
1414

1515
/// Initializes a new simulation session
@@ -99,20 +99,91 @@ impl CliCommand<()> for Fund {
9999
}
100100
}
101101

102+
/// View a resource
103+
#[derive(Debug, Parser)]
104+
pub struct ViewResource {
105+
/// Path to a stored session
106+
#[clap(long)]
107+
session: PathBuf,
108+
109+
/// Account under which the resource is stored
110+
#[clap(long, value_parser = crate::common::types::load_account_arg)]
111+
account: AccountAddress,
112+
113+
/// Resource to view
114+
#[clap(long)]
115+
resource: StructTag,
116+
}
117+
118+
#[async_trait]
119+
impl CliCommand<Option<serde_json::Value>> for ViewResource {
120+
fn command_name(&self) -> &'static str {
121+
"view-resource"
122+
}
123+
124+
async fn execute(self) -> CliTypedResult<Option<serde_json::Value>> {
125+
let mut session = Session::load(&self.session)?;
126+
127+
Ok(session.view_resource(self.account, &self.resource)?)
128+
}
129+
}
130+
131+
/// View a resource group
132+
#[derive(Debug, Parser)]
133+
pub struct ViewResourceGroup {
134+
/// Path to a stored session
135+
#[clap(long)]
136+
session: PathBuf,
137+
138+
/// Account under which the resource group is stored
139+
#[clap(long, value_parser = crate::common::types::load_account_arg)]
140+
account: AccountAddress,
141+
142+
/// Resource group to view
143+
#[clap(long)]
144+
resource_group: StructTag,
145+
146+
/// If specified, derives an object address from the source address and an object
147+
#[clap(long)]
148+
derived_object_address: Option<AccountAddress>,
149+
}
150+
151+
#[async_trait]
152+
impl CliCommand<Option<serde_json::Value>> for ViewResourceGroup {
153+
fn command_name(&self) -> &'static str {
154+
"view-resource-group"
155+
}
156+
157+
async fn execute(self) -> CliTypedResult<Option<serde_json::Value>> {
158+
let mut session = Session::load(&self.session)?;
159+
Ok(session.view_resource_group(
160+
self.account,
161+
&self.resource_group,
162+
self.derived_object_address,
163+
)?)
164+
}
165+
}
166+
102167
/// BETA: Commands for interacting with a local simulation session
103168
///
104169
/// BETA: Subject to change
105170
#[derive(Subcommand)]
106171
pub enum Sim {
107172
Init(Init),
108173
Fund(Fund),
174+
ViewResource(ViewResource),
175+
ViewResourceGroup(ViewResourceGroup),
109176
}
110177

111178
impl Sim {
112179
pub async fn execute(self) -> CliResult {
113180
match self {
114181
Sim::Init(init) => init.execute_serialized_success().await,
115182
Sim::Fund(fund) => fund.execute_serialized_success().await,
183+
Sim::ViewResource(view_resource) => view_resource.execute_serialized().await,
184+
Sim::ViewResourceGroup(view_resource_group) => {
185+
view_resource_group.execute_serialized().await
186+
},
116187
}
117188
}
118189
}

0 commit comments

Comments
 (0)