fix(cli): aiken address

This commit is contained in:
rvcas 2023-02-15 22:04:45 -05:00 committed by Lucas
parent 8b4985498b
commit a311531508
6 changed files with 62 additions and 77 deletions

View File

@ -7,7 +7,7 @@ use aiken_lang::uplc::CodeGenerator;
use error::Error; use error::Error;
use schema::Schema; use schema::Schema;
use std::fmt::{self, Debug, Display}; use std::fmt::{self, Debug, Display};
use validator::{Purpose, Validator}; use validator::Validator;
#[derive(Debug, PartialEq, Clone, serde::Serialize, serde::Deserialize)] #[derive(Debug, PartialEq, Clone, serde::Serialize, serde::Deserialize)]
pub struct Blueprint<T: Default> { pub struct Blueprint<T: Default> {
@ -57,16 +57,13 @@ impl<T> Blueprint<T>
where where
T: Clone + Default, T: Clone + Default,
{ {
pub fn lookup( pub fn lookup(&self, title: Option<&String>) -> Option<LookupResult<Validator<T>>> {
&self,
title: Option<&String>,
purpose: Option<&Purpose>,
) -> Option<LookupResult<Validator<T>>> {
let mut validator = None; let mut validator = None;
for v in self.validators.iter() { for v in self.validators.iter() {
let match_title = Some(&v.title) == title.or(Some(&v.title)); let match_title = title.map(|t| v.title.contains(t)).unwrap_or(false);
let match_purpose = v.purpose.as_ref() == purpose.or(v.purpose.as_ref());
if match_title && match_purpose { if match_title {
validator = Some(if validator.is_none() { validator = Some(if validator.is_none() {
LookupResult::One(v) LookupResult::One(v)
} else { } else {
@ -74,47 +71,27 @@ where
}) })
} }
} }
validator validator
} }
pub fn with_validator<F, A, E>( pub fn with_validator<F, A, E>(
&self, &self,
title: Option<&String>, title: Option<&String>,
purpose: Option<&Purpose>, when_missing: fn(Vec<String>) -> E,
when_missing: fn(Vec<(String, String)>) -> E, when_too_many: fn(Vec<String>) -> E,
when_too_many: fn(Vec<(String, String)>) -> E,
action: F, action: F,
) -> Result<A, E> ) -> Result<A, E>
where where
F: Fn(Validator<T>) -> Result<A, E>, F: Fn(Validator<T>) -> Result<A, E>,
{ {
match self.lookup(title, purpose) { match self.lookup(title) {
Some(LookupResult::One(validator)) => action(validator.to_owned()), Some(LookupResult::One(validator)) => action(validator.to_owned()),
Some(LookupResult::Many) => Err(when_too_many( Some(LookupResult::Many) => Err(when_too_many(
self.validators self.validators.iter().map(|v| v.title.clone()).collect(),
.iter()
.map(|v| {
let mut title = v.title.split('.');
(
title.next().unwrap().to_string(),
title.next().unwrap().to_string(),
)
})
.collect(),
)), )),
None => Err(when_missing( None => Err(when_missing(
self.validators self.validators.iter().map(|v| v.title.clone()).collect(),
.iter()
.map(|v| {
let mut title = v.title.split('-');
(
title.next().unwrap().to_string(),
title.next().unwrap().to_string(),
)
})
.collect(),
)), )),
} }
} }

View File

@ -132,14 +132,10 @@ pub enum Error {
}, },
#[error("I didn't find any validator matching your criteria.")] #[error("I didn't find any validator matching your criteria.")]
NoValidatorNotFound { NoValidatorNotFound { known_validators: Vec<String> },
known_validators: Vec<(String, String)>,
},
#[error("I found multiple suitable validators and I need you to tell me which one to pick.")] #[error("I found multiple suitable validators and I need you to tell me which one to pick.")]
MoreThanOneValidatorFound { MoreThanOneValidatorFound { known_validators: Vec<String> },
known_validators: Vec<(String, String)>,
},
} }
impl Error { impl Error {
@ -374,13 +370,13 @@ impl Diagnostic for Error {
Error::NoValidatorNotFound { known_validators } => { Error::NoValidatorNotFound { known_validators } => {
Some(Box::new(format!( Some(Box::new(format!(
"Here's a list of all validators (and their purpose) I've found in your project. Please double-check this list against the options that you've provided:\n\n{}", "Here's a list of all validators (and their purpose) I've found in your project. Please double-check this list against the options that you've provided:\n\n{}",
known_validators.iter().map(|(name, purpose)| format!("{name} (purpose = {purpose})", name = name.purple().bold(), purpose = purpose.bright_blue())).collect::<Vec<String>>().join("\n") known_validators.iter().map(|title| format!("{title}", title = title.purple().bold())).collect::<Vec<String>>().join("\n")
))) )))
}, },
Error::MoreThanOneValidatorFound { known_validators } => { Error::MoreThanOneValidatorFound { known_validators } => {
Some(Box::new(format!( Some(Box::new(format!(
"Here's a list of all validators (and their purpose) I've found in your project. Select one of them using the appropriate options:\n\n{}", "Here's a list of all validators (and their purpose) I've found in your project. Select one of them using the appropriate options:\n\n{}",
known_validators.iter().map(|(name, purpose)| format!("{name} (purpose = {purpose})", name = name.purple().bold(), purpose = purpose.bright_blue())).collect::<Vec<String>>().join("\n") known_validators.iter().map(|title| format!("{title}", title = title.purple().bold())).collect::<Vec<String>>().join("\n")
))) )))
}, },
} }

View File

@ -12,7 +12,7 @@ pub mod pretty;
pub mod script; pub mod script;
pub mod telemetry; pub mod telemetry;
use crate::blueprint::{schema::Schema, validator, Blueprint}; use crate::blueprint::{schema::Schema, Blueprint};
use aiken_lang::{ use aiken_lang::{
ast::{Definition, Function, ModuleKind, TypedDataType, TypedFunction}, ast::{Definition, Function, ModuleKind, TypedDataType, TypedFunction},
builder::{DataTypeKey, FunctionAccessKey}, builder::{DataTypeKey, FunctionAccessKey},
@ -287,7 +287,6 @@ where
pub fn address( pub fn address(
&self, &self,
title: Option<&String>, title: Option<&String>,
purpose: Option<&validator::Purpose>,
stake_address: Option<&String>, stake_address: Option<&String>,
) -> Result<ShelleyAddress, Error> { ) -> Result<ShelleyAddress, Error> {
// Parse stake address // Parse stake address
@ -318,7 +317,8 @@ where
let when_too_many = let when_too_many =
|known_validators| Error::MoreThanOneValidatorFound { known_validators }; |known_validators| Error::MoreThanOneValidatorFound { known_validators };
let when_missing = |known_validators| Error::NoValidatorNotFound { known_validators }; let when_missing = |known_validators| Error::NoValidatorNotFound { known_validators };
blueprint.with_validator(title, purpose, when_too_many, when_missing, |validator| {
blueprint.with_validator(title, when_too_many, when_missing, |validator| {
let n = validator.parameters.len(); let n = validator.parameters.len();
if n > 0 { if n > 0 {
Err(blueprint::error::Error::ParameterizedValidator { n }.into()) Err(blueprint::error::Error::ParameterizedValidator { n }.into())
@ -333,7 +333,6 @@ where
pub fn apply_parameter( pub fn apply_parameter(
&self, &self,
title: Option<&String>, title: Option<&String>,
purpose: Option<&validator::Purpose>,
param: &Term<DeBruijn>, param: &Term<DeBruijn>,
) -> Result<Blueprint<serde_json::Value>, Error> { ) -> Result<Blueprint<serde_json::Value>, Error> {
// Read blueprint // Read blueprint
@ -346,8 +345,9 @@ where
let when_too_many = let when_too_many =
|known_validators| Error::MoreThanOneValidatorFound { known_validators }; |known_validators| Error::MoreThanOneValidatorFound { known_validators };
let when_missing = |known_validators| Error::NoValidatorNotFound { known_validators }; let when_missing = |known_validators| Error::NoValidatorNotFound { known_validators };
let applied_validator = let applied_validator =
blueprint.with_validator(title, purpose, when_too_many, when_missing, |validator| { blueprint.with_validator(title, when_too_many, when_missing, |validator| {
validator.apply(param).map_err(|e| e.into()) validator.apply(param).map_err(|e| e.into())
})?; })?;

View File

@ -1,5 +1,4 @@
use crate::with_project; use crate::with_project;
use aiken_lang::VALIDATOR_NAMES;
use std::path::PathBuf; use std::path::PathBuf;
#[derive(clap::Args)] #[derive(clap::Args)]
@ -11,11 +10,11 @@ pub struct Args {
/// Name of the validator's module within the project. Optional if there's only one validator. /// Name of the validator's module within the project. Optional if there's only one validator.
#[clap(short, long)] #[clap(short, long)]
validator: Option<String>, module: Option<String>,
/// Purpose of the validator within the module. Optional if there's only one validator. /// Name of the validator within the module. Optional if there's only one validator.
#[clap(short, long, possible_values=&VALIDATOR_NAMES)] #[clap(short, long)]
purpose: Option<String>, validator: Option<String>,
/// Stake address to attach, if any. /// Stake address to attach, if any.
#[clap(long)] #[clap(long)]
@ -29,8 +28,8 @@ pub struct Args {
pub fn exec( pub fn exec(
Args { Args {
directory, directory,
module,
validator, validator,
purpose,
delegated_to, delegated_to,
rebuild, rebuild,
}: Args, }: Args,
@ -39,15 +38,23 @@ pub fn exec(
if rebuild { if rebuild {
p.build(false)?; p.build(false)?;
} }
let address = p.address(
validator.as_ref(), let title = module.as_ref().map(|m| {
purpose format!(
"{m}{}",
validator
.as_ref() .as_ref()
.map(|p| p.clone().try_into().unwrap()) .map(|v| format!(".{v}"))
.as_ref(), .unwrap_or("".to_string())
delegated_to.as_ref(), )
)?; });
let title = title.as_ref().or(validator.as_ref());
let address = p.address(title, delegated_to.as_ref())?;
println!("{}", address.to_bech32().unwrap()); println!("{}", address.to_bech32().unwrap());
Ok(()) Ok(())
}) })
} }

View File

@ -1,5 +1,4 @@
use crate::with_project; use crate::with_project;
use aiken_lang::VALIDATOR_NAMES;
use aiken_project::error::Error; use aiken_project::error::Error;
use miette::IntoDiagnostic; use miette::IntoDiagnostic;
use std::{fs, path::PathBuf}; use std::{fs, path::PathBuf};
@ -17,11 +16,11 @@ pub struct Args {
/// Name of the validator's module within the project. Optional if there's only one validator. /// Name of the validator's module within the project. Optional if there's only one validator.
#[clap(short, long)] #[clap(short, long)]
validator: Option<String>, module: Option<String>,
/// Purpose of the validator within the module. Optional if there's only one validator. /// Name of the validator within the module. Optional if there's only one validator.
#[clap(short, long, possible_values=&VALIDATOR_NAMES)] #[clap(short, long)]
purpose: Option<String>, validator: Option<String>,
/// The parameter, using high-level UPLC-syntax /// The parameter, using high-level UPLC-syntax
parameter: String, parameter: String,
@ -30,8 +29,8 @@ pub struct Args {
pub fn exec( pub fn exec(
Args { Args {
directory, directory,
module,
validator, validator,
purpose,
parameter, parameter,
}: Args, }: Args,
) -> miette::Result<()> { ) -> miette::Result<()> {
@ -41,16 +40,22 @@ pub fn exec(
.into_diagnostic()?; .into_diagnostic()?;
with_project(directory, |p| { with_project(directory, |p| {
let blueprint = p.apply_parameter( let title = module.as_ref().map(|m| {
validator.as_ref(), format!(
purpose "{m}{}",
validator
.as_ref() .as_ref()
.map(|p| p.clone().try_into().unwrap()) .map(|v| format!(".{v}"))
.as_ref(), .unwrap_or("".to_string())
&term, )
)?; });
let title = title.as_ref().or(validator.as_ref());
let blueprint = p.apply_parameter(title, &term)?;
let json = serde_json::to_string_pretty(&blueprint).unwrap(); let json = serde_json::to_string_pretty(&blueprint).unwrap();
fs::write(p.blueprint_path(), json).map_err(|error| Error::FileIo { fs::write(p.blueprint_path(), json).map_err(|error| Error::FileIo {
error, error,
path: p.blueprint_path(), path: p.blueprint_path(),

View File

@ -6,7 +6,7 @@
}, },
"validators": [ "validators": [
{ {
"title": "hello_world-spend", "title": "hello_world.spend",
"datum": { "datum": {
"title": "Datum", "title": "Datum",
"anyOf": [ "anyOf": [