Skip to content

Commit

Permalink
txcontext
Browse files Browse the repository at this point in the history
  • Loading branch information
dariorussi committed Oct 19, 2024
1 parent 05b6018 commit b3cf8bc
Show file tree
Hide file tree
Showing 10 changed files with 692 additions and 37 deletions.
2 changes: 1 addition & 1 deletion crates/sui-framework/packages/sui-framework/Move.lock
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,6 @@ name = "MoveStdlib"
source = { local = "../move-stdlib" }

[move.toolchain-version]
compiler-version = "1.30.0"
compiler-version = "1.34.0"
edition = "2024.beta"
flavor = "sui"
112 changes: 98 additions & 14 deletions crates/sui-framework/packages/sui-framework/sources/tx_context.move
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ const EBadTxHashLength: u64 = 0;
/// Attempt to get the most recent created object ID when none has been created.
const ENoIDsCreated: u64 = 1;

const NATIVE_CONTEXT: bool = false;

const EUnsupportedFunction: u64 = 2;

/// 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`.
Expand All @@ -35,45 +39,106 @@ public struct TxContext has drop {
/// Return the address of the user that signed the current
/// transaction
public fun sender(self: &TxContext): address {
self.sender
if (NATIVE_CONTEXT) {
self.native_sender()
} else {
self.sender
}
}

/// Return the transaction digest (hash of transaction inputs).
/// Please do not use as a source of randomness.
public fun digest(self: &TxContext): &vector<u8> {
&self.tx_hash
if (NATIVE_CONTEXT) {
self.native_digest()
} else {
&self.tx_hash
}
}

/// Return the current epoch
public fun epoch(self: &TxContext): u64 {
self.epoch
if (NATIVE_CONTEXT) {
self.native_epoch()
} else {
self.epoch
}
}

/// Return the epoch start time as a unix timestamp in milliseconds.
public fun epoch_timestamp_ms(self: &TxContext): u64 {
self.epoch_timestamp_ms
if (NATIVE_CONTEXT) {
self.native_epoch_timestamp_ms()
} else {
self.epoch_timestamp_ms
}
}

public fun sponsor(self: &TxContext): Option<address> {
assert!(NATIVE_CONTEXT, EUnsupportedFunction);
self.native_sponsor()
}

/// 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;
let ids_created = ctx.ids_created();
let id = derive_id(*ctx.digest(), ids_created);
ctx.increment_ids_created();
id
}

#[allow(unused_function)]
fun increment_ids_created(self: &mut TxContext) {
if (NATIVE_CONTEXT) {
self.native_inc_ids_created()
} else {
self.ids_created = self.ids_created + 1
}
}

/// 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
if (NATIVE_CONTEXT) {
self.native_ids_created()
} else {
self.ids_created
}
}

/// Native function for deriving an ID via hash(tx_hash || ids_created)
native fun derive_id(tx_hash: vector<u8>, ids_created: u64): address;

native fun native_sender(self: &TxContext): address;

native fun native_digest(self: &TxContext): &vector<u8>;

native fun native_epoch(self: &TxContext): u64;

native fun native_epoch_timestamp_ms(self: &TxContext): u64;

native fun native_sponsor(self: &TxContext): Option<address>;

native fun native_ids_created(self: &TxContext): u64;

native fun native_inc_ids_created(self: &mut TxContext);

#[test_only]
native fun native_inc_epoch(self: &mut TxContext);

#[test_only]
native fun native_inc_epoch_timestamp(self: &mut TxContext, delta_ms: u64);

#[test_only]
native fun native_replace(
sender: address,
tx_hash: vector<u8>,
epoch: u64,
epoch_timestamp_ms: u64,
ids_created: u64,
);

// ==== test-only functions ====

#[test_only]
Expand All @@ -86,7 +151,18 @@ 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 }
if (NATIVE_CONTEXT) {
native_replace(sender, tx_hash, epoch, epoch_timestamp_ms, ids_created);
TxContext {
sender: @0x0,
tx_hash: vector::empty(),
epoch: 0,
epoch_timestamp_ms: 0,
ids_created: 0,
}
} else {
TxContext { sender, tx_hash, epoch, epoch_timestamp_ms, ids_created }
}
}

#[test_only]
Expand Down Expand Up @@ -125,17 +201,25 @@ 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]
public fun increment_epoch_number(self: &mut TxContext) {
self.epoch = self.epoch + 1
if (NATIVE_CONTEXT) {
self.native_inc_epoch()
} else {
self.epoch = self.epoch + 1
}
}

#[test_only]
public fun increment_epoch_timestamp(self: &mut TxContext, delta_ms: u64) {
self.epoch_timestamp_ms = self.epoch_timestamp_ms + delta_ms
if (NATIVE_CONTEXT) {
self.native_inc_epoch_timestamp(delta_ms)
} else {
self.epoch_timestamp_ms = self.epoch_timestamp_ms + delta_ms
}
}
16 changes: 15 additions & 1 deletion crates/sui-protocol-config/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use tracing::{info, warn};

/// The minimum and maximum protocol versions supported by this build.
const MIN_PROTOCOL_VERSION: u64 = 1;
const MAX_PROTOCOL_VERSION: u64 = 65;
const MAX_PROTOCOL_VERSION: u64 = 66;

// Record history of protocol version allocations here:
//
Expand Down Expand Up @@ -186,6 +186,9 @@ const MAX_PROTOCOL_VERSION: u64 = 65;
// Version 62: Makes the event's sending module package upgrade-aware.
// Version 63: Enable gas based congestion control in consensus commit.
// Version 64: Switch to distributed vote scoring in consensus in mainnet
// Version 65: Enable distributed vote scoring for mainnet
// Version 66: Framework natives for transaction context and protocol config
// feature flag to turn it on/off

