Skip to content

Commit

Permalink
Add trasfer_to_object API in Transfer.move
Browse files Browse the repository at this point in the history
  • Loading branch information
lxfind committed Jan 31, 2022
1 parent b8f6ea7 commit 35fa4d3
Show file tree
Hide file tree
Showing 5 changed files with 67 additions and 27 deletions.
25 changes: 16 additions & 9 deletions fastx_programmability/adapter/src/adapter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand All @@ -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 */
Expand All @@ -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!(
Expand Down Expand Up @@ -380,7 +390,7 @@ fn handle_transfer<
E: Debug,
S: ResourceResolver<Error = E> + ModuleResolver<Error = E> + Storage,
>(
recipient: Vec<u8>,
recipient: Authenticator,
type_: TypeTag,
contents: Vec<u8>,
should_freeze: bool,
Expand All @@ -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());

Expand All @@ -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);
Expand Down
17 changes: 9 additions & 8 deletions fastx_programmability/framework/sources/Transfer.move
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -33,11 +33,12 @@ module FastX::Transfer {

native fun transfer_internal<T: key>(obj: T, recipient: vector<u8>, 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<T: key>(obj: T, id: IDBytes);*/
/// Transfer ownership of `obj` to another object `owner`.
// TODO: Add option to freeze after transfer.
public fun transfer_to_object<T: key, R: key>(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<T: key>(obj: T, id: IDBytes);
}
6 changes: 4 additions & 2 deletions fastx_programmability/framework/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}
Expand Down
5 changes: 5 additions & 0 deletions fastx_programmability/framework/src/natives/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
41 changes: 33 additions & 8 deletions fastx_programmability/framework/src/natives/transfer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@ use smallvec::smallvec;
use std::collections::VecDeque;

/// Implementation of Move native function
/// `transfer_internal<T: key>(event: TransferEvent<T>)`
/// `transfer_internal<T: key>(obj: T, recipient: vector<u8>, 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<Type>,
Expand All @@ -33,19 +33,44 @@ pub fn transfer_internal(
let should_freeze = pop_arg!(args, bool);
let recipient = pop_arg!(args, Vec<u8>);
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<T: key>(obj: T, id: IDBytes)`
pub fn transfer_to_object_id(
context: &mut NativeContext,
mut ty_args: Vec<Type>,
mut args: VecDeque<Value>,
) -> PartialVMResult<NativeResult> {
debug_assert!(ty_args.len() == 1);
debug_assert!(args.len() == 2);

let ty = ty_args.pop().unwrap();
let recipient = pop_arg!(args, Vec<u8>);
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<u8>,
event_type: EventType,
) -> PartialVMResult<NativeResult> {
// 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));
}

Expand Down

0 comments on commit 35fa4d3

Please sign in to comment.