Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion crates/tx3-cardano/src/compile/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -434,7 +434,9 @@ fn compile_reference_inputs(tx: &tir::Tx) -> Result<Vec<primitives::TransactionI
let refs = tx
.references
.iter()
.flat_map(coercion::expr_into_utxo_refs)
.map(|r| coercion::expr_into_utxo_refs(&r.utxos))
.collect::<Result<Vec<_>, _>>()?
.into_iter()
.flatten()
.map(|x| primitives::TransactionInput {
transaction_id: x.txid.as_slice().into(),
Expand Down
17 changes: 15 additions & 2 deletions crates/tx3-lang/src/analyzing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ impl Error {
Symbol::Function(name) => format!("Function({})", name),
Symbol::LocalExpr(_) => "LocalExpr".to_string(),
Symbol::Input(_) => "Input".to_string(),
Symbol::Reference(_) => "Reference".to_string(),
Symbol::Output(_) => "Output".to_string(),
Symbol::Fees => "Fees".to_string(),
}
Expand Down Expand Up @@ -387,6 +388,11 @@ impl Scope {
.insert(name.to_string(), Symbol::Input(Box::new(input)));
}

pub fn track_reference(&mut self, name: &str, reference: ReferenceBlock) {
self.symbols
.insert(name.to_string(), Symbol::Reference(Box::new(reference)));
}

pub fn track_output(&mut self, index: usize, output: OutputBlock) {
if let Some(n) = output.name {
self.symbols.insert(n.value, Symbol::Output(index));
Expand Down Expand Up @@ -1140,11 +1146,13 @@ impl Analyzable for SignersBlock {

impl Analyzable for ReferenceBlock {
fn analyze(&mut self, parent: Option<Rc<Scope>>) -> AnalyzeReport {
self.r#ref.analyze(parent)
let ref_report = self.r#ref.analyze(parent.clone());
let datum_report = self.datum_is.analyze(parent);
ref_report + datum_report
}

fn is_resolved(&self) -> bool {
self.r#ref.is_resolved()
self.r#ref.is_resolved() && self.datum_is.is_resolved()
}
}

Expand Down Expand Up @@ -1243,13 +1251,18 @@ impl TxDef {
scope.track_input(&input.name, input.clone())
}

for reference in self.references.iter() {
scope.track_reference(&reference.name, reference.clone());
}

for (index, output) in self.outputs.iter().enumerate() {
scope.track_output(index, output.clone())
}

let scope_snapshot = Rc::new(scope);
let _ = self.locals.analyze(Some(scope_snapshot.clone()));
let _ = self.inputs.analyze(Some(scope_snapshot.clone()));
let _ = self.references.analyze(Some(scope_snapshot.clone()));
let _ = self.outputs.analyze(Some(scope_snapshot.clone()));

Scope::new(Some(scope_snapshot))
Expand Down
9 changes: 9 additions & 0 deletions crates/tx3-lang/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ pub enum Symbol {
LocalExpr(Box<DataExpr>),
Output(usize),
Input(Box<InputBlock>),
Reference(Box<ReferenceBlock>),
PartyDef(Box<PartyDef>),
PolicyDef(Box<PolicyDef>),
AssetDef(Box<AssetDef>),
Expand Down Expand Up @@ -124,6 +125,7 @@ impl Symbol {
Symbol::ParamVar(_, ty) => Some(ty.as_ref().clone()),
Symbol::RecordField(x) => Some(x.r#type.clone()),
Symbol::Input(x) => x.datum_is().cloned(),
Symbol::Reference(x) => x.datum_is().cloned(),
x => {
dbg!(x);
None
Expand Down Expand Up @@ -347,9 +349,16 @@ impl InputBlockField {
pub struct ReferenceBlock {
pub name: String,
pub r#ref: DataExpr,
pub datum_is: Option<Type>,
pub span: Span,
}

impl ReferenceBlock {
pub(crate) fn datum_is(&self) -> Option<&Type> {
self.datum_is.as_ref()
}
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct MetadataBlockField {
pub key: DataExpr,
Expand Down
29 changes: 27 additions & 2 deletions crates/tx3-lang/src/lowering.rs
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,27 @@ impl IntoLower for ast::Identifier {

Ok(out)
}
ast::Symbol::Reference(ref_block) => {
let ref_expr = ref_block.r#ref.into_lower(ctx)?;
let query = ir::InputQuery {
address: ir::Expression::None,
min_amount: ir::Expression::None,
r#ref: ref_expr,
many: false,
collateral: false,
};
let inner =
ir::Param::ExpectInput(ref_block.name.to_lowercase().clone(), query).into();
let out = if ctx.is_asset_expr() {
ir::Coerce::IntoAssets(inner).into()
} else if ctx.is_datum_expr() {
ir::Coerce::IntoDatum(inner).into()
} else {
inner
};

Ok(out)
}
ast::Symbol::Fees => Ok(ir::Param::ExpectFees.into()),
ast::Symbol::EnvVar(n, ty) => {
Ok(ir::Param::ExpectValue(n.to_lowercase().clone(), ty.into_lower(ctx)?).into())
Expand Down Expand Up @@ -786,10 +807,13 @@ impl IntoLower for ast::ChainSpecificBlock {
}

impl IntoLower for ast::ReferenceBlock {
type Output = ir::Expression;
type Output = ir::Reference;

fn into_lower(&self, ctx: &Context) -> Result<Self::Output, Error> {
self.r#ref.into_lower(ctx)
Ok(ir::Reference {
name: self.name.to_lowercase().clone(),
utxos: self.r#ref.into_lower(ctx)?,
})
}
}

Expand Down Expand Up @@ -1018,6 +1042,7 @@ mod tests {
test_lowering!(cardano_witness);

test_lowering!(reference_script);
test_lowering!(reference_input_datum);

test_lowering!(withdrawal);
test_lowering!(map);
Expand Down
36 changes: 28 additions & 8 deletions crates/tx3-lang/src/parsing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -355,20 +355,39 @@ impl AstNode for ReferenceBlock {
const RULE: Rule = Rule::reference_block;

fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
let span = pair.as_span().into();
let span: Span = pair.as_span().into();
let mut inner = pair.into_inner();

let name = inner.next().unwrap().as_str().to_string();

let pair = inner.next().unwrap();
match pair.as_rule() {
Rule::input_block_ref => {
let pair = pair.into_inner().next().unwrap();
let r#ref = DataExpr::parse(pair)?;
Ok(ReferenceBlock { name, r#ref, span })
let mut r#ref = None;
let mut datum_is = None;
for field in inner {
match field.as_rule() {
Rule::input_block_ref => {
let pair = field.into_inner().next().unwrap();
r#ref = Some(DataExpr::parse(pair)?);
}
Rule::input_block_datum_is => {
let pair = field.into_inner().next().unwrap();
datum_is = Some(Type::parse(pair)?);
}
x => unreachable!("Unexpected rule in reference_block: {:?}", x),
}
x => unreachable!("Unexpected rule in ref_input_block: {:?}", x),
}

let r#ref = r#ref.ok_or_else(|| Error {
message: "reference block requires 'ref' field".to_string(),
src: String::new(),
span: span.clone(),
})?;

Ok(ReferenceBlock {
name,
r#ref,
datum_is,
span,
})
}

fn span(&self) -> &Span {
Expand Down Expand Up @@ -2809,6 +2828,7 @@ mod tests {
test_parsing!(cardano_witness);

test_parsing!(reference_script);
test_parsing!(reference_input_datum);
test_parsing!(map);
test_parsing!(burn);

Expand Down
9 changes: 7 additions & 2 deletions crates/tx3-lang/src/tx3.pest
Original file line number Diff line number Diff line change
Expand Up @@ -238,9 +238,14 @@ collateral_block = {
"}"
}

reference_block_field = _{
input_block_ref |
input_block_datum_is
}

reference_block = {
"reference" ~ identifier ~ ("*")? ~ "{" ~
input_block_ref ~ "," ~
"reference" ~ identifier ~ "{" ~
(reference_block_field ~ ",")* ~
"}"
}

Expand Down
2 changes: 1 addition & 1 deletion crates/tx3-resolver/src/inputs/narrow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ pub struct SearchSpace {
}

impl SearchSpace {
fn new() -> Self {
pub fn new() -> Self {
Self {
union: Subset::NotSet,
intersection: Subset::NotSet,
Expand Down
68 changes: 67 additions & 1 deletion crates/tx3-tir/src/model/v1beta0.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@
//! [`lower`](crate::lower) for lowering an AST to the intermediate
//! representation.

use serde::de::{self, Deserializer, SeqAccess, Visitor as SerdeVisitor};
use serde::{Deserialize, Serialize};
use std::collections::{HashMap, HashSet};
use std::fmt;

use crate::{
encoding::{TirRoot, TirVersion},
Expand Down Expand Up @@ -292,6 +294,12 @@ pub struct InputQuery {
pub collateral: bool,
}

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
pub struct Reference {
pub name: String,
pub utxos: Expression,
}

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
pub struct Input {
pub name: String,
Expand Down Expand Up @@ -335,10 +343,57 @@ pub struct Signers {
pub signers: Vec<Expression>,
}

/// Legacy TIR stored references as Vec<Expression>. We accept both formats when deserializing.
#[derive(Deserialize)]
#[serde(untagged)]
enum ReferenceOrLegacy {
New(Reference),
Legacy(Expression),
}

fn deserialize_references<'de, D>(deserializer: D) -> Result<Vec<Reference>, D::Error>
where
D: Deserializer<'de>,
{
struct ReferencesVisitor;

impl<'de> SerdeVisitor<'de> for ReferencesVisitor {
type Value = Vec<Reference>;

fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str("array of Reference or legacy array of Expression")
}

fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where
A: SeqAccess<'de>,
{
let mut refs = Vec::new();
let mut index = 0usize;
while let Some(item) = seq.next_element::<ReferenceOrLegacy>()? {
match item {
ReferenceOrLegacy::New(r) => refs.push(r),
ReferenceOrLegacy::Legacy(utxos) => {
refs.push(Reference {
name: format!("ref_{}", index),
utxos,
});
}
}
index += 1;
}
Ok(refs)
}
}

deserializer.deserialize_seq(ReferencesVisitor)
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Tx {
pub fees: Expression,
pub references: Vec<Expression>,
#[serde(deserialize_with = "deserialize_references")]
pub references: Vec<Reference>,
pub inputs: Vec<Input>,
pub outputs: Vec<Output>,
pub validity: Option<Validity>,
Expand Down Expand Up @@ -416,6 +471,17 @@ impl Node for InputQuery {
}
}

impl Node for Reference {
fn apply<V: Visitor>(self, visitor: &mut V) -> Result<Self, crate::reduce::Error> {
let visited = Self {
utxos: self.utxos.apply(visitor)?,
..self
};

Ok(visited)
}
}

impl Node for Param {
fn apply<V: Visitor>(self, visitor: &mut V) -> Result<Self, crate::reduce::Error> {
let visited = match self {
Expand Down
51 changes: 51 additions & 0 deletions crates/tx3-tir/src/reduce/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -756,6 +756,57 @@ impl Composite for Input {
}
}

impl Apply for Reference {
fn apply_args(self, args: &BTreeMap<String, ArgValue>) -> Result<Self, Error> {
Ok(Self {
utxos: self.utxos.apply_args(args)?,
..self
})
}

fn apply_inputs(self, args: &BTreeMap<String, HashSet<Utxo>>) -> Result<Self, Error> {
Ok(Self {
utxos: self.utxos.apply_inputs(args)?,
..self
})
}

fn apply_fees(self, fees: u64) -> Result<Self, Error> {
Ok(Self {
utxos: self.utxos.apply_fees(fees)?,
..self
})
}

fn is_constant(&self) -> bool {
self.utxos.is_constant()
}

fn params(&self) -> BTreeMap<String, Type> {
self.utxos.params()
}

fn queries(&self) -> BTreeMap<String, InputQuery> {
BTreeMap::from([(
self.name.clone(),
InputQuery {
address: Expression::None,
min_amount: Expression::None,
r#ref: self.utxos.clone(),
many: false,
collateral: false,
},
)])
}

fn reduce(self) -> Result<Self, Error> {
Ok(Self {
utxos: self.utxos.reduce()?,
..self
})
}
}

impl Composite for InputQuery {
fn components(&self) -> Vec<&Expression> {
vec![&self.address, &self.min_amount, &self.r#ref]
Expand Down
Loading