diff --git a/crates/sui-adapter-transactional-tests/tests/size_limits/deleted_id_limits_tests.snap b/crates/sui-adapter-transactional-tests/tests/size_limits/deleted_id_limits_tests.snap index 81c5f83004a75..725d343c7ae2a 100644 --- a/crates/sui-adapter-transactional-tests/tests/size_limits/deleted_id_limits_tests.snap +++ b/crates/sui-adapter-transactional-tests/tests/size_limits/deleted_id_limits_tests.snap @@ -22,14 +22,14 @@ gas summary: computation_cost: 1000000, storage_cost: 988000, storage_rebate: 9 task 4, lines 39-41: //# run Test::M1::delete_n_ids --args 2048 --gas-budget 100000000000000 mutated: object(0,0) -gas summary: computation_cost: 19000000, storage_cost: 988000, storage_rebate: 978120, non_refundable_storage_fee: 9880 +gas summary: computation_cost: 11000000, storage_cost: 988000, storage_rebate: 978120, non_refundable_storage_fee: 9880 task 5, lines 42-44: //# run Test::M1::delete_n_ids --args 2049 --gas-budget 100000000000000 -Error: Transaction Effects Status: Move Primitive Runtime Error. Location: sui::tx_context::derive_id (function index 6) at offset 0. Arithmetic error, stack overflow, max value depth, etc. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MovePrimitiveRuntimeError(MoveLocationOpt(Some(MoveLocation { module: ModuleId { address: sui, name: Identifier("tx_context") }, function: 6, instruction: 0, function_name: Some("derive_id") }))), source: Some(VMError { major_status: MEMORY_LIMIT_EXCEEDED, sub_status: Some(2), message: Some("Creating more than 2048 IDs is not allowed"), exec_state: None, location: Module(ModuleId { address: sui, name: Identifier("tx_context") }), indices: [], offsets: [(FunctionDefinitionIndex(6), 0)] }), command: Some(0) } } +Error: Transaction Effects Status: Move Primitive Runtime Error. Location: sui::tx_context::fresh_id (function index 10) at offset 0. Arithmetic error, stack overflow, max value depth, etc. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MovePrimitiveRuntimeError(MoveLocationOpt(Some(MoveLocation { module: ModuleId { address: sui, name: Identifier("tx_context") }, function: 10, instruction: 0, function_name: Some("fresh_id") }))), source: Some(VMError { major_status: MEMORY_LIMIT_EXCEEDED, sub_status: Some(2), message: Some("Creating more than 2048 IDs is not allowed"), exec_state: None, location: Module(ModuleId { address: sui, name: Identifier("tx_context") }), indices: [], offsets: [(FunctionDefinitionIndex(10), 0)] }), command: Some(0) } } task 6, line 45: //# run Test::M1::delete_n_ids --args 4096 --gas-budget 100000000000000 -Error: Transaction Effects Status: Move Primitive Runtime Error. Location: sui::tx_context::derive_id (function index 6) at offset 0. Arithmetic error, stack overflow, max value depth, etc. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MovePrimitiveRuntimeError(MoveLocationOpt(Some(MoveLocation { module: ModuleId { address: sui, name: Identifier("tx_context") }, function: 6, instruction: 0, function_name: Some("derive_id") }))), source: Some(VMError { major_status: MEMORY_LIMIT_EXCEEDED, sub_status: Some(2), message: Some("Creating more than 2048 IDs is not allowed"), exec_state: None, location: Module(ModuleId { address: sui, name: Identifier("tx_context") }), indices: [], offsets: [(FunctionDefinitionIndex(6), 0)] }), command: Some(0) } } +Error: Transaction Effects Status: Move Primitive Runtime Error. Location: sui::tx_context::fresh_id (function index 10) at offset 0. Arithmetic error, stack overflow, max value depth, etc. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MovePrimitiveRuntimeError(MoveLocationOpt(Some(MoveLocation { module: ModuleId { address: sui, name: Identifier("tx_context") }, function: 10, instruction: 0, function_name: Some("fresh_id") }))), source: Some(VMError { major_status: MEMORY_LIMIT_EXCEEDED, sub_status: Some(2), message: Some("Creating more than 2048 IDs is not allowed"), exec_state: None, location: Module(ModuleId { address: sui, name: Identifier("tx_context") }), indices: [], offsets: [(FunctionDefinitionIndex(10), 0)] }), command: Some(0) } } diff --git a/crates/sui-adapter-transactional-tests/tests/size_limits/new_id_limits_tests.snap b/crates/sui-adapter-transactional-tests/tests/size_limits/new_id_limits_tests.snap index bcc322d61fb38..90df60293c6dd 100644 --- a/crates/sui-adapter-transactional-tests/tests/size_limits/new_id_limits_tests.snap +++ b/crates/sui-adapter-transactional-tests/tests/size_limits/new_id_limits_tests.snap @@ -22,14 +22,14 @@ gas summary: computation_cost: 1000000, storage_cost: 988000, storage_rebate: 9 task 4, lines 40-42: //# run Test::M1::create_n_ids --args 2048 --gas-budget 100000000000000 mutated: object(0,0) -gas summary: computation_cost: 19000000, storage_cost: 988000, storage_rebate: 978120, non_refundable_storage_fee: 9880 +gas summary: computation_cost: 11000000, storage_cost: 988000, storage_rebate: 978120, non_refundable_storage_fee: 9880 task 5, lines 43-45: //# run Test::M1::create_n_ids --args 2049 --gas-budget 100000000000000 -Error: Transaction Effects Status: Move Primitive Runtime Error. Location: sui::tx_context::derive_id (function index 6) at offset 0. Arithmetic error, stack overflow, max value depth, etc. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MovePrimitiveRuntimeError(MoveLocationOpt(Some(MoveLocation { module: ModuleId { address: sui, name: Identifier("tx_context") }, function: 6, instruction: 0, function_name: Some("derive_id") }))), source: Some(VMError { major_status: MEMORY_LIMIT_EXCEEDED, sub_status: Some(2), message: Some("Creating more than 2048 IDs is not allowed"), exec_state: None, location: Module(ModuleId { address: sui, name: Identifier("tx_context") }), indices: [], offsets: [(FunctionDefinitionIndex(6), 0)] }), command: Some(0) } } +Error: Transaction Effects Status: Move Primitive Runtime Error. Location: sui::tx_context::fresh_id (function index 10) at offset 0. Arithmetic error, stack overflow, max value depth, etc. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MovePrimitiveRuntimeError(MoveLocationOpt(Some(MoveLocation { module: ModuleId { address: sui, name: Identifier("tx_context") }, function: 10, instruction: 0, function_name: Some("fresh_id") }))), source: Some(VMError { major_status: MEMORY_LIMIT_EXCEEDED, sub_status: Some(2), message: Some("Creating more than 2048 IDs is not allowed"), exec_state: None, location: Module(ModuleId { address: sui, name: Identifier("tx_context") }), indices: [], offsets: [(FunctionDefinitionIndex(10), 0)] }), command: Some(0) } } task 6, line 46: //# run Test::M1::create_n_ids --args 4096 --gas-budget 100000000000000 -Error: Transaction Effects Status: Move Primitive Runtime Error. Location: sui::tx_context::derive_id (function index 6) at offset 0. Arithmetic error, stack overflow, max value depth, etc. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MovePrimitiveRuntimeError(MoveLocationOpt(Some(MoveLocation { module: ModuleId { address: sui, name: Identifier("tx_context") }, function: 6, instruction: 0, function_name: Some("derive_id") }))), source: Some(VMError { major_status: MEMORY_LIMIT_EXCEEDED, sub_status: Some(2), message: Some("Creating more than 2048 IDs is not allowed"), exec_state: None, location: Module(ModuleId { address: sui, name: Identifier("tx_context") }), indices: [], offsets: [(FunctionDefinitionIndex(6), 0)] }), command: Some(0) } } +Error: Transaction Effects Status: Move Primitive Runtime Error. Location: sui::tx_context::fresh_id (function index 10) at offset 0. Arithmetic error, stack overflow, max value depth, etc. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MovePrimitiveRuntimeError(MoveLocationOpt(Some(MoveLocation { module: ModuleId { address: sui, name: Identifier("tx_context") }, function: 10, instruction: 0, function_name: Some("fresh_id") }))), source: Some(VMError { major_status: MEMORY_LIMIT_EXCEEDED, sub_status: Some(2), message: Some("Creating more than 2048 IDs is not allowed"), exec_state: None, location: Module(ModuleId { address: sui, name: Identifier("tx_context") }), indices: [], offsets: [(FunctionDefinitionIndex(10), 0)] }), command: Some(0) } } diff --git a/crates/sui-adapter-transactional-tests/tests/size_limits/object_runtime_limits.snap b/crates/sui-adapter-transactional-tests/tests/size_limits/object_runtime_limits.snap index 7cc28298d7546..6beb329ecad73 100644 --- a/crates/sui-adapter-transactional-tests/tests/size_limits/object_runtime_limits.snap +++ b/crates/sui-adapter-transactional-tests/tests/size_limits/object_runtime_limits.snap @@ -22,7 +22,7 @@ task 3, line 30: //# run a::m::add_n_items --sender A --args 1000 --gas-budget 1000000000000 --summarize created: 2000 mutated: 1 -gas summary: computation_cost: 198000000, storage_cost: 2691388000, storage_rebate: 978120, non_refundable_storage_fee: 9880 +gas summary: computation_cost: 199000000, storage_cost: 2691388000, storage_rebate: 978120, non_refundable_storage_fee: 9880 task 4, line 32: //# run a::m::add_n_items --sender A --args 1025 --gas-budget 1000000000000 diff --git a/crates/sui-adapter-transactional-tests/tests/size_limits/transfered_id_limits_tests.snap b/crates/sui-adapter-transactional-tests/tests/size_limits/transfered_id_limits_tests.snap index db12714ca5895..194ba2834b325 100644 --- a/crates/sui-adapter-transactional-tests/tests/size_limits/transfered_id_limits_tests.snap +++ b/crates/sui-adapter-transactional-tests/tests/size_limits/transfered_id_limits_tests.snap @@ -25,24 +25,24 @@ task 4, lines 39-41: //# run Test::M1::transfer_n_ids --args 2048 --gas-budget 100000000000000 --summarize created: 2048 mutated: 1 -gas summary: computation_cost: 17000000, storage_cost: 2522485600, storage_rebate: 978120, non_refundable_storage_fee: 9880 +gas summary: computation_cost: 14000000, storage_cost: 2522485600, storage_rebate: 978120, non_refundable_storage_fee: 9880 task 5, lines 42-44: //# run Test::M1::transfer_n_ids --args 2049 --gas-budget 100000000000000 -Error: Transaction Effects Status: Move Primitive Runtime Error. Location: sui::tx_context::derive_id (function index 6) at offset 0. Arithmetic error, stack overflow, max value depth, etc. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MovePrimitiveRuntimeError(MoveLocationOpt(Some(MoveLocation { module: ModuleId { address: sui, name: Identifier("tx_context") }, function: 6, instruction: 0, function_name: Some("derive_id") }))), source: Some(VMError { major_status: MEMORY_LIMIT_EXCEEDED, sub_status: Some(2), message: Some("Creating more than 2048 IDs is not allowed"), exec_state: None, location: Module(ModuleId { address: sui, name: Identifier("tx_context") }), indices: [], offsets: [(FunctionDefinitionIndex(6), 0)] }), command: Some(0) } } +Error: Transaction Effects Status: Move Primitive Runtime Error. Location: sui::tx_context::fresh_id (function index 10) at offset 0. Arithmetic error, stack overflow, max value depth, etc. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MovePrimitiveRuntimeError(MoveLocationOpt(Some(MoveLocation { module: ModuleId { address: sui, name: Identifier("tx_context") }, function: 10, instruction: 0, function_name: Some("fresh_id") }))), source: Some(VMError { major_status: MEMORY_LIMIT_EXCEEDED, sub_status: Some(2), message: Some("Creating more than 2048 IDs is not allowed"), exec_state: None, location: Module(ModuleId { address: sui, name: Identifier("tx_context") }), indices: [], offsets: [(FunctionDefinitionIndex(10), 0)] }), command: Some(0) } } task 6, lines 45-47: //# run Test::M1::transfer_n_ids --args 4096 --gas-budget 100000000000000 -Error: Transaction Effects Status: Move Primitive Runtime Error. Location: sui::tx_context::derive_id (function index 6) at offset 0. Arithmetic error, stack overflow, max value depth, etc. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MovePrimitiveRuntimeError(MoveLocationOpt(Some(MoveLocation { module: ModuleId { address: sui, name: Identifier("tx_context") }, function: 6, instruction: 0, function_name: Some("derive_id") }))), source: Some(VMError { major_status: MEMORY_LIMIT_EXCEEDED, sub_status: Some(2), message: Some("Creating more than 2048 IDs is not allowed"), exec_state: None, location: Module(ModuleId { address: sui, name: Identifier("tx_context") }), indices: [], offsets: [(FunctionDefinitionIndex(6), 0)] }), command: Some(0) } } +Error: Transaction Effects Status: Move Primitive Runtime Error. Location: sui::tx_context::fresh_id (function index 10) at offset 0. Arithmetic error, stack overflow, max value depth, etc. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MovePrimitiveRuntimeError(MoveLocationOpt(Some(MoveLocation { module: ModuleId { address: sui, name: Identifier("tx_context") }, function: 10, instruction: 0, function_name: Some("fresh_id") }))), source: Some(VMError { major_status: MEMORY_LIMIT_EXCEEDED, sub_status: Some(2), message: Some("Creating more than 2048 IDs is not allowed"), exec_state: None, location: Module(ModuleId { address: sui, name: Identifier("tx_context") }), indices: [], offsets: [(FunctionDefinitionIndex(10), 0)] }), command: Some(0) } } task 7, lines 48-50: //# run Test::M1::transfer_n_ids --args 2049 --gas-budget 100000000000000 -Error: Transaction Effects Status: Move Primitive Runtime Error. Location: sui::tx_context::derive_id (function index 6) at offset 0. Arithmetic error, stack overflow, max value depth, etc. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MovePrimitiveRuntimeError(MoveLocationOpt(Some(MoveLocation { module: ModuleId { address: sui, name: Identifier("tx_context") }, function: 6, instruction: 0, function_name: Some("derive_id") }))), source: Some(VMError { major_status: MEMORY_LIMIT_EXCEEDED, sub_status: Some(2), message: Some("Creating more than 2048 IDs is not allowed"), exec_state: None, location: Module(ModuleId { address: sui, name: Identifier("tx_context") }), indices: [], offsets: [(FunctionDefinitionIndex(6), 0)] }), command: Some(0) } } +Error: Transaction Effects Status: Move Primitive Runtime Error. Location: sui::tx_context::fresh_id (function index 10) at offset 0. Arithmetic error, stack overflow, max value depth, etc. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MovePrimitiveRuntimeError(MoveLocationOpt(Some(MoveLocation { module: ModuleId { address: sui, name: Identifier("tx_context") }, function: 10, instruction: 0, function_name: Some("fresh_id") }))), source: Some(VMError { major_status: MEMORY_LIMIT_EXCEEDED, sub_status: Some(2), message: Some("Creating more than 2048 IDs is not allowed"), exec_state: None, location: Module(ModuleId { address: sui, name: Identifier("tx_context") }), indices: [], offsets: [(FunctionDefinitionIndex(10), 0)] }), command: Some(0) } } task 8, line 51: //# run Test::M1::transfer_n_ids --args 4096 --gas-budget 100000000000000 -Error: Transaction Effects Status: Move Primitive Runtime Error. Location: sui::tx_context::derive_id (function index 6) at offset 0. Arithmetic error, stack overflow, max value depth, etc. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MovePrimitiveRuntimeError(MoveLocationOpt(Some(MoveLocation { module: ModuleId { address: sui, name: Identifier("tx_context") }, function: 6, instruction: 0, function_name: Some("derive_id") }))), source: Some(VMError { major_status: MEMORY_LIMIT_EXCEEDED, sub_status: Some(2), message: Some("Creating more than 2048 IDs is not allowed"), exec_state: None, location: Module(ModuleId { address: sui, name: Identifier("tx_context") }), indices: [], offsets: [(FunctionDefinitionIndex(6), 0)] }), command: Some(0) } } +Error: Transaction Effects Status: Move Primitive Runtime Error. Location: sui::tx_context::fresh_id (function index 10) at offset 0. Arithmetic error, stack overflow, max value depth, etc. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MovePrimitiveRuntimeError(MoveLocationOpt(Some(MoveLocation { module: ModuleId { address: sui, name: Identifier("tx_context") }, function: 10, instruction: 0, function_name: Some("fresh_id") }))), source: Some(VMError { major_status: MEMORY_LIMIT_EXCEEDED, sub_status: Some(2), message: Some("Creating more than 2048 IDs is not allowed"), exec_state: None, location: Module(ModuleId { address: sui, name: Identifier("tx_context") }), indices: [], offsets: [(FunctionDefinitionIndex(10), 0)] }), command: Some(0) } } diff --git a/crates/sui-core/src/unit_tests/authority_tests.rs b/crates/sui-core/src/unit_tests/authority_tests.rs index a7de998db8bc7..5afc2a3b85d18 100644 --- a/crates/sui-core/src/unit_tests/authority_tests.rs +++ b/crates/sui-core/src/unit_tests/authority_tests.rs @@ -1679,14 +1679,18 @@ async fn test_publish_dependent_module_ok() { }; let authority = init_state_with_objects(vec![gas_payment_object]).await; + let epoch_store = authority.epoch_store_for_testing(); + let protocol_config = epoch_store.protocol_config(); let rgp = authority.reference_gas_price_for_testing().unwrap(); + let gas_price = rgp; + let gas_budget = gas_price * TEST_ONLY_GAS_UNIT_FOR_PUBLISH; let data = TransactionData::new_module( sender, gas_payment_object_ref, vec![dependent_module_bytes], vec![ObjectID::from(*genesis_module.address())], - rgp * TEST_ONLY_GAS_UNIT_FOR_PUBLISH, - rgp, + gas_budget, + gas_price, ); let transaction = to_sender_signed_transaction(data, &sender_key); @@ -1694,8 +1698,10 @@ async fn test_publish_dependent_module_ok() { &sender, transaction.digest(), &EpochData::new_test(), - rgp, + gas_price, + gas_budget, None, + protocol_config.move_native_context(), ) .fresh_id(); @@ -1718,12 +1724,11 @@ async fn test_publish_module_no_dependencies_ok() { let authority = init_state_with_objects(vec![]).await; let rgp = authority.reference_gas_price_for_testing().unwrap(); let gas_payment_object_id = ObjectID::random(); + + let epoch_store = authority.epoch_store_for_testing(); + let protocol_config = epoch_store.protocol_config(); // Use the max budget to avoid running out of gas. - let gas_balance = { - let epoch_store = authority.epoch_store_for_testing(); - let protocol_config = epoch_store.protocol_config(); - protocol_config.max_tx_gas() - }; + let gas_balance = protocol_config.max_tx_gas(); let gas_payment_object = Object::with_id_owner_gas_for_testing(gas_payment_object_id, sender, gas_balance); let gas_payment_object_ref = gas_payment_object.compute_object_reference(); @@ -1736,21 +1741,25 @@ async fn test_publish_module_no_dependencies_ok() { .unwrap(); let module_bytes = vec![module_bytes]; let dependencies = vec![]; // no dependencies + let gas_price = rgp; + let gas_budget = gas_price * TEST_ONLY_GAS_UNIT_FOR_PUBLISH; let data = TransactionData::new_module( sender, gas_payment_object_ref, module_bytes, dependencies, - rgp * TEST_ONLY_GAS_UNIT_FOR_PUBLISH, - rgp, + gas_budget, + gas_price, ); let transaction = to_sender_signed_transaction(data, &sender_key); let _module_object_id = TxContext::new( &sender, transaction.digest(), &EpochData::new_test(), - rgp, + gas_price, + gas_budget, None, + protocol_config.move_native_context(), ) .fresh_id(); let signed_effects = send_and_confirm_transaction(&authority, transaction) diff --git a/crates/sui-framework/docs/sui/tx_context.md b/crates/sui-framework/docs/sui/tx_context.md index 6d0ee6c248f3f..762b40edaf1b1 100644 --- a/crates/sui-framework/docs/sui/tx_context.md +++ b/crates/sui-framework/docs/sui/tx_context.md @@ -6,15 +6,25 @@ title: Module `sui::tx_context` - [Struct `TxContext`](#sui_tx_context_TxContext) - [Function `sender`](#sui_tx_context_sender) +- [Function `native_sender`](#sui_tx_context_native_sender) - [Function `digest`](#sui_tx_context_digest) - [Function `epoch`](#sui_tx_context_epoch) +- [Function `native_epoch`](#sui_tx_context_native_epoch) - [Function `epoch_timestamp_ms`](#sui_tx_context_epoch_timestamp_ms) +- [Function `native_epoch_timestamp_ms`](#sui_tx_context_native_epoch_timestamp_ms) +- [Function `sponsor`](#sui_tx_context_sponsor) +- [Function `native_sponsor`](#sui_tx_context_native_sponsor) - [Function `fresh_object_address`](#sui_tx_context_fresh_object_address) +- [Function `fresh_id`](#sui_tx_context_fresh_id) - [Function `ids_created`](#sui_tx_context_ids_created) -- [Function `derive_id`](#sui_tx_context_derive_id) +- [Function `native_ids_created`](#sui_tx_context_native_ids_created) +- [Function `native_gas_price`](#sui_tx_context_native_gas_price) +- [Function `native_gas_budget`](#sui_tx_context_native_gas_budget) -
+
use std::option;
+use std::vector;
+
@@ -81,7 +91,7 @@ Return the address of the user that signed the current transaction -
public fun sender(self: &sui::tx_context::TxContext): address
+
public fun sender(_self: &sui::tx_context::TxContext): address
 
