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

Plutus Datum JSON to use Cardano Node format #311

Merged
merged 3 commits into from
Mar 12, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
75 changes: 63 additions & 12 deletions core/rust/src/metadata.rs → chain/rust/src/auxdata/metadata.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
use crate::error::{DeserializeError, DeserializeFailure};

use crate::serialization::{fit_sz, Deserialize, LenEncoding, Serialize, StringEncoding};
use crate::Int;
use crate::json::metadatums::{
decode_metadatum_to_json_value, encode_json_value_to_metadatum, MetadataJsonSchema,
};
use cbor_event::{de::Deserializer, se::Serializer};
use cml_core::{
error::{DeserializeError, DeserializeFailure},
serialization::{fit_sz, Deserialize, LenEncoding, Serialize, StringEncoding},
Int,
};
use derivative::Derivative;

use std::io::{BufRead, Seek, Write};
Expand Down Expand Up @@ -149,13 +153,10 @@ impl Deserialize for Metadata {

/// Handles the extremely rare (2 total instances on mainnet) edge-case of in
/// previous generations allowing duplicate metadatum keys.
#[derive(
Clone, Debug, Default, serde::Deserialize, serde::Serialize, schemars::JsonSchema, Derivative,
)]
#[derive(Clone, Debug, Default, Derivative)]
#[derivative(Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct MetadatumMap {
pub entries: Vec<(TransactionMetadatum, TransactionMetadatum)>,
#[serde(skip)]
#[derivative(
PartialEq = "ignore",
Ord = "ignore",
Expand Down Expand Up @@ -273,7 +274,7 @@ impl Deserialize for MetadatumMap {
}
}

#[derive(Clone, Debug, serde::Deserialize, serde::Serialize, schemars::JsonSchema, Derivative)]
#[derive(Clone, Debug, Derivative)]
#[derivative(
Eq,
PartialEq,
Expand All @@ -291,7 +292,6 @@ pub enum TransactionMetadatum {
PartialOrd = "ignore",
Hash = "ignore"
)]
#[serde(skip)]
elements_encoding: LenEncoding,
},
Int(Int),
Expand All @@ -303,7 +303,6 @@ pub enum TransactionMetadatum {
PartialOrd = "ignore",
Hash = "ignore"
)]
#[serde(skip)]
bytes_encoding: StringEncoding,
},
Text {
Expand All @@ -314,7 +313,6 @@ pub enum TransactionMetadatum {
PartialOrd = "ignore",
Hash = "ignore"
)]
#[serde(skip)]
text_encoding: StringEncoding,
},
}
Expand Down Expand Up @@ -401,6 +399,51 @@ impl TransactionMetadatum {
}
}

impl serde::Serialize for TransactionMetadatum {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let json_value = decode_metadatum_to_json_value(self, MetadataJsonSchema::DetailedSchema)
.expect("DetailedSchema can represent everything");
serde_json::Value::from(json_value).serialize(serializer)
}
}

impl<'de> serde::de::Deserialize<'de> for TransactionMetadatum {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::de::Deserializer<'de>,
{
let serde_json_value =
<serde_json::Value as serde::de::Deserialize>::deserialize(deserializer)?;
let json_value = crate::json::json_serialize::Value::from(serde_json_value);
encode_json_value_to_metadatum(json_value.clone(), MetadataJsonSchema::DetailedSchema)
.map_err(|_e| {
serde::de::Error::invalid_value(
(&json_value).into(),
&"invalid tx metadatum (cardano-node JSON format)",
)
})
}
}

impl schemars::JsonSchema for TransactionMetadatum {
fn schema_name() -> String {
String::from("TransactionMetadatum")
}

fn json_schema(_gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
schemars::schema::Schema::from(schemars::schema::SchemaObject::new_ref(
"TransactionMetadatum".to_owned(),
))
}

fn is_referenceable() -> bool {
true
}
}

