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 21 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
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
processed 5 tasks

task 1 'publish'. lines 3-45:
status EXECUTED

task 2 'run'. lines 47-66:
status EXECUTED

task 3 'run'. lines 68-87:
status EXECUTED

task 4 'run'. lines 89-113:
status EXECUTED
113 changes: 113 additions & 0 deletions crates/rooch-framework-tests/tests/cases/table/list_field_keys.move
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
//# init --addresses test=0x42

//# publish
module test::m {
use std::string::String;
use std::option;

use moveos_std::table::{Self, Table};

use moveos_std::object::ObjectID;
use moveos_std::object;

struct KVStore has store, key {
table: Table<String,vector<u8>>,
}

public fun make_kv_store(): KVStore {
KVStore{
table: table::new(),
}
}

public fun add(store: &mut KVStore, key: String, value: vector<u8>) {
table::add(&mut store.table, key, value);
}

public fun contains(store: &KVStore, key: String): bool {
table::contains(&store.table, key)
}

public fun borrow(store: &KVStore, key: String): &vector<u8> {
table::borrow(&store.table, key)
}

public fun save_to_object_storage(kv: KVStore) : ObjectID {
let object = object::new(kv);
let object_id = object::id(&object);
object::to_shared(object);
object_id
}

public fun list_field_keys(store: &KVStore): vector<address> {
table::list_field_keys(&store.table, option::none(), 10000)
lispking marked this conversation as resolved.
Show resolved Hide resolved
}
}

//# run --signers test
script {
use std::string;

use test::m;

fun main() {
let kv = m::make_kv_store();
m::add(&mut kv, string::utf8(b"test"), b"value");
m::add(&mut kv, string::utf8(b"test2"), b"value2");
m::add(&mut kv, string::utf8(b"test3"), b"value3");

let keys = m::list_field_keys(&kv);
std::debug::print(&keys);

let object_id = m::save_to_object_storage(kv);
std::debug::print(&110120);
std::debug::print(&object_id);
}
}

//# run --signers test --args object:0x79c5dcbfa65443bac7cb2bea1b85bbc0dfd82ab17969c5d620ac6261a458735f

script {
use std::string;
use std::vector;
use moveos_std::object::{Self, Object};
use test::m::{Self, KVStore};

fun main(kv_object: &Object<KVStore>) {
let kv = object::borrow(kv_object);
assert!(m::contains(kv, string::utf8(b"test")), 1000);

let keys = m::list_field_keys(kv);
std::debug::print(&keys);
assert!(vector::length(&keys) == 3, 1001);

let v = m::borrow(kv, string::utf8(b"test"));
assert!(v == &b"value", 1002);
}
}

//# run --signers test --args object:0x79c5dcbfa65443bac7cb2bea1b85bbc0dfd82ab17969c5d620ac6261a458735f

