Skip to content

[3/n][object runtime type tags] Add type tags to object runtime update adapter to handle them #22092

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
May 14, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// Copyright (c) Mysten Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

//# init --addresses Test=0x0

//# publish
module Test::M1 {
public struct X has key {
id: UID,
}

fun init(ctx: &mut TxContext) {
sui::transfer::transfer(X { id: object::new(ctx) }, ctx.sender());
}
}

//# view-object 1,1
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
---
source: external-crates/move/crates/move-transactional-test-runner/src/framework.rs
---
processed 3 tasks

task 1, lines 6-15:
//# publish
created: object(1,0), object(1,1)
mutated: object(0,0)
gas summary: computation_cost: 1000000, storage_cost: 6216800, storage_rebate: 0, non_refundable_storage_fee: 0

task 2, line 17:
//# view-object 1,1
Owner: Account Address ( _ )
Version: 2
Contents: Test::M1::X {
id: sui::object::UID {
id: sui::object::ID {
bytes: fake(1,1),
},
},
}
17 changes: 17 additions & 0 deletions crates/sui-adapter-transactional-tests/tests/init/emit_event.move
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// Copyright (c) Mysten Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

//# init --addresses Test=0x0

//# publish
module Test::M1 {
public struct Event has copy, drop, store {
x: u64,
}

fun init(_ctx: &mut TxContext) {
sui::event::emit(Event { x: 1 });
}
}

//# view-object 1,0
15 changes: 15 additions & 0 deletions crates/sui-adapter-transactional-tests/tests/init/emit_event.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
source: external-crates/move/crates/move-transactional-test-runner/src/framework.rs
---
processed 3 tasks

task 1, lines 6-15:
//# publish
events: Event { package_id: Test, transaction_module: Identifier("M1"), sender: _, type_: StructTag { address: Test, module: Identifier("M1"), name: Identifier("Event"), type_params: [] }, contents: [1, 0, 0, 0, 0, 0, 0, 0] }
created: object(1,0)
mutated: object(0,0)
gas summary: computation_cost: 1000000, storage_cost: 4689200, storage_rebate: 0, non_refundable_storage_fee: 0

task 2, line 17:
//# view-object 1,0
1,0::M1
1 change: 1 addition & 0 deletions crates/sui-open-rpc/spec/openrpc.json
Original file line number Diff line number Diff line change
Expand Up @@ -1375,6 +1375,7 @@
"soft_bundle": false,
"throughput_aware_consensus_submission": false,
"txn_base_cost_as_multiplier": false,
"type_tags_in_object_runtime": false,
"uncompressed_g1_group_elements": false,
"upgraded_multisig_supported": false,
"validate_identifier_inputs": false,
Expand Down
9 changes: 9 additions & 0 deletions crates/sui-protocol-config/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -694,6 +694,10 @@ struct FeatureFlags {
// Enable native function for party transfer
#[serde(skip_serializing_if = "is_false")]
enable_party_transfer: bool,

// Signifies the cut-over of using type tags instead of `Type`s in the object runtime.
#[serde(skip_serializing_if = "is_false")]
type_tags_in_object_runtime: bool,
}

fn is_false(b: &bool) -> bool {
Expand Down Expand Up @@ -1978,6 +1982,10 @@ impl ProtocolConfig {
pub fn enable_party_transfer(&self) -> bool {
self.feature_flags.enable_party_transfer
}

pub fn type_tags_in_object_runtime(&self) -> bool {
self.feature_flags.type_tags_in_object_runtime
}
}

#[cfg(not(msim))]
Expand Down Expand Up @@ -3539,6 +3547,7 @@ impl ProtocolConfig {
// native function on mainnet.
cfg.feature_flags.enable_nitro_attestation_upgraded_parsing = true;
cfg.feature_flags.enable_nitro_attestation = true;
cfg.feature_flags.type_tags_in_object_runtime = true;
}
// Use this template when making changes:
//
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ feature_flags:
enforce_checkpoint_timestamp_monotonicity: true
max_ptb_value_size_v2: true
resolve_type_input_ids_to_defining_id: true
type_tags_in_object_runtime: true
max_tx_size_bytes: 131072
max_input_objects: 2048
max_size_written_objects: 5000000
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ feature_flags:
enforce_checkpoint_timestamp_monotonicity: true
max_ptb_value_size_v2: true
resolve_type_input_ids_to_defining_id: true
type_tags_in_object_runtime: true
max_tx_size_bytes: 131072
max_input_objects: 2048
max_size_written_objects: 5000000
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ feature_flags:
enforce_checkpoint_timestamp_monotonicity: true
max_ptb_value_size_v2: true
resolve_type_input_ids_to_defining_id: true
type_tags_in_object_runtime: true
max_tx_size_bytes: 131072
max_input_objects: 2048
max_size_written_objects: 5000000
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ use move_core_types::{
};
use move_vm_config::runtime::VMRuntimeLimitsConfig;
use move_vm_types::{
loaded_data::runtime_types::Type, natives::function::NativeResult, values::Value,
data_store::DataStore, loaded_data::runtime_types::Type, natives::function::NativeResult,
values::Value,
};
use std::{
cell::RefCell,
Expand Down Expand Up @@ -158,6 +159,36 @@ impl<'b> NativeContext<'_, 'b> {
}
}