impl Serialize for TransactionMetadatum {
fn serialize<'se, W: Write>(
&self,
Expand Down Expand Up @@ -556,4 +599,12 @@ mod tests {
let output_bytes = decode_arbitrary_bytes_from_metadatum(&metadata).expect("decode failed");
assert_eq!(input_bytes, output_bytes);
}

#[test]
fn metadatum_default_json() {
let json_str = "{\"map\":[{\"k\":{\"list\":[{\"map\":[{\"k\":{\"int\":5},\"v\":{\"int\":-7}},{\"k\":{\"string\":\"hello\"},\"v\":{\"string\":\"world\"}}]},{\"bytes\":\"ff00ff00\"}]},\"v\":{\"int\":5}}]}";
let metadatum: TransactionMetadatum = serde_json::from_str(json_str).unwrap();
let roundtrip_str = serde_json::to_string(&metadatum).unwrap();
assert_eq!(json_str, roundtrip_str);
}
}
3 changes: 2 additions & 1 deletion chain/rust/src/auxdata/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@
// https://github.com/dcSpark/cddl-codegen

pub mod cbor_encodings;
pub mod metadata;
pub mod serialization;
pub mod utils;

use crate::plutus::{PlutusV1Script, PlutusV2Script, PlutusV3Script};
use crate::transaction::NativeScript;
use cbor_encodings::{ConwayFormatAuxDataEncoding, ShelleyMaFormatAuxDataEncoding};

pub use cml_core::metadata::*;
pub use metadata::*;

