Skip to content

Commit

Permalink
Move RawBytesEncoding and standardize use (#340)
Browse files Browse the repository at this point in the history
Fixes #334

Moves RawBytesEncoding to cml_core::serialization as there is nothing
specific about crypto with it, and it can be used in many other places
(Asset names, plutus scripts, etc).

Add wasm macros for declaring the RawBytesEncoding API automatically
using the rust type's trait impl

Add missing hash() to PlutusV3Script

Document AssetName on how to convert to/from using utf8 traits in rust

Use dcSpark/cddl-codegen#240 to remove confusing `get()` (what is it
getting?) functions on some wrapper types. These are replaced with `RawBytesEncoding` to standardize use with the rest of CML
  • Loading branch information
rooooooooob authored Jul 10, 2024
1 parent 8429a73 commit 653fd14
Show file tree
Hide file tree
Showing 18 changed files with 172 additions and 153 deletions.
5 changes: 1 addition & 4 deletions chain/rust/src/assets/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use cml_core::error::*;

use std::convert::TryFrom;

/// Use TryFrom<&str> / TryInto<&str> for utf8 text conversion and RawBytesEncoding for direct bytes access
#[derive(Clone, Debug, derivative::Derivative)]
#[derivative(Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct AssetName {
Expand All @@ -26,10 +27,6 @@ pub struct AssetName {
}

