Skip to content

Commit

Permalink
fix: aptos compatibility + json & event natives (#109)
Browse files Browse the repository at this point in the history
* add functions for compatibility

* fix lint

* fix lint

* fix json and eventg

* add test for minstdlib

* fix test
  • Loading branch information
beer-1 authored Aug 16, 2024
1 parent c8db08b commit 1ee3ce4
Show file tree
Hide file tree
Showing 15 changed files with 154 additions and 16 deletions.
8 changes: 8 additions & 0 deletions crates/json/src/json_to_value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,14 @@ pub fn convert_json_value_to_value(
}
Struct(layout) => match layout {
WithTypes { fields, type_ } => {
// The move compiler inserts a dummy field with the value of false
// for structs with no fields.
if fields.len() == 1 && fields[0].name.as_str() == "dummy_field" {
return Ok(Value::struct_(Struct::pack(vec![
Value::bool(false)
])));
}

let full_name =
format!("{}::{}", type_.module_id().short_str_lossless(), type_.name);
match full_name.as_str() {
Expand Down
12 changes: 12 additions & 0 deletions crates/json/src/move_to_json.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,12 @@ fn convert_move_value_to_json_value(val: &MoveValue, depth: usize) -> VMResult<J
Ok(JSONValue::Array(fields_array))
}
MoveStruct::WithFields(fields) | MoveStruct::WithVariantFields(_, _, fields) => {
// The move compiler inserts a dummy field with the value of false
// for structs with no fields.
if fields.len() == 1 && fields[0].0.as_str() == "dummy_field" {
return Ok(JSONValue::Object(Map::new()));
}

let mut fields_map: Map<String, JSONValue> = Map::new();
for (id, mv) in fields.iter() {
let value = convert_move_value_to_json_value(mv, depth + 1)?;
Expand All @@ -68,6 +74,12 @@ fn convert_move_value_to_json_value(val: &MoveValue, depth: usize) -> VMResult<J
Ok(JSONValue::Object(fields_map))
}
MoveStruct::WithTypes { type_, fields } => {
// The move compiler inserts a dummy field with the value of false
// for structs with no fields.
if fields.len() == 1 && fields[0].0.as_str() == "dummy_field" {
return Ok(JSONValue::Object(Map::new()));
}

// check the struct type is string
// if yes, then convert move value to json string
// else, execute convert function recursively
Expand Down
36 changes: 26 additions & 10 deletions crates/natives/src/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ const EUNABLE_TO_EMIT_EVENT_DELAYED_FIELD: u64 = (ECATEGORY_INVALID_ARGUMENT <<
#[derive(Default, Tid)]
pub struct NativeEventContext {
events: Vec<(ContractEvent, MoveTypeLayout)>,

#[cfg(feature = "testing")]
events_for_testing: Vec<(Vec<u8>, TypeTag)>,
}

impl NativeEventContext {
Expand All @@ -35,11 +38,11 @@ impl NativeEventContext {
}

#[cfg(feature = "testing")]
fn emitted_events(&self, ty_tag: &TypeTag) -> Vec<(&str, &MoveTypeLayout)> {
let mut events = vec![];
for (event, ty_layout) in self.events.iter() {
if event.type_tag() == ty_tag {
events.push((event.event_data(), ty_layout));
fn emitted_events(&self, ty_tag: &TypeTag) -> Vec<&[u8]> {
let mut events: Vec<&[u8]> = vec![];
for (data, tt) in self.events_for_testing.iter() {
if tt == ty_tag {
events.push(data);
}
}
events
Expand Down Expand Up @@ -116,6 +119,19 @@ fn native_emit_event(
})?;

let ctx = context.extensions_mut().get_mut::<NativeEventContext>();

// Cache the emitted event for testing.
#[cfg(feature = "testing")]
{
let blob = msg.simple_serialize(&layout).ok_or_else(|| {
SafeNativeError::InvariantViolation(PartialVMError::new(
StatusCode::VALUE_SERIALIZATION_ERROR,
))
})?;

ctx.events_for_testing.push((blob, type_tag.clone()));
}

ctx.events.push((
ContractEvent::new(type_tag, serde_value.to_string()),
annotated_layout,
Expand All @@ -130,18 +146,18 @@ fn native_emitted_events(
ty_args: Vec<Type>,
arguments: VecDeque<Value>,
) -> SafeNativeResult<SmallVec<[Value; 1]>> {
use initia_move_json::deserialize_json_to_value;

debug_assert!(ty_args.len() == 1);
debug_assert!(arguments.is_empty());

let ty_tag = context.type_to_type_tag(&ty_args[0])?;
let ty = &ty_args[0];
let ty_tag = context.type_to_type_tag(ty)?;
let ty_layout = context.type_to_type_layout(ty)?;
let ctx = context.extensions_mut().get_mut::<NativeEventContext>();
let events = ctx
.emitted_events(&ty_tag)
.into_iter()
.map(|(str, ty_layout)| {
deserialize_json_to_value(ty_layout, str.as_bytes()).map_err(|_| {
.map(|blob| {
Value::simple_deserialize(blob, &ty_layout).ok_or_else(|| {
SafeNativeError::InvariantViolation(PartialVMError::new(
StatusCode::VALUE_DESERIALIZATION_ERROR,
))
Expand Down
Binary file modified precompile/binaries/minlib/block.mv
Binary file not shown.
Binary file modified precompile/binaries/stdlib/block.mv
Binary file not shown.
7 changes: 7 additions & 0 deletions precompile/modules/initia_stdlib/sources/account.move
Original file line number Diff line number Diff line change
Expand Up @@ -398,4 +398,11 @@ module initia_std::account {
create_table_account(new_address);
create_object_account(new_address);
}

// functions for compatibility with the aptos

#[test_only]
public fun create_account_for_test(new_address: address): signer {
create_signer_for_test(new_address)
}
}
28 changes: 28 additions & 0 deletions precompile/modules/initia_stdlib/sources/block.move
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,32 @@ module initia_std::block {
assert!(height == 12321u64, 0);
assert!(timestamp == 9999999u64, 1);
}

// Functions for compatibility with the aptos

#[view]
public fun get_current_block_height(): u64 {
let (height, _) = get_block_info();
height
}

#[view]
public fun get_current_block_timestamp(): u64 {
let (_, timestamp) = get_block_info();
timestamp
}

#[test_only]
public fun initialize_for_test(
_vm: &signer, _epoch_interval_microsecs: u64
) {
// no-op
}

#[test_only]
public fun emit_writeset_block_event(
_vm: &signer, _fake_block_hash: address
) {
// no-op
}
}
4 changes: 1 addition & 3 deletions precompile/modules/initia_stdlib/sources/code.move
Original file line number Diff line number Diff line change
Expand Up @@ -177,9 +177,7 @@ module initia_std::code {
&mut registry.metadata, option::none(), option::none(), 1
);
loop {
if (!table::prepare_mut(iter)) {
break;
};
if (!table::prepare_mut(iter)) { break };

let (_, metadata) = table::next_mut(iter);
metadata.upgrade_policy = UPGRADE_POLICY_IMMUTABLE;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#[test_only]
module initia_std::reconfiguration {
public fun initialize_for_test(_: &signer) {
// no-op
}
}
12 changes: 12 additions & 0 deletions precompile/modules/initia_stdlib/sources/json.move
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,18 @@ module initia_std::json {
c: vector<u8>,
}

#[test_only]
struct EmptyObject has copy, drop {}

#[test]
fun test_empty_marshal_unmarshal_empty() {
let json = marshal(&EmptyObject{});
assert!(json == b"{}", 1);

let val = unmarshal<EmptyObject>(json);
assert!(val == EmptyObject{}, 2);
}

#[test]
fun test_marshal_unmarshal_u64() {
let json = marshal(&10u64);
Expand Down
7 changes: 7 additions & 0 deletions precompile/modules/minitia_stdlib/sources/account.move
Original file line number Diff line number Diff line change
Expand Up @@ -397,4 +397,11 @@ module minitia_std::account {
create_table_account(new_address);
create_object_account(new_address);
}

// functions for compatibility with the aptos

#[test_only]
public fun create_account_for_test(new_address: address): signer {
create_signer_for_test(new_address)
}
}
28 changes: 28 additions & 0 deletions precompile/modules/minitia_stdlib/sources/block.move
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,32 @@ module minitia_std::block {
assert!(height == 12321u64, 0);
assert!(timestamp == 9999999u64, 1);
}

// Functions for compatibility with the aptos

#[view]
public fun get_current_block_height(): u64 {
let (height, _) = get_block_info();
height
}

#[view]
public fun get_current_block_timestamp(): u64 {
let (_, timestamp) = get_block_info();
timestamp
}

#[test_only]
public fun initialize_for_test(
_vm: &signer, _epoch_interval_microsecs: u64
) {
// no-op
}

#[test_only]
public fun emit_writeset_block_event(
_vm: &signer, _fake_block_hash: address
) {
// no-op
}
}
4 changes: 1 addition & 3 deletions precompile/modules/minitia_stdlib/sources/code.move
Original file line number Diff line number Diff line change
Expand Up @@ -177,9 +177,7 @@ module minitia_std::code {
&mut registry.metadata, option::none(), option::none(), 1
);
loop {
if (!table::prepare_mut(iter)) {
break;
};
if (!table::prepare_mut(iter)) { break };

let (_, metadata) = table::next_mut(iter);
metadata.upgrade_policy = UPGRADE_POLICY_IMMUTABLE;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#[test_only]
module minitia_std::reconfiguration {
public fun initialize_for_test(_: &signer) {
// no-op
}
}
12 changes: 12 additions & 0 deletions precompile/modules/minitia_stdlib/sources/json.move
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,18 @@ module minitia_std::json {
c: vector<u8>,
}

#[test_only]
struct EmptyObject has copy, drop {}

#[test]
fun test_empty_marshal_unmarshal_empty() {
let json = marshal(&EmptyObject{});
assert!(json == b"{}", 1);

let val = unmarshal<EmptyObject>(json);
assert!(val == EmptyObject{}, 2);
}

#[test]
fun test_marshal_unmarshal_u64() {
let json = marshal(&10u64);
Expand Down

0 comments on commit 1ee3ce4

Please sign in to comment.