diff --git a/crates/sui-json-rpc/src/transaction_execution_api.rs b/crates/sui-json-rpc/src/transaction_execution_api.rs index 749cb3ebee8a4b..d38a70be4c5536 100644 --- a/crates/sui-json-rpc/src/transaction_execution_api.rs +++ b/crates/sui-json-rpc/src/transaction_execution_api.rs @@ -10,6 +10,12 @@ use fastcrypto::traits::ToFromBytes; use jsonrpsee::core::RpcResult; use jsonrpsee::RpcModule; +use crate::authority_state::StateRead; +use crate::error::{Error, SuiRpcInputError}; +use crate::{ + get_balance_changes_from_effect, get_object_changes, with_tracing, ObjectProviderCache, + SuiRpcModule, +}; use mysten_metrics::spawn_monitored_task; use shared_crypto::intent::{AppId, Intent, IntentMessage, IntentScope, IntentVersion}; use sui_core::authority::AuthorityState; @@ -29,19 +35,13 @@ use sui_types::quorum_driver_types::{ ExecuteTransactionRequestType, ExecuteTransactionRequestV3, ExecuteTransactionResponseV3, }; use sui_types::signature::GenericSignature; +use sui_types::storage::PostExecutionPackageResolver; use sui_types::sui_serde::BigInt; use sui_types::transaction::{ InputObjectKind, Transaction, TransactionData, TransactionDataAPI, TransactionKind, }; use tracing::instrument; -use crate::authority_state::StateRead; -use crate::error::{Error, SuiRpcInputError}; -use crate::{ - get_balance_changes_from_effect, get_object_changes, with_tracing, ObjectProviderCache, - SuiRpcModule, -}; - pub struct TransactionExecutionApi { state: Arc, transaction_orchestrator: Arc>, @@ -117,7 +117,10 @@ impl TransactionExecutionApi { transaction: txn.clone(), include_events: opts.show_events, include_input_objects: opts.show_balance_changes || opts.show_object_changes, - include_output_objects: opts.show_balance_changes || opts.show_object_changes, + include_output_objects: opts.show_balance_changes + || opts.show_object_changes + // In order to resolve events, we may need access to the newly published packages. + || opts.show_events, include_auxiliary_data: false, }; @@ -182,10 +185,13 @@ impl TransactionExecutionApi { let events = if opts.show_events { let epoch_store = self.state.load_epoch_store_one_call_per_task(); - let backing_package_store = self.state.get_backing_package_store(); + let backing_package_store = PostExecutionPackageResolver::new( + self.state.get_backing_package_store().clone(), + &response.output_objects, + ); let mut layout_resolver = epoch_store .executor() - .type_layout_resolver(Box::new(backing_package_store.as_ref())); + .type_layout_resolver(Box::new(backing_package_store)); Some(SuiTransactionBlockEvents::try_from( response.events.unwrap_or_default(), digest, diff --git a/crates/sui-types/src/storage/mod.rs b/crates/sui-types/src/storage/mod.rs index c9de3fd31080ab..93cb31330eb24f 100644 --- a/crates/sui-types/src/storage/mod.rs +++ b/crates/sui-types/src/storage/mod.rs @@ -22,6 +22,10 @@ use itertools::Itertools; use move_binary_format::CompiledModule; use move_core_types::language_storage::ModuleId; pub use object_store_trait::ObjectStore; +pub use read_store::AccountOwnedObjectInfo; +pub use read_store::CoinInfo; +pub use read_store::DynamicFieldIndexInfo; +pub use read_store::DynamicFieldKey; pub use read_store::ReadStore; pub use read_store::RestStateReader; use serde::{Deserialize, Serialize}; @@ -33,11 +37,6 @@ use std::fmt::{Display, Formatter}; use std::sync::Arc; pub use write_store::WriteStore; -pub use read_store::AccountOwnedObjectInfo; -pub use read_store::CoinInfo; -pub use read_store::DynamicFieldIndexInfo; -pub use read_store::DynamicFieldKey; - /// A potential input to a transaction. #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] pub enum InputKey { @@ -340,6 +339,48 @@ pub fn get_module_by_id( .map(|bytes| CompiledModule::deserialize_with_defaults(&bytes).unwrap())) } +/// A `BackingPackageStore` that resolves packages from a backing store, but also includes any +/// packages that were published in the current transaction execution. This can be used to resolve +/// Move modules right after transaction execution, but newly published packages have not yet been +/// committed to the backing store on a fullnode. +pub struct PostExecutionPackageResolver { + backing_store: Arc, + new_packages: BTreeMap, +} + +impl PostExecutionPackageResolver { + pub fn new( + backing_store: Arc, + output_objects: &Option>, + ) -> Self { + let new_packages = output_objects + .iter() + .flatten() + .filter_map(|o| { + if o.is_package() { + Some((o.id(), PackageObject::new(o.clone()))) + } else { + None + } + }) + .collect(); + Self { + backing_store, + new_packages, + } + } +} + +impl BackingPackageStore for PostExecutionPackageResolver { + fn get_package_object(&self, package_id: &ObjectID) -> SuiResult> { + if let Some(package) = self.new_packages.get(package_id) { + Ok(Some(package.clone())) + } else { + self.backing_store.get_package_object(package_id) + } + } +} + pub trait ParentSync { /// This function is only called by older protocol versions. /// It creates an explicit dependency to tombstones, which is not desired.