#[derive(Copy, Clone, Debug, Hash, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
pub struct ProtocolVersion(u64);
Expand Down Expand Up @@ -548,6 +551,10 @@ struct FeatureFlags {
// Makes the event's sending module version-aware.
#[serde(skip_serializing_if = "is_false")]
relocate_event_module: bool,

// Make transaction context native and zero out the Move struct
#[serde(skip_serializing_if = "is_false")]
transaction_context_native: bool,
}

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

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

#[cfg(not(msim))]
Expand Down Expand Up @@ -2844,6 +2855,9 @@ impl ProtocolConfig {
cfg.feature_flags
.consensus_distributed_vote_scoring_strategy = true;
}
66 => {
cfg.feature_flags.transaction_context_native = false;
}
// Use this template when making changes:
//
// // modify an existing constant.
Expand Down
37 changes: 32 additions & 5 deletions crates/sui-types/src/base_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -971,6 +971,10 @@ impl TxContext {
self.epoch
}

pub fn epoch_timestamp_ms(&self) -> CheckpointTimestamp {
self.epoch_timestamp_ms
}

/// 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);
Expand All @@ -979,6 +983,11 @@ impl TxContext {
id
}

/// Return the number of `ObjectID`'s generated during execution of the current transaction
pub fn ids_created(&self) -> u64 {
self.ids_created
}

/// Return the transaction digest, to include in new objects
pub fn digest(&self) -> TransactionDigest {
TransactionDigest::new(self.digest.clone().try_into().unwrap())
Expand All @@ -997,16 +1006,34 @@ impl TxContext {
/// serialize/deserialize and this is the reason why this method
/// consumes the other context..
pub fn update_state(&mut self, other: TxContext) -> Result<(), ExecutionError> {
if self.sender != other.sender
|| self.digest != other.digest
|| other.ids_created < self.ids_created
{
self.update_fresh_ids(&other.sender, &other.digest(), other.ids_created)
// TODO(dario): remove
// 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;
// Ok(())
}

pub fn update_fresh_ids(
&mut self,
sender: &AccountAddress,
digest: &TransactionDigest,
ids_created: u64,
) -> Result<(), ExecutionError> {
if &self.sender != sender || &self.digest() != digest || self.ids_created > ids_created {
return Err(ExecutionError::new_with_source(
ExecutionErrorKind::InvariantViolation,
"Immutable fields for TxContext changed",
));
}
self.ids_created = other.ids_created;
self.ids_created = ids_created;
Ok(())
}

Expand Down
13 changes: 10 additions & 3 deletions sui-execution/latest/sui-adapter/src/adapter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// SPDX-License-Identifier: Apache-2.0

pub use checked::*;

#[sui_macros::with_checked_arithmetic]
mod checked {
#[cfg(feature = "gas-profiler")]
Expand All @@ -23,11 +24,13 @@ mod checked {
native_functions::NativeFunctionTable,
};
use sui_move_natives::object_runtime;
use sui_types::metrics::BytecodeVerifierMetrics;
use sui_types::{base_types::TxContext, metrics::BytecodeVerifierMetrics};
use sui_verifier::check_for_verifier_timeout;
use tracing::instrument;

use sui_move_natives::{object_runtime::ObjectRuntime, NativesCostTable};
use sui_move_natives::{
native_tx_context::NativeTxContext, object_runtime::ObjectRuntime, NativesCostTable,
};
use sui_protocol_config::ProtocolConfig;
use sui_types::{
base_types::*,
Expand Down Expand Up @@ -84,8 +87,9 @@ mod checked {
is_metered: bool,
protocol_config: &'r ProtocolConfig,
metrics: Arc<LimitsMetrics>,
current_epoch_id: EpochId,
tx_context: &TxContext,
) -> NativeContextExtensions<'r> {
let current_epoch_id = tx_context.epoch();
let mut extensions = NativeContextExtensions::default();
extensions.add(ObjectRuntime::new(
child_resolver,
Expand All @@ -96,6 +100,9 @@ mod checked {
current_epoch_id,
));
extensions.add(NativesCostTable::from_protocol_config(protocol_config));
if protocol_config.transaction_context_native() {
extensions.add(NativeTxContext::from(tx_context));
}
extensions
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,11 @@ mod checked {
};
use move_vm_types::data_store::DataStore;
use move_vm_types::loaded_data::runtime_types::Type;
use sui_move_natives::object_runtime::{
self, get_all_uids, max_event_error, LoadedRuntimeObject, ObjectRuntime, RuntimeResults,
use sui_move_natives::{
native_tx_context::NativeTxContext,
object_runtime::{
self, get_all_uids, max_event_error, LoadedRuntimeObject, ObjectRuntime, RuntimeResults,
},
};
use sui_protocol_config::ProtocolConfig;
use sui_types::execution::ExecutionResults;
Expand Down Expand Up @@ -189,7 +192,7 @@ mod checked {
!gas_charger.is_unmetered(),
protocol_config,
metrics.clone(),
tx_context.epoch(),
tx_context,
);

// Set the profiler if in CLI
Expand Down Expand Up @@ -234,6 +237,16 @@ mod checked {
self.native_extensions.get()
}

pub fn native_tx_context(&mut self) -> &NativeTxContext {
// TODO: this is not going to fly with config versions
self.native_extensions.get()
}

pub fn native_tx_context_mut(&mut self) -> &mut NativeTxContext {
// TODO: this is not going to fly with config versions
self.native_extensions.get_mut()
}

/// Create a new ID and update the state
pub fn fresh_id(&mut self) -> Result<ObjectID, ExecutionError> {
let object_id = self.tx_context.fresh_id();
Expand Down
Loading

0 comments on commit b3cf8bc

Please sign in to comment.