@@ -90,13 +100,35 @@ transaction Implementation -
public fun sender(self: &TxContext): address {
-    self.sender
+
public fun sender(_self: &TxContext): address {
+    native_sender()
 }
 
+ + + + +## Function `native_sender` + + + +
fun native_sender(): address
+
+ + + +
+Implementation + + +
native fun native_sender(): address;
+
+ + +
@@ -132,7 +164,7 @@ Please do not use as a source of randomness. Return the current epoch -
public fun epoch(self: &sui::tx_context::TxContext): u64
+
public fun epoch(_self: &sui::tx_context::TxContext): u64
 
@@ -141,13 +173,35 @@ Return the current epoch Implementation -
public fun epoch(self: &TxContext): u64 {
-    self.epoch
+
public fun epoch(_self: &TxContext): u64 {
+    native_epoch()
 }
 
+ + + + +## Function `native_epoch` + + + +
fun native_epoch(): u64
+
+ + + +
+Implementation + + +
native fun native_epoch(): u64;
+
+ + +
@@ -157,7 +211,54 @@ Return the current epoch Return the epoch start time as a unix timestamp in milliseconds. -
public fun epoch_timestamp_ms(self: &sui::tx_context::TxContext): u64
+
public fun epoch_timestamp_ms(_self: &sui::tx_context::TxContext): u64
+
+ + + +
+Implementation + + +
public fun epoch_timestamp_ms(_self: &TxContext): u64 {
+    native_epoch_timestamp_ms()
+}
+
+ + + +
+ + + +## Function `native_epoch_timestamp_ms` + + + +
fun native_epoch_timestamp_ms(): u64
+
+ + + +
+Implementation + + +
native fun native_epoch_timestamp_ms(): u64;
+
+ + + +
+ + + +## Function `sponsor` + +Return the adress of the transaction sponsor or None if there was no sponsor. + + +
public fun sponsor(_self: &sui::tx_context::TxContext): std::option::Option<address>
 
@@ -166,13 +267,35 @@ Return the epoch start time as a unix timestamp in milliseconds. Implementation -
public fun epoch_timestamp_ms(self: &TxContext): u64 {
-    self.epoch_timestamp_ms
+
public fun sponsor(_self: &TxContext): Option<address> {
+    native_sponsor()
 }
 
+ + + + +## Function `native_sponsor` + + + +
fun native_sponsor(): std::option::Option<address>
+
+ + + +
+Implementation + + +
native fun native_sponsor(): Option<address>;
+
+ + +
@@ -184,7 +307,7 @@ occur as the address for a user. In other words, the generated address is a globally unique object ID. -
public fun fresh_object_address(ctx: &mut sui::tx_context::TxContext): address
+
public fun fresh_object_address(_ctx: &mut sui::tx_context::TxContext): address
 
@@ -193,16 +316,35 @@ In other words, the generated address is a globally unique object ID. Implementation -
public fun fresh_object_address(ctx: &mut TxContext): address {
-    let ids_created = ctx.ids_created;
-    let id = derive_id(*&ctx.tx_hash, ids_created);
-    ctx.ids_created = ids_created + 1;
-    id
+
public fun fresh_object_address(_ctx: &mut TxContext): address {
+    fresh_id()
 }
 
+ + + + +## Function `fresh_id` + + + +
fun fresh_id(): address
+
+ + + +
+Implementation + + +
native fun fresh_id(): address;
+
+ + +
@@ -213,7 +355,7 @@ Return the number of id's created by the current transaction. Hidden for now, but may expose later -
fun ids_created(self: &sui::tx_context::TxContext): u64
+
fun ids_created(_self: &sui::tx_context::TxContext): u64
 
@@ -222,8 +364,8 @@ Hidden for now, but may expose later Implementation -
fun ids_created(self: &TxContext): u64 {
-    self.ids_created
+
fun ids_created(_self: &TxContext): u64 {
+    native_ids_created()
 }
 
@@ -231,14 +373,57 @@ Hidden for now, but may expose later - + + +## Function `native_ids_created` + + + +
fun native_ids_created(): u64
+
+ + + +
+Implementation + + +
native fun native_ids_created(): u64;
+
+ + + +
+ + + +## Function `native_gas_price` + + + +
fun native_gas_price(): u64
+
+ + + +
+Implementation + + +
native fun native_gas_price(): u64;
+
+ + + +
+ + -## Function `derive_id` +## Function `native_gas_budget` -Native function for deriving an ID via hash(tx_hash || ids_created) -
fun derive_id(tx_hash: vector<u8>, ids_created: u64): address
+
fun native_gas_budget(): u64
 
@@ -247,7 +432,7 @@ Native function for deriving an ID via hash(tx_hash || ids_created) Implementation -
native fun derive_id(tx_hash: vector<u8>, ids_created: u64): address;
+
native fun native_gas_budget(): u64;
 
diff --git a/crates/sui-framework/packages/sui-framework/sources/tx_context.move b/crates/sui-framework/packages/sui-framework/sources/tx_context.move index 1fdef9ff83a81..ed63c4ac3b616 100644 --- a/crates/sui-framework/packages/sui-framework/sources/tx_context.move +++ b/crates/sui-framework/packages/sui-framework/sources/tx_context.move @@ -15,6 +15,7 @@ const EBadTxHashLength: u64 = 0; /// Attempt to get the most recent created object ID when none has been created. const ENoIDsCreated: u64 = 1; +#[allow(unused_field)] /// Information about the transaction currently being executed. /// This cannot be constructed by a transaction--it is a privileged object created by /// the VM and passed in to the entrypoint of the transaction as `&mut TxContext`. @@ -34,9 +35,10 @@ public struct TxContext has drop { /// Return the address of the user that signed the current /// transaction -public fun sender(self: &TxContext): address { - self.sender +public fun sender(_self: &TxContext): address { + native_sender() } +native fun native_sender(): address; /// Return the transaction digest (hash of transaction inputs). /// Please do not use as a source of randomness. @@ -45,34 +47,46 @@ public fun digest(self: &TxContext): &vector { } /// Return the current epoch -public fun epoch(self: &TxContext): u64 { - self.epoch +public fun epoch(_self: &TxContext): u64 { + native_epoch() } +native fun native_epoch(): u64; /// Return the epoch start time as a unix timestamp in milliseconds. -public fun epoch_timestamp_ms(self: &TxContext): u64 { - self.epoch_timestamp_ms +public fun epoch_timestamp_ms(_self: &TxContext): u64 { + native_epoch_timestamp_ms() } +native fun native_epoch_timestamp_ms(): u64; + +/// Return the adress of the transaction sponsor or `None` if there was no sponsor. +public fun sponsor(_self: &TxContext): Option
{ + native_sponsor() +} +native fun native_sponsor(): Option
; /// Create an `address` that has not been used. As it is an object address, it will never /// occur as the address for a user. /// In other words, the generated address is a globally unique object ID. -public fun fresh_object_address(ctx: &mut TxContext): address { - let ids_created = ctx.ids_created; - let id = derive_id(*&ctx.tx_hash, ids_created); - ctx.ids_created = ids_created + 1; - id +public fun fresh_object_address(_ctx: &mut TxContext): address { + fresh_id() } +native fun fresh_id(): address; #[allow(unused_function)] /// Return the number of id's created by the current transaction. /// Hidden for now, but may expose later -fun ids_created(self: &TxContext): u64 { - self.ids_created +fun ids_created(_self: &TxContext): u64 { + native_ids_created() } +native fun native_ids_created(): u64; -/// Native function for deriving an ID via hash(tx_hash || ids_created) -native fun derive_id(tx_hash: vector, ids_created: u64): address; +#[allow(unused_function)] +// native function to retrieve gas price, currently not exposed +native fun native_gas_price(): u64; + +#[allow(unused_function)] +// native function to retrieve gas budget, currently not exposed +native fun native_gas_budget(): u64; // ==== test-only functions ==== @@ -86,7 +100,15 @@ public fun new( ids_created: u64, ): TxContext { assert!(tx_hash.length() == TX_HASH_LENGTH, EBadTxHashLength); - TxContext { sender, tx_hash, epoch, epoch_timestamp_ms, ids_created } + replace(sender, tx_hash, epoch, epoch_timestamp_ms, ids_created); + // return an empty TxContext given all the info is held on the native side (call above) + TxContext { + sender: @0x0, + tx_hash, + epoch: 0, + epoch_timestamp_ms: 0, + ids_created: 0, + } } #[test_only] @@ -125,17 +147,39 @@ public fun get_ids_created(self: &TxContext): u64 { #[test_only] /// Return the most recent created object ID. public fun last_created_object_id(self: &TxContext): address { - let ids_created = self.ids_created; + let ids_created = self.ids_created(); assert!(ids_created > 0, ENoIDsCreated); - derive_id(*&self.tx_hash, ids_created - 1) + derive_id(*self.digest(), ids_created - 1) } +#[test_only] +/// Native function for deriving an ID via hash(tx_hash || ids_created) +native fun derive_id(tx_hash: vector, ids_created: u64): address; #[test_only] public fun increment_epoch_number(self: &mut TxContext) { - self.epoch = self.epoch + 1 + let sender = self.sender(); + let tx_hash = *self.digest(); + let epoch = self.epoch() + 1; + let epoch_timestamp_ms = self.epoch_timestamp_ms(); + let ids_created = self.ids_created(); + replace(sender, tx_hash, epoch, epoch_timestamp_ms, ids_created); } #[test_only] public fun increment_epoch_timestamp(self: &mut TxContext, delta_ms: u64) { - self.epoch_timestamp_ms = self.epoch_timestamp_ms + delta_ms + let sender = self.sender(); + let tx_hash = *self.digest(); + let epoch = self.epoch(); + let epoch_timestamp_ms = self.epoch_timestamp_ms() + delta_ms; + let ids_created = self.ids_created(); + replace(sender, tx_hash, epoch, epoch_timestamp_ms, ids_created); } + +#[test_only] +native fun replace( + sender: address, + tx_hash: vector, + epoch: u64, + epoch_timestamp_ms: u64, + ids_created: u64, +); diff --git a/crates/sui-framework/packages_compiled/sui-framework b/crates/sui-framework/packages_compiled/sui-framework index 2ff5694239ff8..a708fc27d723b 100644 Binary files a/crates/sui-framework/packages_compiled/sui-framework and b/crates/sui-framework/packages_compiled/sui-framework differ diff --git a/crates/sui-framework/published_api.txt b/crates/sui-framework/published_api.txt index 383546c067f34..ce999d5d2b68d 100644 --- a/crates/sui-framework/published_api.txt +++ b/crates/sui-framework/published_api.txt @@ -1126,22 +1126,46 @@ TxContext sender public fun 0x2::tx_context +native_sender + fun + 0x2::tx_context digest public fun 0x2::tx_context epoch public fun 0x2::tx_context +native_epoch + fun + 0x2::tx_context epoch_timestamp_ms public fun 0x2::tx_context +native_epoch_timestamp_ms + fun + 0x2::tx_context +sponsor + public fun + 0x2::tx_context +native_sponsor + fun + 0x2::tx_context fresh_object_address public fun 0x2::tx_context +fresh_id + fun + 0x2::tx_context ids_created fun 0x2::tx_context -derive_id +native_ids_created + fun + 0x2::tx_context +native_gas_price + fun + 0x2::tx_context +native_gas_budget fun 0x2::tx_context ID diff --git a/crates/sui-move/src/unit_test.rs b/crates/sui-move/src/unit_test.rs index 6d9afd93b35e5..c8a9bcf93a8b8 100644 --- a/crates/sui-move/src/unit_test.rs +++ b/crates/sui-move/src/unit_test.rs @@ -10,13 +10,16 @@ use move_package::BuildConfig; use move_unit_test::{extensions::set_extension_hook, UnitTestingConfig}; use move_vm_runtime::native_extensions::NativeContextExtensions; use once_cell::sync::Lazy; -use std::{cell::RefCell, collections::BTreeMap, path::Path, sync::Arc}; +use std::{cell::RefCell, collections::BTreeMap, path::Path, rc::Rc, sync::Arc}; use sui_move_build::decorate_warnings; -use sui_move_natives::test_scenario::InMemoryTestStore; use sui_move_natives::{object_runtime::ObjectRuntime, NativesCostTable}; +use sui_move_natives::{test_scenario::InMemoryTestStore, transaction_context::TransactionContext}; use sui_protocol_config::ProtocolConfig; use sui_types::{ - gas_model::tables::initial_cost_schedule_for_unit_tests, in_memory_storage::InMemoryStorage, + base_types::{SuiAddress, TxContext}, + digests::TransactionDigest, + gas_model::tables::initial_cost_schedule_for_unit_tests, + in_memory_storage::InMemoryStorage, metrics::LimitsMetrics, }; @@ -113,6 +116,7 @@ fn new_testing_object_and_natives_cost_runtime(ext: &mut NativeContextExtensions let registry = prometheus::Registry::new(); let metrics = Arc::new(LimitsMetrics::new(®istry)); let store = Lazy::force(&TEST_STORE); + let protocol_config = ProtocolConfig::get_for_max_version_UNSAFE(); ext.add(ObjectRuntime::new( store, @@ -122,9 +126,19 @@ fn new_testing_object_and_natives_cost_runtime(ext: &mut NativeContextExtensions metrics, 0, // epoch id )); - ext.add(NativesCostTable::from_protocol_config( - &ProtocolConfig::get_for_max_version_UNSAFE(), - )); - + ext.add(NativesCostTable::from_protocol_config(&protocol_config)); + let tx_context = TxContext::new_from_components( + Box::leak(Box::new(SuiAddress::ZERO)), + Box::leak(Box::new(TransactionDigest::default())), + &0, + 0, + 0, + 0, + None, + protocol_config.move_native_context(), + ); + ext.add(TransactionContext::new_for_testing(Rc::new(RefCell::new( + tx_context, + )))); ext.add(store); } diff --git a/crates/sui-open-rpc/spec/openrpc.json b/crates/sui-open-rpc/spec/openrpc.json index a8d128dc6de7f..0f4d42d1e2ed0 100644 --- a/crates/sui-open-rpc/spec/openrpc.json +++ b/crates/sui-open-rpc/spec/openrpc.json @@ -1334,6 +1334,7 @@ "loaded_child_object_format_type": false, "loaded_child_objects_fixed": true, "missing_type_is_compatibility_error": true, + "move_native_context": false, "mysticeti_fastpath": false, "mysticeti_leader_scoring_and_schedule": false, "mysticeti_use_committed_subdag_digest": false, @@ -1944,6 +1945,15 @@ "tx_context_derive_id_cost_base": { "u64": "52" }, + "tx_context_epoch_cost_base": null, + "tx_context_epoch_timestamp_ms_cost_base": null, + "tx_context_fresh_id_cost_base": null, + "tx_context_gas_budget_cost_base": null, + "tx_context_gas_price_cost_base": null, + "tx_context_ids_created_cost_base": null, + "tx_context_replace_cost_base": null, + "tx_context_sender_cost_base": null, + "tx_context_sponsor_cost_base": null, "type_name_get_base_cost": null, "type_name_get_per_byte_cost": null, "types_is_one_time_witness_cost_base": { diff --git a/crates/sui-protocol-config/src/lib.rs b/crates/sui-protocol-config/src/lib.rs index bf889c41e3fd2..94e23db19502c 100644 --- a/crates/sui-protocol-config/src/lib.rs +++ b/crates/sui-protocol-config/src/lib.rs @@ -219,6 +219,8 @@ const MAX_PROTOCOL_VERSION: u64 = 76; // Enable the new commit rule for devnet. // Version 75: Enable passkey auth in testnet. // Version 76: Deprecate Deepbook V2 order placement and deposit. +// Make `TxContext` Move API native + #[derive(Copy, Clone, Debug, Hash, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)] pub struct ProtocolVersion(u64); @@ -623,6 +625,10 @@ struct FeatureFlags { // If true, enable zstd compression for consensus tonic network. #[serde(skip_serializing_if = "is_false")] consensus_zstd_compression: bool, + + // If true, enable `TxContext` Move API to go native. + #[serde(skip_serializing_if = "is_false")] + move_native_context: bool, } fn is_false(b: &bool) -> bool { @@ -1085,6 +1091,15 @@ pub struct ProtocolConfig { // TxContext // Cost params for the Move native function `transfer_impl(obj: T, recipient: address)` tx_context_derive_id_cost_base: Option, + tx_context_fresh_id_cost_base: Option, + tx_context_sender_cost_base: Option, + tx_context_epoch_cost_base: Option, + tx_context_epoch_timestamp_ms_cost_base: Option, + tx_context_sponsor_cost_base: Option, + tx_context_gas_price_cost_base: Option, + tx_context_gas_budget_cost_base: Option, + tx_context_ids_created_cost_base: Option, + tx_context_replace_cost_base: Option, // Types // Cost params for the Move native function `is_one_time_witness(_: &T): bool` @@ -1799,6 +1814,7 @@ impl ProtocolConfig { pub fn consensus_zstd_compression(&self) -> bool { self.feature_flags.consensus_zstd_compression } + pub fn enable_nitro_attestation(&self) -> bool { self.feature_flags.enable_nitro_attestation } @@ -1808,6 +1824,10 @@ impl ProtocolConfig { // parameters. 0 } + + pub fn move_native_context(&self) -> bool { + self.feature_flags.move_native_context + } } #[cfg(not(msim))] @@ -2100,6 +2120,15 @@ impl ProtocolConfig { // `tx_context` module // Cost params for the Move native function `transfer_impl(obj: T, recipient: address)` tx_context_derive_id_cost_base: Some(52), + tx_context_fresh_id_cost_base: None, + tx_context_sender_cost_base: None, + tx_context_epoch_cost_base: None, + tx_context_epoch_timestamp_ms_cost_base: None, + tx_context_sponsor_cost_base: None, + tx_context_gas_price_cost_base: None, + tx_context_gas_budget_cost_base: None, + tx_context_ids_created_cost_base: None, + tx_context_replace_cost_base: None, // `types` module // Cost params for the Move native function `is_one_time_witness(_: &T): bool` @@ -3254,7 +3283,19 @@ impl ProtocolConfig { cfg.feature_flags.passkey_auth = true; } } - 76 => {} + 76 => { + cfg.feature_flags.move_native_context = true; + + cfg.tx_context_fresh_id_cost_base = Some(30); + cfg.tx_context_sender_cost_base = Some(30); + cfg.tx_context_epoch_cost_base = Some(30); + cfg.tx_context_epoch_timestamp_ms_cost_base = Some(30); + cfg.tx_context_sponsor_cost_base = Some(30); + cfg.tx_context_gas_price_cost_base = Some(30); + cfg.tx_context_gas_budget_cost_base = Some(30); + cfg.tx_context_ids_created_cost_base = Some(30); + cfg.tx_context_replace_cost_base = Some(30); + } // Use this template when making changes: // // // modify an existing constant. diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_76.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_76.snap index 655be0bd4431d..7218258d9e4e7 100644 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_76.snap +++ b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_76.snap @@ -71,6 +71,7 @@ feature_flags: convert_type_argument_error: true variant_nodes: true consensus_zstd_compression: true + move_native_context: true max_tx_size_bytes: 131072 max_input_objects: 2048 max_size_written_objects: 5000000 @@ -194,6 +195,15 @@ transfer_freeze_object_cost_base: 52 transfer_share_object_cost_base: 52 transfer_receive_object_cost_base: 52 tx_context_derive_id_cost_base: 52 +tx_context_fresh_id_cost_base: 30 +tx_context_sender_cost_base: 30 +tx_context_epoch_cost_base: 30 +tx_context_epoch_timestamp_ms_cost_base: 30 +tx_context_sponsor_cost_base: 30 +tx_context_gas_price_cost_base: 30 +tx_context_gas_budget_cost_base: 30 +tx_context_ids_created_cost_base: 30 +tx_context_replace_cost_base: 30 types_is_one_time_witness_cost_base: 52 types_is_one_time_witness_type_tag_cost_per_byte: 2 types_is_one_time_witness_type_cost_per_byte: 2 diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_76.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_76.snap index 2725b0958ee18..7f2a00d8ee428 100644 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_76.snap +++ b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_76.snap @@ -1,7 +1,6 @@ --- source: crates/sui-protocol-config/src/lib.rs expression: "ProtocolConfig::get_for_version(cur, *chain_id)" -snapshot_kind: text --- version: 76 feature_flags: @@ -74,6 +73,7 @@ feature_flags: convert_type_argument_error: true variant_nodes: true consensus_zstd_compression: true + move_native_context: true max_tx_size_bytes: 131072 max_input_objects: 2048 max_size_written_objects: 5000000 @@ -197,6 +197,15 @@ transfer_freeze_object_cost_base: 52 transfer_share_object_cost_base: 52 transfer_receive_object_cost_base: 52 tx_context_derive_id_cost_base: 52 +tx_context_fresh_id_cost_base: 30 +tx_context_sender_cost_base: 30 +tx_context_epoch_cost_base: 30 +tx_context_epoch_timestamp_ms_cost_base: 30 +tx_context_sponsor_cost_base: 30 +tx_context_gas_price_cost_base: 30 +tx_context_gas_budget_cost_base: 30 +tx_context_ids_created_cost_base: 30 +tx_context_replace_cost_base: 30 types_is_one_time_witness_cost_base: 52 types_is_one_time_witness_type_tag_cost_per_byte: 2 types_is_one_time_witness_type_cost_per_byte: 2 diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_76.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_76.snap index 8cea8608b8131..ef1bfef3d12b1 100644 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_76.snap +++ b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_76.snap @@ -80,6 +80,7 @@ feature_flags: convert_type_argument_error: true variant_nodes: true consensus_zstd_compression: true + move_native_context: true max_tx_size_bytes: 131072 max_input_objects: 2048 max_size_written_objects: 5000000 @@ -203,6 +204,15 @@ transfer_freeze_object_cost_base: 52 transfer_share_object_cost_base: 52 transfer_receive_object_cost_base: 52 tx_context_derive_id_cost_base: 52 +tx_context_fresh_id_cost_base: 30 +tx_context_sender_cost_base: 30 +tx_context_epoch_cost_base: 30 +tx_context_epoch_timestamp_ms_cost_base: 30 +tx_context_sponsor_cost_base: 30 +tx_context_gas_price_cost_base: 30 +tx_context_gas_budget_cost_base: 30 +tx_context_ids_created_cost_base: 30 +tx_context_replace_cost_base: 30 types_is_one_time_witness_cost_base: 52 types_is_one_time_witness_type_tag_cost_per_byte: 2 types_is_one_time_witness_type_cost_per_byte: 2 diff --git a/crates/sui-swarm-config/tests/snapshots/snapshot_tests__populated_genesis_snapshot_matches-2.snap b/crates/sui-swarm-config/tests/snapshots/snapshot_tests__populated_genesis_snapshot_matches-2.snap index 2e494f01cdb9a..a250a59954a83 100644 --- a/crates/sui-swarm-config/tests/snapshots/snapshot_tests__populated_genesis_snapshot_matches-2.snap +++ b/crates/sui-swarm-config/tests/snapshots/snapshot_tests__populated_genesis_snapshot_matches-2.snap @@ -240,13 +240,13 @@ validators: next_epoch_worker_address: ~ extra_fields: id: - id: "0x63c951f50d71f7fa58e90fee1820ed27a15f47602cbc0640d58c5675d9cc93cf" + id: "0xfbc66761ecf533bf49976257c3a7a73df702bcb74bca68cff29ed3654aa253ee" size: 0 voting_power: 10000 - operation_cap_id: "0x99a1cb0cfa940302fd08144dec6460b0225cf8ba438081ac32fcd00389092c4d" + operation_cap_id: "0x4ea8c7e54ff773b09caa5f5ee9d299750c2c7d9415edcf0a76ab7cab5e1687ae" gas_price: 1000 staking_pool: - id: "0x430f34db68b99ed1c4a02d009f6423b35dd2ce2bb5015c02df4a3ab8fd671a6f" + id: "0x509cba75e0bd7dc2bd7183dbf731d4f704c7f6d4b07323f723e31ad1231ea4ac" activation_epoch: 0 deactivation_epoch: ~ sui_balance: 20000000000000000 @@ -254,14 +254,14 @@ validators: value: 0 pool_token_balance: 20000000000000000 exchange_rates: - id: "0x68047818ec2262573e5a7241853b364559e84d2b7a93973853c3f52c46e6103d" + id: "0xbd714ff50b7c26029ffede3a3d319035e51f9a068b912d0a7ed1f3adcd1792bd" size: 1 pending_stake: 0 pending_total_sui_withdraw: 0 pending_pool_token_withdraw: 0 extra_fields: id: - id: "0x1203f7e9fb0a1503d530013ab3e1df797ed34e6e72d457caea9a250ed64e9b12" + id: "0xfa7b5626df86afe793d2f3594776b7dcef30a299fafa9d691cdbe5a281a6bc02" size: 0 commission_rate: 200 next_epoch_stake: 20000000000000000 @@ -269,27 +269,27 @@ validators: next_epoch_commission_rate: 200 extra_fields: id: - id: "0xa208610c482bbf00d12ecb7ed113e3ec6cead7d292b5ddba487c67ae343b7420" + id: "0x2ec475193b06c3cf9463998dc5d314ae2e5ab422e389bda6315afb4633cc5464" size: 0 pending_active_validators: contents: - id: "0x4ce4f20ae616257e491b61ed95f256062baf815b92181cd2028436bc9ffaedf6" + id: "0x6a533ee971df19eb82f59e2f6ed6752a0e694c7e49f398193056b30c2dede4da" size: 0 pending_removals: [] staking_pool_mappings: - id: "0xc226eef39a3c111c373bb4dd3871640d8ce2f9adca35da36d1363a707eda918b" + id: "0x4bb65144da3bad311a1c6731149d6d44275f8fbaa1f55b44cad676be4f3c7b45" size: 1 inactive_validators: - id: "0xb7cf484096138508283d7e305874cd6e73eccca33d9ac2a8abbe33f8c854c11c" + id: "0x10f7df5eab007a95baed107d2d9ce9b01817f2110a95a87ea81fbaee6a781a9f" size: 0 validator_candidates: - id: "0x05d9257a640e27a15f19b4e8aef7f892c2a66924e30c4af57153e3240cee33de" + id: "0xad0024d42975862931f1ceed3220766632924d017136122a294a8ff552c6eb6e" size: 0 at_risk_validators: contents: [] extra_fields: id: - id: "0xf91d9dc9849f07f3f38732aa9c40a9b0bb83a68a9b6324f8d59e66bc2dec76e0" + id: "0x716df94174cc205f3b9fdbd5f756e3457a95f7c83f0e7e577aeefbce5c5e9661" size: 0 storage_fund: total_object_storage_rebates: @@ -306,7 +306,7 @@ parameters: validator_low_stake_grace_period: 7 extra_fields: id: - id: "0xb86c133b102926c433bc95f2cb054c956e0a80567a3b39b9a9163520e725b1a8" + id: "0xe63c4f6f34480af9081c2138b8578462aa46237fd2766e4a10ced32d8f35de11" size: 0 reference_gas_price: 1000 validator_report_records: @@ -320,7 +320,7 @@ stake_subsidy: stake_subsidy_decrease_rate: 1000 extra_fields: id: - id: "0x311ae5223405603a7741ce24339390240c2a97c70d785f5116e4316520920156" + id: "0xb44969eac6b234d4e436fc607aa22d7bdc4276d9fe22c20e5d4cbe8884d76cca" size: 0 safe_mode: false safe_mode_storage_rewards: @@ -332,5 +332,5 @@ safe_mode_non_refundable_storage_fee: 0 epoch_start_timestamp_ms: 10 extra_fields: id: - id: "0xfe0661290995d4a00c6d2775d900c03b5dc67ba1294f823b2c8d6f29b0a677f2" + id: "0x7d45dd0ddecf7817735c7f3c57d6f9ad01f91e9ec710e35ff04195267017c49a" size: 0 diff --git a/crates/sui-types/src/base_types.rs b/crates/sui-types/src/base_types.rs index f5efa88d1eba8..309dd017f8df0 100644 --- a/crates/sui-types/src/base_types.rs +++ b/crates/sui-types/src/base_types.rs @@ -1019,8 +1019,12 @@ pub struct TxContext { ids_created: u64, // gas price passed to transaction as input gas_price: u64, + // gas budget passed to transaction as input + gas_budget: u64, // address of the sponsor if any sponsor: Option, + // flag to indicate whether the Move implementaion is native or not + is_native: bool, } #[derive(PartialEq, Eq, Clone, Copy)] @@ -1039,7 +1043,9 @@ impl TxContext { digest: &TransactionDigest, epoch_data: &EpochData, gas_price: u64, + gas_budget: u64, sponsor: Option, + is_native: bool, ) -> Self { Self::new_from_components( sender, @@ -1047,7 +1053,9 @@ impl TxContext { &epoch_data.epoch_id(), epoch_data.epoch_start_timestamp(), gas_price, + gas_budget, sponsor, + is_native, ) } @@ -1057,7 +1065,9 @@ impl TxContext { epoch_id: &EpochId, epoch_timestamp_ms: u64, gas_price: u64, + gas_budget: u64, sponsor: Option, + is_native: bool, ) -> Self { Self { sender: AccountAddress::new(sender.0), @@ -1066,7 +1076,9 @@ impl TxContext { epoch_timestamp_ms, ids_created: 0, gas_price, + gas_budget, sponsor: sponsor.map(|s| s.into()), + is_native, } } @@ -1099,12 +1111,12 @@ impl TxContext { self.epoch } - /// Derive a globally unique object ID by hashing self.digest | self.ids_created - pub fn fresh_id(&mut self) -> ObjectID { - let id = ObjectID::derive_id(self.digest(), self.ids_created); + pub fn sender(&self) -> SuiAddress { + SuiAddress::from(ObjectID(self.sender)) + } - self.ids_created += 1; - id + pub fn epoch_timestamp_ms(&self) -> u64 { + self.epoch_timestamp_ms } /// Return the transaction digest, to include in new objects @@ -1112,12 +1124,47 @@ impl TxContext { TransactionDigest::new(self.digest.clone().try_into().unwrap()) } - pub fn sender(&self) -> SuiAddress { - SuiAddress::from(ObjectID(self.sender)) + pub fn sponsor(&self) -> Option { + self.sponsor.map(SuiAddress::from) + } + + pub fn gas_price(&self) -> u64 { + self.gas_price + } + + pub fn gas_budget(&self) -> u64 { + self.gas_budget + } + + pub fn ids_created(&self) -> u64 { + self.ids_created + } + + /// Derive a globally unique object ID by hashing self.digest | self.ids_created + pub fn fresh_id(&mut self) -> ObjectID { + let id = ObjectID::derive_id(self.digest(), self.ids_created); + + self.ids_created += 1; + id } pub fn to_bcs_legacy_context(&self) -> Vec { - let move_context: MoveLegacyTxContext = self.into(); + let move_context: MoveLegacyTxContext = if self.is_native { + let tx_context = &TxContext { + sender: AccountAddress::ZERO, + digest: self.digest.clone(), + epoch: 0, + epoch_timestamp_ms: 0, + ids_created: 0, + gas_price: 0, + gas_budget: 0, + sponsor: None, + is_native: true, + }; + tx_context.into() + } else { + self.into() + }; bcs::to_bytes(&move_context).unwrap() } @@ -1130,18 +1177,38 @@ impl TxContext { /// serialize/deserialize and this is the reason why this method /// consumes the other context.. pub fn update_state(&mut self, other: MoveLegacyTxContext) -> Result<(), ExecutionError> { - if self.sender != other.sender - || self.digest != other.digest - || other.ids_created < self.ids_created - { - return Err(ExecutionError::new_with_source( - ExecutionErrorKind::InvariantViolation, - "Immutable fields for TxContext changed", - )); + if !self.is_native { + if self.sender != other.sender + || self.digest != other.digest + || other.ids_created < self.ids_created + { + return Err(ExecutionError::new_with_source( + ExecutionErrorKind::InvariantViolation, + "Immutable fields for TxContext changed", + )); + } + self.ids_created = other.ids_created; } - self.ids_created = other.ids_created; Ok(()) } + + // + // Move test only API + // + pub fn replace( + &mut self, + sender: AccountAddress, + tx_hash: Vec, + epoch: u64, + epoch_timestamp_ms: u64, + ids_created: u64, + ) { + self.sender = sender; + self.digest = tx_hash; + self.epoch = epoch; + self.epoch_timestamp_ms = epoch_timestamp_ms; + self.ids_created = ids_created; + } } // TODO: rename to version diff --git a/sui-execution/latest/sui-adapter/src/adapter.rs b/sui-execution/latest/sui-adapter/src/adapter.rs index 99551458bb1e7..5b78aee4a6621 100644 --- a/sui-execution/latest/sui-adapter/src/adapter.rs +++ b/sui-execution/latest/sui-adapter/src/adapter.rs @@ -6,7 +6,9 @@ pub use checked::*; mod checked { #[cfg(feature = "tracing")] use move_vm_config::runtime::VMProfilerConfig; + use std::cell::RefCell; use std::path::PathBuf; + use std::rc::Rc; use std::{collections::BTreeMap, sync::Arc}; use anyhow::Result; @@ -22,7 +24,7 @@ mod checked { move_vm::MoveVM, native_extensions::NativeContextExtensions, native_functions::NativeFunctionTable, }; - use sui_move_natives::object_runtime; + use sui_move_natives::{object_runtime, transaction_context::TransactionContext}; use sui_types::metrics::BytecodeVerifierMetrics; use sui_verifier::check_for_verifier_timeout; use tracing::instrument; @@ -85,8 +87,9 @@ mod checked { is_metered: bool, protocol_config: &'r ProtocolConfig, metrics: Arc, - current_epoch_id: EpochId, + tx_context: Rc>, ) -> NativeContextExtensions<'r> { + let current_epoch_id: EpochId = tx_context.borrow().epoch(); let mut extensions = NativeContextExtensions::default(); extensions.add(ObjectRuntime::new( child_resolver, @@ -97,6 +100,7 @@ mod checked { current_epoch_id, )); extensions.add(NativesCostTable::from_protocol_config(protocol_config)); + extensions.add(TransactionContext::new(tx_context)); extensions } diff --git a/sui-execution/latest/sui-adapter/src/execution_engine.rs b/sui-execution/latest/sui-adapter/src/execution_engine.rs index 21aa916b65e87..0907916dedc3e 100644 --- a/sui-execution/latest/sui-adapter/src/execution_engine.rs +++ b/sui-execution/latest/sui-adapter/src/execution_engine.rs @@ -10,7 +10,7 @@ mod checked { use move_binary_format::CompiledModule; use move_trace_format::format::MoveTraceBuilder; use move_vm_runtime::move_vm::MoveVM; - use std::{collections::HashSet, sync::Arc}; + use std::{cell::RefCell, collections::HashSet, rc::Rc, sync::Arc}; use sui_types::balance::{ BALANCE_CREATE_REWARDS_FUNCTION_NAME, BALANCE_DESTROY_REBATES_FUNCTION_NAME, BALANCE_MODULE_NAME, @@ -140,14 +140,17 @@ mod checked { protocol_config, ); - let mut tx_ctx = TxContext::new_from_components( + let tx_ctx = TxContext::new_from_components( &transaction_signer, &transaction_digest, epoch_id, epoch_timestamp_ms, gas_price, + gas_data.budget, sponsor, + protocol_config.move_native_context(), ); + let tx_ctx = Rc::new(RefCell::new(tx_ctx)); let is_epoch_change = transaction_kind.is_end_of_epoch_tx(); @@ -156,7 +159,7 @@ mod checked { &mut temporary_store, transaction_kind, &mut gas_charger, - &mut tx_ctx, + tx_ctx, move_vm, protocol_config, metrics, @@ -260,7 +263,7 @@ mod checked { protocol_config: &ProtocolConfig, metrics: Arc, move_vm: &Arc, - tx_context: &mut TxContext, + tx_context: Rc>, input_objects: CheckedInputObjects, pt: ProgrammableTransaction, ) -> Result { @@ -269,11 +272,11 @@ mod checked { store, input_objects, vec![], - tx_context.digest(), + tx_context.borrow().digest(), protocol_config, 0, ); - let mut gas_charger = GasCharger::new_unmetered(tx_context.digest()); + let mut gas_charger = GasCharger::new_unmetered(tx_context.borrow().digest()); programmable_transactions::execution::execute::( protocol_config, metrics, @@ -294,7 +297,7 @@ mod checked { temporary_store: &mut TemporaryStore<'_>, transaction_kind: TransactionKind, gas_charger: &mut GasCharger, - tx_ctx: &mut TxContext, + tx_ctx: Rc>, move_vm: &Arc, protocol_config: &ProtocolConfig, metrics: Arc, @@ -318,7 +321,7 @@ mod checked { let is_genesis_tx = matches!(transaction_kind, TransactionKind::Genesis(_)); let advance_epoch_gas_summary = transaction_kind.get_advance_epoch_tx_gas_summary(); - let digest = tx_ctx.digest(); + let digest = tx_ctx.borrow().digest(); // We must charge object read here during transaction execution, because if this fails // we must still ensure an effect is committed and all objects versions incremented @@ -585,7 +588,7 @@ mod checked { fn execution_loop( temporary_store: &mut TemporaryStore<'_>, transaction_kind: TransactionKind, - tx_ctx: &mut TxContext, + tx_ctx: Rc>, move_vm: &Arc, gas_charger: &mut GasCharger, protocol_config: &ProtocolConfig, @@ -610,7 +613,7 @@ mod checked { Ok((Mode::empty_results(), vec![])) } TransactionKind::Genesis(GenesisTransaction { objects }) => { - if tx_ctx.epoch() != 0 { + if tx_ctx.borrow().epoch() != 0 { panic!("BUG: Genesis Transactions can only be executed in epoch 0"); } @@ -620,7 +623,7 @@ mod checked { let object = ObjectInner { data, owner, - previous_transaction: tx_ctx.digest(), + previous_transaction: tx_ctx.borrow().digest(), storage_rebate: 0, }; temporary_store.create_object(object.into()); @@ -917,7 +920,7 @@ mod checked { builder: ProgrammableTransactionBuilder, change_epoch: ChangeEpoch, temporary_store: &mut TemporaryStore<'_>, - tx_ctx: &mut TxContext, + tx_ctx: Rc>, move_vm: &Arc, gas_charger: &mut GasCharger, protocol_config: &ProtocolConfig, @@ -941,7 +944,7 @@ mod checked { metrics.clone(), move_vm, temporary_store, - tx_ctx, + tx_ctx.clone(), gas_charger, advance_epoch_pt, trace_builder_opt, @@ -971,7 +974,7 @@ mod checked { metrics.clone(), move_vm, temporary_store, - tx_ctx, + tx_ctx.clone(), gas_charger, advance_epoch_safe_mode_pt, trace_builder_opt, @@ -1016,14 +1019,14 @@ mod checked { fn process_system_packages( change_epoch: ChangeEpoch, temporary_store: &mut TemporaryStore<'_>, - tx_ctx: &mut TxContext, + tx_ctx: Rc>, move_vm: &MoveVM, gas_charger: &mut GasCharger, protocol_config: &ProtocolConfig, metrics: Arc, trace_builder_opt: &mut Option, ) { - let digest = tx_ctx.digest(); + let digest = tx_ctx.borrow().digest(); let binary_config = to_binary_config(protocol_config); for (version, modules, dependencies) in change_epoch.system_packages.into_iter() { let deserialized_modules: Vec<_> = modules @@ -1046,7 +1049,7 @@ mod checked { metrics.clone(), move_vm, temporary_store, - tx_ctx, + tx_ctx.clone(), gas_charger, publish_pt, trace_builder_opt, @@ -1087,7 +1090,7 @@ mod checked { fn setup_consensus_commit( consensus_commit_timestamp_ms: CheckpointTimestamp, temporary_store: &mut TemporaryStore<'_>, - tx_ctx: &mut TxContext, + tx_ctx: Rc>, move_vm: &Arc, gas_charger: &mut GasCharger, protocol_config: &ProtocolConfig, @@ -1228,7 +1231,7 @@ mod checked { fn setup_authenticator_state_update( update: AuthenticatorStateUpdate, temporary_store: &mut TemporaryStore<'_>, - tx_ctx: &mut TxContext, + tx_ctx: Rc>, move_vm: &Arc, gas_charger: &mut GasCharger, protocol_config: &ProtocolConfig, @@ -1297,7 +1300,7 @@ mod checked { fn setup_randomness_state_update( update: RandomnessStateUpdate, temporary_store: &mut TemporaryStore<'_>, - tx_ctx: &mut TxContext, + tx_ctx: Rc>, move_vm: &Arc, gas_charger: &mut GasCharger, protocol_config: &ProtocolConfig, diff --git a/sui-execution/latest/sui-adapter/src/programmable_transactions/context.rs b/sui-execution/latest/sui-adapter/src/programmable_transactions/context.rs index 4048df3c2dbc5..784c1eb805c1f 100644 --- a/sui-execution/latest/sui-adapter/src/programmable_transactions/context.rs +++ b/sui-execution/latest/sui-adapter/src/programmable_transactions/context.rs @@ -5,10 +5,11 @@ pub use checked::*; #[sui_macros::with_checked_arithmetic] mod checked { - use std::collections::BTreeSet; use std::{ borrow::Borrow, - collections::{BTreeMap, HashMap}, + cell::RefCell, + collections::{BTreeMap, BTreeSet, HashMap}, + rc::Rc, sync::Arc, }; @@ -80,7 +81,7 @@ mod checked { pub state_view: &'state dyn ExecutionState, /// A shared transaction context, contains transaction digest information and manages the /// creation of new object IDs - pub tx_context: &'a mut TxContext, + pub tx_context: Rc>, /// The gas charger used for metering pub gas_charger: &'a mut GasCharger, /// Additional transfers not from the Move runtime @@ -122,7 +123,7 @@ mod checked { metrics: Arc, vm: &'vm MoveVM, state_view: &'state dyn ExecutionState, - tx_context: &'a mut TxContext, + tx_context: Rc>, gas_charger: &'a mut GasCharger, inputs: Vec, ) -> Result @@ -190,7 +191,7 @@ mod checked { !gas_charger.is_unmetered(), protocol_config, metrics.clone(), - tx_context.epoch(), + tx_context.clone(), ); // Set the profiler if in CLI @@ -199,7 +200,8 @@ mod checked { use move_vm_profiler::GasProfiler; use move_vm_types::gas::GasMeter; - let tx_digest = tx_context.digest(); + let ref_context: &RefCell = tx_context.borrow(); + let tx_digest = ref_context.borrow().digest(); let remaining_gas: u64 = move_vm_types::gas::GasMeter::remaining_gas(gas_charger.move_gas_status()) .into(); @@ -237,7 +239,7 @@ mod checked { /// Create a new ID and update the state pub fn fresh_id(&mut self) -> Result { - let object_id = self.tx_context.fresh_id(); + let object_id = self.tx_context.borrow_mut().fresh_id(); let object_runtime: &mut ObjectRuntime = self.native_extensions.get_mut(); object_runtime .new_id(object_id) @@ -610,7 +612,8 @@ mod checked { state_view, .. } = self; - let tx_digest = tx_context.digest(); + let ref_context: &RefCell = tx_context.borrow(); + let tx_digest = ref_context.borrow().digest(); let gas_id_opt = gas.object_metadata.as_ref().map(|info| info.id()); let mut loaded_runtime_objects = BTreeMap::new(); let mut additional_writes = BTreeMap::new(); @@ -843,7 +846,7 @@ mod checked { Event::new( module_id.address(), module_id.name(), - tx_context.sender(), + ref_context.borrow().sender(), tag, contents, ) diff --git a/sui-execution/latest/sui-adapter/src/programmable_transactions/execution.rs b/sui-execution/latest/sui-adapter/src/programmable_transactions/execution.rs index 6f765602511e3..cbb5cbc546a55 100644 --- a/sui-execution/latest/sui-adapter/src/programmable_transactions/execution.rs +++ b/sui-execution/latest/sui-adapter/src/programmable_transactions/execution.rs @@ -30,11 +30,13 @@ mod checked { }; use move_vm_types::loaded_data::runtime_types::{CachedDatatype, Type}; use serde::{de::DeserializeSeed, Deserialize}; - use std::time::Instant; use std::{ + cell::RefCell, collections::{BTreeMap, BTreeSet}, fmt, + rc::Rc, sync::Arc, + time::Instant, }; use sui_move_natives::object_runtime::ObjectRuntime; use sui_protocol_config::ProtocolConfig; @@ -75,7 +77,7 @@ mod checked { metrics: Arc, vm: &MoveVM, state_view: &mut dyn ExecutionState, - tx_context: &mut TxContext, + tx_context: Rc>, gas_charger: &mut GasCharger, pt: ProgrammableTransaction, trace_builder_opt: &mut Option, @@ -105,7 +107,7 @@ mod checked { metrics: Arc, vm: &MoveVM, state_view: &mut dyn ExecutionState, - tx_context: &mut TxContext, + tx_context: Rc>, gas_charger: &mut GasCharger, pt: ProgrammableTransaction, trace_builder_opt: &mut Option, @@ -552,7 +554,7 @@ mod checked { // do not calculate or substitute id for predefined packages (*modules[0].self_id().address()).into() } else { - let id = context.tx_context.fresh_id(); + let id = context.tx_context.borrow_mut().fresh_id(); substitute_package_id(&mut modules, id)?; id }; @@ -666,7 +668,7 @@ mod checked { substitute_package_id(&mut modules, runtime_id)?; // Upgraded packages share their predecessor's runtime ID but get a new storage ID. - let storage_id = context.tx_context.fresh_id(); + let storage_id = context.tx_context.borrow_mut().fresh_id(); let dependencies = fetch_packages(context, &dep_ids)?; let package = context.upgrade_package( @@ -843,7 +845,7 @@ mod checked { match tx_context_kind { TxContextKind::None => (), TxContextKind::Mutable | TxContextKind::Immutable => { - serialized_arguments.push(context.tx_context.to_bcs_legacy_context()); + serialized_arguments.push(context.tx_context.borrow().to_bcs_legacy_context()); } } // script visibility checked manually for entry points @@ -873,7 +875,7 @@ mod checked { "Unable to deserialize TxContext bytes. {e}" )) })?; - context.tx_context.update_state(updated_ctx)?; + context.tx_context.borrow_mut().update_state(updated_ctx)?; } Ok(result) } diff --git a/sui-execution/latest/sui-move-natives/src/lib.rs b/sui-execution/latest/sui-move-natives/src/lib.rs index f89dfb8ecb709..dac3914d38974 100644 --- a/sui-execution/latest/sui-move-natives/src/lib.rs +++ b/sui-execution/latest/sui-move-natives/src/lib.rs @@ -31,7 +31,12 @@ use self::{ transfer::{ TransferFreezeObjectCostParams, TransferInternalCostParams, TransferShareObjectCostParams, }, - tx_context::TxContextDeriveIdCostParams, + tx_context::{ + TxContextDeriveIdCostParams, TxContextEpochCostParams, TxContextEpochTimestampMsCostParams, + TxContextFreshIdCostParams, TxContextGasBudgetCostParams, TxContextGasPriceCostParams, + TxContextIdsCreatedCostParams, TxContextReplaceCostParams, TxContextSenderCostParams, + TxContextSponsorCostParams, + }, types::TypesIsOneTimeWitnessCostParams, validator::ValidatorValidateMetadataBcsCostParams, }; @@ -74,11 +79,14 @@ pub mod object_runtime; mod random; pub mod test_scenario; mod test_utils; +pub mod transaction_context; mod transfer; mod tx_context; mod types; mod validator; +// TODO: remove in later PRs once we define the proper cost of native functions +const DEFAULT_UNUSED_TX_CONTEXT_ENTRY_COST: u64 = 10; #[derive(Tid)] pub struct NativesCostTable { // Address natives @@ -113,6 +121,15 @@ pub struct NativesCostTable { // TxContext pub tx_context_derive_id_cost_params: TxContextDeriveIdCostParams, + pub tx_context_fresh_id_cost_params: TxContextFreshIdCostParams, + pub tx_context_sender_cost_params: TxContextSenderCostParams, + pub tx_context_epoch_cost_params: TxContextEpochCostParams, + pub tx_context_epoch_timestamp_ms_cost_params: TxContextEpochTimestampMsCostParams, + pub tx_context_sponsor_cost_params: TxContextSponsorCostParams, + pub tx_context_gas_price_cost_params: TxContextGasPriceCostParams, + pub tx_context_gas_budget_cost_params: TxContextGasBudgetCostParams, + pub tx_context_ids_created_cost_params: TxContextIdsCreatedCostParams, + pub tx_context_replace_cost_params: TxContextReplaceCostParams, // Type pub type_is_one_time_witness_cost_params: TypesIsOneTimeWitnessCostParams, @@ -338,11 +355,77 @@ impl NativesCostTable { .transfer_share_object_cost_base() .into(), }, + // tx_context tx_context_derive_id_cost_params: TxContextDeriveIdCostParams { tx_context_derive_id_cost_base: protocol_config .tx_context_derive_id_cost_base() .into(), }, + tx_context_fresh_id_cost_params: TxContextFreshIdCostParams { + tx_context_fresh_id_cost_base: if protocol_config.move_native_context() { + protocol_config.tx_context_fresh_id_cost_base().into() + } else { + DEFAULT_UNUSED_TX_CONTEXT_ENTRY_COST.into() + }, + }, + tx_context_sender_cost_params: TxContextSenderCostParams { + tx_context_sender_cost_base: if protocol_config.move_native_context() { + protocol_config.tx_context_sender_cost_base().into() + } else { + DEFAULT_UNUSED_TX_CONTEXT_ENTRY_COST.into() + }, + }, + tx_context_epoch_cost_params: TxContextEpochCostParams { + tx_context_epoch_cost_base: if protocol_config.move_native_context() { + protocol_config.tx_context_epoch_cost_base().into() + } else { + DEFAULT_UNUSED_TX_CONTEXT_ENTRY_COST.into() + }, + }, + tx_context_epoch_timestamp_ms_cost_params: TxContextEpochTimestampMsCostParams { + tx_context_epoch_timestamp_ms_cost_base: if protocol_config.move_native_context() { + protocol_config + .tx_context_epoch_timestamp_ms_cost_base() + .into() + } else { + DEFAULT_UNUSED_TX_CONTEXT_ENTRY_COST.into() + }, + }, + tx_context_sponsor_cost_params: TxContextSponsorCostParams { + tx_context_sponsor_cost_base: if protocol_config.move_native_context() { + protocol_config.tx_context_sponsor_cost_base().into() + } else { + DEFAULT_UNUSED_TX_CONTEXT_ENTRY_COST.into() + }, + }, + tx_context_gas_price_cost_params: TxContextGasPriceCostParams { + tx_context_gas_price_cost_base: if protocol_config.move_native_context() { + protocol_config.tx_context_gas_price_cost_base().into() + } else { + DEFAULT_UNUSED_TX_CONTEXT_ENTRY_COST.into() + }, + }, + tx_context_gas_budget_cost_params: TxContextGasBudgetCostParams { + tx_context_gas_budget_cost_base: if protocol_config.move_native_context() { + protocol_config.tx_context_gas_budget_cost_base().into() + } else { + DEFAULT_UNUSED_TX_CONTEXT_ENTRY_COST.into() + }, + }, + tx_context_ids_created_cost_params: TxContextIdsCreatedCostParams { + tx_context_ids_created_cost_base: if protocol_config.move_native_context() { + protocol_config.tx_context_ids_created_cost_base().into() + } else { + DEFAULT_UNUSED_TX_CONTEXT_ENTRY_COST.into() + }, + }, + tx_context_replace_cost_params: TxContextReplaceCostParams { + tx_context_replace_cost_base: if protocol_config.move_native_context() { + protocol_config.tx_context_replace_cost_base().into() + } else { + DEFAULT_UNUSED_TX_CONTEXT_ENTRY_COST.into() + }, + }, type_is_one_time_witness_cost_params: TypesIsOneTimeWitnessCostParams { types_is_one_time_witness_cost_base: protocol_config .types_is_one_time_witness_cost_base() @@ -1027,6 +1110,43 @@ pub fn all_natives(silent: bool, protocol_config: &ProtocolConfig) -> NativeFunc "derive_id", make_native!(tx_context::derive_id), ), + ("tx_context", "fresh_id", make_native!(tx_context::fresh_id)), + ( + "tx_context", + "native_sender", + make_native!(tx_context::sender), + ), + ( + "tx_context", + "native_epoch", + make_native!(tx_context::epoch), + ), + ( + "tx_context", + "native_epoch_timestamp_ms", + make_native!(tx_context::epoch_timestamp_ms), + ), + ( + "tx_context", + "native_sponsor", + make_native!(tx_context::sponsor), + ), + ( + "tx_context", + "native_gas_price", + make_native!(tx_context::gas_price), + ), + ( + "tx_context", + "native_gas_budget", + make_native!(tx_context::gas_budget), + ), + ( + "tx_context", + "native_ids_created", + make_native!(tx_context::ids_created), + ), + ("tx_context", "replace", make_native!(tx_context::replace)), ( "types", "is_one_time_witness", diff --git a/sui-execution/latest/sui-move-natives/src/transaction_context/mod.rs b/sui-execution/latest/sui-move-natives/src/transaction_context/mod.rs new file mode 100644 index 0000000000000..17e1375303309 --- /dev/null +++ b/sui-execution/latest/sui-move-natives/src/transaction_context/mod.rs @@ -0,0 +1,95 @@ +// Copyright (c) Mysten Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 + +use better_any::{Tid, TidAble}; +use move_core_types::account_address::AccountAddress; +use std::{cell::RefCell, rc::Rc}; +use sui_types::{ + base_types::{ObjectID, SuiAddress, TxContext}, + committee::EpochId, + digests::TransactionDigest, +}; + +// TransactionContext is a wrapper around TxContext that is exposed to NativeContextExtensions +// in order to provide transaction context information to Move native functions. +// Holds a Rc> to allow for mutation of the TxContext. +#[derive(Tid)] +pub struct TransactionContext { + pub(crate) tx_context: Rc>, + test_only: bool, +} + +impl TransactionContext { + pub fn new(tx_context: Rc>) -> Self { + Self { + tx_context, + test_only: false, + } + } + + pub fn new_for_testing(tx_context: Rc>) -> Self { + Self { + tx_context, + test_only: true, + } + } + + pub fn sender(&self) -> SuiAddress { + self.tx_context.borrow().sender() + } + + pub fn epoch(&self) -> EpochId { + self.tx_context.borrow().epoch() + } + + pub fn epoch_timestamp_ms(&self) -> u64 { + self.tx_context.borrow().epoch_timestamp_ms() + } + + pub fn digest(&self) -> TransactionDigest { + self.tx_context.borrow().digest() + } + + pub fn sponsor(&self) -> Option { + self.tx_context.borrow().sponsor() + } + + pub fn gas_price(&self) -> u64 { + self.tx_context.borrow().gas_price() + } + + pub fn gas_budget(&self) -> u64 { + self.tx_context.borrow().gas_budget() + } + + pub fn ids_created(&self) -> u64 { + self.tx_context.borrow().ids_created() + } + + pub fn fresh_id(&self) -> ObjectID { + self.tx_context.borrow_mut().fresh_id() + } + + // + // Test only function + // + pub fn replace( + &self, + sender: AccountAddress, + tx_hash: Vec, + epoch: u64, + epoch_timestamp_ms: u64, + ids_created: u64, + ) { + if !self.test_only { + unreachable!("`replace` called on a non testing scenario"); + } + self.tx_context.borrow_mut().replace( + sender, + tx_hash, + epoch, + epoch_timestamp_ms, + ids_created, + ); + } +} diff --git a/sui-execution/latest/sui-move-natives/src/tx_context.rs b/sui-execution/latest/sui-move-natives/src/tx_context.rs index 1a208098b409d..35d22ac75ee9b 100644 --- a/sui-execution/latest/sui-move-natives/src/tx_context.rs +++ b/sui-execution/latest/sui-move-natives/src/tx_context.rs @@ -5,13 +5,18 @@ use move_binary_format::errors::PartialVMResult; use move_core_types::{account_address::AccountAddress, gas_algebra::InternalGas}; use move_vm_runtime::{native_charge_gas_early_exit, native_functions::NativeContext}; use move_vm_types::{ - loaded_data::runtime_types::Type, natives::function::NativeResult, pop_arg, values::Value, + loaded_data::runtime_types::Type, + natives::function::NativeResult, + pop_arg, + values::{Struct, Value, Vector}, }; use smallvec::smallvec; use std::{collections::VecDeque, convert::TryFrom}; -use sui_types::base_types::{ObjectID, TransactionDigest}; +use sui_types::base_types::{ObjectID, SuiAddress, TransactionDigest}; -use crate::{object_runtime::ObjectRuntime, NativesCostTable}; +use crate::{ + object_runtime::ObjectRuntime, transaction_context::TransactionContext, NativesCostTable, +}; #[derive(Clone)] pub struct TxContextDeriveIdCostParams { @@ -54,3 +59,346 @@ pub fn derive_id( smallvec![Value::address(address)], )) } + +#[derive(Clone)] +pub struct TxContextFreshIdCostParams { + pub tx_context_fresh_id_cost_base: InternalGas, +} +/*************************************************************************************************** + * native fun fresh_id + * Implementation of the Move native function `fun fresh_id(): address` + **************************************************************************************************/ +pub fn fresh_id( + context: &mut NativeContext, + ty_args: Vec, + args: VecDeque, +) -> PartialVMResult { + debug_assert!(ty_args.is_empty()); + debug_assert!(args.is_empty()); + + let tx_context_fresh_id_cost_params = context + .extensions_mut() + .get::() + .tx_context_fresh_id_cost_params + .clone(); + native_charge_gas_early_exit!( + context, + tx_context_fresh_id_cost_params.tx_context_fresh_id_cost_base + ); + + let transaction_context: &mut TransactionContext = context.extensions_mut().get_mut(); + let fresh_id = transaction_context.fresh_id(); + let object_runtime: &mut ObjectRuntime = context.extensions_mut().get_mut(); + object_runtime.new_id(fresh_id)?; + + Ok(NativeResult::ok( + context.gas_used(), + smallvec![Value::address(fresh_id.into())], + )) +} + +#[derive(Clone)] +pub struct TxContextSenderCostParams { + pub tx_context_sender_cost_base: InternalGas, +} +/*************************************************************************************************** + * native fun native_sender + * Implementation of the Move native function `fun native_sender(): address` + **************************************************************************************************/ +pub fn sender( + context: &mut NativeContext, + ty_args: Vec, + args: VecDeque, +) -> PartialVMResult { + debug_assert!(ty_args.is_empty()); + debug_assert!(args.is_empty()); + + let tx_context_sender_cost_params = context + .extensions_mut() + .get::() + .tx_context_sender_cost_params + .clone(); + native_charge_gas_early_exit!( + context, + tx_context_sender_cost_params.tx_context_sender_cost_base + ); + + let transaction_context: &mut TransactionContext = context.extensions_mut().get_mut(); + let sender = transaction_context.sender(); + + Ok(NativeResult::ok( + context.gas_used(), + smallvec![Value::address(sender.into())], + )) +} + +#[derive(Clone)] +pub struct TxContextEpochCostParams { + pub tx_context_epoch_cost_base: InternalGas, +} +/*************************************************************************************************** + * native fun native_epoch + * Implementation of the Move native function `fun native_epoch(): u64` + **************************************************************************************************/ +pub fn epoch( + context: &mut NativeContext, + ty_args: Vec, + args: VecDeque, +) -> PartialVMResult { + debug_assert!(ty_args.is_empty()); + debug_assert!(args.is_empty()); + + let tx_context_epoch_cost_params = context + .extensions_mut() + .get::() + .tx_context_epoch_cost_params + .clone(); + native_charge_gas_early_exit!( + context, + tx_context_epoch_cost_params.tx_context_epoch_cost_base + ); + + let transaction_context: &mut TransactionContext = context.extensions_mut().get_mut(); + let epoch = transaction_context.epoch(); + + Ok(NativeResult::ok( + context.gas_used(), + smallvec![Value::u64(epoch)], + )) +} + +#[derive(Clone)] +pub struct TxContextEpochTimestampMsCostParams { + pub tx_context_epoch_timestamp_ms_cost_base: InternalGas, +} +/*************************************************************************************************** + * native fun native_epoch_timestamp_ms + * Implementation of the Move native function `fun native_epoch_timestamp_ms(): u64` + **************************************************************************************************/ +pub fn epoch_timestamp_ms( + context: &mut NativeContext, + ty_args: Vec, + args: VecDeque, +) -> PartialVMResult { + debug_assert!(ty_args.is_empty()); + debug_assert!(args.is_empty()); + + let tx_context_epoch_timestamp_ms_cost_params = context + .extensions_mut() + .get::() + .tx_context_epoch_timestamp_ms_cost_params + .clone(); + native_charge_gas_early_exit!( + context, + tx_context_epoch_timestamp_ms_cost_params.tx_context_epoch_timestamp_ms_cost_base + ); + + let transaction_context: &mut TransactionContext = context.extensions_mut().get_mut(); + let timestamp = transaction_context.epoch_timestamp_ms(); + + Ok(NativeResult::ok( + context.gas_used(), + smallvec![Value::u64(timestamp)], + )) +} + +#[derive(Clone)] +pub struct TxContextSponsorCostParams { + pub tx_context_sponsor_cost_base: InternalGas, +} +/*************************************************************************************************** + * native fun native_sponsor + * Implementation of the Move native function `fun native_sponsor(): Option
` + **************************************************************************************************/ +pub fn sponsor( + context: &mut NativeContext, + ty_args: Vec, + args: VecDeque, +) -> PartialVMResult { + debug_assert!(ty_args.is_empty()); + debug_assert!(args.is_empty()); + + let tx_context_sponsor_cost_params = context + .extensions_mut() + .get::() + .tx_context_sponsor_cost_params + .clone(); + native_charge_gas_early_exit!( + context, + tx_context_sponsor_cost_params.tx_context_sponsor_cost_base + ); + + let transaction_context: &mut TransactionContext = context.extensions_mut().get_mut(); + let sponsor = to_option(transaction_context.sponsor())?; + + Ok(NativeResult::ok(context.gas_used(), smallvec![sponsor])) +} + +fn to_option(value: Option) -> PartialVMResult { + let vector = Type::Vector(Box::new(Type::Address)); + match value { + Some(value) => { + let value = vec![AccountAddress::new(value.to_inner())]; + Ok(Value::struct_(Struct::pack(vec![Vector::pack( + &vector, + vec![Value::vector_address(value)], + )?]))) + } + None => Ok(Value::struct_(Struct::pack(vec![Vector::empty(&vector)?]))), + } +} + +#[derive(Clone)] +pub struct TxContextGasPriceCostParams { + pub tx_context_gas_price_cost_base: InternalGas, +} +/*************************************************************************************************** + * native fun native_gas_price + * Implementation of the Move native function `fun native_gas_price(): u64` + **************************************************************************************************/ +pub fn gas_price( + context: &mut NativeContext, + ty_args: Vec, + args: VecDeque, +) -> PartialVMResult { + debug_assert!(ty_args.is_empty()); + debug_assert!(args.is_empty()); + + let tx_context_gas_price_cost_params = context + .extensions_mut() + .get::() + .tx_context_gas_price_cost_params + .clone(); + native_charge_gas_early_exit!( + context, + tx_context_gas_price_cost_params.tx_context_gas_price_cost_base + ); + + let transaction_context: &mut TransactionContext = context.extensions_mut().get_mut(); + let gas_price = transaction_context.gas_price(); + + Ok(NativeResult::ok( + context.gas_used(), + smallvec![Value::u64(gas_price)], + )) +} + +#[derive(Clone)] +pub struct TxContextGasBudgetCostParams { + pub tx_context_gas_budget_cost_base: InternalGas, +} +/*************************************************************************************************** + * native fun native_gas_budget + * Implementation of the Move native function `fun native_gas_budget(): u64` + **************************************************************************************************/ +pub fn gas_budget( + context: &mut NativeContext, + ty_args: Vec, + args: VecDeque, +) -> PartialVMResult { + debug_assert!(ty_args.is_empty()); + debug_assert!(args.is_empty()); + + let tx_context_gas_budget_cost_params = context + .extensions_mut() + .get::() + .tx_context_gas_budget_cost_params + .clone(); + native_charge_gas_early_exit!( + context, + tx_context_gas_budget_cost_params.tx_context_gas_budget_cost_base + ); + + let transaction_context: &mut TransactionContext = context.extensions_mut().get_mut(); + let gas_budget = transaction_context.gas_budget(); + + Ok(NativeResult::ok( + context.gas_used(), + smallvec![Value::u64(gas_budget)], + )) +} + +#[derive(Clone)] +pub struct TxContextIdsCreatedCostParams { + pub tx_context_ids_created_cost_base: InternalGas, +} +/*************************************************************************************************** + * native fun native_ids_created + * Implementation of the Move native function `fun native_ids_created(): u64` + **************************************************************************************************/ +pub fn ids_created( + context: &mut NativeContext, + ty_args: Vec, + args: VecDeque, +) -> PartialVMResult { + debug_assert!(ty_args.is_empty()); + debug_assert!(args.is_empty()); + + let tx_context_ids_created_cost_params = context + .extensions_mut() + .get::() + .tx_context_ids_created_cost_params + .clone(); + native_charge_gas_early_exit!( + context, + tx_context_ids_created_cost_params.tx_context_ids_created_cost_base + ); + + let transaction_context: &mut TransactionContext = context.extensions_mut().get_mut(); + let ids_created = transaction_context.ids_created(); + + Ok(NativeResult::ok( + context.gas_used(), + smallvec![Value::u64(ids_created)], + )) +} + +// // +// // Test only function +// // +#[derive(Clone)] +pub struct TxContextReplaceCostParams { + pub tx_context_replace_cost_base: InternalGas, +} +/*************************************************************************************************** + * native fun native_replace + * Implementation of the Move native function + * ``` + * fun native_replace( + * sender: address, + * tx_hash: vector, + * epoch: u64, + * epoch_timestamp_ms: u64, + * ids_created: u64, + * ) + * ``` + * Used by all testing functions that have to change a value in the `TransactionContext`. + **************************************************************************************************/ +pub fn replace( + context: &mut NativeContext, + ty_args: Vec, + mut args: VecDeque, +) -> PartialVMResult { + debug_assert!(ty_args.is_empty()); + debug_assert!(args.len() == 5); + + let tx_context_replace_cost_params = context + .extensions_mut() + .get::() + .tx_context_replace_cost_params + .clone(); + native_charge_gas_early_exit!( + context, + tx_context_replace_cost_params.tx_context_replace_cost_base + ); + + let ids_created: u64 = pop_arg!(args, u64); + let epoch_timestamp_ms: u64 = pop_arg!(args, u64); + let epoch: u64 = pop_arg!(args, u64); + let tx_hash: Vec = pop_arg!(args, Vec); + let sender: AccountAddress = pop_arg!(args, AccountAddress); + let transaction_context: &mut TransactionContext = context.extensions_mut().get_mut(); + transaction_context.replace(sender, tx_hash, epoch, epoch_timestamp_ms, ids_created); + + Ok(NativeResult::ok(context.gas_used(), smallvec![])) +} diff --git a/sui-execution/src/latest.rs b/sui-execution/src/latest.rs index 125cd9dcd8a02..821c9cd5a7d1d 100644 --- a/sui-execution/src/latest.rs +++ b/sui-execution/src/latest.rs @@ -4,7 +4,7 @@ use move_binary_format::CompiledModule; use move_trace_format::format::MoveTraceBuilder; use move_vm_config::verifier::{MeterConfig, VerifierConfig}; -use std::{collections::HashSet, path::PathBuf, sync::Arc}; +use std::{cell::RefCell, collections::HashSet, path::PathBuf, rc::Rc, sync::Arc}; use sui_protocol_config::ProtocolConfig; use sui_types::execution::ExecutionTiming; use sui_types::transaction::GasData; @@ -180,21 +180,24 @@ impl executor::Executor for Executor { input_objects: CheckedInputObjects, pt: ProgrammableTransaction, ) -> Result { - let mut tx_context = TxContext::new_from_components( + let tx_context = TxContext::new_from_components( &SuiAddress::default(), transaction_digest, &epoch_id, epoch_timestamp_ms, - // genesis transaction: RGP: 1, sponsor: None + // genesis transaction: RGP: 1, budget: 1M, sponsor: None 1, + 1_000_000, None, + protocol_config.move_native_context(), ); + let tx_context = Rc::new(RefCell::new(tx_context)); execute_genesis_state_update( store, protocol_config, metrics, &self.0, - &mut tx_context, + tx_context, input_objects, pt, ) diff --git a/sui-execution/src/v0.rs b/sui-execution/src/v0.rs index 3d19d57eb172a..08aeac9c5f835 100644 --- a/sui-execution/src/v0.rs +++ b/sui-execution/src/v0.rs @@ -188,10 +188,12 @@ impl executor::Executor for Executor { transaction_digest, &epoch_id, epoch_timestamp_ms, - // genesis transaction: RGP: 1, sponsor: None + // genesis transaction: RGP: 1, budget: 1M, sponsor: None // Those values are unused anyway in execution versions before 3 (or latest) 1, + 1_000_000, None, + protocol_config.move_native_context(), ); execute_genesis_state_update( store, diff --git a/sui-execution/src/v1.rs b/sui-execution/src/v1.rs index 8fdf1996f4bd2..04bc7fd89a163 100644 --- a/sui-execution/src/v1.rs +++ b/sui-execution/src/v1.rs @@ -188,10 +188,12 @@ impl executor::Executor for Executor { transaction_digest, &epoch_id, epoch_timestamp_ms, - // genesis transaction: RGP: 1, sponsor: None + // genesis transaction: RGP: 1, budget: 1M, sponsor: None // Those values are unused anyway in execution versions before 3 (or latest) 1, + 1_000_000, None, + protocol_config.move_native_context(), ); execute_genesis_state_update( store, diff --git a/sui-execution/src/v2.rs b/sui-execution/src/v2.rs index fd332db0663b4..b8d5b442d2b22 100644 --- a/sui-execution/src/v2.rs +++ b/sui-execution/src/v2.rs @@ -188,10 +188,12 @@ impl executor::Executor for Executor { transaction_digest, &epoch_id, epoch_timestamp_ms, - // genesis transaction: RGP: 1, sponsor: None + // genesis transaction: RGP: 1, budget: 1M, sponsor: None // Those values are unused anyway in execution versions before 3 (or latest) 1, + 1_000_000, None, + protocol_config.move_native_context(), ); execute_genesis_state_update( store, diff --git a/sui-execution/v0/sui-adapter/src/execution_engine.rs b/sui-execution/v0/sui-adapter/src/execution_engine.rs index 920e1552cd733..20c2e7960ff29 100644 --- a/sui-execution/v0/sui-adapter/src/execution_engine.rs +++ b/sui-execution/v0/sui-adapter/src/execution_engine.rs @@ -89,7 +89,9 @@ mod checked { epoch_timestamp_ms, // Those values are unused in execution versions before 3 (or latest) 1, + 1_000_000, None, + protocol_config.move_native_context(), ); let is_epoch_change = matches!(transaction_kind, TransactionKind::ChangeEpoch(_)); diff --git a/sui-execution/v1/sui-adapter/src/execution_engine.rs b/sui-execution/v1/sui-adapter/src/execution_engine.rs index 1670794ed301e..1722ebc09db1c 100644 --- a/sui-execution/v1/sui-adapter/src/execution_engine.rs +++ b/sui-execution/v1/sui-adapter/src/execution_engine.rs @@ -105,7 +105,9 @@ mod checked { epoch_timestamp_ms, // Those values are unused in execution versions before 3 (or latest) 1, + 1_000_000, None, + protocol_config.move_native_context(), ); let is_epoch_change = transaction_kind.is_end_of_epoch_tx(); diff --git a/sui-execution/v2/sui-adapter/src/execution_engine.rs b/sui-execution/v2/sui-adapter/src/execution_engine.rs index 1cf536717eb6c..b16f514de8640 100644 --- a/sui-execution/v2/sui-adapter/src/execution_engine.rs +++ b/sui-execution/v2/sui-adapter/src/execution_engine.rs @@ -116,7 +116,9 @@ mod checked { epoch_timestamp_ms, // Those values are unused in execution versions before 3 (or latest) 1, + 1_000_000, None, + protocol_config.move_native_context(), ); let is_epoch_change = transaction_kind.is_end_of_epoch_tx();