Skip to content

Commit

Permalink
Generalize TransferCoin to TransferObject (MystenLabs#2605)
Browse files Browse the repository at this point in the history
* Generalize TransferCoin to TransferObject

- TransferObject works over any type with store
- Added a field to MoveObject in order to store this flag
  • Loading branch information
tnowacki authored Jun 28, 2022
1 parent e08f36b commit fa16180
Show file tree
Hide file tree
Showing 49 changed files with 1,071 additions and 939 deletions.
25 changes: 21 additions & 4 deletions crates/sui-adapter/src/adapter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use move_binary_format::{
access::ModuleAccess,
binary_views::BinaryIndexedView,
errors::PartialVMResult,
file_format::{CompiledModule, LocalIndex, SignatureToken, StructHandleIndex},
file_format::{AbilitySet, CompiledModule, LocalIndex, SignatureToken, StructHandleIndex},
};
use move_core_types::{
account_address::AccountAddress,
Expand Down Expand Up @@ -195,6 +195,18 @@ fn execute_internal<
.into_iter()
.filter(|(id, _obj)| by_value_objects.contains(id))
.collect();
let session = vm.new_session(state_view);
let events = events
.into_iter()
.map(|(recipient, event_type, type_, event_bytes)| {
let loaded_type = session.load_type(&type_)?;
let abilities = session.get_type_abilities(&loaded_type)?;
Ok((recipient, event_type, type_, abilities, event_bytes))
})
.collect::<Result<_, ExecutionError>>()?;
let (empty_changes, empty_events) = session.finish()?;
debug_assert!(empty_changes.into_inner().is_empty());
debug_assert!(empty_events.is_empty());
process_successful_execution(
state_view,
module_id,
Expand Down Expand Up @@ -386,7 +398,7 @@ pub fn generate_package_id(
Ok(package_id)
}

type MoveEvent = (Vec<u8>, u64, TypeTag, Vec<u8>);
type MoveEvent = (Vec<u8>, u64, TypeTag, AbilitySet, Vec<u8>);

/// Update `state_view` with the effects of successfully executing a transaction:
/// - Look for each input in `by_value_objects` to determine whether the object was transferred, frozen, or deleted
Expand Down Expand Up @@ -423,7 +435,7 @@ fn process_successful_execution<
state_view.set_create_object_ids(newly_generated_ids.clone());
// process events to identify transfers, freezes
for e in events {
let (recipient, event_type, type_, event_bytes) = e;
let (recipient, event_type, type_, abilities, event_bytes) = e;
let event_type = EventType::try_from(event_type as u8)
.expect("Safe because event_type is derived from an EventType enum");
match event_type {
Expand All @@ -446,6 +458,7 @@ fn process_successful_execution<
ctx.sender(),
new_owner,
type_,
abilities,
event_bytes,
tx_digest,
&mut by_value_objects,
Expand Down Expand Up @@ -551,6 +564,7 @@ fn handle_transfer<
sender: SuiAddress,
recipient: Owner,
type_: TypeTag,
abilities: AbilitySet,
contents: Vec<u8>,
tx_digest: TransactionDigest,
by_value_objects: &mut BTreeMap<ObjectID, (object::Owner, SequenceNumber)>,
Expand All @@ -561,7 +575,10 @@ fn handle_transfer<
) -> Result<(), ExecutionError> {
match type_ {
TypeTag::Struct(s_type) => {
let mut move_obj = MoveObject::new(s_type, contents);
let has_public_transfer = abilities.has_store();
// safe because `has_public_transfer` was properly determined from the abilities
let mut move_obj =
unsafe { MoveObject::new_from_execution(s_type, has_public_transfer, contents) };
let old_object = by_value_objects.remove(&move_obj.id());

#[cfg(debug_assertions)]
Expand Down
2 changes: 1 addition & 1 deletion crates/sui-cluster-test/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ impl ClusterTest {
let obj_to_transfer = coins.remove(0);
let data = wallet_context
.gateway
.transfer_coin(
.public_transfer_object(
signer,
*obj_to_transfer.id(),
Some(gas_obj_id),
Expand Down
11 changes: 4 additions & 7 deletions crates/sui-core/src/event_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ use tokio_stream::Stream;
use tracing::{debug, error};

use sui_types::base_types::TransactionDigest;
use sui_types::object::{MoveObject, ObjectFormatOptions};
use sui_types::{
error::{SuiError, SuiResult},
event::{Event, EventEnvelope},
Expand Down Expand Up @@ -65,13 +64,11 @@ impl EventHandler {
type_, contents, ..
} => {
debug!(event =? event, "Process MoveEvent.");
// Piggyback on MoveObject's conversion logic.
let move_object = MoveObject::new(type_.clone(), contents.clone());
let layout =
move_object.get_layout(ObjectFormatOptions::default(), &self.module_cache)?;
let move_struct =
Event::move_event_to_move_struct(type_, contents, &self.module_cache)?;
// Convert into `SuiMoveStruct` which is a mirror of MoveStruct but with additional type supports, (e.g. ascii::String).
let move_struct = move_object.to_move_struct(&layout)?.into();
Some(to_json_value(move_struct).map_err(|e| {
let sui_move_struct = move_struct.into();
Some(to_json_value(sui_move_struct).map_err(|e| {
SuiError::ObjectSerializationError {
error: e.to_string(),
}
Expand Down
13 changes: 6 additions & 7 deletions crates/sui-core/src/execution_engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ use sui_types::{
event::{Event, TransferType},
gas::{self, SuiGasStatus},
messages::{
CallArg, ChangeEpoch, ExecutionStatus, MoveCall, MoveModulePublish, SingleTransactionKind,
TransactionData, TransactionEffects, TransferCoin, TransferSui,
CallArg, ChangeEpoch, ExecutionStatus, MoveCall, MoveModulePublish, PublicTransferObject,
SingleTransactionKind, TransactionData, TransactionEffects, TransferSui,
},
object::Object,
storage::{BackingPackageStore, Storage},
Expand Down Expand Up @@ -117,7 +117,7 @@ fn execute_transaction<S: BackingPackageStore>(
// once across single tx, we should be able to run them in parallel.
for single_tx in transaction_data.kind.into_single_transactions() {
result = match single_tx {
SingleTransactionKind::TransferCoin(TransferCoin {
SingleTransactionKind::PublicTransferObject(PublicTransferObject {
recipient,
object_ref,
}) => {
Expand All @@ -127,7 +127,7 @@ fn execute_transaction<S: BackingPackageStore>(
.get(&object_ref.0)
.unwrap()
.clone();
transfer_coin(temporary_store, object, tx_ctx.sender(), recipient)
transfer_object(temporary_store, object, tx_ctx.sender(), recipient)
}
SingleTransactionKind::TransferSui(TransferSui { recipient, amount }) => {
let gas_object = temporary_store
Expand Down Expand Up @@ -241,7 +241,7 @@ fn execute_transaction<S: BackingPackageStore>(
(cost_summary, result)
}

fn transfer_coin<S>(
fn transfer_object<S>(
temporary_store: &mut AuthorityTemporaryStore<S>,
mut object: Object,
sender: SuiAddress,
Expand Down Expand Up @@ -293,8 +293,7 @@ fn transfer_sui<S>(

// Creat a new gas coin with the amount.
let new_object = Object::new_move(
MoveObject::new(
GasCoin::type_(),
MoveObject::new_gas_coin(
bcs::to_bytes(&GasCoin::new(
tx_ctx.fresh_id(),
OBJECT_START_VERSION,
Expand Down
36 changes: 19 additions & 17 deletions crates/sui-core/src/gateway_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,9 @@ use crate::{
use sui_json::{resolve_move_function_args, SuiJsonCallArg, SuiJsonValue};
use sui_json_rpc_api::rpc_types::{
GetObjectDataResponse, GetRawObjectDataResponse, MergeCoinResponse, MoveCallParams,
PublishResponse, RPCTransactionRequestParams, SplitCoinResponse, SuiMoveObject, SuiObject,
SuiObjectInfo, SuiTransactionEffects, SuiTypeTag, TransactionEffectsResponse,
TransactionResponse, TransferCoinParams,
PublicTransferObjectParams, PublishResponse, RPCTransactionRequestParams, SplitCoinResponse,
SuiMoveObject, SuiObject, SuiObjectInfo, SuiTransactionEffects, SuiTypeTag,
TransactionEffectsResponse, TransactionResponse,
};

use crate::transaction_input_checker::InputObjects;
Expand Down Expand Up @@ -254,8 +254,8 @@ pub trait GatewayAPI {
tx: Transaction,
) -> Result<TransactionResponse, anyhow::Error>;

/// Send coin object to a Sui address.
async fn transfer_coin(
/// Send an object to a Sui address. The object's type must allow public transfers
async fn public_transfer_object(
&self,
signer: SuiAddress,
object_id: ObjectID,
Expand Down Expand Up @@ -335,7 +335,7 @@ pub trait GatewayAPI {

/// Create a Batch Transaction that contains a vector of parameters needed to construct
/// all the single transactions in it.
/// Supported single transactions are TransferCoin and MoveCall.
/// Supported single transactions are PublicTransferObject and MoveCall.
async fn batch_transaction(
&self,
signer: SuiAddress,
Expand Down Expand Up @@ -853,18 +853,20 @@ where
Ok(coins)
}

async fn create_transfer_coin_transaction_kind(
async fn create_public_transfer_object_transaction_kind(
&self,
params: TransferCoinParams,
params: PublicTransferObjectParams,
used_object_ids: &mut BTreeSet<ObjectID>,
) -> Result<SingleTransactionKind, anyhow::Error> {
used_object_ids.insert(params.object_id);
let object = self.get_object_internal(&params.object_id).await?;
let object_ref = object.compute_object_reference();
Ok(SingleTransactionKind::TransferCoin(TransferCoin {
recipient: params.recipient,
object_ref,
}))
Ok(SingleTransactionKind::PublicTransferObject(
PublicTransferObject {
recipient: params.recipient,
object_ref,
},
))
}

async fn create_move_call_transaction_kind(
Expand Down Expand Up @@ -1052,7 +1054,7 @@ where
));
}

async fn transfer_coin(
async fn public_transfer_object(
&self,
signer: SuiAddress,
object_id: ObjectID,
Expand All @@ -1061,12 +1063,12 @@ where
recipient: SuiAddress,
) -> Result<TransactionData, anyhow::Error> {
let mut used_object_ids = BTreeSet::new();
let params = TransferCoinParams {
let params = PublicTransferObjectParams {
recipient,
object_id,
};
let kind = TransactionKind::Single(
self.create_transfer_coin_transaction_kind(params, &mut used_object_ids)
self.create_public_transfer_object_transaction_kind(params, &mut used_object_ids)
.await?,
);
let gas_payment = self
Expand Down Expand Up @@ -1108,8 +1110,8 @@ where
let mut used_object_ids = BTreeSet::new();
for param in single_transaction_params {
let kind = match param {
RPCTransactionRequestParams::TransferCoinRequestParams(t) => {
self.create_transfer_coin_transaction_kind(t, &mut used_object_ids)
RPCTransactionRequestParams::PublicTransferObjectRequestParams(t) => {
self.create_public_transfer_object_transaction_kind(t, &mut used_object_ids)
.await?
}
RPCTransactionRequestParams::MoveCallRequestParams(m) => {
Expand Down
4 changes: 2 additions & 2 deletions crates/sui-core/src/transaction_input_checker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ where
.kind
.single_transactions()
.filter_map(|s| {
if let SingleTransactionKind::TransferCoin(t) = s {
if let SingleTransactionKind::PublicTransferObject(t) = s {
Some(t.object_ref.0)
} else {
None
Expand All @@ -238,7 +238,7 @@ where
}
};
if transfer_object_ids.contains(&object.id()) {
object.is_transfer_eligible()?;
object.ensure_public_transfer_eligible()?;
}
// Check if the object contents match the type of lock we need for
// this object.
Expand Down
4 changes: 2 additions & 2 deletions crates/sui-core/src/unit_tests/authority_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ async fn test_handle_shared_object_with_max_sequence_number() {
use sui_types::object::MoveObject;

let content = GasCoin::new(shared_object_id, SequenceNumber::MAX, 10);
let obj = MoveObject::new(/* type */ GasCoin::type_(), content.to_bcs_bytes());
let obj = MoveObject::new_gas_coin(content.to_bcs_bytes());
Object::new_move(obj, Owner::Shared, TransactionDigest::genesis())
};
let authority = init_state_with_objects(vec![gas_object, shared_object]).await;
Expand Down Expand Up @@ -1791,7 +1791,7 @@ async fn shared_object() {
use sui_types::object::MoveObject;

let content = GasCoin::new(shared_object_id, OBJECT_START_VERSION, 10);
let obj = MoveObject::new(/* type */ GasCoin::type_(), content.to_bcs_bytes());
let obj = MoveObject::new_gas_coin(content.to_bcs_bytes());
Object::new_move(obj, Owner::Shared, TransactionDigest::genesis())
};

Expand Down
36 changes: 20 additions & 16 deletions crates/sui-core/src/unit_tests/batch_transaction_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,16 @@ async fn test_batch_transaction_ok() -> anyhow::Result<()> {
init_state_with_ids([sender; TOTAL].into_iter().zip(all_ids.clone().into_iter())).await;
let mut transactions = vec![];
for obj_id in all_ids.iter().take(N) {
transactions.push(SingleTransactionKind::TransferCoin(TransferCoin {
recipient,
object_ref: authority_state
.get_object(obj_id)
.await?
.unwrap()
.compute_object_reference(),
}));
transactions.push(SingleTransactionKind::PublicTransferObject(
PublicTransferObject {
recipient,
object_ref: authority_state
.get_object(obj_id)
.await?
.unwrap()
.compute_object_reference(),
},
));
}
let package_object_ref = authority_state.get_framework_object_ref().await?;
for _ in 0..N {
Expand Down Expand Up @@ -94,14 +96,16 @@ async fn test_batch_transaction_last_one_fail() -> anyhow::Result<()> {
init_state_with_ids([sender; TOTAL].into_iter().zip(all_ids.clone().into_iter())).await;
let mut transactions = vec![];
for obj_id in all_ids.iter().take(N) {
transactions.push(SingleTransactionKind::TransferCoin(TransferCoin {
recipient,
object_ref: authority_state
.get_object(obj_id)
.await?
.unwrap()
.compute_object_reference(),
}));
transactions.push(SingleTransactionKind::PublicTransferObject(
PublicTransferObject {
recipient,
object_ref: authority_state
.get_object(obj_id)
.await?
.unwrap()
.compute_object_reference(),
},
));
}
let package_object_ref = authority_state.get_framework_object_ref().await?;
transactions.push(SingleTransactionKind::Call(MoveCall {
Expand Down
2 changes: 1 addition & 1 deletion crates/sui-core/src/unit_tests/consensus_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ pub fn test_shared_object() -> Object {
let seed = "0x6666666666666660";
let shared_object_id = ObjectID::from_hex_literal(seed).unwrap();
let content = GasCoin::new(shared_object_id, OBJECT_START_VERSION, 10);
let obj = MoveObject::new(/* type */ GasCoin::type_(), content.to_bcs_bytes());
let obj = MoveObject::new_gas_coin(content.to_bcs_bytes());
Object::new_move(obj, Owner::Shared, TransactionDigest::genesis())
}

Expand Down
8 changes: 3 additions & 5 deletions crates/sui-core/src/unit_tests/event_handler_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
use move_core_types::account_address::AccountAddress;
use move_core_types::identifier::Identifier;

use move_core_types::value::MoveStruct;
use move_core_types::{
ident_str,
language_storage::StructTag,
Expand All @@ -17,7 +18,6 @@ use serde_json::json;
use crate::event_handler::to_json_value;
use sui_types::base_types::{ObjectID, SequenceNumber};
use sui_types::gas_coin::GasCoin;
use sui_types::object::MoveObject;
use sui_types::SUI_FRAMEWORK_ADDRESS;

#[test]
Expand All @@ -33,12 +33,10 @@ fn test_to_json_value() {
],
};
let event_bytes = bcs::to_bytes(&move_event).unwrap();
let move_object = MoveObject::new(TestEvent::type_(), event_bytes);
let move_struct = move_object
.to_move_struct(&TestEvent::layout())
let sui_move_struct = MoveStruct::simple_deserialize(&event_bytes, &TestEvent::layout())
.unwrap()
.into();
let json_value = to_json_value(move_struct).unwrap();
let json_value = to_json_value(sui_move_struct).unwrap();

assert_eq!(
Some(&json!(1000000)),
Expand Down
10 changes: 6 additions & 4 deletions crates/sui-core/src/unit_tests/gas_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -508,10 +508,12 @@ async fn execute_transfer_with_price(
.unwrap()
.unwrap();

let kind = TransactionKind::Single(SingleTransactionKind::TransferCoin(TransferCoin {
recipient,
object_ref: object.compute_object_reference(),
}));
let kind = TransactionKind::Single(SingleTransactionKind::PublicTransferObject(
PublicTransferObject {
recipient,
object_ref: object.compute_object_reference(),
},
));
let data =
TransactionData::new_with_gas_price(kind, sender, gas_object_ref, gas_budget, gas_price);
let signature = Signature::new(&data, &sender_key);
Expand Down
Loading

0 comments on commit fa16180

Please sign in to comment.