Skip to content
12 changes: 12 additions & 0 deletions crates/sui-protocol-config/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -894,6 +894,10 @@ struct FeatureFlags {
// If true, skip GC'ed accept votes in CommitFinalizer.
#[serde(skip_serializing_if = "is_false")]
consensus_skip_gced_accept_votes: bool,

// If true, automatically convert withdrawal PTB arguments to coin or balance when needed.
#[serde(skip_serializing_if = "is_false")]
convert_withdrawal_ptb_arguments: bool,
}

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

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

#[cfg(not(msim))]
Expand Down Expand Up @@ -4646,6 +4654,10 @@ impl ProtocolConfig {
pub fn set_consensus_skip_gced_accept_votes_for_testing(&mut self, val: bool) {
self.feature_flags.consensus_skip_gced_accept_votes = val;
}

pub fn enable_withdrawal_ptb_argument_conversion_for_testing(&mut self, val: bool) {
self.feature_flags.convert_withdrawal_ptb_arguments = val;
}
}

type OverrideFn = dyn Fn(ProtocolVersion, ProtocolConfig) -> ProtocolConfig + Send;
Expand Down
2 changes: 2 additions & 0 deletions crates/sui-types/src/coin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ pub const PAY_MODULE_NAME: &IdentStr = ident_str!("pay");
pub const PAY_JOIN_FUNC_NAME: &IdentStr = ident_str!("join");
pub const PAY_SPLIT_N_FUNC_NAME: &IdentStr = ident_str!("divide_and_keep");
pub const PAY_SPLIT_VEC_FUNC_NAME: &IdentStr = ident_str!("split_vec");
pub const REDEEM_FUNDS_FUNC_NAME: &IdentStr = ident_str!("redeem_funds");
pub const SEND_FUNDS_FUNC_NAME: &IdentStr = ident_str!("send_funds");

// Rust version of the Move sui::coin::Coin type
#[derive(Debug, Serialize, Deserialize, Clone, JsonSchema, Eq, PartialEq)]
Expand Down
1 change: 1 addition & 0 deletions crates/sui-types/src/funds_accumulator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ pub const RESOLVED_WITHDRAWAL_STRUCT: (&AccountAddress, &IdentStr, &IdentStr) =
FUNDS_ACCUMULATOR_MODULE_NAME,
WITHDRAWAL_STRUCT_NAME,
);
pub const WITHDRAWAL_OWNER_FUNC_NAME: &IdentStr = ident_str!("withdrawal_owner");

/// Rust bindings for the Move struct `sui::funds_accumulator::Withdrawal`.
#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)]
Expand Down
28 changes: 14 additions & 14 deletions external-crates/move/crates/move-binary-format/src/file_format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -824,53 +824,53 @@ impl AbilitySet {
| (Ability::Key as u8),
);

