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

[Break RPC]optimize memory usage of query_object_states #2884

Merged
merged 10 commits into from
Nov 15, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
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
44 changes: 44 additions & 0 deletions crates/rooch-open-rpc-spec/schemas/openrpc.json
Original file line number Diff line number Diff line change
Expand Up @@ -861,6 +861,47 @@
}
}
},
"AnnotatedMoveStructVectorView": {
"type": "object",
"required": [
"abilities",
"field",
"type",
"value"
],
"properties": {
"abilities": {
"description": "alilities of each element",
"type": "integer",
"format": "uint8",
"minimum": 0.0
},
"field": {
"description": "field of each element",
"type": "array",
"items": {
"$ref": "#/components/schemas/move_core_types::identifier::Identifier"
}
},
"type": {
"description": "type of each element",
"allOf": [
{
"$ref": "#/components/schemas/move_core_types::language_storage::StructTag"
}
]
},
"value": {
"type": "array",
"items": {
"type": "array",
"items": {
"$ref": "#/components/schemas/AnnotatedMoveValueView"
}
}
}
}
},
"AnnotatedMoveStructView": {
"type": "object",
"required": [
Expand Down Expand Up @@ -915,6 +956,9 @@
"$ref": "#/components/schemas/AnnotatedMoveValueView"
}
},
{
"$ref": "#/components/schemas/AnnotatedMoveStructVectorView"
},
{
"$ref": "#/components/schemas/alloc::vec::Vec<u8>"
},
Expand Down
65 changes: 62 additions & 3 deletions crates/rooch-rpc-api/src/jsonrpc_types/move_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,61 @@ impl From<AnnotatedMoveStruct> for AnnotatedMoveStructView {
}
}

#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, Eq, PartialEq, PartialOrd, Ord)]
pub struct AnnotatedMoveStructVectorView {
/// alilities of each element
pub abilities: u8,
#[serde(rename = "type")]
/// type of each element
pub type_: StructTagView,
/// field of each element
pub field: Vec<IdentifierView>,
// values of the whole vector
pub value: Vec<Vec<AnnotatedMoveValueView>>,
}

impl AnnotatedMoveStructVectorView {
fn try_from(origin: Vec<AnnotatedMoveValue>) -> Result<Self, AnnotatedMoveValueView> {
if origin.is_empty() {
Err(AnnotatedMoveValueView::Vector(
origin.into_iter().map(Into::into).collect(),
))
} else {
let first = origin.first().unwrap();
if let AnnotatedMoveValue::Struct(ele) = first {
let field = ele
.value
.iter()
.map(|x| IdentifierView::from(x.0.clone()))
.collect();
let abilities = ele.abilities.into_u8();
let type_ = StrView(ele.type_.clone());
let value: Vec<Vec<AnnotatedMoveValueView>> = origin
.into_iter()
.map(|v| {
if let AnnotatedMoveValue::Struct(s) = v {
s.value.into_iter().map(|(_, v)| v.into()).collect()
} else {
unreachable!("AnnotatedMoveStructVectorView")
}
})
.collect();

Ok(Self {
abilities,
type_,
field,
value,
})
} else {
Err(AnnotatedMoveValueView::Vector(
origin.into_iter().map(Into::into).collect(),
))
}
}
}
}

/// Some specific struct that we want to display in a special way for better readability
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, Eq, PartialEq, PartialOrd, Ord)]
#[serde(untagged)]
Expand All @@ -161,7 +216,7 @@ pub enum SpecificStructView {
}

