diff --git a/crates/aiken-project/src/blueprint/mod.rs b/crates/aiken-project/src/blueprint/mod.rs index 0f23a14d..6e9c2343 100644 --- a/crates/aiken-project/src/blueprint/mod.rs +++ b/crates/aiken-project/src/blueprint/mod.rs @@ -7,12 +7,12 @@ use aiken_lang::uplc::CodeGenerator; use error::Error; use schema::Schema; use std::fmt::{self, Debug, Display}; -use validator::Validator; +use validator::{Purpose, Validator}; #[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, serde::Deserialize)] @@ -25,6 +25,12 @@ pub struct Preamble { pub license: Option, } +#[derive(Debug, PartialEq, Clone)] +pub enum LookupResult<'a, T> { + One(&'a T), + Many, +} + impl Blueprint { pub fn new( config: &Config, @@ -47,6 +53,56 @@ impl Blueprint { } } +impl Blueprint { + pub fn lookup( + &self, + title: Option<&String>, + purpose: Option<&Purpose>, + ) -> Option>> { + let mut validator = None; + for v in self.validators.iter() { + let match_title = Some(&v.title) == title.or(Some(&v.title)); + let match_purpose = Some(&v.purpose) == purpose.or(Some(&v.purpose)); + if match_title && match_purpose { + validator = Some(if validator.is_none() { + LookupResult::One(v) + } else { + LookupResult::Many + }) + } + } + validator + } + + pub fn with_validator( + &self, + title: Option<&String>, + purpose: Option<&Purpose>, + when_missing: fn(Vec<(String, Purpose)>) -> E, + when_too_many: fn(Vec<(String, Purpose)>) -> E, + action: F, + ) -> Result + where + F: Fn(&Validator) -> Result, + { + match self.lookup(title, purpose) { + Some(LookupResult::One(validator)) => action(validator), + Some(LookupResult::Many) => Err(when_too_many( + self.validators + .iter() + .map(|v| (v.title.clone(), v.purpose.clone())) + .collect(), + )), + None => Err(when_missing( + self.validators + .iter() + .map(|v| (v.title.clone(), v.purpose.clone())) + .collect(), + )), + } + } +} + 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)?; diff --git a/crates/aiken-project/src/lib.rs b/crates/aiken-project/src/lib.rs index ae14e46f..4f5e55ad 100644 --- a/crates/aiken-project/src/lib.rs +++ b/crates/aiken-project/src/lib.rs @@ -12,7 +12,7 @@ pub mod pretty; pub mod script; pub mod telemetry; -use crate::blueprint::{schema::Schema, validator, Blueprint}; +use crate::blueprint::{schema::Schema, validator, Blueprint, LookupResult}; use aiken_lang::{ ast::{Definition, Function, ModuleKind, TypedDataType, TypedFunction}, builder::{DataTypeKey, FunctionAccessKey}, @@ -283,8 +283,8 @@ where pub fn address( &self, - with_title: Option<&String>, - with_purpose: Option<&validator::Purpose>, + title: Option<&String>, + purpose: Option<&validator::Purpose>, stake_address: Option<&String>, ) -> Result { // Parse stake address @@ -312,38 +312,15 @@ where let blueprint: Blueprint = serde_json::from_reader(BufReader::new(blueprint))?; - // Find validator's program - let mut program = None; - for v in blueprint.validators.iter() { - if Some(&v.title) == with_title.or(Some(&v.title)) - && Some(&v.purpose) == with_purpose.or(Some(&v.purpose)) - { - program = Some(if program.is_none() { - Ok(v.program.clone()) - } else { - Err(Error::MoreThanOneValidatorFound { - known_validators: blueprint - .validators - .iter() - .map(|v| (v.title.clone(), v.purpose.clone())) - .collect(), - }) - }) - } - } - - // Print the address - match program { - Some(Ok(program)) => Ok(program.address(Network::Testnet, delegation_part)), - Some(Err(e)) => Err(e), - None => Err(Error::NoValidatorNotFound { - known_validators: blueprint - .validators - .iter() - .map(|v| (v.title.clone(), v.purpose.clone())) - .collect(), - }), - } + // Calculate the address + let when_too_many = + |known_validators| Error::MoreThanOneValidatorFound { known_validators }; + let when_missing = |known_validators| Error::NoValidatorNotFound { known_validators }; + blueprint.with_validator(title, purpose, when_too_many, when_missing, |validator| { + Ok(validator + .program + .address(Network::Testnet, delegation_part.to_owned())) + }) } fn compile_deps(&mut self) -> Result<(), Error> {