pub fn singleton(ability: Ability) -> Self {
pub const fn singleton(ability: Ability) -> Self {
Self(ability as u8)
}

pub fn has_ability(self, ability: Ability) -> bool {
pub const fn has_ability(self, ability: Ability) -> bool {
let a = ability as u8;
(a & self.0) == a
}

pub fn has_copy(self) -> bool {
pub const fn has_copy(self) -> bool {
self.has_ability(Ability::Copy)
}

pub fn has_drop(self) -> bool {
pub const fn has_drop(self) -> bool {
self.has_ability(Ability::Drop)
}

pub fn has_store(self) -> bool {
pub const fn has_store(self) -> bool {
self.has_ability(Ability::Store)
}

pub fn has_key(self) -> bool {
pub const fn has_key(self) -> bool {
self.has_ability(Ability::Key)
}

pub fn remove(self, ability: Ability) -> Self {
pub const fn remove(self, ability: Ability) -> Self {
self.difference(Self::singleton(ability))
}

pub fn intersect(self, other: Self) -> Self {
pub const fn intersect(self, other: Self) -> Self {
Self(self.0 & other.0)
}

pub fn union(self, other: Self) -> Self {
pub const fn union(self, other: Self) -> Self {
Self(self.0 | other.0)
}

pub fn difference(self, other: Self) -> Self {
pub const fn difference(self, other: Self) -> Self {
Self(self.0 & !other.0)
}

#[inline]
fn is_subset_bits(sub: u8, sup: u8) -> bool {
const fn is_subset_bits(sub: u8, sup: u8) -> bool {
(sub & sup) == sub
}

pub fn is_subset(self, other: Self) -> bool {
pub const fn is_subset(self, other: Self) -> bool {
Self::is_subset_bits(self.0, other.0)
}

Expand Down Expand Up @@ -922,7 +922,7 @@ impl AbilitySet {
Ok(abs)
}

pub fn from_u8(byte: u8) -> Option<Self> {
pub const fn from_u8(byte: u8) -> Option<Self> {
// If there is a bit set in the read `byte`, that bit must be set in the
// `AbilitySet` containing all `Ability`s
// This corresponds the byte being a bit set subset of ALL
Expand All @@ -934,7 +934,7 @@ impl AbilitySet {
}
}

pub fn into_u8(self) -> u8 {
pub const fn into_u8(self) -> u8 {
self.0
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ use move_binary_format::{
};
use move_core_types::{
annotated_value,
identifier::IdentStr,
language_storage::{ModuleId, StructTag},
runtime_value::{self, MoveTypeLayout},
vm_status::StatusCode,
Expand All @@ -37,9 +38,10 @@ use move_vm_types::{data_store::DataStore, loaded_data::runtime_types as vm_runt
use std::{cell::OnceCell, rc::Rc, sync::Arc};
use sui_protocol_config::ProtocolConfig;
use sui_types::{
Identifier, TypeTag,
Identifier, SUI_FRAMEWORK_PACKAGE_ID, TypeTag,
balance::RESOLVED_BALANCE_STRUCT,
base_types::{ObjectID, TxContext},
coin::RESOLVED_COIN_STRUCT,
error::{ExecutionError, ExecutionErrorKind},
execution_status::TypeArgumentError,
funds_accumulator::RESOLVED_WITHDRAWAL_STRUCT,
Expand Down Expand Up @@ -163,6 +165,24 @@ impl<'pc, 'vm, 'state, 'linkage> Env<'pc, 'vm, 'state, 'linkage> {
.map_err(|e| self.convert_vm_error(e))
}

pub fn load_framework_function(
&self,
module: &IdentStr,
function: &IdentStr,
type_arguments: Vec<Type>,
) -> Result<LoadedFunction, ExecutionError> {
let call_linkage = self
.linkage_analysis
.framework_call_linkage(&type_arguments, self.linkable_store)?;
self.load_function(
SUI_FRAMEWORK_PACKAGE_ID,
module.to_string(),
function.to_string(),
type_arguments,
call_linkage,
)
}

pub fn load_function(
&self,
package: ObjectID,
Expand Down Expand Up @@ -295,28 +315,37 @@ impl<'pc, 'vm, 'state, 'linkage> Env<'pc, 'vm, 'state, 'linkage> {
get_or_init_ty!(self, tx_context_type, TxContext::type_())
}

pub fn coin_type(&self, inner_type: Type) -> Result<Type, ExecutionError> {
const COIN_ABILITIES: AbilitySet =
AbilitySet::singleton(Ability::Key).union(AbilitySet::singleton(Ability::Store));
let (a, m, n) = RESOLVED_COIN_STRUCT;
let module = ModuleId::new(*a, m.to_owned());
Ok(Type::Datatype(Rc::new(Datatype {
abilities: COIN_ABILITIES,
module,
name: n.to_owned(),
type_arguments: vec![inner_type],
})))
}

pub fn balance_type(&self, inner_type: Type) -> Result<Type, ExecutionError> {
let Some(abilities) = AbilitySet::from_u8(Ability::Store as u8) else {
invariant_violation!("Unable to create balance abilities");
};
const BALANCE_ABILITIES: AbilitySet = AbilitySet::singleton(Ability::Store);
let (a, m, n) = RESOLVED_BALANCE_STRUCT;
let module = ModuleId::new(*a, m.to_owned());
Ok(Type::Datatype(Rc::new(Datatype {
abilities,
abilities: BALANCE_ABILITIES,
module,
name: n.to_owned(),
type_arguments: vec![inner_type],
})))
}

pub fn withdrawal_type(&self, inner_type: Type) -> Result<Type, ExecutionError> {
let Some(abilities) = AbilitySet::from_u8(Ability::Drop as u8) else {
invariant_violation!("Unable to create withdrawal abilities");
};
const WITHDRAWAL_ABILITIES: AbilitySet = AbilitySet::singleton(Ability::Drop);
let (a, m, n) = RESOLVED_WITHDRAWAL_STRUCT;
let module = ModuleId::new(*a, m.to_owned());
Ok(Type::Datatype(Rc::new(Datatype {
abilities,
abilities: WITHDRAWAL_ABILITIES,
module,
name: n.to_owned(),
type_arguments: vec![inner_type],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ where
withdrawals,
pure,
receiving,
withdrawal_conversions: _,
commands,
} = ast;
let mut context = Context::new(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
// Copyright (c) Mysten Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

use std::rc::Rc;

use crate::{
data_store::PackageStore,
execution_mode::ExecutionMode,
static_programmable_transactions::linkage::{
config::{LinkageConfig, ResolutionConfig},
resolution::{ResolutionTable, VersionConstraint, add_and_unify, get_package},
resolved_linkage::ResolvedLinkage,
static_programmable_transactions::{
linkage::{
config::{LinkageConfig, ResolutionConfig},
resolution::{ResolutionTable, VersionConstraint, add_and_unify, get_package},
resolved_linkage::{ResolvedLinkage, RootedLinkage},
},
loading::ast::Type,
},
};
use sui_protocol_config::ProtocolConfig;
Expand Down Expand Up @@ -57,6 +62,22 @@ impl LinkageAnalyzer {
&self.internal
}

pub fn framework_call_linkage(
&self,
// Type arguments do not need to be included in the linkage in the current VM.
_type_args: &[Type],
store: &dyn PackageStore,
) -> Result<RootedLinkage, ExecutionError> {
Ok(RootedLinkage {
link_context: *sui_types::SUI_FRAMEWORK_PACKAGE_ID,
resolved_linkage: Rc::new(ResolvedLinkage::from_resolution_table(
self.internal
.linkage_config
.resolution_table_with_native_packages(store)?,
)),
})
}

fn compute_call_linkage_(
&self,
move_call: &P::ProgrammableMoveCall,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,10 @@ fn input(
)
}
CallArg::FundsWithdrawal(f) => {
assert_invariant!(
env.protocol_config.enable_accumulators(),
"Withdrawals should be rejected at signing if accumulators are not enabled"
);
let FundsWithdrawalArg {
reservation,
type_arg,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
use crate::static_programmable_transactions::{
linkage::resolved_linkage::ResolvedLinkage, loading::ast as L, spanned::Spanned,
};
use indexmap::IndexSet;
use indexmap::{IndexMap, IndexSet};
use move_core_types::{account_address::AccountAddress, u256::U256};
use move_vm_types::values::VectorSpecialization;
use std::cell::OnceCell;
Expand All @@ -26,6 +26,7 @@ pub struct Transaction {
pub pure: Vec<PureInput>,
/// All receiving inputs
pub receiving: Vec<ReceivingInput>,
pub withdrawal_conversions: IndexMap<Location, WithdrawalConversion>,
pub commands: Commands,
}

Expand Down Expand Up @@ -73,6 +74,20 @@ pub struct WithdrawalInput {
pub amount: U256,
}

#[derive(Debug, Clone, Copy)]
pub struct WithdrawalConversion {
// Result index to a call to `sui::funds_accumulator::withdrawal_owner`
pub owner_result: u16,
// Result index to conversion call
pub conversion_result: u16,
pub conversion_kind: WithdrawalConversionKind,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum WithdrawalConversionKind {
ToCoin,
}

pub type Commands = Vec<Command>;

pub type ObjectArg = L::ObjectArg;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,7 @@ impl Context {
withdrawals,
pure,
receiving,
withdrawal_conversions: _,
commands: _,
} = txn;
let tx_context = Location::non_ref(T::Location::TxContext);
Expand Down Expand Up @@ -525,6 +526,7 @@ fn verify_(txn: &T::Transaction) -> anyhow::Result<()> {
withdrawals: _,
pure: _,
receiving: _,
withdrawal_conversions: _,
commands,
} = txn;
for c in commands {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ fn verify_<Mode: ExecutionMode>(env: &Env, txn: &T::Transaction) -> anyhow::Resu
withdrawals,
pure,
receiving,
withdrawal_conversions: _,
commands,
} = txn;
for obj in objects {
Expand Down
Loading
Loading