Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support list fields for object.move #3142

Merged
merged 33 commits into from
Jan 5, 2025
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
e041dd1
feat: support list fields for object.move
lispking Dec 31, 2024
71ebff9
Merge branch 'main' into object-support-list
lispking Dec 31, 2024
eba4105
fix UNKNOWN_INVARIANT_VIOLATION_ERROR
jolestar Jan 2, 2025
14a510b
Merge branch 'main' into object-support-list
lispking Jan 2, 2025
4680640
rename list_fields to list_field_names
lispking Jan 2, 2025
c87f419
fix native return types
jolestar Jan 2, 2025
fe8df10
make code tidy
lispking Jan 2, 2025
f876e1b
make code tidy
lispking Jan 2, 2025
08137bb
make code tidy
lispking Jan 2, 2025
7a2bfe0
support cursor and limit for list_field_keys
lispking Jan 3, 2025
40e719f
update object list_field_keys gas handle and adjust fetch data from db
lispking Jan 3, 2025
7dd4cb1
Merge branch 'main' into object-support-list
lispking Jan 3, 2025
2efe903
make code tidy
lispking Jan 3, 2025
66b468e
Merge branch 'main' into object-support-list
lispking Jan 3, 2025
ba929a6
update native_list_field_keys default value to 0
lispking Jan 3, 2025
1686dac
check is_empty that before add native_list_field_keys
lispking Jan 3, 2025
9684834
update is_empty for ListFieldsGasParametersOption
lispking Jan 3, 2025
11d3ed1
fix review notes
lispking Jan 4, 2025
0de2426
fix lint
lispking Jan 4, 2025
9867ccd
add list_field_keys for table and add rooch-framework-tests
lispking Jan 4, 2025
455c446
update ut assert value
lispking Jan 4, 2025
3488bfa
update list_field_keys of table notes
lispking Jan 4, 2025
4688189
add length ut for list_field_keys
lispking Jan 4, 2025
d387871
add more ut for list_field_keys
lispking Jan 4, 2025
5d400a4
make ut tidy
lispking Jan 4, 2025
3840b28
add iterator for table
lispking Jan 4, 2025
9738258
fix next/next_mut for table issue
lispking Jan 4, 2025
3028208
update borrow_field_key_internal and borrow_mut_field_key_internal notes
lispking Jan 4, 2025
1962a0e
add How to test move contract? notes
lispking Jan 4, 2025
cda0f0b
update borrow_field_key_internal and borrow_mut_field_key_internal notes
lispking Jan 4, 2025
c951e0c
update review notes
lispking Jan 4, 2025
b647253
update review notes
lispking Jan 4, 2025
ca62697
Merge branch 'main' into object-support-list
lispking Jan 4, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion crates/rooch-genesis/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use move_vm_runtime::native_functions::NativeFunction;
use moveos::gas::table::VMGasParameters;
use moveos::moveos::{MoveOS, MoveOSConfig};
use moveos_stdlib::natives::moveos_stdlib::base64::EncodeDecodeGasParametersOption;
use moveos_stdlib::natives::moveos_stdlib::object::ListFieldsGasParametersOption;
use moveos_store::MoveOSStore;
use moveos_types::genesis_info::GenesisInfo;
use moveos_types::h256::H256;
Expand Down Expand Up @@ -162,8 +163,20 @@ impl FrameworksGasParameters {
v1_gas_parameter
}

pub fn v3() -> Self {
let mut v2_gas_parameter = FrameworksGasParameters::v2();

v2_gas_parameter
.rooch_framework_gas_params
.moveos_stdlib
.object_list_field_keys
.list_field_keys = ListFieldsGasParametersOption::init(1000.into(), 150.into());

v2_gas_parameter
}

pub fn latest() -> Self {
FrameworksGasParameters::v2()
FrameworksGasParameters::v3()
}