#[derive(Clone, Debug, serde::Deserialize, serde::Serialize, schemars::JsonSchema)]
pub enum AuxiliaryData {
Expand Down
2 changes: 1 addition & 1 deletion chain/rust/src/auxdata/utils.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use cml_core::metadata::Metadata;
use crate::auxdata::metadata::Metadata;

use crate::{
plutus::{PlutusV1Script, PlutusV2Script},
Expand Down
4 changes: 1 addition & 3 deletions chain/rust/src/builders/tx_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1876,16 +1876,14 @@ mod tests {
use std::collections::BTreeMap;
use std::ops::Deref;

use cml_core::metadata::{
Metadata, MetadatumMap, TransactionMetadatum, TransactionMetadatumLabel,
};
use cml_core::Int;
use cml_crypto::{
Bip32PrivateKey, Bip32PublicKey, DatumHash, Deserialize, PrivateKey, RawBytesEncoding,
TransactionHash,
};

use crate::address::{Address, BaseAddress, EnterpriseAddress, Pointer, PointerAddress};
use crate::auxdata::{Metadata, MetadatumMap, TransactionMetadatum, TransactionMetadatumLabel};
use crate::builders::witness_builder::{PartialPlutusWitness, PlutusScriptWitness};
use crate::builders::{
input_builder::SingleInputBuilder, mint_builder::SingleMintBuilder,
Expand Down
60 changes: 60 additions & 0 deletions chain/rust/src/json/json_serialize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -539,6 +539,42 @@ impl Value {
}
}

impl From<Value> for serde_json::Value {
fn from(value: Value) -> Self {
match value {
Value::Bool(b) => serde_json::Value::Bool(b),
Value::Null => serde_json::Value::Null,
Value::Number(n) => {
serde_json::Value::Number(serde_json::Number::from_str(&n.to_string()).unwrap())
}
Value::String(s) => serde_json::Value::String(s),
Value::Array(arr) => {
serde_json::Value::Array(arr.into_iter().map(|e| e.into()).collect())
}
Value::Object(obj) => {
serde_json::Value::Object(obj.into_iter().map(|(k, v)| (k, v.into())).collect())
}
}
}
}

impl From<serde_json::Value> for Value {
fn from(from: serde_json::Value) -> Self {
match from {
serde_json::Value::Bool(b) => Self::Bool(b),
serde_json::Value::Null => Self::Null,
serde_json::Value::Number(n) => {
Self::Number(BigInteger::from_str(&n.to_string()).unwrap())
}
serde_json::Value::String(s) => Self::String(s),
serde_json::Value::Array(arr) => Self::Array(arr.into_iter().map(Self::from).collect()),
serde_json::Value::Object(obj) => {
Self::Object(obj.into_iter().map(|(k, v)| (k, Self::from(v))).collect())
}
}
}
}

impl From<Vec<Value>> for Value {
fn from(vec: Vec<Value>) -> Self {
Value::Array(vec)
Expand Down Expand Up @@ -569,6 +605,30 @@ impl From<BTreeMap<String, Value>> for Value {
}
}

impl<'a> From<&'a Value> for serde::de::Unexpected<'a> {
fn from(from: &'a Value) -> Self {
match from {
Value::Array(_) => Self::Seq,
Value::String(s) => Self::Str(s),
Value::Bool(b) => Self::Bool(*b),
Value::Null => Self::Unit,
Value::Number(x) => {
if let Some(as_u64) = x.as_u64() {
Self::Unsigned(as_u64)
} else if let Some(as_i64) = x.as_int().and_then(|i| {
use std::convert::TryFrom;
i64::try_from(i128::from(&i)).ok()
}) {
Self::Signed(as_i64)
} else {
Self::Other("Large int")
}
}
Value::Object(_) => Self::Map,
}
}
}

#[cfg(test)]
mod tests {
use std::collections::BTreeMap;
Expand Down
6 changes: 2 additions & 4 deletions chain/rust/src/json/metadatums.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
use wasm_bindgen::prelude::wasm_bindgen;

use crate::{
auxdata::{MetadatumMap, TransactionMetadatum},
json::json_serialize::{JsonParseError, Value as JSONValue},
utils::BigInteger,
};

use cml_core::{
metadata::{MetadatumMap, TransactionMetadatum},
DeserializeError, Int,
};
use cml_core::{DeserializeError, Int};

use std::collections::BTreeMap;
use std::convert::TryFrom;
Expand Down
2 changes: 1 addition & 1 deletion chain/rust/src/json/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
mod json_serialize;
pub(crate) mod json_serialize;
pub mod metadatums;
pub mod plutus_datums;
13 changes: 13 additions & 0 deletions chain/rust/src/json/plutus_datums.rs
Original file line number Diff line number Diff line change
Expand Up @@ -333,3 +333,16 @@ pub fn decode_plutus_datum_to_json_value(
_ => Ok(json_value),
}
}

#[cfg(test)]
mod tests {
use crate::plutus::PlutusData;

#[test]
fn plutus_datum_json() {
let json = "{\"map\":[{\"k\":{\"int\":100},\"v\":{\"list\":[{\"map\":[{\"k\":{\"bytes\":\"78\"},\"v\":{\"bytes\":\"30\"}},{\"k\":{\"bytes\":\"79\"},\"v\":{\"int\":1}}]}]}},{\"k\":{\"bytes\":\"666f6f\"},\"v\":{\"bytes\":\"0000baadf00d0000cafed00d0000deadbeef0000\"}}]}";
// let datum = encode_json_str_to_plutus_datum(json, crate::json::plutus_datums::CardanoNodePlutusDatumSchema::DetailedSchema).unwrap();
let datum: PlutusData = serde_json::from_str(json).unwrap();
assert_eq!(json, serde_json::to_string(&datum).unwrap());
}
}
1 change: 0 additions & 1 deletion chain/rust/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ pub use utils::NetworkId;

pub use cml_core::{
error::{DeserializeError, DeserializeFailure},
metadata::{TransactionMetadatum, TransactionMetadatumLabel},
ordered_hash_map::OrderedHashMap,
serialization::{Deserialize, LenEncoding, Serialize, StringEncoding},
CertificateIndex, Epoch, Int, Slot, TransactionIndex,
Expand Down
6 changes: 1 addition & 5 deletions chain/rust/src/plutus/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,9 +105,7 @@ pub enum Language {
PlutusV3,
}

#[derive(
Clone, Debug, serde::Deserialize, serde::Serialize, schemars::JsonSchema, derivative::Derivative,
)]
#[derive(Clone, Debug, derivative::Derivative)]
#[derivative(
Eq,
PartialEq,
Expand All @@ -126,7 +124,6 @@ pub enum PlutusData {
PartialOrd = "ignore",
Hash = "ignore"
)]
#[serde(skip)]
list_encoding: LenEncoding,
},
Integer(BigInteger),
Expand All @@ -138,7 +135,6 @@ pub enum PlutusData {
PartialOrd = "ignore",
Hash = "ignore"
)]
#[serde(skip)]
bytes_encoding: StringEncoding,
},
}
Expand Down
Loading
Loading