diff --git a/src/lib.rs b/src/lib.rs index 702089a..b1ccb20 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -89,6 +89,14 @@ impl TemplateProgram { debug_symbols: self.simfony.debug_symbols(self.file.as_ref()), simplicity: commit, witness_types: self.simfony.witness_types().shallow_clone(), + parameter_types: self.simfony.parameters().shallow_clone(), + }) + } + + pub fn generate_abi_meta(&self) -> Result { + Ok(AbiMeta { + witness_types: self.simfony.witness_types().shallow_clone(), + param_types: self.parameters().shallow_clone(), }) } } @@ -99,6 +107,7 @@ pub struct CompiledProgram { simplicity: Arc>, witness_types: WitnessTypes, debug_symbols: DebugSymbols, + parameter_types: Parameters, } impl CompiledProgram { @@ -162,6 +171,19 @@ impl CompiledProgram { debug_symbols: self.debug_symbols.clone(), }) } + + pub fn generate_abi_meta(&self) -> Result { + Ok(AbiMeta { + witness_types: self.witness_types.shallow_clone(), + param_types: self.parameter_types.shallow_clone(), + }) + } +} + +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct AbiMeta { + pub witness_types: WitnessTypes, + pub param_types: Parameters, } /// A SimplicityHL program, compiled to Simplicity and satisfied with witness data. diff --git a/src/main.rs b/src/main.rs index 1135a31..4aa1d55 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,7 +2,7 @@ use base64::display::Base64Display; use base64::engine::general_purpose::STANDARD; use clap::{Arg, ArgAction, Command}; -use simplicityhl::{Arguments, CompiledProgram}; +use simplicityhl::{AbiMeta, Arguments, CompiledProgram}; use std::{env, fmt}; #[cfg_attr(feature = "serde", derive(serde::Serialize))] @@ -12,6 +12,8 @@ struct Output { program: String, /// Simplicity witness result, base64 encoded, if the .wit file was provided. witness: Option, + /// Simplicity program ABI metadata to the program which the user provides. + abi_meta: Option, } impl fmt::Display for Output { @@ -20,6 +22,9 @@ impl fmt::Display for Output { if let Some(witness) = &self.witness { writeln!(f, "Witness:\n{}", witness)?; } + if let Some(witness) = &self.abi_meta { + writeln!(f, "ABI meta:\n{:?}", witness)?; + } Ok(()) } } @@ -59,6 +64,12 @@ fn main() -> Result<(), Box> { .action(ArgAction::SetTrue) .help("Output in JSON"), ) + .arg( + Arg::new("abi") + .long("abi") + .action(ArgAction::SetTrue) + .help("Additional ABI .simf contract types"), + ) }; let matches = command.get_matches(); @@ -68,6 +79,7 @@ fn main() -> Result<(), Box> { let prog_text = std::fs::read_to_string(prog_path).map_err(|e| e.to_string())?; let include_debug_symbols = matches.get_flag("debug"); let output_json = matches.get_flag("json"); + let abi_param = matches.get_flag("abi"); let compiled = CompiledProgram::new(prog_text, Arguments::default(), include_debug_symbols)?; @@ -103,9 +115,16 @@ fn main() -> Result<(), Box> { } }; + let abi_opt = if abi_param { + Some(compiled.generate_abi_meta()?) + } else { + None + }; + let output = Output { program: Base64Display::new(&program_bytes, &STANDARD).to_string(), witness: witness_bytes.map(|bytes| Base64Display::new(&bytes, &STANDARD).to_string()), + abi_meta: abi_opt, }; if output_json { diff --git a/src/serde.rs b/src/serde.rs index 2a12550..18c6ef0 100644 --- a/src/serde.rs +++ b/src/serde.rs @@ -1,13 +1,13 @@ use std::collections::HashMap; use std::fmt; -use serde::{de, ser::SerializeMap, Deserialize, Deserializer, Serialize, Serializer}; - use crate::parse::ParseFromStr; use crate::str::WitnessName; use crate::types::ResolvedType; use crate::value::Value; use crate::witness::{Arguments, WitnessValues}; +use crate::{AbiMeta, Parameters, WitnessTypes}; +use serde::{de, ser::SerializeMap, Deserialize, Deserializer, Serialize, Serializer}; struct WitnessMapVisitor; @@ -43,6 +43,66 @@ impl<'de> Deserialize<'de> for WitnessValues { } } +impl Serialize for ResolvedType { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str(&self.to_string()) + } +} + +impl Serialize for WitnessName { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str(self.as_ref()) + } +} + +impl Serialize for AbiMeta { + fn serialize(&self, serializer: S) -> Result + where + S: ::serde::Serializer, + { + use ::serde::ser::SerializeStruct; + + let mut state = serializer.serialize_struct("AbiMeta", 2)?; + state.serialize_field("witness_types", &self.witness_types)?; + state.serialize_field("parameter_types", &self.param_types)?; + state.end() + } +} + +impl Serialize for Parameters { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let map_ref = self.as_ref(); + let mut map = serializer.serialize_map(Some(map_ref.len()))?; + for (key, value) in map_ref { + map.serialize_entry(key, value)?; + } + map.end() + } +} + +impl Serialize for WitnessTypes { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let map_ref = self.as_ref(); + let mut map = serializer.serialize_map(Some(map_ref.len()))?; + for (key, value) in map_ref { + map.serialize_entry(key, value)?; + } + map.end() + } +} + impl<'de> Deserialize<'de> for Arguments { fn deserialize(deserializer: D) -> Result where diff --git a/src/str.rs b/src/str.rs index 71190b6..a113a70 100644 --- a/src/str.rs +++ b/src/str.rs @@ -125,6 +125,12 @@ pub struct WitnessName(Arc); wrapped_string!(WitnessName, "witness name"); impl_arbitrary_lowercase_alpha!(WitnessName); +impl AsRef for WitnessName { + fn as_ref(&self) -> &str { + self.0.as_ref() + } +} + /// The name of a jet. #[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] pub struct JetName(Arc); diff --git a/src/witness.rs b/src/witness.rs index 031b3a7..6d6ffef 100644 --- a/src/witness.rs +++ b/src/witness.rs @@ -94,6 +94,12 @@ pub struct WitnessTypes(Arc>); impl_name_type_map!(WitnessTypes); +impl AsRef> for WitnessTypes { + fn as_ref(&self) -> &HashMap { + self.0.as_ref() + } +} + /// Map of witness values. #[derive(Clone, Debug, Eq, PartialEq, Default)] #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] @@ -151,6 +157,12 @@ pub struct Parameters(Arc>); impl_name_type_map!(Parameters); +impl AsRef> for Parameters { + fn as_ref(&self) -> &HashMap { + self.0.as_ref() + } +} + /// Map of arguments. /// /// An argument is the value of a parameter.