Skip to content

Commit

Permalink
[Sui CLI / UX] - Improved wallet object command (MystenLabs#2013)
Browse files Browse the repository at this point in the history
* impl display for SuiMoveValue, improve wellet cli object command output

* add bytearray SuiMoveValue type

* update schema file

* fix clippy
  • Loading branch information
patrickkuo authored May 17, 2022
1 parent b3b306c commit 15c1dc3
Show file tree
Hide file tree
Showing 5 changed files with 188 additions and 40 deletions.
37 changes: 27 additions & 10 deletions crates/sui-types/src/sui_serde.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,13 @@ where
{
if deserializer.is_human_readable() {
let value = E::deserialize_as(deserializer)?;
if value.len() != N {
return Err(D::Error::custom(anyhow!(
"invalid array length {}, expecting {}",
value.len(),
N
)));
}
let mut array = [0u8; N];
array.copy_from_slice(&value[..N]);
Ok(array)
Expand Down Expand Up @@ -141,18 +148,28 @@ where
}

pub trait Encoding {
fn decode(s: String) -> Result<Vec<u8>, anyhow::Error>;
fn decode(s: &str) -> Result<Vec<u8>, anyhow::Error>;
fn encode<T: AsRef<[u8]>>(data: T) -> String;
}

#[derive(Serialize, Deserialize, Debug, JsonSchema)]
pub struct Hex(pub String);
pub struct Hex(String);
#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq, JsonSchema)]
pub struct Base64(pub String);
#[serde(try_from = "String")]
pub struct Base64(String);

impl TryFrom<String> for Base64 {
type Error = anyhow::Error;
fn try_from(value: String) -> Result<Self, Self::Error> {
// Make sure the value is valid base64 string.
Base64::decode(&value)?;
Ok(Self(value))
}
}

impl Base64 {
pub fn to_vec(self) -> Result<Vec<u8>, anyhow::Error> {
Self::decode(self.0)
Self::decode(&self.0)
}

pub fn from_bytes(bytes: &[u8]) -> Self {
Expand All @@ -161,17 +178,17 @@ impl Base64 {
}

impl Encoding for Hex {
fn decode(s: String) -> Result<Vec<u8>, anyhow::Error> {
decode_bytes_hex(&s)
fn decode(s: &str) -> Result<Vec<u8>, anyhow::Error> {
decode_bytes_hex(s)
}

fn encode<T: AsRef<[u8]>>(data: T) -> String {
format!("0x{}", encode_bytes_hex(&data).to_lowercase())
}
}
impl Encoding for Base64 {
fn decode(s: String) -> Result<Vec<u8>, anyhow::Error> {
base64ct::Base64::decode_vec(&s).map_err(|e| anyhow!(e))
fn decode(s: &str) -> Result<Vec<u8>, anyhow::Error> {
base64ct::Base64::decode_vec(s).map_err(|e| anyhow!(e))
}

fn encode<T: AsRef<[u8]>>(data: T) -> String {
Expand All @@ -185,7 +202,7 @@ impl<'de> DeserializeAs<'de, Vec<u8>> for Base64 {
D: Deserializer<'de>,
{
let s = String::deserialize(deserializer)?;
Self::decode(s).map_err(to_custom_error::<'de, D, _>)
Self::decode(&s).map_err(to_custom_error::<'de, D, _>)
}
}

Expand All @@ -207,7 +224,7 @@ impl<'de> DeserializeAs<'de, Vec<u8>> for Hex {
D: Deserializer<'de>,
{
let s = String::deserialize(deserializer)?;
Self::decode(s).map_err(to_custom_error::<'de, D, _>)
Self::decode(&s).map_err(to_custom_error::<'de, D, _>)
}
}

Expand Down
15 changes: 9 additions & 6 deletions sui/open_rpc/spec/openrpc.json
Original file line number Diff line number Diff line change
Expand Up @@ -840,12 +840,6 @@
"$ref": "#/components/schemas/MoveValue"
}
},
{
"type": "object",
"additionalProperties": {
"$ref": "#/components/schemas/MoveValue"
}
},
{
"type": "object",
"required": [
Expand All @@ -863,6 +857,12 @@
"type": "string"
}
}
},
{
"type": "object",
"additionalProperties": {
"$ref": "#/components/schemas/MoveValue"
}
}
]
},
Expand All @@ -885,6 +885,9 @@
"$ref": "#/components/schemas/MoveValue"
}
},
{
"$ref": "#/components/schemas/Base64"
},
{
"type": "string"
},
Expand Down
2 changes: 1 addition & 1 deletion sui/src/wallet_commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -684,7 +684,7 @@ impl Display for WalletCommandResult {
writeln!(writer, "{}", object)?;
}
}
write!(f, "{}", writer)
write!(f, "{}", writer.trim_end_matches('\n'))
}
}

Expand Down
168 changes: 148 additions & 20 deletions sui_core/src/gateway_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ use std::fmt;
use std::fmt::Write;
use std::fmt::{Display, Formatter};

use colored::Colorize;
use itertools::Itertools;
use move_core_types::identifier::Identifier;
use move_core_types::language_storage::StructTag;
use move_core_types::value::{MoveStruct, MoveStructLayout, MoveValue};
Expand All @@ -18,7 +20,6 @@ use serde::Deserialize;
use serde::Serialize;
use serde_json::Value;

use colored::Colorize;
use sui_types::base_types::{
ObjectDigest, ObjectID, ObjectRef, SequenceNumber, SuiAddress, TransactionDigest,
};
Expand Down Expand Up @@ -193,19 +194,44 @@ impl From<ObjectRef> for SuiObjectRef {

impl Display for SuiObject {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let type_string = self
.data
.type_()
.map_or("Move Package".to_owned(), |type_| type_.to_string());

write!(
f,
"ID: {:?}\nVersion: {:?}\nOwner: {}\nType: {}",
self.id(),
self.version().value(),
self.owner,
type_string
)
let type_ = if self.data.type_().is_some() {
"Move Object"
} else {
"Move Package"
};
let mut writer = String::new();
writeln!(
writer,
"{}",
format!(
"----- {type_} ({}[{}]) -----",
self.id(),
self.version().value()
)
.bold()
)?;
writeln!(writer, "{}: {}", "Owner".bold().bright_black(), self.owner)?;
writeln!(
writer,
"{}: {}",
"Version".bold().bright_black(),
self.version().value()
)?;
writeln!(
writer,
"{}: {}",
"Storage Rebate".bold().bright_black(),
self.storage_rebate
)?;
writeln!(
writer,
"{}: {:?}",
"Previous Transaction".bold().bright_black(),
self.previous_transaction
)?;
writeln!(writer, "{}", "----- Data -----".bold())?;
write!(writer, "{}", &self.data)?;
write!(f, "{}", writer)
}
}

Expand Down Expand Up @@ -260,6 +286,34 @@ pub enum SuiData {
Package(SuiMovePackage),
}

impl Display for SuiData {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
let mut writer = String::new();
match self {
SuiData::MoveObject(o) => {
writeln!(writer, "{}: {}", "type".bold().bright_black(), o.type_)?;
write!(writer, "{}", &o.fields)?;
}
SuiData::Package(p) => {
write!(
writer,
"{}: {:?}",
"Modules".bold().bright_black(),
p.disassembled.keys()
)?;
}
}
write!(f, "{}", writer)
}
}

fn indent<T: Display>(d: &T, indent: usize) -> String {
d.to_string()
.lines()
.map(|line| format!("{:indent$}{}", "", line))
.join("\n")
}

#[derive(Debug, Deserialize, Serialize, JsonSchema, Clone, Eq, PartialEq)]
#[serde(rename = "MoveObject")]
pub struct SuiMoveObject {
Expand Down Expand Up @@ -339,9 +393,9 @@ pub struct PublishResponse {
impl Display for PublishResponse {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let mut writer = String::new();
writeln!(writer, "----- Certificate ----")?;
writeln!(writer, "{}", "----- Certificate ----".bold())?;
write!(writer, "{}", self.certificate)?;
writeln!(writer, "----- Publish Results ----")?;
writeln!(writer, "{}", "----- Publish Results ----".bold())?;
writeln!(
writer,
"The newly published package object ID: {:?}",
Expand Down Expand Up @@ -417,12 +471,58 @@ pub enum SuiMoveValue {
Bool(bool),
Address(SuiAddress),
Vector(Vec<SuiMoveValue>),
Bytearray(Base64),
String(String),
VersionedID { id: ObjectID, version: u64 },
Struct(SuiMoveStruct),
Option(Box<Option<SuiMoveValue>>),
}

impl Display for SuiMoveValue {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
let mut writer = String::new();
match self {
SuiMoveValue::Number(value) => {
write!(writer, "{}", value)?;
}
SuiMoveValue::Bool(value) => {
write!(writer, "{}", value)?;
}
SuiMoveValue::Address(value) => {
write!(writer, "{}", value)?;
}
SuiMoveValue::Vector(vec) => {
write!(
writer,
"{}",
vec.iter().map(|value| format!("{value}")).join(",\n")
)?;
}
SuiMoveValue::String(value) => {
write!(writer, "{}", value)?;
}
SuiMoveValue::VersionedID { id, version } => {
write!(writer, "{id}[{version}]")?;
}
SuiMoveValue::Struct(value) => {
write!(writer, "{}", value)?;
}
SuiMoveValue::Option(value) => {
write!(writer, "{:?}", value)?;
}
SuiMoveValue::Bytearray(value) => {
write!(
writer,
"{:?}",
value.clone().to_vec().map_err(fmt::Error::custom)?
)?;
}
}

write!(f, "{}", writer.trim_end_matches('\n'))
}
}

impl From<MoveValue> for SuiMoveValue {
fn from(value: MoveValue) -> Self {
match value {
Expand All @@ -443,7 +543,7 @@ impl From<MoveValue> for SuiMoveValue {
}
})
.collect::<Vec<_>>();
return SuiMoveValue::String(Base64::encode(&bytearray));
return SuiMoveValue::Bytearray(Base64::from_bytes(&bytearray));
}
SuiMoveValue::Vector(value.into_iter().map(|value| value.into()).collect())
}
Expand All @@ -467,12 +567,40 @@ impl From<MoveValue> for SuiMoveValue {
#[serde(untagged, rename = "MoveStruct")]
pub enum SuiMoveStruct {
Runtime(Vec<SuiMoveValue>),
WithFields(BTreeMap<String, SuiMoveValue>),
WithTypes {
#[serde(rename = "type")]
type_: String,
fields: BTreeMap<String, SuiMoveValue>,
},
WithFields(BTreeMap<String, SuiMoveValue>),
}

impl Display for SuiMoveStruct {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
let mut writer = String::new();
match self {
SuiMoveStruct::Runtime(_) => {}
SuiMoveStruct::WithFields(fields) => {
for (name, value) in fields {
writeln!(writer, "{}: {value}", name.bold().bright_black())?;
}
}
SuiMoveStruct::WithTypes { type_, fields } => {
writeln!(writer)?;
writeln!(writer, " {}: {type_}", "type".bold().bright_black())?;
for (name, value) in fields {
let value = format!("{}", value);
let value = if value.starts_with('\n') {
indent(&value, 2)
} else {
value
};
writeln!(writer, " {}: {value}", name.bold().bright_black())?;
}
}
}
write!(f, "{}", writer.trim_end_matches('\n'))
}
}

fn try_convert_type(type_: &StructTag, fields: &[(Identifier, MoveValue)]) -> Option<SuiMoveValue> {
Expand All @@ -488,8 +616,8 @@ fn try_convert_type(type_: &StructTag, fields: &[(Identifier, MoveValue)]) -> Op
.collect::<BTreeMap<_, SuiMoveValue>>();
match struct_name.as_str() {
"0x2::UTF8::String" | "0x1::ASCII::String" => {
if let SuiMoveValue::String(bytes_string) = fields["bytes"].clone() {
if let Ok(bytes) = Base64::decode(bytes_string) {
if let SuiMoveValue::Bytearray(bytes) = fields["bytes"].clone() {
if let Ok(bytes) = bytes.to_vec() {
if let Ok(s) = String::from_utf8(bytes) {
return Some(SuiMoveValue::String(s));
}
Expand Down
Loading

0 comments on commit 15c1dc3

Please sign in to comment.