// TODO: This is a bit hacky right now since we need to pass the store, however this is only
// used in test scenarios so we have some special knowledge that makes this work. In the new VM
// however this is _MUCH_ nicer as we don't need to pass the datastore as the VM's linkage
// tables must have the type present.
pub fn type_tag_to_fully_annotated_layout_for_test_scenario_only(
&self,
tag: &TypeTag,
store: &impl DataStore,
) -> PartialVMResult<A::MoveTypeLayout> {
self.resolver
.loader()
.get_fully_annotated_type_layout(tag, store)
.map_err(|e| e.to_partial())
}

// TODO: This is a bit hacky right now since we need to pass the store, however this is only
// used in test scenarios so we have some special knowledge that makes this work. In the new VM
// however this is _MUCH_ nicer as we don't need to pass the datastore as the VM's linkage
// tables must have the type present.
pub fn type_tag_to_layout_for_test_scenario_only(
&self,
tag: &TypeTag,
store: &impl DataStore,
) -> PartialVMResult<R::MoveTypeLayout> {
self.resolver
.loader()
.get_type_layout(tag, store)
.map_err(|e| e.to_partial())
}

pub fn type_to_abilities(&self, ty: &Type) -> PartialVMResult<AbilitySet> {
self.resolver.loader().abilities(ty)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@ mod checked {
},
gas_charger::GasCharger,
gas_meter::SuiGasMeter,
programmable_transactions::{data_store::SuiDataStore, linkage_view::LinkageView},
programmable_transactions::{
data_store::{PackageStore, SuiDataStore},
linkage_view::LinkageView,
},
type_resolver::TypeTagResolver,
};
use move_binary_format::{
Expand Down Expand Up @@ -59,7 +62,7 @@ mod checked {
metrics::LimitsMetrics,
move_package::MovePackage,
object::{Authenticator, Data, MoveObject, Object, ObjectInner, Owner},
storage::{BackingPackageStore, DenyListResult, PackageObject},
storage::DenyListResult,
transaction::{Argument, CallArg, ObjectArg},
};
use tracing::instrument;
Expand Down Expand Up @@ -285,10 +288,10 @@ mod checked {
.unwrap_or(*package_id));
}

let package = package_for_linkage(&self.linkage_view, package_id)
let move_package = get_package(&self.linkage_view, package_id)
.map_err(|e| self.convert_vm_error(e))?;

self.linkage_view.set_linkage(package.move_package())
self.linkage_view.set_linkage(&move_package)
}

