Merge branch 'fix/blueprint-pairs'
Signed-off-by: KtorZ <5680256+KtorZ@users.noreply.github.com>
This commit is contained in:
commit
f85d9460f6
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
- **aiken**: support for `bench` keyword to define benchmarks. @Riley-Kilgore
|
- **aiken**: support for `bench` keyword to define benchmarks. @Riley-Kilgore
|
||||||
- **aiken-lang**: The compiler now raises a warning when attempting to destructure a record constructor without using named fields. See [#1084](https://github.com/aiken-lang/aiken/issues/1084). @KtorZ
|
- **aiken-lang**: The compiler now raises a warning when attempting to destructure a record constructor without using named fields. See [#1084](https://github.com/aiken-lang/aiken/issues/1084). @KtorZ
|
||||||
|
- **aiken-lang**: Fix blueprint schema definitions related to pairs (no longer omit (sometimes) Pairs definitions, and generate them as data List). See [#1086](https://github.com/aiken-lang/aiken/issues/1086) and [#970](https://github.com/aiken-lang/aiken/issues/970). @KtorZ
|
||||||
|
|
||||||
## v1.1.10 - 2025-01-21
|
## v1.1.10 - 2025-01-21
|
||||||
|
|
||||||
|
|
|
@ -66,11 +66,15 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn g1_element() {
|
fn g1_element() {
|
||||||
assert_expr!("#<Bls12_381, G1>\"950dfd33da2682260c76038dfb8bad6e84ae9d599a3c151815945ac1e6ef6b1027cd917f3907479d20d636ce437a41f5\"");
|
assert_expr!(
|
||||||
|
"#<Bls12_381, G1>\"950dfd33da2682260c76038dfb8bad6e84ae9d599a3c151815945ac1e6ef6b1027cd917f3907479d20d636ce437a41f5\""
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn g2_element() {
|
fn g2_element() {
|
||||||
assert_expr!("#<Bls12_381, G2>\"b0629fa1158c2d23a10413fe91d381a84d25e31d041cd0377d25828498fd02011b35893938ced97535395e4815201e67108bcd4665e0db25d602d76fa791fab706c54abf5e1a9e44b4ac1e6badf3d2ac0328f5e30be341677c8bac5dda7682f1\"");
|
assert_expr!(
|
||||||
|
"#<Bls12_381, G2>\"b0629fa1158c2d23a10413fe91d381a84d25e31d041cd0377d25828498fd02011b35893938ced97535395e4815201e67108bcd4665e0db25d602d76fa791fab706c54abf5e1a9e44b4ac1e6badf3d2ac0328f5e30be341677c8bac5dda7682f1\""
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,10 @@
|
||||||
|
use crate::{
|
||||||
|
blueprint::{
|
||||||
|
parameter::Parameter,
|
||||||
|
schema::{Data, Declaration, Items},
|
||||||
|
},
|
||||||
|
Annotated, Schema,
|
||||||
|
};
|
||||||
use aiken_lang::tipo::{pretty::resolve_alias, Type, TypeAliasAnnotation, TypeVar};
|
use aiken_lang::tipo::{pretty::resolve_alias, Type, TypeAliasAnnotation, TypeVar};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use serde::{
|
use serde::{
|
||||||
|
@ -6,7 +13,7 @@ use serde::{
|
||||||
ser::{Serialize, SerializeStruct, Serializer},
|
ser::{Serialize, SerializeStruct, Serializer},
|
||||||
};
|
};
|
||||||
use std::{
|
use std::{
|
||||||
collections::{BTreeMap, HashMap},
|
collections::{BTreeMap, BTreeSet, HashMap},
|
||||||
fmt::{self, Display},
|
fmt::{self, Display},
|
||||||
ops::Deref,
|
ops::Deref,
|
||||||
rc::Rc,
|
rc::Rc,
|
||||||
|
@ -88,6 +95,218 @@ impl<T> Definitions<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Definitions<Annotated<Schema>> {
|
||||||
|
/// Remove orphan definitions. Such definitions can exist due to List of pairs being
|
||||||
|
/// transformed to Maps. As a consequence, we may generate temporary Pair definitions
|
||||||
|
/// which needs to get cleaned up later.
|
||||||
|
///
|
||||||
|
/// Initially, we would clean those Pair definitions right-away, but this would cause
|
||||||
|
/// Pair definitions to be missing in some legit cases when the Pair is also used as a
|
||||||
|
/// standalone type.
|
||||||
|
pub fn prune_orphan_pairs(&mut self, parameters: Vec<&Parameter>) -> &mut Self {
|
||||||
|
fn traverse_schema(
|
||||||
|
src: Reference,
|
||||||
|
schema: &Schema,
|
||||||
|
usage: &mut BTreeMap<Reference, BTreeSet<Reference>>,
|
||||||
|
) {
|
||||||
|
match schema {
|
||||||
|
Schema::Unit
|
||||||
|
| Schema::Boolean
|
||||||
|
| Schema::Integer
|
||||||
|
| Schema::Bytes
|
||||||
|
| Schema::String => (),
|
||||||
|
Schema::Pair(left, right) => {
|
||||||
|
mark(src.clone(), left, usage, traverse_schema);
|
||||||
|
mark(src, right, usage, traverse_schema);
|
||||||
|
}
|
||||||
|
Schema::List(Items::One(item)) => {
|
||||||
|
mark(src, item, usage, traverse_schema);
|
||||||
|
}
|
||||||
|
Schema::List(Items::Many(items)) => {
|
||||||
|
items.iter().for_each(|item| {
|
||||||
|
mark(src.clone(), item, usage, traverse_schema);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Schema::Data(data) => traverse_data(src, data, usage),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn traverse_data(
|
||||||
|
src: Reference,
|
||||||
|
data: &Data,
|
||||||
|
usage: &mut BTreeMap<Reference, BTreeSet<Reference>>,
|
||||||
|
) {
|
||||||
|
match data {
|
||||||
|
Data::Opaque | Data::Integer | Data::Bytes => (),
|
||||||
|
Data::List(Items::One(item)) => {
|
||||||
|
mark(src, item, usage, traverse_data);
|
||||||
|
}
|
||||||
|
Data::List(Items::Many(items)) => {
|
||||||
|
items.iter().for_each(|item| {
|
||||||
|
mark(src.clone(), item, usage, traverse_data);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Data::Map(keys, values) => {
|
||||||
|
mark(src.clone(), keys, usage, traverse_data);
|
||||||
|
mark(src, values, usage, traverse_data);
|
||||||
|
}
|
||||||
|
Data::AnyOf(items) => {
|
||||||
|
items.iter().for_each(|item| {
|
||||||
|
item.annotated.fields.iter().for_each(|field| {
|
||||||
|
mark(src.clone(), &field.annotated, usage, traverse_data);
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A mutually recursive function which works with either traverse_data or traverse_schema;
|
||||||
|
/// it is meant to peel the 'Declaration' and keep traversing if needed (when inline).
|
||||||
|
fn mark<F, T>(
|
||||||
|
src: Reference,
|
||||||
|
declaration: &Declaration<T>,
|
||||||
|
usage: &mut BTreeMap<Reference, BTreeSet<Reference>>,
|
||||||
|
mut traverse: F,
|
||||||
|
) where
|
||||||
|
F: FnMut(Reference, &T, &mut BTreeMap<Reference, BTreeSet<Reference>>),
|
||||||
|
{
|
||||||
|
match declaration {
|
||||||
|
Declaration::Referenced(reference) => {
|
||||||
|
if let Some(dependencies) = usage.get_mut(reference) {
|
||||||
|
dependencies.insert(src);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Declaration::Inline(ref schema) => traverse(src, schema, usage),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut usage: BTreeMap<Reference, BTreeSet<Reference>> = BTreeMap::new();
|
||||||
|
|
||||||
|
// 1. List all Pairs definitions
|
||||||
|
for (src, annotated) in self.inner.iter() {
|
||||||
|
if let Some(schema) = annotated.as_ref().map(|entry| &entry.annotated) {
|
||||||
|
if matches!(schema, Schema::Pair(_, _)) {
|
||||||
|
usage.insert(Reference::new(src), BTreeSet::new());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Mark those used in other definitions
|
||||||
|
for (src, annotated) in self.inner.iter() {
|
||||||
|
if let Some(schema) = annotated.as_ref().map(|entry| &entry.annotated) {
|
||||||
|
traverse_schema(Reference::new(src), schema, &mut usage)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Mark also pairs definitions used in parameters / datums / redeemers
|
||||||
|
for (ix, param) in parameters.iter().enumerate() {
|
||||||
|
mark(
|
||||||
|
// NOTE: The name isn't important, so long as it doesn't clash with other typical
|
||||||
|
// references. If a definition is used in either of the parameter, it'll appear in
|
||||||
|
// its dependencies and won't ever be removed because parameters are considered
|
||||||
|
// always necessary.
|
||||||
|
Reference::new(&format!("__param^{ix}")),
|
||||||
|
¶m.schema,
|
||||||
|
&mut usage,
|
||||||
|
traverse_schema,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. Repeatedly remove pairs definitions that aren't used. We need doing this repeatedly
|
||||||
|
// because a Pair definition may only be used by an unused one; so as we prune the first
|
||||||
|
// unused definitions, new ones may become unused.
|
||||||
|
let mut last_len = usage.len();
|
||||||
|
loop {
|
||||||
|
let mut unused = None;
|
||||||
|
for (k, v) in usage.iter() {
|
||||||
|
if v.is_empty() {
|
||||||
|
unused = Some(k.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(k) = unused {
|
||||||
|
usage.remove(&k);
|
||||||
|
self.inner.remove(k.as_key().as_str());
|
||||||
|
for (_, v) in usage.iter_mut() {
|
||||||
|
v.remove(&k);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if usage.len() == last_len {
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
last_len = usage.len();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn replace_pairs_with_data_lists(&mut self) {
|
||||||
|
fn swap_declaration(declaration: &mut Declaration<Schema>) -> Declaration<Data> {
|
||||||
|
match std::mem::replace(declaration, Declaration::Inline(Schema::Unit.into())) {
|
||||||
|
Declaration::Referenced(reference) => Declaration::Referenced(reference),
|
||||||
|
Declaration::Inline(mut inline) => {
|
||||||
|
schema_to_data(&mut inline);
|
||||||
|
if let Schema::Data(data) = *inline {
|
||||||
|
Declaration::Inline(data.into())
|
||||||
|
} else {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn schema_to_data(schema: &mut Schema) {
|
||||||
|
let items = match schema {
|
||||||
|
Schema::Data(_) => None,
|
||||||
|
Schema::Pair(ref mut left, ref mut right) => {
|
||||||
|
let left = swap_declaration(left);
|
||||||
|
let right = swap_declaration(right);
|
||||||
|
Some(Items::Many(vec![left, right]))
|
||||||
|
}
|
||||||
|
Schema::List(Items::One(ref mut item)) => {
|
||||||
|
let item = swap_declaration(item);
|
||||||
|
Some(Items::One(item))
|
||||||
|
}
|
||||||
|
Schema::List(Items::Many(ref mut items)) => Some(Items::Many(
|
||||||
|
items.iter_mut().map(swap_declaration).collect(),
|
||||||
|
)),
|
||||||
|
Schema::Integer => {
|
||||||
|
*schema = Schema::Data(Data::Integer);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
Schema::Bytes => {
|
||||||
|
*schema = Schema::Data(Data::Bytes);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
Schema::String => {
|
||||||
|
*schema = Schema::Data(Data::Bytes);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
Schema::Unit => {
|
||||||
|
*schema = Schema::void();
|
||||||
|
None
|
||||||
|
}
|
||||||
|
Schema::Boolean => {
|
||||||
|
*schema = Schema::bool();
|
||||||
|
None
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(items) = items {
|
||||||
|
*schema = Schema::Data(Data::List(items));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (_, entry) in self.inner.iter_mut() {
|
||||||
|
if let Some(ref mut annotated) = entry {
|
||||||
|
schema_to_data(&mut annotated.annotated);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ---------- Reference
|
// ---------- Reference
|
||||||
|
|
||||||
/// A URI pointer to an underlying data-type.
|
/// A URI pointer to an underlying data-type.
|
||||||
|
|
|
@ -97,6 +97,48 @@ pub enum Schema {
|
||||||
Data(Data),
|
Data(Data),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Schema {
|
||||||
|
pub fn void() -> Self {
|
||||||
|
Schema::Data(Data::AnyOf(vec![Annotated {
|
||||||
|
title: None,
|
||||||
|
description: None,
|
||||||
|
annotated: Constructor {
|
||||||
|
index: 0,
|
||||||
|
fields: vec![],
|
||||||
|
},
|
||||||
|
}]))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn int() -> Self {
|
||||||
|
Schema::Data(Data::Integer)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn bytes() -> Self {
|
||||||
|
Schema::Data(Data::Bytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn bool() -> Self {
|
||||||
|
Schema::Data(Data::AnyOf(vec![
|
||||||
|
Annotated {
|
||||||
|
title: Some("False".to_string()),
|
||||||
|
description: None,
|
||||||
|
annotated: Constructor {
|
||||||
|
index: 0,
|
||||||
|
fields: vec![],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Annotated {
|
||||||
|
title: Some("True".to_string()),
|
||||||
|
description: None,
|
||||||
|
annotated: Constructor {
|
||||||
|
index: 1,
|
||||||
|
fields: vec![],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A schema for Plutus' Data.
|
/// A schema for Plutus' Data.
|
||||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||||
pub enum Data {
|
pub enum Data {
|
||||||
|
@ -205,46 +247,22 @@ impl Annotated<Schema> {
|
||||||
annotated: Schema::Data(Data::Opaque),
|
annotated: Schema::Data(Data::Opaque),
|
||||||
}),
|
}),
|
||||||
|
|
||||||
"ByteArray" => Ok(with_title(title.as_ref(), Schema::Data(Data::Bytes))),
|
"ByteArray" => Ok(with_title(title.as_ref(), Schema::bytes())),
|
||||||
|
|
||||||
"Int" => Ok(with_title(title.as_ref(), Schema::Data(Data::Integer))),
|
"Int" => Ok(with_title(title.as_ref(), Schema::int())),
|
||||||
|
|
||||||
"String" => Ok(with_title(title.as_ref(), Schema::String)),
|
"String" => Ok(with_title(title.as_ref(), Schema::String)),
|
||||||
|
|
||||||
"Void" => Ok(Annotated {
|
"Void" => Ok(Annotated {
|
||||||
title: title.or(Some("Unit".to_string())),
|
title: title.or(Some("Unit".to_string())),
|
||||||
description: None,
|
description: None,
|
||||||
annotated: Schema::Data(Data::AnyOf(vec![Annotated {
|
annotated: Schema::void(),
|
||||||
title: None,
|
|
||||||
description: None,
|
|
||||||
annotated: Constructor {
|
|
||||||
index: 0,
|
|
||||||
fields: vec![],
|
|
||||||
},
|
|
||||||
}])),
|
|
||||||
}),
|
}),
|
||||||
|
|
||||||
"Bool" => Ok(Annotated {
|
"Bool" => Ok(Annotated {
|
||||||
title: title.or(Some("Bool".to_string())),
|
title: title.or(Some("Bool".to_string())),
|
||||||
description: None,
|
description: None,
|
||||||
annotated: Schema::Data(Data::AnyOf(vec![
|
annotated: Schema::bool(),
|
||||||
Annotated {
|
|
||||||
title: Some("False".to_string()),
|
|
||||||
description: None,
|
|
||||||
annotated: Constructor {
|
|
||||||
index: 0,
|
|
||||||
fields: vec![],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Annotated {
|
|
||||||
title: Some("True".to_string()),
|
|
||||||
description: None,
|
|
||||||
annotated: Constructor {
|
|
||||||
index: 1,
|
|
||||||
fields: vec![],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
])),
|
|
||||||
}),
|
}),
|
||||||
|
|
||||||
"Ordering" => Ok(Annotated {
|
"Ordering" => Ok(Annotated {
|
||||||
|
@ -346,8 +364,6 @@ impl Annotated<Schema> {
|
||||||
annotated: Schema::Pair(left, right),
|
annotated: Schema::Pair(left, right),
|
||||||
..
|
..
|
||||||
}) => {
|
}) => {
|
||||||
definitions.remove(&generic);
|
|
||||||
|
|
||||||
let left = left.map(|inner| match inner {
|
let left = left.map(|inner| match inner {
|
||||||
Schema::Data(data) => data,
|
Schema::Data(data) => data,
|
||||||
_ => panic!("impossible: left inhabitant of pair isn't Data but: {inner:#?}"),
|
_ => panic!("impossible: left inhabitant of pair isn't Data but: {inner:#?}"),
|
||||||
|
|
|
@ -0,0 +1,73 @@
|
||||||
|
---
|
||||||
|
source: crates/aiken-project/src/blueprint/validator.rs
|
||||||
|
description: "Code:\n\npub type OuterMap =\n List<Pair<Int, InnerMap>>\n\npub type InnerMap =\n List<Pair<Int, Bool>>\n\nvalidator placeholder {\n spend(_datum: Option<Void>, _redeemer: OuterMap, _utxo: Data, _self: Data,) {\n True\n }\n}\n"
|
||||||
|
---
|
||||||
|
{
|
||||||
|
"title": "test_module.placeholder.spend",
|
||||||
|
"datum": {
|
||||||
|
"title": "_datum",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/Void"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"redeemer": {
|
||||||
|
"title": "_redeemer",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/OuterMap"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compiledCode": "<redacted>",
|
||||||
|
"hash": "<redacted>",
|
||||||
|
"definitions": {
|
||||||
|
"Bool": {
|
||||||
|
"title": "Bool",
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"title": "False",
|
||||||
|
"dataType": "constructor",
|
||||||
|
"index": 0,
|
||||||
|
"fields": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "True",
|
||||||
|
"dataType": "constructor",
|
||||||
|
"index": 1,
|
||||||
|
"fields": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"InnerMap": {
|
||||||
|
"title": "InnerMap",
|
||||||
|
"dataType": "map",
|
||||||
|
"keys": {
|
||||||
|
"$ref": "#/definitions/Int"
|
||||||
|
},
|
||||||
|
"values": {
|
||||||
|
"$ref": "#/definitions/Bool"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Int": {
|
||||||
|
"dataType": "integer"
|
||||||
|
},
|
||||||
|
"OuterMap": {
|
||||||
|
"title": "OuterMap",
|
||||||
|
"dataType": "map",
|
||||||
|
"keys": {
|
||||||
|
"$ref": "#/definitions/Int"
|
||||||
|
},
|
||||||
|
"values": {
|
||||||
|
"$ref": "#/definitions/InnerMap"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Void": {
|
||||||
|
"title": "Unit",
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"dataType": "constructor",
|
||||||
|
"index": 0,
|
||||||
|
"fields": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,72 @@
|
||||||
|
---
|
||||||
|
source: crates/aiken-project/src/blueprint/validator.rs
|
||||||
|
description: "Code:\n\npub type MyPair =\n Pair<Int, InnerPair>\n\npub type InnerPair =\n Pair<Int, Bool>\n\nvalidator placeholder {\n spend(_datum: Option<Void>, _redeemer: List<MyPair>, _utxo: Data, _self: Data,) {\n True\n }\n}\n"
|
||||||
|
---
|
||||||
|
{
|
||||||
|
"title": "test_module.placeholder.spend",
|
||||||
|
"datum": {
|
||||||
|
"title": "_datum",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/Void"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"redeemer": {
|
||||||
|
"title": "_redeemer",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/List$MyPair"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compiledCode": "<redacted>",
|
||||||
|
"hash": "<redacted>",
|
||||||
|
"definitions": {
|
||||||
|
"Bool": {
|
||||||
|
"title": "Bool",
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"title": "False",
|
||||||
|
"dataType": "constructor",
|
||||||
|
"index": 0,
|
||||||
|
"fields": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "True",
|
||||||
|
"dataType": "constructor",
|
||||||
|
"index": 1,
|
||||||
|
"fields": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"InnerPair": {
|
||||||
|
"title": "InnerPair",
|
||||||
|
"dataType": "#pair",
|
||||||
|
"left": {
|
||||||
|
"$ref": "#/definitions/Int"
|
||||||
|
},
|
||||||
|
"right": {
|
||||||
|
"$ref": "#/definitions/Bool"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Int": {
|
||||||
|
"dataType": "integer"
|
||||||
|
},
|
||||||
|
"List$MyPair": {
|
||||||
|
"dataType": "map",
|
||||||
|
"keys": {
|
||||||
|
"$ref": "#/definitions/Int"
|
||||||
|
},
|
||||||
|
"values": {
|
||||||
|
"$ref": "#/definitions/InnerPair"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Void": {
|
||||||
|
"title": "Unit",
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"dataType": "constructor",
|
||||||
|
"index": 0,
|
||||||
|
"fields": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,65 @@
|
||||||
|
---
|
||||||
|
source: crates/aiken-project/src/blueprint/validator.rs
|
||||||
|
description: "Code:\n\npub type MyPair =\n Pair<List<Int>, Bool>\n\nvalidator placeholder {\n spend(_datum: Option<Data>, _redeemer: MyPair, _utxo: Data, _self: Data,) {\n True\n }\n}\n"
|
||||||
|
---
|
||||||
|
{
|
||||||
|
"title": "test_module.placeholder.spend",
|
||||||
|
"datum": {
|
||||||
|
"title": "_datum",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/Data"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"redeemer": {
|
||||||
|
"title": "_redeemer",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/MyPair"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compiledCode": "<redacted>",
|
||||||
|
"hash": "<redacted>",
|
||||||
|
"definitions": {
|
||||||
|
"Bool": {
|
||||||
|
"title": "Bool",
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"title": "False",
|
||||||
|
"dataType": "constructor",
|
||||||
|
"index": 0,
|
||||||
|
"fields": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "True",
|
||||||
|
"dataType": "constructor",
|
||||||
|
"index": 1,
|
||||||
|
"fields": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"Data": {
|
||||||
|
"title": "Data",
|
||||||
|
"description": "Any Plutus data."
|
||||||
|
},
|
||||||
|
"Int": {
|
||||||
|
"dataType": "integer"
|
||||||
|
},
|
||||||
|
"List$Int": {
|
||||||
|
"dataType": "list",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/Int"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"MyPair": {
|
||||||
|
"title": "MyPair",
|
||||||
|
"dataType": "list",
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/List$Int"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/Bool"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,77 @@
|
||||||
|
---
|
||||||
|
source: crates/aiken-project/src/blueprint/validator.rs
|
||||||
|
description: "Code:\n\npub type MyPair =\n Pair<Int, Int>\n\npub type MyDatum {\n pairs: List<MyPair>,\n pair: MyPair,\n}\n\nvalidator placeholder {\n spend(_datum: Option<MyDatum>, _redeemer: Void, _utxo: Data, _self: Data,) {\n True\n }\n}\n"
|
||||||
|
---
|
||||||
|
{
|
||||||
|
"title": "test_module.placeholder.spend",
|
||||||
|
"datum": {
|
||||||
|
"title": "_datum",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/test_module~1MyDatum"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"redeemer": {
|
||||||
|
"title": "_redeemer",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/Void"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compiledCode": "<redacted>",
|
||||||
|
"hash": "<redacted>",
|
||||||
|
"definitions": {
|
||||||
|
"Int": {
|
||||||
|
"dataType": "integer"
|
||||||
|
},
|
||||||
|
"List$MyPair": {
|
||||||
|
"dataType": "map",
|
||||||
|
"keys": {
|
||||||
|
"$ref": "#/definitions/Int"
|
||||||
|
},
|
||||||
|
"values": {
|
||||||
|
"$ref": "#/definitions/Int"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"MyPair": {
|
||||||
|
"title": "MyPair",
|
||||||
|
"dataType": "list",
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/Int"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/Int"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"Void": {
|
||||||
|
"title": "Unit",
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"dataType": "constructor",
|
||||||
|
"index": 0,
|
||||||
|
"fields": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"test_module/MyDatum": {
|
||||||
|
"title": "MyDatum",
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"title": "MyDatum",
|
||||||
|
"dataType": "constructor",
|
||||||
|
"index": 0,
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"title": "pairs",
|
||||||
|
"$ref": "#/definitions/List$MyPair"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "pair",
|
||||||
|
"$ref": "#/definitions/MyPair"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,77 @@
|
||||||
|
---
|
||||||
|
source: crates/aiken-project/src/blueprint/validator.rs
|
||||||
|
description: "Code:\n\npub type MyPair =\n Pair<Int, Int>\n\npub type MyDatum {\n pair: MyPair,\n pairs: List<MyPair>,\n}\n\nvalidator placeholder {\n spend(_datum: Option<MyDatum>, _redeemer: Void, _utxo: Data, _self: Data,) {\n True\n }\n}\n"
|
||||||
|
---
|
||||||
|
{
|
||||||
|
"title": "test_module.placeholder.spend",
|
||||||
|
"datum": {
|
||||||
|
"title": "_datum",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/test_module~1MyDatum"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"redeemer": {
|
||||||
|
"title": "_redeemer",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/Void"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compiledCode": "<redacted>",
|
||||||
|
"hash": "<redacted>",
|
||||||
|
"definitions": {
|
||||||
|
"Int": {
|
||||||
|
"dataType": "integer"
|
||||||
|
},
|
||||||
|
"List$MyPair": {
|
||||||
|
"dataType": "map",
|
||||||
|
"keys": {
|
||||||
|
"$ref": "#/definitions/Int"
|
||||||
|
},
|
||||||
|
"values": {
|
||||||
|
"$ref": "#/definitions/Int"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"MyPair": {
|
||||||
|
"title": "MyPair",
|
||||||
|
"dataType": "list",
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/Int"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/Int"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"Void": {
|
||||||
|
"title": "Unit",
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"dataType": "constructor",
|
||||||
|
"index": 0,
|
||||||
|
"fields": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"test_module/MyDatum": {
|
||||||
|
"title": "MyDatum",
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"title": "MyDatum",
|
||||||
|
"dataType": "constructor",
|
||||||
|
"index": 0,
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"title": "pair",
|
||||||
|
"$ref": "#/definitions/MyPair"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "pairs",
|
||||||
|
"$ref": "#/definitions/List$MyPair"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -78,13 +78,15 @@ description: "Code:\n\npub type Asset = (ByteArray, Int)\n\npub type POSIXTime =
|
||||||
},
|
},
|
||||||
"Pair$POSIXTime_Bool": {
|
"Pair$POSIXTime_Bool": {
|
||||||
"title": "Pair",
|
"title": "Pair",
|
||||||
"dataType": "#pair",
|
"dataType": "list",
|
||||||
"left": {
|
"items": [
|
||||||
"$ref": "#/definitions/POSIXTime"
|
{
|
||||||
},
|
"$ref": "#/definitions/POSIXTime"
|
||||||
"right": {
|
},
|
||||||
"$ref": "#/definitions/Bool"
|
{
|
||||||
}
|
"$ref": "#/definitions/Bool"
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"Pairs$Asset_POSIXTime": {
|
"Pairs$Asset_POSIXTime": {
|
||||||
"title": "Pairs<a, POSIXTime>",
|
"title": "Pairs<a, POSIXTime>",
|
||||||
|
|
|
@ -122,7 +122,7 @@ impl Validator {
|
||||||
),
|
),
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.collect::<Result<_, _>>()?;
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
|
|
||||||
let (datum, redeemer) = if func.name == well_known::VALIDATOR_ELSE {
|
let (datum, redeemer) = if func.name == well_known::VALIDATOR_ELSE {
|
||||||
(None, None)
|
(None, None)
|
||||||
|
@ -202,6 +202,16 @@ impl Validator {
|
||||||
schema: Declaration::Inline(Box::new(Schema::Data(Data::Opaque))),
|
schema: Declaration::Inline(Box::new(Schema::Data(Data::Opaque))),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
definitions
|
||||||
|
.prune_orphan_pairs(
|
||||||
|
parameters
|
||||||
|
.iter()
|
||||||
|
.chain(redeemer.as_ref().map(|x| vec![x]).unwrap_or_default())
|
||||||
|
.chain(datum.as_ref().map(|x| vec![x]).unwrap_or_default())
|
||||||
|
.collect::<Vec<&Parameter>>(),
|
||||||
|
)
|
||||||
|
.replace_pairs_with_data_lists();
|
||||||
|
|
||||||
Ok(Validator {
|
Ok(Validator {
|
||||||
title: format!("{}.{}.{}", &module.name, &def.name, &func.name,),
|
title: format!("{}.{}.{}", &module.name, &def.name, &func.name,),
|
||||||
description: func.doc.clone(),
|
description: func.doc.clone(),
|
||||||
|
@ -736,6 +746,83 @@ mod tests {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn pair_used_after_map() {
|
||||||
|
assert_validator!(
|
||||||
|
r#"
|
||||||
|
pub type MyPair =
|
||||||
|
Pair<Int, Int>
|
||||||
|
|
||||||
|
pub type MyDatum {
|
||||||
|
pairs: List<MyPair>,
|
||||||
|
pair: MyPair,
|
||||||
|
}
|
||||||
|
|
||||||
|
validator placeholder {
|
||||||
|
spend(_datum: Option<MyDatum>, _redeemer: Void, _utxo: Data, _self: Data,) {
|
||||||
|
True
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"#
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn pair_used_before_map() {
|
||||||
|
assert_validator!(
|
||||||
|
r#"
|
||||||
|
pub type MyPair =
|
||||||
|
Pair<Int, Int>
|
||||||
|
|
||||||
|
pub type MyDatum {
|
||||||
|
pair: MyPair,
|
||||||
|
pairs: List<MyPair>,
|
||||||
|
}
|
||||||
|
|
||||||
|
validator placeholder {
|
||||||
|
spend(_datum: Option<MyDatum>, _redeemer: Void, _utxo: Data, _self: Data,) {
|
||||||
|
True
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"#
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn map_in_map() {
|
||||||
|
assert_validator!(
|
||||||
|
r#"
|
||||||
|
pub type OuterMap =
|
||||||
|
List<Pair<Int, InnerMap>>
|
||||||
|
|
||||||
|
pub type InnerMap =
|
||||||
|
List<Pair<Int, Bool>>
|
||||||
|
|
||||||
|
validator placeholder {
|
||||||
|
spend(_datum: Option<Void>, _redeemer: OuterMap, _utxo: Data, _self: Data,) {
|
||||||
|
True
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"#
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn pair_of_lists() {
|
||||||
|
assert_validator!(
|
||||||
|
r#"
|
||||||
|
pub type MyPair =
|
||||||
|
Pair<List<Int>, Bool>
|
||||||
|
|
||||||
|
validator placeholder {
|
||||||
|
spend(_datum: Option<Data>, _redeemer: MyPair, _utxo: Data, _self: Data,) {
|
||||||
|
True
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"#
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn else_redeemer() {
|
fn else_redeemer() {
|
||||||
assert_validator!(
|
assert_validator!(
|
||||||
|
|
Loading…
Reference in New Issue