From 35fa4d398d78a452b0a1275efd9b90174a8fddb7 Mon Sep 17 00:00:00 2001 From: Xun Li Date: Thu, 27 Jan 2022 13:40:56 -0800 Subject: [PATCH] Add trasfer_to_object API in Transfer.move --- fastx_programmability/adapter/src/adapter.rs | 25 +++++++---- .../framework/sources/Transfer.move | 17 ++++---- fastx_programmability/framework/src/lib.rs | 6 ++- .../framework/src/natives/mod.rs | 5 +++ .../framework/src/natives/transfer.rs | 41 +++++++++++++++---- 5 files changed, 67 insertions(+), 27 deletions(-) diff --git a/fastx_programmability/adapter/src/adapter.rs b/fastx_programmability/adapter/src/adapter.rs index 95f8e112be420..64b03fcc9b231 100644 --- a/fastx_programmability/adapter/src/adapter.rs +++ b/fastx_programmability/adapter/src/adapter.rs @@ -333,8 +333,8 @@ fn process_successful_execution< match EventType::try_from(event_type as u8) .expect("Safe because event_type is derived from an EventType enum") { - EventType::Transfer => handle_transfer( - recipient, + EventType::TransferToAddress => handle_transfer( + Authenticator::Address(FastPayAddress::try_from(recipient.borrow()).unwrap()), type_, event_bytes, false, /* should_freeze */ @@ -343,8 +343,8 @@ fn process_successful_execution< &mut gas_used, state_view, ), - EventType::TransferAndFreeze => handle_transfer( - recipient, + EventType::TransferToAddressAndFreeze => handle_transfer( + Authenticator::Address(FastPayAddress::try_from(recipient.borrow()).unwrap()), type_, event_bytes, true, /* should_freeze */ @@ -353,6 +353,16 @@ fn process_successful_execution< &mut gas_used, state_view, ), + EventType::TransferToObject => handle_transfer( + Authenticator::Object(ObjectID::try_from(recipient.borrow()).unwrap()), + type_, + event_bytes, + false, /* should_freeze */ + tx_digest, + &mut by_value_objects, + &mut gas_used, + state_view, + ), EventType::User => match type_ { TypeTag::Struct(s) => state_view.log_event(Event::new(s, event_bytes)), _ => unreachable!( @@ -380,7 +390,7 @@ fn handle_transfer< E: Debug, S: ResourceResolver + ModuleResolver + Storage, >( - recipient: Vec, + recipient: Authenticator, type_: TypeTag, contents: Vec, should_freeze: bool, @@ -389,11 +399,8 @@ fn handle_transfer< gas_used: &mut u64, state_view: &mut S, ) { - debug_assert!(!recipient.is_empty()); match type_ { TypeTag::Struct(s_type) => { - // unwrap safe due to size enforcement in Move code for `Authenticator - let recipient = FastPayAddress::try_from(recipient.borrow()).unwrap(); let mut move_obj = MoveObject::new(s_type, contents); let old_object = by_value_objects.remove(&move_obj.id()); @@ -409,7 +416,7 @@ fn handle_transfer< if should_freeze { move_obj.freeze(); } - let obj = Object::new_move(move_obj, Authenticator::Address(recipient), tx_digest); + let obj = Object::new_move(move_obj, recipient, tx_digest); if old_object.is_none() { // Charge extra gas based on object size if we are creating a new object. *gas_used += gas::calculate_object_creation_cost(&obj); diff --git a/fastx_programmability/framework/sources/Transfer.move b/fastx_programmability/framework/sources/Transfer.move index df4b53e83b07a..90512c5ac5e74 100644 --- a/fastx_programmability/framework/sources/Transfer.move +++ b/fastx_programmability/framework/sources/Transfer.move @@ -1,6 +1,6 @@ module FastX::Transfer { use FastX::Address::{Self, Address}; - //use FastX::ID::IDBytes; + use FastX::ID::{Self, IDBytes}; /// Transfers are implemented by emitting a /// special `TransferEvent` that the fastX adapter @@ -33,11 +33,12 @@ module FastX::Transfer { native fun transfer_internal(obj: T, recipient: vector, should_freeze: bool); - /*/// Transfer ownership of `obj` to another object `id`. Afterward, `obj` - /// can only be used in a transaction that also includes the object with - /// `id`. - /// WARNING: Use with caution. Improper use can create ownership cycles - /// between objects, which will cause all objects involved in the cycle to - /// be locked. - public native fun transfer_to_id(obj: T, id: IDBytes);*/ + /// Transfer ownership of `obj` to another object `owner`. + // TODO: Add option to freeze after transfer. + public fun transfer_to_object(obj: T, owner: &mut R) { + transfer_to_object_id(obj, *ID::get_id_bytes(owner)); + } + + /// Transfer ownership of `obj` to another object with `id`. + native fun transfer_to_object_id(obj: T, id: IDBytes); } diff --git a/fastx_programmability/framework/src/lib.rs b/fastx_programmability/framework/src/lib.rs index 26a622e74b2d5..d0757d10ce4dc 100644 --- a/fastx_programmability/framework/src/lib.rs +++ b/fastx_programmability/framework/src/lib.rs @@ -20,9 +20,11 @@ const MAX_UNIT_TEST_INSTRUCTIONS: u64 = 100_000; #[repr(u8)] pub enum EventType { /// System event: transfer between addresses - Transfer, + TransferToAddress, /// System event: freeze, then transfer between addresses - TransferAndFreeze, + TransferToAddressAndFreeze, + /// System event: transfer object to another object + TransferToObject, /// User-defined event User, } diff --git a/fastx_programmability/framework/src/natives/mod.rs b/fastx_programmability/framework/src/natives/mod.rs index d4cc783c17e99..cf4a0b5ab2d16 100644 --- a/fastx_programmability/framework/src/natives/mod.rs +++ b/fastx_programmability/framework/src/natives/mod.rs @@ -17,6 +17,11 @@ pub fn all_natives( ("Event", "emit", event::emit), ("ID", "bytes_to_address", id::bytes_to_address), ("Transfer", "transfer_internal", transfer::transfer_internal), + ( + "Transfer", + "transfer_to_object_id", + transfer::transfer_to_object_id, + ), ("TxContext", "fresh_id", tx_context::fresh_id), ]; FASTX_NATIVES diff --git a/fastx_programmability/framework/src/natives/transfer.rs b/fastx_programmability/framework/src/natives/transfer.rs index 637a7cb2b138c..e877553f1eb0c 100644 --- a/fastx_programmability/framework/src/natives/transfer.rs +++ b/fastx_programmability/framework/src/natives/transfer.rs @@ -15,12 +15,12 @@ use smallvec::smallvec; use std::collections::VecDeque; /// Implementation of Move native function -/// `transfer_internal(event: TransferEvent)` +/// `transfer_internal(obj: T, recipient: vector, should_freeze: bool)` /// Here, we simply emit this event. The fastX adapter /// treats this as a special event that is handled -/// differently from user events--for each `TransferEvent`, +/// differently from user events: /// the adapter will change the owner of the object -/// in question to `TransferEvent.recipient` +/// in question to `recipient`. pub fn transfer_internal( context: &mut NativeContext, mut ty_args: Vec, @@ -33,19 +33,44 @@ pub fn transfer_internal( let should_freeze = pop_arg!(args, bool); let recipient = pop_arg!(args, Vec); let transferred_obj = args.pop_back().unwrap(); - let event_type = if should_freeze { - EventType::TransferAndFreeze + EventType::TransferToAddressAndFreeze } else { - EventType::Transfer - } as u64; + EventType::TransferToAddress + }; + transfer_common(context, ty, transferred_obj, recipient, event_type) +} + +/// Implementation of Move native function +/// `transfer_to_object_id(obj: T, id: IDBytes)` +pub fn transfer_to_object_id( + context: &mut NativeContext, + mut ty_args: Vec, + mut args: VecDeque, +) -> PartialVMResult { + debug_assert!(ty_args.len() == 1); + debug_assert!(args.len() == 2); + + let ty = ty_args.pop().unwrap(); + let recipient = pop_arg!(args, Vec); + let transferred_obj = args.pop_back().unwrap(); + let event_type = EventType::TransferToObject; + transfer_common(context, ty, transferred_obj, recipient, event_type) +} +fn transfer_common( + context: &mut NativeContext, + ty: Type, + transferred_obj: Value, + recipient: Vec, + event_type: EventType, +) -> PartialVMResult { // Charge a constant native gas cost here, since // we will charge it properly when processing // all the events in adapter. // TODO: adjust native_gas cost size base. let cost = native_gas(context.cost_table(), NativeCostIndex::EMIT_EVENT, 1); - if !context.save_event(recipient, event_type, ty, transferred_obj)? { + if !context.save_event(recipient, event_type as u64, ty, transferred_obj)? { return Ok(NativeResult::err(cost, 0)); }