/// Load a type using the context's current session.
Expand Down Expand Up @@ -341,7 +344,12 @@ mod checked {
}
let new_events = events
.into_iter()
.map(|(ty, tag, value)| {
.map(|(tag, value)| {
let ty = unwrap_type_tag_load(
self.protocol_config,
self.load_type_from_struct(&tag)
.map_err(|e| self.convert_vm_error(e)),
)?;
let layout = self
.vm
.get_runtime()
Expand Down Expand Up @@ -704,7 +712,7 @@ mod checked {
let Self {
protocol_config,
vm,
linkage_view,
mut linkage_view,
mut native_extensions,
tx_context,
gas_charger,
Expand Down Expand Up @@ -839,12 +847,6 @@ mod checked {
loaded_runtime_objects.extend(loaded_child_objects);

let mut written_objects = BTreeMap::new();
for package in new_packages {
let package_obj = Object::new_from_package(package, tx_digest);
let id = package_obj.id();
created_object_ids.insert(id);
written_objects.insert(id, package_obj);
}
for (id, additional_write) in additional_writes {
let AdditionalWrite {
recipient,
Expand Down Expand Up @@ -872,7 +874,24 @@ mod checked {
}
}

for (id, (recipient, ty, value)) in writes {
for (id, (recipient, tag, value)) in writes {
let ty = unwrap_type_tag_load(
protocol_config,
load_type_from_struct(
vm,
&mut linkage_view,
&new_packages,
&StructTag::from(tag.clone()),
)
.map_err(|e| {
convert_vm_error(
e,
vm,
&linkage_view,
protocol_config.resolve_abort_locations_to_package_id(),
)
}),
)?;
let abilities = vm.get_runtime().get_type_abilities(&ty).map_err(|e| {
convert_vm_error(
e,
Expand Down Expand Up @@ -910,6 +929,13 @@ mod checked {
written_objects.insert(id, object);
}

for package in new_packages {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This got moved down as we need to use new_package up above when loading the type. This shouldn't have any effect, but double check me 🙏🏻

let package_obj = Object::new_from_package(package, tx_digest);
let id = package_obj.id();
created_object_ids.insert(id);
written_objects.insert(id, package_obj);
}

// Before finishing, ensure that any shared object taken by value by the transaction is either:
// 1. Mutated (and still has a shared ownership); or
// 2. Deleted.
Expand Down Expand Up @@ -1023,7 +1049,6 @@ mod checked {

/// Special case errors for type arguments to Move functions
pub fn convert_type_argument_error(&self, idx: usize, error: VMError) -> ExecutionError {
use move_core_types::vm_status::StatusCode;
use sui_types::execution_status::TypeArgumentError;
match error.major_status() {
StatusCode::NUMBER_OF_TYPE_ARGUMENTS_MISMATCH => {
Expand Down Expand Up @@ -1284,22 +1309,17 @@ mod checked {

/// Fetch the package at `package_id` with a view to using it as a link context. Produces an error
/// if the object at that ID does not exist, or is not a package.
fn package_for_linkage(
linkage_view: &LinkageView,
fn get_package(
package_store: &dyn PackageStore,
package_id: ObjectID,
) -> VMResult<PackageObject> {
use move_binary_format::errors::PartialVMError;
use move_core_types::vm_status::StatusCode;

match linkage_view.get_package_object(&package_id) {
) -> VMResult<Rc<MovePackage>> {
match package_store.get_package(&package_id) {
Ok(Some(package)) => Ok(package),
Ok(None) => Err(PartialVMError::new(StatusCode::LINKER_ERROR)
.with_message(format!("Cannot find link context {package_id} in store"))
.finish(Location::Undefined)),
Err(err) => Err(PartialVMError::new(StatusCode::LINKER_ERROR)
.with_message(format!(
"Error loading link context {package_id} from store: {err}"
))
.with_message(format!("Error loading {package_id} from store: {err}"))
.finish(Location::Undefined)),
}
}
Expand All @@ -1323,22 +1343,27 @@ mod checked {

// Load the package that the struct is defined in, in storage
let defining_id = ObjectID::from_address(*address);
let package = package_for_linkage(linkage_view, defining_id)?;

let data_store = SuiDataStore::new(linkage_view, new_packages);
let move_package = get_package(&data_store, defining_id)?;

// Save the link context as we need to set it while loading the struct and we don't want to
// clobber it.
let saved_linkage = linkage_view.steal_linkage();

// Set the defining package as the link context while loading the
// struct
let original_address = linkage_view
.set_linkage(package.move_package())
.map_err(|e| {
PartialVMError::new(StatusCode::UNKNOWN_INVARIANT_VIOLATION_ERROR)
.with_message(e.to_string())
.finish(Location::Undefined)
})?;
.set_linkage(&move_package)
.expect("Linkage context was just stolen. Therefore must be empty");

let runtime_id = ModuleId::new(original_address, module.clone());
let data_store = SuiDataStore::new(linkage_view, new_packages);
let res = vm.get_runtime().load_type(&runtime_id, name, &data_store);
linkage_view.reset_linkage();
linkage_view
.restore_linkage(saved_linkage)
.expect("Linkage context was just reset. Therefore must be empty");
let (idx, struct_type) = res?;

// Recursively load type parameters, if necessary
Expand Down Expand Up @@ -1707,6 +1732,17 @@ mod checked {
}
}

fn unwrap_type_tag_load(
protocol_config: &ProtocolConfig,
ty: Result<Type, ExecutionError>,
) -> Result<Type, ExecutionError> {
if ty.is_err() && !protocol_config.type_tags_in_object_runtime() {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should never happen, but just to be paranoid, panic in case it does and we're before this feature is enabled

panic!("Failed to load a type tag from the object runtime -- this shouldn't happen")
} else {
ty
}
}

enum EitherError {
CommandArgument(CommandArgumentError),
Execution(ExecutionError),
Expand Down
Loading
Loading