Skip to content

Commit

Permalink
feat: support list fields for object.move (#3142)
Browse files Browse the repository at this point in the history
* feat: support list fields for object.move

* fix UNKNOWN_INVARIANT_VIOLATION_ERROR

* rename list_fields to list_field_names

* fix native return types

* make code tidy

* make code tidy

* make code tidy

* support cursor and limit for list_field_keys

* update object list_field_keys gas handle and adjust fetch data from db

* make code tidy

* update native_list_field_keys default value to 0

* check is_empty that before add native_list_field_keys

* update is_empty for ListFieldsGasParametersOption

* fix review notes

* fix lint

* add list_field_keys for table and add rooch-framework-tests

* update ut assert value

* update list_field_keys of table notes

* add length ut for list_field_keys

* add more ut for list_field_keys

* make ut tidy

* add iterator for table

* fix next/next_mut for table issue

* update borrow_field_key_internal and borrow_mut_field_key_internal notes

* add How to test move contract? notes

* update borrow_field_key_internal and borrow_mut_field_key_internal notes

* update review notes

* update review notes

---------

Co-authored-by: jolestar <jolestar@gmail.com>
  • Loading branch information
lispking and jolestar committed Jan 8, 2025
1 parent 511e2c8 commit e328ff4
Show file tree
Hide file tree
Showing 16 changed files with 625 additions and 16 deletions.
12 changes: 11 additions & 1 deletion crates/rooch-framework-tests/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,14 @@

```bash
cargo run -p rooch-framework-tests -- --btc-rpc-url http://localhost:9332 --btc-rpc-username your_username --btc-rpc-password your_pwd --ord-event-dir your_local_event_dir --blocks 790964 --blocks 855396
```
```

## How to test move contract?

UB=1 cargo test -p rooch-framework-tests $case/$method_name

Fox example:

```bash
UB=1 cargo test -p rooch-framework-tests table/list_field_keys
```
10 changes: 10 additions & 0 deletions crates/rooch-framework-tests/tests/cases/table/list_field_keys.exp
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
processed 4 tasks

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

task 2 'run'. lines 69-123:
status EXECUTED

task 3 'run'. lines 125-145:
status EXECUTED
145 changes: 145 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,145 @@
//# init --addresses test=0x42

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

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

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): Iterator<String, vector<u8>> {
table::list_field_keys(&store.table, option::none(), 10000)
}

public fun list_field_keys_with_name(store: &KVStore, key: String, limit: u64): Iterator<String, vector<u8>> {
table::list_field_keys(&store.table, option::some(key), limit)
}

public fun field_keys_len(iterator: &Iterator<String, vector<u8>>): u64 {
table::field_keys_len(iterator)
}

public fun next(iterator: &mut Iterator<String, vector<u8>>): (String, vector<u8>) {
let (k, v) = table::next(iterator);
(*k, *v)
}

public fun next_mut(iterator: &mut Iterator<String, vector<u8>>): (String, vector<u8>) {
let (k, v) = table::next_mut(iterator);
(*k, *v)
}

public fun length(store: &KVStore): u64 {
table::length(&store.table)
}
}

//# 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 iter = m::list_field_keys(&kv);
std::debug::print(&iter);
assert!(m::field_keys_len(&iter) == 3, 1001);

m::add(&mut kv, string::utf8(b"test4"), b"value4");
let iter = m::list_field_keys(&kv);
std::debug::print(&iter);
assert!(m::field_keys_len(&iter) == 4, 1002);

let (k, v) = m::next_mut(&mut iter);
std::debug::print(&k);
std::debug::print(&string::utf8(v));
v = b"new_value";
std::debug::print(&string::utf8(v));

let (k, v) = m::next(&mut iter);
std::debug::print(&k);
std::debug::print(&string::utf8(v));

let (k, v) = m::next(&mut iter);
std::debug::print(&k);
std::debug::print(&string::utf8(v));

let (k, v) = m::next(&mut iter);
std::debug::print(&k);
std::debug::print(&string::utf8(v));

let iter = m::list_field_keys_with_name(&kv, string::utf8(b"test"), 2);
std::debug::print(&iter);
assert!(m::field_keys_len(&iter) == 2, 1003);

let (k, v) = m::next(&mut iter);
std::debug::print(&k);
std::debug::print(&string::utf8(v));

let (k, v) = m::next(&mut iter);
std::debug::print(&k);
std::debug::print(&string::utf8(v));

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

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

script {
use std::string;
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 iter = m::list_field_keys(kv);
assert!(m::field_keys_len(&iter) == 4, 1001);

let size = m::length(kv);
assert!(size == 4, 1002);

let v = m::borrow(kv, string::utf8(b"test"));
assert!(v == &b"value", 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
41 changes: 41 additions & 0 deletions frameworks/moveos-stdlib/doc/object.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,11 @@ For more details, please refer to https://rooch.network/docs/developer-guides/ob
- [Function `add_field_internal`](#0x2_object_add_field_internal)
- [Function `borrow_field`](#0x2_object_borrow_field)
- [Function `borrow_field_internal`](#0x2_object_borrow_field_internal)
- [Function `borrow_field_with_key_internal`](#0x2_object_borrow_field_with_key_internal)
- [Function `borrow_field_with_default`](#0x2_object_borrow_field_with_default)
- [Function `borrow_mut_field`](#0x2_object_borrow_mut_field)
- [Function `borrow_mut_field_internal`](#0x2_object_borrow_mut_field_internal)
- [Function `borrow_mut_field_with_key_internal`](#0x2_object_borrow_mut_field_with_key_internal)
- [Function `borrow_mut_field_with_default`](#0x2_object_borrow_mut_field_with_default)
- [Function `upsert_field`](#0x2_object_upsert_field)
- [Function `remove_field`](#0x2_object_remove_field)
Expand All @@ -66,9 +68,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 @@ -843,6 +847,18 @@ Borrow FieldValue and return the val of FieldValue



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

## Function `borrow_field_with_key_internal`

Direct field access based on field_key and return field value reference.


<pre><code><b>public</b>(<b>friend</b>) <b>fun</b> <a href="object.md#0x2_object_borrow_field_with_key_internal">borrow_field_with_key_internal</a>&lt;Name: <b>copy</b>, drop, store, Value&gt;(obj_id: <a href="object.md#0x2_object_ObjectID">object::ObjectID</a>, field_key: <b>address</b>): (&Name, &Value)
</code></pre>



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

## Function `borrow_field_with_default`
Expand Down Expand Up @@ -883,6 +899,19 @@ Aborts if there is no field for <code>key</code>.



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

## Function `borrow_mut_field_with_key_internal`

Obtain a mutable reference to the value associated with <code>field_key</code>.
Will abort if no field exists for the given <code>field_key</code>.


<pre><code><b>public</b>(<b>friend</b>) <b>fun</b> <a href="object.md#0x2_object_borrow_mut_field_with_key_internal">borrow_mut_field_with_key_internal</a>&lt;Name: <b>copy</b>, drop, store, Value&gt;(obj_id: <a href="object.md#0x2_object_ObjectID">object::ObjectID</a>, field_key: <b>address</b>): (&Name, &<b>mut</b> Value)
</code></pre>



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

## Function `borrow_mut_field_with_default`
Expand Down Expand Up @@ -980,3 +1009,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, Name: <b>copy</b>, drop, store&gt;(obj: &<a href="object.md#0x2_object_Object">object::Object</a>&lt;T&gt;, name: <a href="_Option">option::Option</a>&lt;Name&gt;, limit: u64): <a href="">vector</a>&lt;<b>address</b>&gt;
</code></pre>
69 changes: 68 additions & 1 deletion frameworks/moveos-stdlib/doc/table.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ struct itself, while the operations are implemented as native functions. No trav

- [Resource `TablePlaceholder`](#0x2_table_TablePlaceholder)
- [Struct `Table`](#0x2_table_Table)
- [Struct `Iterator`](#0x2_table_Iterator)
- [Function `new`](#0x2_table_new)
- [Function `new_with_object_id_by_system`](#0x2_table_new_with_object_id_by_system)
- [Function `add`](#0x2_table_add)
Expand All @@ -23,14 +24,19 @@ 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 `field_keys_len`](#0x2_table_field_keys_len)
- [Function `next`](#0x2_table_next)
- [Function `next_mut`](#0x2_table_next_mut)
- [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 @@ -59,6 +65,17 @@ Type of tables



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

## Struct `Iterator`



<pre><code><b>struct</b> <a href="table.md#0x2_table_Iterator">Iterator</a>&lt;K: <b>copy</b>, drop, store, V&gt; <b>has</b> drop, store
</code></pre>



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

## Function `new`
Expand Down Expand Up @@ -187,6 +204,56 @@ 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 keys in the table from the given cursor position, up to the specified limit.
cursor: Optional address to start listing from. If None, starts from the beginning.
limit: Maximum number of keys to return.


<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;K&gt;, limit: u64): <a href="table.md#0x2_table_Iterator">table::Iterator</a>&lt;K, V&gt;
</code></pre>



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

## Function `field_keys_len`

Returns the number of keys in the table.


<pre><code><b>public</b> <b>fun</b> <a href="table.md#0x2_table_field_keys_len">field_keys_len</a>&lt;K: <b>copy</b>, drop, store, V: store&gt;(iterator: &<a href="table.md#0x2_table_Iterator">table::Iterator</a>&lt;K, V&gt;): u64
</code></pre>



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

## Function `next`

Returns a immutable reference to the next key-value pair in the table, starting from the given iterator.


<pre><code><b>public</b> <b>fun</b> <a href="table.md#0x2_table_next">next</a>&lt;K: <b>copy</b>, drop, store, V: store&gt;(iterator: &<b>mut</b> <a href="table.md#0x2_table_Iterator">table::Iterator</a>&lt;K, V&gt;): (&K, &V)
</code></pre>



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

## Function `next_mut`

Returns a mutable reference to the next key-value pair in the table, starting from the given iterator.


<pre><code><b>public</b> <b>fun</b> <a href="table.md#0x2_table_next_mut">next_mut</a>&lt;K: <b>copy</b>, drop, store, V: store&gt;(iterator: &<b>mut</b> <a href="table.md#0x2_table_Iterator">table::Iterator</a>&lt;K, V&gt;): (&K, &<b>mut</b> V)
</code></pre>



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

## Function `destroy_empty`
Expand Down
Loading

0 comments on commit e328ff4

Please sign in to comment.