impl SpecificStructView {
pub fn try_from_annotated(move_struct: AnnotatedMoveStruct) -> Option<Self> {
pub fn try_from_annotated(move_struct: &AnnotatedMoveStruct) -> Option<Self> {
if MoveString::struct_tag_match(&move_struct.type_) {
MoveString::try_from(move_struct)
.ok()
Expand Down Expand Up @@ -192,6 +247,7 @@ pub enum AnnotatedMoveValueView {
Bool(bool),
Address(AccountAddressView),
Vector(Vec<AnnotatedMoveValueView>),
StructVector(Box<AnnotatedMoveStructVectorView>),
Bytes(BytesView),
Struct(AnnotatedMoveStructView),
SpecificStruct(SpecificStructView),
Expand All @@ -209,11 +265,14 @@ impl From<AnnotatedMoveValue> for AnnotatedMoveValueView {
AnnotatedMoveValue::Bool(b) => AnnotatedMoveValueView::Bool(b),
AnnotatedMoveValue::Address(data) => AnnotatedMoveValueView::Address(StrView(data)),
AnnotatedMoveValue::Vector(_type_tag, data) => {
AnnotatedMoveValueView::Vector(data.into_iter().map(Into::into).collect())
match AnnotatedMoveStructVectorView::try_from(data) {
Ok(v) => AnnotatedMoveValueView::StructVector(Box::new(v)),
Err(v) => v,
}
}
AnnotatedMoveValue::Bytes(data) => AnnotatedMoveValueView::Bytes(StrView(data)),
AnnotatedMoveValue::Struct(data) => {
match SpecificStructView::try_from_annotated(data.clone()) {
match SpecificStructView::try_from_annotated(&data) {
Some(struct_view) => AnnotatedMoveValueView::SpecificStruct(struct_view),
None => AnnotatedMoveValueView::Struct(data.into()),
}
Expand Down
4 changes: 2 additions & 2 deletions crates/rooch-rpc-server/src/service/rpc_service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -404,7 +404,7 @@ impl RpcService {
} else {
BTreeMap::new()
};
let mut object_states = annotated_states
let mut object_states: Vec<IndexerObjectStateView> = annotated_states
.into_iter()
.zip(indexer_ids)
.filter_map(|(state_opt, (object_id, indexer_state_id))| {
Expand All @@ -423,7 +423,7 @@ impl RpcService {
}
}
})
.collect::<Vec<_>>();
.collect();
if !displays.is_empty() {
object_states.iter_mut().for_each(|object_state| {
object_state.display_fields =
Expand Down
26 changes: 19 additions & 7 deletions crates/testsuite/features/bitseed.feature
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@ Feature: Rooch CLI bitseed tests
# Check mint generator validity
Then cmd: "move view --function 0x4::ord::view_validity --args string:{{$.bitseed[-1].inscriptions[0].Id}} "
Then assert: "{{$.move[-1].vm_status}} == Executed"
Then assert: "{{$.move[-1].return_values[0].decoded_value.value.vec[0].value.is_valid}} == true"
# For `.vec.value[0][1]`, the first index `0` means the first element of vec;
# the second index `1` means the second field of `0x4::ord::MetaprotocolValidity`, that is `is_valid`.
Then assert: "{{$.move[-1].return_values[0].decoded_value.value.vec.value[0][1]}} == true"

# deploy
Then cmd: "bitseed deploy --fee-rate 6000 --generator {{$.bitseed[-1].inscriptions[0].Id}} --tick bits --amount 210000000000 --deploy-args '{"height":{"type":"range","data":{"min":1,"max":1000}}}'"
Expand All @@ -48,7 +50,9 @@ Feature: Rooch CLI bitseed tests
# Check deploy validity
Then cmd: "move view --function 0x4::ord::view_validity --args string:{{$.bitseed[-1].inscriptions[0].Id}} "
Then assert: "{{$.move[-1].vm_status}} == Executed"
Then assert: "{{$.move[-1].return_values[0].decoded_value.value.vec[0].value.is_valid}} == true"
# For `.vec.value[0][1]`, the first index `0` means the first element of vec;
# the second index `1` means the second field of `0x4::ord::MetaprotocolValidity`, that is `is_valid`.
Then assert: "{{$.move[-1].return_values[0].decoded_value.value.vec.value[0][1]}} == true"

# mint 1
Then cmd: "bitseed mint --fee-rate 6000 --deploy-inscription-id {{$.bitseed[-1].inscriptions[0].Id}} --user-input test"
Expand All @@ -72,11 +76,15 @@ Feature: Rooch CLI bitseed tests
# Check mint bits validity
Then cmd: "move view --function 0x4::ord::view_validity --args string:{{$.bitseed[-1].inscriptions[0].Id}} "
Then assert: "{{$.move[-1].vm_status}} == Executed"
Then assert: "{{$.move[-1].return_values[0].decoded_value.value.vec[0].value.is_valid}} == true"
# For `.vec.value[0][1]`, the first index `0` means the first element of vec;
# the second index `1` means the second field of `0x4::ord::MetaprotocolValidity`, that is `is_valid`.
Then assert: "{{$.move[-1].return_values[0].decoded_value.value.vec.value[0][1]}} == true"

Then cmd: "move view --function 0x4::ord::view_validity --args string:{{$.bitseed[-2].inscriptions[0].Id}} "
Then assert: "{{$.move[-1].vm_status}} == Executed"
Then assert: "{{$.move[-1].return_values[0].decoded_value.value.vec[0].value.is_valid}} == true"
# For `.vec.value[0][1]`, the first index `0` means the first element of vec;
# the second index `1` means the second field of `0x4::ord::MetaprotocolValidity`, that is `is_valid`.
Then assert: "{{$.move[-1].return_values[0].decoded_value.value.vec.value[0][1]}} == true"

Then cmd: "bitseed merge --fee-rate 6000 --sft-inscription-ids {{$.bitseed[-1].inscriptions[0].Id}} --sft-inscription-ids {{$.bitseed[-2].inscriptions[0].Id}}"
Then assert: "'{{$.bitseed[-1]}}' not_contains error"
Expand All @@ -90,8 +98,10 @@ Feature: Rooch CLI bitseed tests

Then cmd: "move view --function 0x4::ord::view_validity --args string:{{$.bitseed[-1].inscriptions[0].Id}} "
Then assert: "{{$.move[-1].vm_status}} == Executed"
Then assert: "{{$.move[-1].return_values[0].decoded_value.value.vec[0].value.is_valid}} == true"

# For `.vec.value[0][1]`, the first index `0` means the first element of vec;
# the second index `1` means the second field of `0x4::ord::MetaprotocolValidity`, that is `is_valid`.
Then assert: "{{$.move[-1].return_values[0].decoded_value.value.vec.value[0][1]}} == true"

# release servers
Then stop the server
Then stop the bitcoind server
Expand Down Expand Up @@ -130,7 +140,9 @@ Feature: Rooch CLI bitseed tests
# Check deploy validity
Then cmd: "move view --function 0x4::ord::view_validity --args string:{{$.bitseed[-1].inscriptions[0].Id}} "
Then assert: "{{$.move[-1].vm_status}} == Executed"
Then assert: "{{$.move[-1].return_values[0].decoded_value.value.vec[0].value.is_valid}} == true"
# For `.vec.value[0][1]`, the first index `0` means the first element of vec;
# the second index `1` means the second field of `0x4::ord::MetaprotocolValidity`, that is `is_valid`.
Then assert: "{{$.move[-1].return_values[0].decoded_value.value.vec.value[0][1]}} == true"

# mint on rooch
Then cmd: "move run --function 0xa::mint_get_factory::mint --args string:bitseed --args string:test --json"
Expand Down
4 changes: 3 additions & 1 deletion crates/testsuite/features/ord.feature
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,9 @@ Feature: Rooch Bitcoin ord tests
# Check inscription burned
Then cmd: "move view --function 0x4::ord::view_inscription_charm --args string:{{$.wallet[-3][0].inscription}} "
Then assert: "{{$.move[-1].vm_status}} == Executed"
Then assert: "{{$.move[-1].return_values[0].decoded_value.value.vec[0].value.burned}} == true"
# For `.vec.value[0][1]`, the first index `0` means the first element of vec;
# the second index `12` means the 13th field of `0x4::ord::InscriptionCharm`, that is `burned`.
Then assert: "{{$.move[-1].return_values[0].decoded_value.value.vec.value[0][12]}} == true"

# release servers
Then stop the server
Expand Down
20 changes: 20 additions & 0 deletions moveos/moveos-types/src/move_std/ascii.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,26 @@ impl TryFrom<AnnotatedMoveStruct> for MoveAsciiString {
}
}

impl TryFrom<&AnnotatedMoveStruct> for MoveAsciiString {
type Error = anyhow::Error;

fn try_from(value: &AnnotatedMoveStruct) -> Result<Self, Self::Error> {
let annotated_move_struct = value;
let (field_name, field_value) = annotated_move_struct
.value
.first()
.ok_or_else(|| anyhow::anyhow!("Invalid MoveAsciiString"))?;
debug_assert!(field_name.as_str() == "bytes");
let bytes = match field_value {
AnnotatedMoveValue::Bytes(bytes) => bytes,
_ => return Err(anyhow::anyhow!("Invalid MoveAsciiString")),
};
Ok(MoveAsciiString {
bytes: bytes.clone(),
})
}
}

impl TryFrom<MoveAsciiString> for Identifier {
type Error = anyhow::Error;

Expand Down
20 changes: 20 additions & 0 deletions moveos/moveos-types/src/move_std/string.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,26 @@ impl TryFrom<AnnotatedMoveStruct> for MoveString {
}
}

impl TryFrom<&AnnotatedMoveStruct> for MoveString {
type Error = anyhow::Error;

fn try_from(value: &AnnotatedMoveStruct) -> Result<Self, Self::Error> {
let annotated_move_struct = value;
let (field_name, field_value) = annotated_move_struct
.value
.first()
.ok_or_else(|| anyhow::anyhow!("Invalid MoveString"))?;
debug_assert!(field_name.as_str() == "bytes");
let bytes = match field_value {
AnnotatedMoveValue::Bytes(bytes) => bytes,
_ => return Err(anyhow::anyhow!("Invalid MoveString")),
};
Ok(MoveString {
bytes: bytes.clone(),
})
}
}

impl TryFrom<MoveString> for Identifier {
type Error = anyhow::Error;

Expand Down
21 changes: 21 additions & 0 deletions moveos/moveos-types/src/moveos_std/object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,19 @@ impl TryFrom<AnnotatedMoveValue> for ObjectID {
}
}

impl TryFrom<&AnnotatedMoveValue> for ObjectID {
type Error = anyhow::Error;

fn try_from(value: &AnnotatedMoveValue) -> Result<Self, Self::Error> {
match value {
AnnotatedMoveValue::Struct(annotated_move_struct) => {
ObjectID::try_from(annotated_move_struct)
}
_ => Err(anyhow::anyhow!("Invalid ObjectID")),
}
}
}

impl TryFrom<AnnotatedMoveStruct> for ObjectID {
type Error = anyhow::Error;

Expand All @@ -303,6 +316,14 @@ impl TryFrom<AnnotatedMoveStruct> for ObjectID {
}
}

impl TryFrom<&AnnotatedMoveStruct> for ObjectID {
type Error = anyhow::Error;

fn try_from(value: &AnnotatedMoveStruct) -> Result<Self, Self::Error> {
ObjectID::try_from_annotated_move_struct_ref(value)
}
}

impl From<AccountAddress> for ObjectID {
fn from(address: AccountAddress) -> Self {
ObjectID(vec![address])
Expand Down
Loading