Define serde's Serialize/Deserialize for Program<DeBrujin>
This will be useful to re-use this behavior in other structure that contains a Program<DeBruijn> without having to manually serialize or deserialize the entire structure.
This commit is contained in:
parent
4588ccd040
commit
cab59c188a
|
@ -1,6 +1,20 @@
|
|||
use std::{fmt::Display, rc::Rc};
|
||||
use std::{
|
||||
fmt::{self, Display},
|
||||
rc::Rc,
|
||||
};
|
||||
|
||||
use pallas_primitives::{alonzo::PlutusData, babbage::Language};
|
||||
use serde::{
|
||||
self,
|
||||
de::{self, Deserialize, Deserializer, MapAccess, Visitor},
|
||||
ser::{Serialize, SerializeStruct, Serializer},
|
||||
};
|
||||
|
||||
use pallas_addresses::{Network, ShelleyAddress, ShelleyDelegationPart, ShelleyPaymentPart};
|
||||
use pallas_primitives::{
|
||||
alonzo::PlutusData,
|
||||
babbage::{self as cardano, Language},
|
||||
};
|
||||
use pallas_traverse::ComputeHash;
|
||||
|
||||
use crate::{
|
||||
builtins::DefaultFunction,
|
||||
|
@ -79,6 +93,81 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl Serialize for Program<DeBruijn> {
|
||||
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||
let cbor = self.to_cbor().unwrap();
|
||||
let mut s = serializer.serialize_struct("Program<DeBruijn>", 2)?;
|
||||
s.serialize_field("compiledCode", &hex::encode(&cbor))?;
|
||||
s.serialize_field("hash", &cardano::PlutusV2Script(cbor.into()).compute_hash())?;
|
||||
s.end()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Deserialize<'a> for Program<DeBruijn> {
|
||||
fn deserialize<D: Deserializer<'a>>(deserializer: D) -> Result<Self, D::Error> {
|
||||
#[derive(serde::Deserialize)]
|
||||
#[serde(field_identifier, rename_all = "camelCase")]
|
||||
enum Fields {
|
||||
CompiledCode,
|
||||
}
|
||||
|
||||
struct ProgramVisitor;
|
||||
|
||||
impl<'a> Visitor<'a> for ProgramVisitor {
|
||||
type Value = Program<DeBruijn>;
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
formatter.write_str("Program<Visitor>")
|
||||
}
|
||||
|
||||
fn visit_map<V>(self, mut map: V) -> Result<Program<DeBruijn>, V::Error>
|
||||
where
|
||||
V: MapAccess<'a>,
|
||||
{
|
||||
let mut compiled_code: Option<String> = None;
|
||||
while let Some(key) = map.next_key()? {
|
||||
match key {
|
||||
Fields::CompiledCode => {
|
||||
if compiled_code.is_some() {
|
||||
return Err(de::Error::duplicate_field("compiledCode"));
|
||||
}
|
||||
compiled_code = Some(map.next_value()?);
|
||||
}
|
||||
}
|
||||
}
|
||||
let compiled_code =
|
||||
compiled_code.ok_or_else(|| de::Error::missing_field("compiledCode"))?;
|
||||
|
||||
let mut cbor_buffer = Vec::new();
|
||||
let mut flat_buffer = Vec::new();
|
||||
|
||||
Program::<DeBruijn>::from_hex(&compiled_code, &mut cbor_buffer, &mut flat_buffer)
|
||||
.map_err(|e| {
|
||||
de::Error::invalid_value(
|
||||
de::Unexpected::Other(&format!("{}", e)),
|
||||
&"a base16-encoded CBOR-serialized UPLC program",
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const FIELDS: &[&str] = &["compiledCode"];
|
||||
deserializer.deserialize_struct("Program<DeBruijn>", FIELDS, ProgramVisitor)
|
||||
}
|
||||
}
|
||||
|
||||
impl Program<DeBruijn> {
|
||||
pub fn address(&self, network: Network, delegation: ShelleyDelegationPart) -> ShelleyAddress {
|
||||
let cbor = self.to_cbor().unwrap();
|
||||
let validator_hash = cardano::PlutusV2Script(cbor.into()).compute_hash();
|
||||
ShelleyAddress::new(
|
||||
network,
|
||||
ShelleyPaymentPart::Script(validator_hash),
|
||||
delegation,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// This represents a term in Untyped Plutus Core.
|
||||
/// We need a generic type for the different forms that a program may be in.
|
||||
/// Specifically, `Var` and `parameter_name` in `Lambda` can be a `Name`,
|
||||
|
|
Loading…
Reference in New Issue