impl AssetName {
pub fn get(&self) -> &Vec<u8> {
&self.inner
}

pub fn new(inner: Vec<u8>) -> Result<Self, DeserializeError> {
if inner.len() > 32 {
return Err(DeserializeError::new(
Expand Down
14 changes: 12 additions & 2 deletions chain/rust/src/assets/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,17 @@ impl<'a> TryInto<&'a str> for &'a AssetName {
type Error = std::str::Utf8Error;

fn try_into(self) -> Result<&'a str, Self::Error> {
std::str::from_utf8(self.get())
std::str::from_utf8(self.to_raw_bytes())
}
}

impl RawBytesEncoding for AssetName {
fn to_raw_bytes(&self) -> &[u8] {
self.inner.as_ref()
}

fn from_raw_bytes(bytes: &[u8]) -> Result<Self, DeserializeError> {
Self::new(bytes.to_vec())
}
}

Expand All @@ -71,7 +81,7 @@ impl<T: std::fmt::Debug> std::fmt::Debug for AssetBundle<T> {
for (pid, assets) in self.0.iter() {
let pid_hex = hex::encode(pid.to_raw_bytes());
for (an, val) in assets.iter() {
let an_hex = hex::encode(an.get());
let an_hex = hex::encode(an.to_raw_bytes());
let an_name = if an_hex.len() > 8 {
format!(
"{}..{}",
Expand Down
3 changes: 3 additions & 0 deletions chain/rust/src/genesis/byron/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use base64::{
Engine,
};
use cbor_event::cbor;
use cml_core::DeserializeError;
use cml_crypto::{CryptoError, RawBytesEncoding};
use serde_json;
use std::collections::BTreeMap;
Expand All @@ -29,6 +30,8 @@ pub enum GenesisJSONError {
Serde(#[from] serde_json::Error),
#[error("Crypto: {0:?}")]
CryptoError(#[from] CryptoError),
#[error("Deserialize: {0:?}")]
DeserializeError(#[from] DeserializeError),
#[error("Base64: {0:?}")]
Base64(#[from] base64::DecodeError),
#[error("ParseInt: {0:?}")]
Expand Down
12 changes: 0 additions & 12 deletions chain/rust/src/plutus/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -244,10 +244,6 @@ pub struct PlutusV1Script {
}

impl PlutusV1Script {
pub fn get(&self) -> &Vec<u8> {
&self.inner
}

pub fn new(inner: Vec<u8>) -> Self {
Self {
inner,
Expand Down Expand Up @@ -317,10 +313,6 @@ pub struct PlutusV2Script {
}

impl PlutusV2Script {
pub fn get(&self) -> &Vec<u8> {
&self.inner
}

pub fn new(inner: Vec<u8>) -> Self {
Self {
inner,
Expand Down Expand Up @@ -390,10 +382,6 @@ pub struct PlutusV3Script {
}

impl PlutusV3Script {
pub fn get(&self) -> &Vec<u8> {
&self.inner
}

pub fn new(inner: Vec<u8>) -> Self {
Self {
inner,
Expand Down
36 changes: 33 additions & 3 deletions chain/rust/src/plutus/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -452,19 +452,49 @@ impl From<PlutusV3Script> for PlutusScript {

impl PlutusV1Script {
pub fn hash(&self) -> ScriptHash {
hash_script(ScriptHashNamespace::PlutusV1, self.get())
hash_script(ScriptHashNamespace::PlutusV1, self.to_raw_bytes())
}
}

impl PlutusV2Script {
pub fn hash(&self) -> ScriptHash {
hash_script(ScriptHashNamespace::PlutusV2, self.get())
hash_script(ScriptHashNamespace::PlutusV2, self.to_raw_bytes())
}
}

impl PlutusV3Script {
pub fn hash(&self) -> ScriptHash {
hash_script(ScriptHashNamespace::PlutusV3, self.get())
hash_script(ScriptHashNamespace::PlutusV3, self.to_raw_bytes())
}
}

impl RawBytesEncoding for PlutusV1Script {
fn to_raw_bytes(&self) -> &[u8] {
self.inner.as_ref()
}

fn from_raw_bytes(bytes: &[u8]) -> Result<Self, DeserializeError> {
Ok(Self::new(bytes.to_vec()))
}
}

impl RawBytesEncoding for PlutusV2Script {
fn to_raw_bytes(&self) -> &[u8] {
self.inner.as_ref()
}

fn from_raw_bytes(bytes: &[u8]) -> Result<Self, DeserializeError> {
Ok(Self::new(bytes.to_vec()))
}
}

impl RawBytesEncoding for PlutusV3Script {
fn to_raw_bytes(&self) -> &[u8] {
self.inner.as_ref()
}

fn from_raw_bytes(bytes: &[u8]) -> Result<Self, DeserializeError> {
Ok(Self::new(bytes.to_vec()))
}
}

Expand Down
7 changes: 0 additions & 7 deletions chain/wasm/src/assets/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,3 @@ pub struct AssetName(cml_chain::assets::AssetName);
impl_wasm_cbor_json_api!(AssetName);

impl_wasm_conversions!(cml_chain::assets::AssetName, AssetName);

#[wasm_bindgen]
impl AssetName {
pub fn get(&self) -> Vec<u8> {
self.0.get().clone()
}
}
15 changes: 5 additions & 10 deletions chain/wasm/src/assets/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ use std::{
use crate::{assets::AssetName, AssetNameList, MapAssetNameToNonZeroInt64, PolicyId, PolicyIdList};
use wasm_bindgen::{prelude::wasm_bindgen, JsError, JsValue};

use cml_core_wasm::{impl_wasm_cbor_json_api, impl_wasm_conversions, impl_wasm_map};
use cml_core_wasm::{
impl_raw_bytes_api, impl_wasm_cbor_json_api, impl_wasm_conversions, impl_wasm_map,
};

use super::Coin;

Expand All @@ -25,15 +27,6 @@ impl_wasm_map!(

#[wasm_bindgen]
impl AssetName {
/**
* Create an AssetName from raw bytes. 64 byte maximum.
*/
pub fn from_bytes(bytes: Vec<u8>) -> Result<AssetName, JsError> {
cml_chain::assets::AssetName::try_from(bytes)
.map(Into::into)
.map_err(Into::into)
}

/**
* Create an AssetName from utf8 string. 64 byte (not char!) maximum.
*/
Expand All @@ -55,6 +48,8 @@ impl AssetName {
}
}

impl_raw_bytes_api!(cml_chain::assets::AssetName, AssetName);

#[derive(Clone, Debug)]
#[wasm_bindgen]
pub struct MultiAsset(cml_chain::assets::MultiAsset);
Expand Down
21 changes: 0 additions & 21 deletions chain/wasm/src/plutus/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -224,13 +224,6 @@ impl_wasm_cbor_json_api!(PlutusV1Script);

impl_wasm_conversions!(cml_chain::plutus::PlutusV1Script, PlutusV1Script);

#[wasm_bindgen]
impl PlutusV1Script {
pub fn get(&self) -> Vec<u8> {
self.0.get().clone()
}
}

#[derive(Clone, Debug)]
#[wasm_bindgen]
pub struct PlutusV2Script(cml_chain::plutus::PlutusV2Script);
Expand All @@ -239,13 +232,6 @@ impl_wasm_cbor_json_api!(PlutusV2Script);

impl_wasm_conversions!(cml_chain::plutus::PlutusV2Script, PlutusV2Script);

#[wasm_bindgen]
impl PlutusV2Script {
pub fn get(&self) -> Vec<u8> {
self.0.get().clone()
}
}

#[derive(Clone, Debug)]
#[wasm_bindgen]
pub struct PlutusV3Script(cml_chain::plutus::PlutusV3Script);
Expand All @@ -254,13 +240,6 @@ impl_wasm_cbor_json_api!(PlutusV3Script);

impl_wasm_conversions!(cml_chain::plutus::PlutusV3Script, PlutusV3Script);

#[wasm_bindgen]
impl PlutusV3Script {
pub fn get(&self) -> Vec<u8> {
self.0.get().clone()
}
}

#[derive(Clone, Debug)]
#[wasm_bindgen]
pub struct RedeemerKey(cml_chain::plutus::RedeemerKey);
Expand Down
17 changes: 16 additions & 1 deletion chain/wasm/src/plutus/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ use crate::{
LegacyRedeemerList, PlutusDataList,
};
use cml_chain::plutus::Language;
use cml_core_wasm::{impl_wasm_cbor_api, impl_wasm_cbor_json_api, impl_wasm_conversions};
use cml_core_wasm::{
impl_raw_bytes_api, impl_wasm_cbor_api, impl_wasm_cbor_json_api, impl_wasm_conversions,
};
use cml_crypto_wasm::ScriptHash;
use wasm_bindgen::prelude::{wasm_bindgen, JsError, JsValue};

Expand Down Expand Up @@ -152,6 +154,19 @@ impl PlutusV2Script {
}
}

#[wasm_bindgen]
impl PlutusV3Script {
pub fn hash(&self) -> ScriptHash {
self.0.hash().into()
}
}

impl_raw_bytes_api!(cml_chain::plutus::PlutusV1Script, PlutusV1Script);

impl_raw_bytes_api!(cml_chain::plutus::PlutusV2Script, PlutusV2Script);

impl_raw_bytes_api!(cml_chain::plutus::PlutusV3Script, PlutusV3Script);

#[wasm_bindgen]
impl Redeemers {
pub fn to_flat_format(&self) -> LegacyRedeemerList {
Expand Down
8 changes: 4 additions & 4 deletions cip25/rust/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ pub use cml_chain::{
PolicyId,
};
pub use cml_core::{error::*, serialization::*};
use cml_crypto::RawBytesEncoding;
use std::io::{BufRead, Seek, SeekFrom, Write};

use crate::{CIP25ChunkableString, CIP25Metadata, CIP25MetadataDetails, CIP25String64};
Expand Down Expand Up @@ -251,7 +250,7 @@ impl CIP25LabelMetadata {
details: CIP25MetadataDetails,
) -> Result<Option<CIP25MetadataDetails>, CIP25Error> {
if self.version == CIP25Version::V1 {
if let Err(e) = String::from_utf8(asset_name.get().clone()) {
if let Err(e) = String::from_utf8(asset_name.to_raw_bytes().to_vec()) {
return Err(CIP25Error::Version1NonStringAsset(asset_name, e));
}
}
Expand Down Expand Up @@ -296,7 +295,8 @@ impl cbor_event::se::Serialize for CIP25LabelMetadata {
for (asset_name, details) in assets.iter() {
// hand-edit: write as string
// note: this invariant is checked during setting and data is private
let asset_name_str = String::from_utf8(asset_name.get().clone()).unwrap();
let asset_name_str =
String::from_utf8(asset_name.to_raw_bytes().to_vec()).unwrap();
serializer.write_text(asset_name_str)?;
details.serialize(serializer)?;
}
Expand All @@ -313,7 +313,7 @@ impl cbor_event::se::Serialize for CIP25LabelMetadata {
serializer.write_map(cbor_event::Len::Len(assets.len() as u64))?;
for (asset_name, details) in assets.iter() {
// hand-edit: write bytes
serializer.write_bytes(asset_name.get())?;
serializer.write_bytes(asset_name.to_raw_bytes())?;

details.serialize(serializer)?;
}
Expand Down
21 changes: 21 additions & 0 deletions core/rust/src/serialization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -288,3 +288,24 @@ impl<T: Deserialize> FromBytes for T {
Self::deserialize(&mut raw).map_err(Into::into)
}
}
pub trait RawBytesEncoding {
fn to_raw_bytes(&self) -> &[u8];

fn from_raw_bytes(bytes: &[u8]) -> Result<Self, DeserializeError>
where
Self: Sized;

fn to_raw_hex(&self) -> String {
hex::encode(self.to_raw_bytes())
}

fn from_raw_hex(hex_str: &str) -> Result<Self, DeserializeError>
where
Self: Sized,
{
let bytes = hex::decode(hex_str).map_err(|e| {
DeserializeError::from(DeserializeFailure::InvalidStructure(Box::new(e)))
})?;
Self::from_raw_bytes(bytes.as_ref())
}
}
3 changes: 3 additions & 0 deletions core/wasm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ use wasm_bindgen::prelude::{wasm_bindgen, JsValue};

use cml_core::serialization::{Deserialize, Serialize};

// re-export to make macros easier to use
pub use cml_core::serialization::RawBytesEncoding;

#[macro_use]
pub mod wasm_wrappers;

Expand Down
43 changes: 43 additions & 0 deletions core/wasm/src/wasm_wrappers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -550,3 +550,46 @@ macro_rules! impl_wasm_json_api {
}
};
}

#[macro_export]
macro_rules! impl_raw_bytes_api {
($rust:ty, $wasm:ident) => {
#[wasm_bindgen]
impl $wasm {
/**
* Direct raw bytes without any CBOR structure
*/
pub fn to_raw_bytes(&self) -> Vec<u8> {
use cml_core_wasm::RawBytesEncoding;
self.0.to_raw_bytes().to_vec()
}

/**
* Parse from the direct raw bytes, without any CBOR structure
*/
pub fn from_raw_bytes(bytes: &[u8]) -> Result<$wasm, wasm_bindgen::JsError> {
use cml_core_wasm::RawBytesEncoding;
<$rust>::from_raw_bytes(bytes).map(Self).map_err(Into::into)
}

/**
* Direct raw bytes without any CBOR structure, as a hex-encoded string
*/
pub fn to_hex(&self) -> String {
use cml_core_wasm::RawBytesEncoding;
self.0.to_raw_hex()
}

/**
* Parse from a hex string of the direct raw bytes, without any CBOR structure
*/
pub fn from_hex(input: &str) -> Result<$wasm, wasm_bindgen::JsError> {
use cml_core_wasm::RawBytesEncoding;
<$rust>::from_raw_hex(input)
.map(Into::into)
.map(Self)
.map_err(Into::into)
}
}
};
}
Loading

0 comments on commit 653fd14

Please sign in to comment.