From 1aa12fb3687d54e558c51b2ed267784af54289cc Mon Sep 17 00:00:00 2001 From: KtorZ Date: Tue, 31 Jan 2023 15:26:41 +0100 Subject: [PATCH] Implement serde's Deserialize for blueprints. Here's a trick though: I got lazy (a bit) and did not write a full deserializer for Schema because this is busywork and not at all necessary at this stage. Instead, I've made the blueprint parameterized by a generic type ; which represents the type of the underlying blueprint's schema. When deserializing from JSON, we can default to 'Value' to get a free deserializer. Since all we're interested about is the program and the metadata (purpose and title) of a validator, it works nicely. Serialization however expects a Blueprint, and most of the functions operates over a Blueprint anyway. --- crates/aiken-project/src/blueprint/mod.rs | 17 ++-- crates/aiken-project/src/blueprint/schema.rs | 2 +- .../aiken-project/src/blueprint/validator.rs | 86 ++++++------------- crates/aiken-project/src/lib.rs | 2 +- 4 files changed, 39 insertions(+), 68 deletions(-) diff --git a/crates/aiken-project/src/blueprint/mod.rs b/crates/aiken-project/src/blueprint/mod.rs index 29f7329f..0f23a14d 100644 --- a/crates/aiken-project/src/blueprint/mod.rs +++ b/crates/aiken-project/src/blueprint/mod.rs @@ -5,16 +5,17 @@ pub mod validator; use crate::{config::Config, module::CheckedModules}; use aiken_lang::uplc::CodeGenerator; use error::Error; +use schema::Schema; use std::fmt::{self, Debug, Display}; use validator::Validator; -#[derive(Debug, PartialEq, Clone, serde::Serialize)] -pub struct Blueprint { +#[derive(Debug, PartialEq, Clone, serde::Serialize, serde::Deserialize)] +pub struct Blueprint { pub preamble: Preamble, - pub validators: Vec, + pub validators: Vec>, } -#[derive(Debug, PartialEq, Clone, serde::Serialize)] +#[derive(Debug, PartialEq, Clone, serde::Serialize, serde::Deserialize)] pub struct Preamble { pub title: String, #[serde(skip_serializing_if = "Option::is_none")] @@ -24,7 +25,7 @@ pub struct Preamble { pub license: Option, } -impl Blueprint { +impl Blueprint { pub fn new( config: &Config, modules: &CheckedModules, @@ -46,7 +47,7 @@ impl Blueprint { } } -impl Display for Blueprint { +impl Display for Blueprint { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let s = serde_json::to_string_pretty(self).map_err(|_| fmt::Error)?; f.write_str(&s) @@ -75,7 +76,7 @@ mod test { #[test] fn serialize_no_description() { - let blueprint = Blueprint { + let blueprint: Blueprint = Blueprint { preamble: Preamble { title: "Foo".to_string(), description: None, @@ -99,7 +100,7 @@ mod test { #[test] fn serialize_with_description() { - let blueprint = Blueprint { + let blueprint: Blueprint = Blueprint { preamble: Preamble { title: "Foo".to_string(), description: Some("Lorem ipsum".to_string()), diff --git a/crates/aiken-project/src/blueprint/schema.rs b/crates/aiken-project/src/blueprint/schema.rs index 223172bc..f598199b 100644 --- a/crates/aiken-project/src/blueprint/schema.rs +++ b/crates/aiken-project/src/blueprint/schema.rs @@ -16,7 +16,7 @@ use std::{ sync::Arc, }; -#[derive(Debug, PartialEq, Eq, Clone, serde::Serialize)] +#[derive(Debug, PartialEq, Eq, Clone, serde::Serialize, serde::Deserialize)] pub struct Annotated { #[serde(skip_serializing_if = "Option::is_none")] pub title: Option, diff --git a/crates/aiken-project/src/blueprint/validator.rs b/crates/aiken-project/src/blueprint/validator.rs index 4d17aa50..97b21d9b 100644 --- a/crates/aiken-project/src/blueprint/validator.rs +++ b/crates/aiken-project/src/blueprint/validator.rs @@ -5,29 +5,27 @@ use super::{ use crate::module::{CheckedModule, CheckedModules}; use aiken_lang::{ast::TypedFunction, uplc::CodeGenerator}; use miette::NamedSource; -use pallas::ledger::primitives::babbage as cardano; -use pallas_traverse::ComputeHash; -use serde::{ - self, - ser::{Serialize, SerializeStruct, Serializer}, -}; +use serde; use std::{ collections::HashMap, fmt::{self, Display}, }; -use uplc::ast::{NamedDeBruijn, Program}; +use uplc::ast::{DeBruijn, Program}; -#[derive(Debug, PartialEq, Clone)] -pub struct Validator { +#[derive(Debug, PartialEq, Clone, serde::Serialize, serde::Deserialize)] +pub struct Validator { pub title: String, pub purpose: Purpose, + #[serde(skip_serializing_if = "Option::is_none")] pub description: Option, - pub datum: Option>, - pub redeemer: Annotated, - pub program: Program, + #[serde(skip_serializing_if = "Option::is_none")] + pub datum: Option>, + pub redeemer: Annotated, + #[serde(flatten)] + pub program: Program, } -#[derive(Debug, PartialEq, Clone, serde::Serialize)] +#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, serde::Serialize, serde::Deserialize)] #[serde(rename_all = "camelCase")] pub enum Purpose { Spend, @@ -36,48 +34,20 @@ pub enum Purpose { Publish, } -impl Serialize for Validator { - fn serialize(&self, serializer: S) -> Result { - let cbor = self.program.to_cbor().unwrap(); - - let source_code = hex::encode(&cbor); - - let hash = cardano::PlutusV2Script(cbor.into()).compute_hash(); - - let fields = 5 - + self.description.as_ref().map(|_| 1).unwrap_or_default() - + self.datum.as_ref().map(|_| 1).unwrap_or_default(); - - let mut s = serializer.serialize_struct("Validator", fields)?; - s.serialize_field("title", &self.title)?; - s.serialize_field("purpose", &self.purpose)?; - s.serialize_field("hash", &hash)?; - if let Some { .. } = self.description { - s.serialize_field("description", &self.description)?; - } - if let Some { .. } = self.datum { - s.serialize_field("datum", &self.datum)?; - } - s.serialize_field("redeemer", &self.redeemer)?; - s.serialize_field("compiledCode", &source_code)?; - s.end() - } -} - -impl Display for Validator { +impl Display for Validator { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let s = serde_json::to_string_pretty(self).map_err(|_| fmt::Error)?; f.write_str(&s) } } -impl Validator { +impl Validator { pub fn from_checked_module( modules: &CheckedModules, generator: &mut CodeGenerator, validator: &CheckedModule, def: &TypedFunction, - ) -> Result { + ) -> Result, Error> { let purpose: Purpose = def .name .clone() @@ -293,12 +263,12 @@ mod test { json!({ "title": "test_module", "purpose": "mint", - "hash": "da4a98cee05a17be402b07c414d59bf894c9ebd0487186417121de8f", + "hash": "f9fcaa5bfce8bde3b85e595b5235a184fe0fb79916d38273c74a23cf", "redeemer": { "title": "Data", "description": "Any Plutus data." }, - "compiledCode": "581d010000210872656465656d657200210363747800533357349445261601" + "compiledCode": "582e0100003232225333573494452616300100122253335573e004293099ab9b3001357420046660060066ae88008005" }), ); } @@ -344,7 +314,7 @@ mod test { json!({ "title": "test_module", "purpose": "spend", - "hash": "cf2cd3bed32615bfecbd280618c1c1bec2198fc0f72b04f323a8a0d2", + "hash": "3b7ee6139deb59d892955ac3cad15d53e48dcb1643227256b29d2b6f", "datum": { "title": "State", "description": "On-chain state", @@ -411,7 +381,7 @@ mod test { } ] }, - "compiledCode": "58250100002105646174756d00210872656465656d657200210363747800533357349445261601" + "compiledCode": "582f01000032322225333573494452616300100122253335573e004293099ab9b3001357420046660060066ae880080041" }), ); } @@ -427,7 +397,7 @@ mod test { json!({ "title": "test_module", "purpose": "spend", - "hash": "12065ad2edb75b9e497e50c4f8130b90c9108f8ae0991abc5442e074", + "hash": "4a0c0768ff3e8c8f9da5fc2c499e592ae37f676a11dbc6e9de958116", "datum": { "dataType": "#pair", "left": { @@ -440,7 +410,7 @@ mod test { "redeemer": { "dataType": "#string" }, - "compiledCode": "589f0100002105646174756d00320105646174756d00210872656465656d65720032010872656465656d657200210363747800533357349445261637326eb8010872656465656d6572000132010b5f5f6c6973745f64617461003201065f5f7461696c00337606ae84010b5f5f6c6973745f646174610002357421065f5f7461696c00013574410b5f5f6c6973745f64617461000137580105646174756d000101" + "compiledCode": "584901000032322322322533357349445261637326eb8004c8c8cdd81aba1002357420026ae88004dd600098008009112999aab9f00214984cd5cd98009aba100233300300335744004003" }), ) } @@ -456,7 +426,7 @@ mod test { json!({ "title": "test_module", "purpose": "spend", - "hash": "5c470f297728051a920bd9e70e14197c8fb0eaf4413e419827b0ec38", + "hash": "5e7487927f32a4d6e8c3b462c8e0e0f685506621f5f2683807805d0e", "datum": { "title": "Tuple", "dataType": "#list", @@ -476,7 +446,7 @@ mod test { "title": "Data", "description": "Any Plutus data." }, - "compiledCode": "58390100002105646174756d00320105646174756d00210872656465656d657200210363747800533357349445261637580105646174756d000101" + "compiledCode": "5833010000323223222533357349445261637580026002002444a666aae7c008526133573660026ae84008ccc00c00cd5d10010009" }), ) } @@ -503,7 +473,7 @@ mod test { { "title": "test_module", "purpose": "withdraw", - "hash": "da4a98cee05a17be402b07c414d59bf894c9ebd0487186417121de8f", + "hash": "f9fcaa5bfce8bde3b85e595b5235a184fe0fb79916d38273c74a23cf", "redeemer": { "title": "Either", "anyOf": [ @@ -547,7 +517,7 @@ mod test { } ] }, - "compiledCode": "581d010000210872656465656d657200210363747800533357349445261601" + "compiledCode": "582e0100003232225333573494452616300100122253335573e004293099ab9b3001357420046660060066ae88008005" } ), ) @@ -571,7 +541,7 @@ mod test { { "title": "test_module", "purpose": "mint", - "hash": "da4a98cee05a17be402b07c414d59bf894c9ebd0487186417121de8f", + "hash": "f9fcaa5bfce8bde3b85e595b5235a184fe0fb79916d38273c74a23cf", "redeemer": { "title": "Dict", "anyOf": [ @@ -594,7 +564,7 @@ mod test { } ] }, - "compiledCode": "581d010000210872656465656d657200210363747800533357349445261601" + "compiledCode": "582e0100003232225333573494452616300100122253335573e004293099ab9b3001357420046660060066ae88008005" } ), ); @@ -618,7 +588,7 @@ mod test { { "title": "test_module", "purpose": "mint", - "hash": "da4a98cee05a17be402b07c414d59bf894c9ebd0487186417121de8f", + "hash": "f9fcaa5bfce8bde3b85e595b5235a184fe0fb79916d38273c74a23cf", "redeemer": { "title": "Dict", "dataType": "map", @@ -629,7 +599,7 @@ mod test { "dataType": "integer" } }, - "compiledCode": "581d010000210872656465656d657200210363747800533357349445261601" + "compiledCode": "582e0100003232225333573494452616300100122253335573e004293099ab9b3001357420046660060066ae88008005" } ), ); diff --git a/crates/aiken-project/src/lib.rs b/crates/aiken-project/src/lib.rs index e3172ca8..10b0fc47 100644 --- a/crates/aiken-project/src/lib.rs +++ b/crates/aiken-project/src/lib.rs @@ -169,7 +169,7 @@ where self.compile(options) } - pub fn dump_uplc(&self, blueprint: &Blueprint) -> Result<(), Error> { + pub fn dump_uplc(&self, blueprint: &Blueprint) -> Result<(), Error> { let dir = self.root.join("artifacts"); self.event_listener .handle_event(Event::DumpingUPLC { path: dir.clone() });