pub fn to_gas_schedule_config(&self, chain_id: ChainID) -> GasScheduleConfig {
Expand Down
1 change: 1 addition & 0 deletions frameworks/moveos-stdlib/doc/object.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ For more details, please refer to https://rooch.network/docs/developer-guides/ob


<pre><code><b>use</b> <a href="">0x1::hash</a>;
<b>use</b> <a href="">0x1::option</a>;
<b>use</b> <a href="">0x1::string</a>;
<b>use</b> <a href="">0x1::vector</a>;
<b>use</b> <a href="address.md#0x2_address">0x2::address</a>;
Expand Down
54 changes: 47 additions & 7 deletions frameworks/moveos-stdlib/sources/object.move
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
/// For more details, please refer to https://rooch.network/docs/developer-guides/object
module moveos_std::object {
use std::hash;
use std::option::Option;
use std::vector;
use moveos_std::signer;
use moveos_std::tx_context;
Expand Down Expand Up @@ -40,7 +41,7 @@ module moveos_std::object {
const ErrorTypeMismatch: u64 = 10;
/// The child object level is too deep
const ErrorChildObjectTooDeep: u64 = 11;
/// The object has no parent
/// The object has no parent
const ErrorWithoutParent: u64 = 12;
/// The parent object is not match
const ErrorParentNotMatch: u64 = 13;
Expand Down Expand Up @@ -138,10 +139,10 @@ module moveos_std::object {
let child = derive_object_key<ID, T>(id);
let path = parent_id.path;
vector::push_back(&mut path, child);
ObjectID { path }
ObjectID { path }
}

/// Object<T> is a pointer type to the Object in storage, It has `key` and `store` ability.
/// Object<T> is a pointer type to the Object in storage, It has `key` and `store` ability.
struct Object<phantom T> has key, store {
id: ObjectID,
}
Expand Down Expand Up @@ -291,7 +292,7 @@ module moveos_std::object {
}

/// Remove the object from the global storage, and return the object value
/// Do not check if the dynamic fields are empty
/// Do not check if the dynamic fields are empty
public(friend) fun remove_unchecked<T: key>(self: Object<T>): T {
let Object{id} = self;
let (parent, key) = into_parent_id_and_key(id);
Expand Down Expand Up @@ -472,7 +473,7 @@ module moveos_std::object {
let DynamicField { name:_, value } = native_remove_field<DynamicField<Name, Value>>(obj_id, key);
value
}

/// Returns true if `object` contains an field for `key`, include normal field and object field
public fun contains_field<T: key, Name: copy + drop + store>(obj: &Object<T>, name: Name): bool {
contains_field_internal<Name>(obj.id, name)
Expand All @@ -494,6 +495,11 @@ module moveos_std::object {
native_object_size(obj.id)
}

/// List all field names of the object
fun list_field_keys<T: key>(obj: &Object<T>, cursor: Option<address>, limit: u64): vector<address> {
lispking marked this conversation as resolved.
Show resolved Hide resolved
native_list_field_keys(obj.id, cursor, limit)
}


// ====== Utility functions ======

Expand Down Expand Up @@ -538,7 +544,7 @@ module moveos_std::object {
native fun native_transfer_object<T: key>(obj: Object<T>, new_owner: address);

native fun native_to_shared_object<T: key>(obj: Object<T>);

native fun native_to_frozen_object<T: key>(obj: Object<T>);

native fun native_borrow_object<T: key>(object_id: ObjectID): &Object<T>;
Expand All @@ -562,6 +568,8 @@ module moveos_std::object {

native fun native_remove_field<V>(obj_id: ObjectID, key: address): V;

native fun native_list_field_keys(obj_id: ObjectID, cursor: Option<address>, limit: u64): vector<address>;

#[test_only]
/// Testing only: allows to drop a Object even if it's fields is not empty.
public fun drop_unchecked<T: key>(self: Object<T>): T {
Expand Down Expand Up @@ -752,7 +760,7 @@ module moveos_std::object {
let _obj = borrow_mut_object<TestStruct>(alice, object_id);
};

// borrow_mut_object by non-owner failed
// borrow_mut_object by non-owner failed
{
let _obj = borrow_mut_object<TestStruct>(bob, object_id);
};
Expand Down Expand Up @@ -990,4 +998,36 @@ module moveos_std::object {
//test address
field_key_derive_test(@0x1, @0x07d29b5cffb95d39f98baed1a973e676891bc9d379022aba6f4a2e4912a5e552);
}

#[test]
fun test_list_fields(){
use std::option;
let obj = new(TestStruct { count: 1 });
add_field(&mut obj, b"key1", 1u64);
add_field(&mut obj, b"key2", 2u64);

assert!(field_size(&obj) == 2, 1000);

let field_keys = list_field_keys<TestStruct>(&obj, option::none(), 10);
std::debug::print(&field_keys);

assert!(!vector::is_empty(&field_keys), 1001);
assert!(vector::length(&field_keys) == 2, 1002);

let field_key1 = *vector::borrow(&field_keys, 0);
std::debug::print(&field_key1);

let field1 = native_borrow_field<DynamicField<vector<u8>, u64>>(obj.id, field_key1);
assert!(field1.name == b"key1", 1003);
assert!(field1.value == 1u64, 1004);

let field_key2 = *vector::borrow(&field_keys, 1);
std::debug::print(&field_key2);

let field2 = native_borrow_field<DynamicField<vector<u8>, u64>>(obj.id, field_key2);
assert!(field2.name == b"key2", 1005);
assert!(field2.value == 2u64, 1006);

let TestStruct{ count: _} = drop_unchecked(obj);
}
}
2 changes: 2 additions & 0 deletions frameworks/moveos-stdlib/src/natives/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ pub struct GasParameters {
pub bls12381: moveos_stdlib::bls12381::GasParameters,
pub evm: moveos_stdlib::evm::GasParameters,
pub groth16: moveos_stdlib::groth16::GasParameters,
pub object_list_field_keys: moveos_stdlib::object::ListFieldsGasParameters,
}

impl GasParameters {
Expand All @@ -91,6 +92,7 @@ impl GasParameters {
bls12381: moveos_stdlib::bls12381::GasParameters::zeros(),
evm: moveos_stdlib::evm::GasParameters::zeros(),
groth16: moveos_stdlib::groth16::GasParameters::zeros(),
object_list_field_keys: moveos_stdlib::object::ListFieldsGasParameters::zeros(),
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ mod object_field_fn;
mod object_fn;
mod object_meta_fn;

pub use object_field_fn::{ListFieldsGasParameters, ListFieldsGasParametersOption};

#[derive(Debug, Clone)]
pub struct CommonGasParameters {
pub load_base: InternalGas,
Expand Down Expand Up @@ -108,6 +110,7 @@ pub struct GasParameters {
pub native_contains_field: ContainsFieldGasParameters,
pub native_contains_field_with_value_type: ContainsFieldGasParameters,
pub native_remove_field: RemoveFieldGasParameters,
pub native_list_field_keys: ListFieldsGasParameters,
}

impl GasParameters {
Expand Down Expand Up @@ -144,6 +147,7 @@ impl GasParameters {
base: 0.into(),
per_byte_serialized: 0.into(),
},
native_list_field_keys: ListFieldsGasParameters::zeros(),
}
}
}
Expand Down Expand Up @@ -218,6 +222,10 @@ pub fn make_all(gas_params: GasParameters) -> impl Iterator<Item = (String, Nati
"native_contains_field_with_value_type",
helpers::make_native(gas_params.clone(), native_contains_field_with_value_type),
),
(
"native_list_field_keys",
helpers::make_native(gas_params.clone(), native_list_field_keys),
),
];

make_module_natives(natives)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
// Copyright (c) RoochNetwork
// SPDX-License-Identifier: Apache-2.0

use move_binary_format::errors::PartialVMResult;
use move_binary_format::errors::{PartialVMError, PartialVMResult};
use move_core_types::gas_algebra::{GasQuantity, InternalGasUnit};
use move_core_types::{
account_address::AccountAddress,
gas_algebra::{InternalGas, InternalGasPerByte, NumBytes},
vm_status::StatusCode,
};
use move_vm_runtime::native_functions::NativeContext;
use move_vm_types::{
Expand All @@ -22,7 +23,8 @@ use moveos_object_runtime::{
};
use moveos_types::moveos_std::onchain_features::VALUE_SIZE_GAS_FEATURE;
use moveos_types::{
moveos_std::object::ObjectID, state::FieldKey, state_resolver::StatelessResolver,
move_std::option::MoveOption, moveos_std::object::ObjectID, state::FieldKey, state::MoveState,
state_resolver::StatelessResolver,
};

/***************************************************************************************************
Expand Down Expand Up @@ -244,6 +246,104 @@ pub(crate) fn native_remove_field(
)
}

/***************************************************************************************************
* native fun native_list_field_keys(obj_id: ObjectID, cursor: Option<address>, limit: u64): vector<address>;
**************************************************************************************************/
#[derive(Debug, Clone)]
pub struct ListFieldsGasParametersOption {
pub base: Option<InternalGas>,
pub per_byte: Option<InternalGasPerByte>,
}

impl ListFieldsGasParametersOption {
pub fn zeros() -> Self {
Self {
base: Some(0.into()),
per_byte: Some(0.into()),
}
}

pub fn init(base: InternalGas, per_byte: InternalGasPerByte) -> Self {
Self {
base: Some(base),
per_byte: Some(per_byte),
}
}

fn calculate_load_cost(&self, loaded: Option<Option<NumBytes>>) -> InternalGas {
match loaded {
Some(Some(num_bytes)) => {
self.per_byte.unwrap_or_else(InternalGasPerByte::zero) * num_bytes
}
Some(None) => 0.into(),
None => 0.into(),
}
}
}

#[derive(Debug, Clone)]
pub struct ListFieldsGasParameters {
pub list_field_keys: ListFieldsGasParametersOption,
}

impl ListFieldsGasParameters {
pub fn zeros() -> Self {
Self {
list_field_keys: ListFieldsGasParametersOption::zeros(),
}
}
}

pub(crate) fn native_list_field_keys(
gas_parameters: &GasParameters,
context: &mut NativeContext,
ty_args: Vec<Type>,
mut args: VecDeque<Value>,
) -> PartialVMResult<NativeResult> {
debug_assert_eq!(ty_args.len(), 0);
debug_assert_eq!(args.len(), 3);

let limit = pop_arg!(args, u64);
let cursor_arg = args.pop_back().expect("cursor is missing");
let obj_id = pop_object_id(&mut args)?;

let cursor_address: Option<AccountAddress> = MoveOption::from_runtime_value(cursor_arg)
.map_err(|e| {
PartialVMError::new(StatusCode::UNKNOWN_INVARIANT_VIOLATION_ERROR)
.with_message(format!("Failed to parse cursor: {}", e))
})?
.into();
let cursor: Option<FieldKey> = cursor_address.map(|addr| addr.into());

let gas_params = gas_parameters
.native_list_field_keys
.list_field_keys
.clone();

let object_context = context.extensions().get::<ObjectRuntimeContext>();
let binding = object_context.object_runtime();
let mut object_runtime = binding.write();
let resolver = object_runtime.resolver();
let (rt_obj, object_load_gas) = object_runtime.load_object(context, &obj_id)?;
let field_key_bytes = AccountAddress::LENGTH as u64;
let gas_cost = gas_params.base.unwrap_or_else(InternalGas::zero)
+ (gas_params.per_byte.unwrap_or_else(InternalGasPerByte::zero)
* NumBytes::new(field_key_bytes))
+ gas_params.calculate_load_cost(object_load_gas);

let result = rt_obj.list_field_keys(resolver, cursor, limit as usize);
match result {
Ok((field_keys, field_load_gas)) => Ok(NativeResult::ok(
gas_cost + gas_params.calculate_load_cost(field_load_gas),
smallvec![Value::vector_address(field_keys)],
)),
Err(err) => {
let abort_code = error_to_abort_code(err);
Ok(NativeResult::err(gas_cost, abort_code))
}
}
}

fn object_field_fn_dispatch(
common_gas_params: &CommonGasParameters,
base: InternalGas,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ pub mod move_std;
pub mod native;
pub mod nursery;
mod object;
mod object_list_field_keys;
mod rlp;
mod signer;
mod test_helper;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// Copyright (c) RoochNetwork
// SPDX-License-Identifier: Apache-2.0

use crate::natives::gas_parameter::native::MUL;
use moveos_stdlib::natives::moveos_stdlib::object::ListFieldsGasParameters;

crate::natives::gas_parameter::native::define_gas_parameters_for_natives!(ListFieldsGasParameters, "native_list_field_keys", [
[.list_field_keys.base, optional "list_field_keys.base", 1000 * MUL],
[.list_field_keys.per_byte, optional "list_field_keys.per_byte", 150 * MUL],
lispking marked this conversation as resolved.
Show resolved Hide resolved
]);
6 changes: 6 additions & 0 deletions frameworks/rooch-framework/src/natives/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,10 @@ impl FromOnChainGasSchedule for MoveOSStdlibGasParameters {
bls12381: FromOnChainGasSchedule::from_on_chain_gas_schedule(gas_schedule).unwrap(),
evm: FromOnChainGasSchedule::from_on_chain_gas_schedule(gas_schedule).unwrap(),
groth16: FromOnChainGasSchedule::from_on_chain_gas_schedule(gas_schedule).unwrap(),
object_list_field_keys: FromOnChainGasSchedule::from_on_chain_gas_schedule(
gas_schedule,
)
.unwrap(),
})
}
}
Expand Down Expand Up @@ -116,6 +120,7 @@ impl ToOnChainGasSchedule for MoveOSStdlibGasParameters {
entires.extend(self.bls12381.to_on_chain_gas_schedule());
entires.extend(self.evm.to_on_chain_gas_schedule());
entires.extend(self.groth16.to_on_chain_gas_schedule());
entires.extend(self.object_list_field_keys.to_on_chain_gas_schedule());
entires
}
}
Expand Down Expand Up @@ -144,6 +149,7 @@ impl InitialGasSchedule for MoveOSStdlibGasParameters {
bls12381: InitialGasSchedule::initial(),
evm: InitialGasSchedule::initial(),
groth16: InitialGasSchedule::initial(),
object_list_field_keys: InitialGasSchedule::initial(),
}
}
}
Expand Down
Loading
Loading