script {
use std::string;
use std::vector;
use moveos_std::object::{Self, Object};
use test::m::{Self, KVStore};

fun main(kv_object: &mut Object<KVStore>) {
let kv = object::borrow_mut(kv_object);
assert!(m::contains(kv, string::utf8(b"test")), 1000);

m::add(kv, string::utf8(b"test4"), b"value4");
m::add(kv, string::utf8(b"test5"), b"value5");

let keys = m::list_field_keys(kv);
assert!(vector::length(&keys) == 3, 1001);

let v = m::borrow(kv, string::utf8(b"test4"));
lispking marked this conversation as resolved.
Show resolved Hide resolved
assert!(v == &b"value4", 1002);

let v = m::borrow(kv, string::utf8(b"test5"));
assert!(v == &b"value5", 1003);
}
}
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
14 changes: 14 additions & 0 deletions frameworks/moveos-stdlib/doc/object.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,11 @@ For more details, please refer to https://rooch.network/docs/developer-guides/ob
- [Function `contains_field_internal`](#0x2_object_contains_field_internal)
- [Function `contains_field_with_type`](#0x2_object_contains_field_with_type)
- [Function `field_size`](#0x2_object_field_size)
- [Function `list_field_keys`](#0x2_object_list_field_keys)


<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 Expand Up @@ -980,3 +982,15 @@ Returns the size of the object fields, the number of key-value pairs

<pre><code><b>public</b> <b>fun</b> <a href="object.md#0x2_object_field_size">field_size</a>&lt;T: key&gt;(obj: &<a href="object.md#0x2_object_Object">object::Object</a>&lt;T&gt;): u64
</code></pre>



<a name="0x2_object_list_field_keys"></a>

## Function `list_field_keys`

List all field names of the object


<pre><code><b>public</b>(<b>friend</b>) <b>fun</b> <a href="object.md#0x2_object_list_field_keys">list_field_keys</a>&lt;T: key&gt;(obj: &<a href="object.md#0x2_object_Object">object::Object</a>&lt;T&gt;, cursor: <a href="_Option">option::Option</a>&lt;<b>address</b>&gt;, limit: u64): <a href="">vector</a>&lt;<b>address</b>&gt;
</code></pre>
16 changes: 15 additions & 1 deletion frameworks/moveos-stdlib/doc/table.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,16 @@ struct itself, while the operations are implemented as native functions. No trav
- [Function `upsert`](#0x2_table_upsert)
- [Function `remove`](#0x2_table_remove)
- [Function `contains`](#0x2_table_contains)
- [Function `list_field_keys`](#0x2_table_list_field_keys)
- [Function `destroy_empty`](#0x2_table_destroy_empty)
- [Function `length`](#0x2_table_length)
- [Function `is_empty`](#0x2_table_is_empty)
- [Function `drop`](#0x2_table_drop)
- [Function `handle`](#0x2_table_handle)


<pre><code><b>use</b> <a href="core_addresses.md#0x2_core_addresses">0x2::core_addresses</a>;
<pre><code><b>use</b> <a href="">0x1::option</a>;
<b>use</b> <a href="core_addresses.md#0x2_core_addresses">0x2::core_addresses</a>;
<b>use</b> <a href="object.md#0x2_object">0x2::object</a>;
</code></pre>

Expand Down Expand Up @@ -187,6 +189,18 @@ Returns true if <code><a href="table.md#0x2_table">table</a></code> contains an



<a name="0x2_table_list_field_keys"></a>

## Function `list_field_keys`

Returns a vector of all keys in the table.


<pre><code><b>public</b> <b>fun</b> <a href="table.md#0x2_table_list_field_keys">list_field_keys</a>&lt;K: <b>copy</b>, drop, store, V: store&gt;(<a href="table.md#0x2_table">table</a>: &<a href="table.md#0x2_table_Table">table::Table</a>&lt;K, V&gt;, cursor: <a href="_Option">option::Option</a>&lt;<b>address</b>&gt;, limit: u64): <a href="">vector</a>&lt;<b>address</b>&gt;
</code></pre>



<a name="0x2_table_destroy_empty"></a>

## Function `destroy_empty`
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
public(friend) fun list_field_keys<T: key>(obj: &Object<T>, cursor: Option<address>, limit: u64): vector<address> {
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);
}
}
7 changes: 7 additions & 0 deletions frameworks/moveos-stdlib/sources/table.move
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
/// struct itself, while the operations are implemented as native functions. No traversal is provided.

module moveos_std::table {
use std::option::Option;

use moveos_std::core_addresses;
use moveos_std::object::ObjectID;
use moveos_std::object::{Self, Object};
Expand Down Expand Up @@ -87,6 +89,11 @@ module moveos_std::table {
object::contains_field(&table.handle, key)
}

/// Returns a vector of all keys in the table.
public fun list_field_keys<K: copy + drop + store, V:store>(table: &Table<K, V>, cursor: Option<address>, limit: u64): vector<address> {
object::list_field_keys(&table.handle, cursor, limit)
}
lispking marked this conversation as resolved.
Show resolved Hide resolved

/// Destroy a table. Aborts if the table is not empty.
public fun destroy_empty<K: copy + drop + store, V:store>(table: Table<K, V>) {
let Table { handle } = table;
Expand Down
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
Loading
Loading