@@ -7,14 +7,15 @@ use crate::{
77 txn_output:: { save_events, save_write_set} ,
88} ;
99use anyhow:: Result ;
10- use aptos_resource_viewer:: AptosValueAnnotator ;
10+ use aptos_resource_viewer:: { AnnotatedMoveValue , AptosValueAnnotator } ;
1111use aptos_rest_client:: { AptosBaseUrl , Client } ;
1212use aptos_transaction_simulation:: {
1313 DeltaStateStore , EitherStateView , EmptyStateView , SimulationStateStore , GENESIS_CHANGE_SET_HEAD ,
1414} ;
1515use 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};
2526use aptos_vm:: { data_cache:: AsMoveResolver , AptosVM } ;
2627use aptos_vm_environment:: environment:: AptosEnvironment ;
2728use 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 ;
2930use move_core_types:: {
3031 identifier:: Identifier ,
31- language_storage:: { ModuleId , TypeTag } ,
32+ language_storage:: { ModuleId , StructTag , TypeTag } ,
3233} ;
3334use serde:: { Deserialize , Serialize } ;
35+ use serde_json:: json;
3436use std:: {
35- collections:: HashMap ,
37+ collections:: { BTreeMap , HashMap } ,
3638 path:: { Path , PathBuf } ,
3739 sync:: Arc ,
3840} ;
3941use url:: Url ;
4042
4143type 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.
4457fn 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]
0 commit comments