Fix script context translations for withdrawals and validity intervals.

This commit is contained in:
KtorZ 2024-08-13 23:43:47 +02:00
parent fe5c5650a1
commit f879f6d183
No known key found for this signature in database
GPG Key ID: 33173CB6F77F4277
27 changed files with 1674 additions and 258 deletions

View File

@ -9,7 +9,7 @@ use std::{fmt, fs, path::PathBuf, process};
use uplc::{ use uplc::{
machine::cost_model::ExBudget, machine::cost_model::ExBudget,
tx::{ tx::{
self, self, redeemer_tag_to_string,
script_context::{ResolvedInput, SlotConfig}, script_context::{ResolvedInput, SlotConfig},
}, },
}; };
@ -110,11 +110,11 @@ pub fn exec(
let with_redeemer = |redeemer: &Redeemer| { let with_redeemer = |redeemer: &Redeemer| {
eprintln!( eprintln!(
"{} {:?}[{}]", "{} {}[{}]",
" Evaluating" " Evaluating"
.if_supports_color(Stderr, |s| s.purple()) .if_supports_color(Stderr, |s| s.purple())
.if_supports_color(Stderr, |s| s.bold()), .if_supports_color(Stderr, |s| s.bold()),
redeemer.tag, redeemer_tag_to_string(&redeemer.tag),
redeemer.index redeemer.index
) )
}; };

View File

@ -16,6 +16,7 @@ pub use pallas_primitives::{
babbage::{PostAlonzoTransactionOutput, TransactionInput, TransactionOutput, Value}, babbage::{PostAlonzoTransactionOutput, TransactionInput, TransactionOutput, Value},
Error, Fragment, Error, Fragment,
}; };
pub use tx::redeemer_tag_to_string;
pub fn plutus_data(bytes: &[u8]) -> Result<PlutusData, Error> { pub fn plutus_data(bytes: &[u8]) -> Result<PlutusData, Error> {
PlutusData::decode_fragment(bytes) PlutusData::decode_fragment(bytes)

View File

@ -13,9 +13,19 @@ pub enum Error {
OpenTermEvaluated(Term<NamedDeBruijn>), OpenTermEvaluated(Term<NamedDeBruijn>),
#[error("The validator crashed / exited prematurely")] #[error("The validator crashed / exited prematurely")]
EvaluationFailure, EvaluationFailure,
#[error("Attempted to instantiate a non-polymorphic term:\n\n{0:#?}")] #[error(
"Attempted to instantiate a non-polymorphic term\n{:>13} {}",
"Term",
indent(redacted(format!("{:#?}", .0), 10)),
)]
NonPolymorphicInstantiation(Value), NonPolymorphicInstantiation(Value),
#[error("Attempted to apply a non-function:\n\n{0:#?} to argument:\n\n{1:#?}")] #[error(
"Attempted to apply an argument to a non-function\n{:>13} {}\n{:>13} {}",
"Thing",
indent(redacted(format!("{:#?}", .0), 5)),
"Argument",
indent(redacted(format!("{:#?}", .1), 5)),
)]
NonFunctionalApplication(Value, Value), NonFunctionalApplication(Value, Value),
#[error("Attempted to case a non-const:\n\n{0:#?}")] #[error("Attempted to case a non-const:\n\n{0:#?}")]
NonConstrScrutinized(Value), NonConstrScrutinized(Value),
@ -61,7 +71,10 @@ pub enum Error {
UnexpectedEd25519PublicKeyLength(usize), UnexpectedEd25519PublicKeyLength(usize),
#[error("Ed25519S Signature should be 64 bytes but it was {0}")] #[error("Ed25519S Signature should be 64 bytes but it was {0}")]
UnexpectedEd25519SignatureLength(usize), UnexpectedEd25519SignatureLength(usize),
#[error("Failed to deserialise PlutusData using {0}:\n\n{1:#?}")] #[error(
"Failed to deserialise PlutusData using {0}:\n\n{}",
redacted(format!("{:#?}", .1), 10),
)]
DeserialisationError(String, Value), DeserialisationError(String, Value),
#[error("Integer overflow")] #[error("Integer overflow")]
OverflowError, OverflowError,
@ -83,3 +96,21 @@ impl From<k256::ecdsa::Error> for Error {
Error::K256Error(format!("K256 error: {}", error)) Error::K256Error(format!("K256 error: {}", error))
} }
} }
/// Print only the first n lines of possibly long output, and redact the rest if longer.
fn redacted(s: String, max_rows: usize) -> String {
let rows = s.lines();
if rows.count() > max_rows {
let last_line = s.lines().last().unwrap();
let mut s = s.lines().take(max_rows).collect::<Vec<_>>().join("\n");
s.push_str(&format!("\n ...redacted...\n{last_line}"));
s
} else {
s
}
}
fn indent(s: String) -> String {
s.lines().collect::<Vec<_>>().join(&format!("\n{:>14}", ""))
}

View File

@ -9,7 +9,7 @@ use pallas_primitives::{
Fragment, Fragment,
}; };
use pallas_traverse::{Era, MultiEraTx}; use pallas_traverse::{Era, MultiEraTx};
pub use phase_one::eval_phase_one; pub use phase_one::{eval_phase_one, redeemer_tag_to_string};
pub use script_context::{DataLookupTable, ResolvedInput, SlotConfig}; pub use script_context::{DataLookupTable, ResolvedInput, SlotConfig};
pub mod error; pub mod error;

View File

@ -99,4 +99,6 @@ pub enum Error {
MissingScriptForRedeemer, MissingScriptForRedeemer,
#[error("failed to apply parameters to Plutus script")] #[error("failed to apply parameters to Plutus script")]
ApplyParamsError, ApplyParamsError,
#[error("validity start or end too far in the past")]
SlotTooFarInThePast { oldest_allowed: u64 },
} }

View File

@ -4,15 +4,16 @@ use super::{
Error, Error,
}; };
use crate::{ use crate::{
ast::{Data, FakeNamedDeBruijn, NamedDeBruijn, Program}, ast::{FakeNamedDeBruijn, NamedDeBruijn, Program},
machine::cost_model::ExBudget, machine::cost_model::ExBudget,
tx::script_context::{DataLookupTable, ScriptVersion, TxInfoV1, TxInfoV2, TxInfoV3}, tx::{
phase_one::redeemer_tag_to_string,
script_context::{DataLookupTable, ScriptVersion, TxInfoV1, TxInfoV2, TxInfoV3},
},
PlutusData, PlutusData,
}; };
use pallas_codec::utils::Bytes; use pallas_codec::utils::Bytes;
use pallas_primitives::conway::{ use pallas_primitives::conway::{CostMdls, CostModel, ExUnits, Language, MintedTx, Redeemer};
CostMdls, CostModel, ExUnits, Language, MintedTx, Redeemer, RedeemerTag,
};
pub fn eval_redeemer( pub fn eval_redeemer(
tx: &MintedTx, tx: &MintedTx,
@ -44,21 +45,16 @@ pub fn eval_redeemer(
} }
.apply_data(redeemer.data.clone()) .apply_data(redeemer.data.clone())
.apply_data(script_context.to_plutus_data()), .apply_data(script_context.to_plutus_data()),
ScriptContext::V3 { .. } if datum.is_some() => {
// FIXME: Temporary, but needed until https://github.com/aiken-lang/aiken/pull/977
// is implemented.
ScriptContext::V3 { .. } => if let Some(datum) = datum {
program.apply_data(datum)
} else {
program program
// FIXME: Temporary, but needed until https://github.com/aiken-lang/aiken/pull/977
// is implemented.
.apply_data(Data::constr(0, vec![]))
.apply_data(Data::constr(0, vec![]))
.apply_data(script_context.to_plutus_data())
}
ScriptContext::V3 { .. } => {
program
// FIXME: Temporary, but needed until https://github.com/aiken-lang/aiken/pull/977
// is implemented.
.apply_data(Data::constr(0, vec![]))
.apply_data(script_context.to_plutus_data())
} }
.apply_data(redeemer.data.clone())
.apply_data(script_context.to_plutus_data()),
}; };
let mut eval_result = if let Some(costs) = cost_mdl_opt { let mut eval_result = if let Some(costs) = cost_mdl_opt {
@ -154,15 +150,3 @@ pub fn eval_redeemer(
err: Box::new(err), err: Box::new(err),
}) })
} }
fn redeemer_tag_to_string(redeemer_tag: &RedeemerTag) -> String {
match redeemer_tag {
RedeemerTag::Spend => "Spend",
RedeemerTag::Mint => "Mint",
RedeemerTag::Reward => "Withdraw",
RedeemerTag::Cert => "Publish",
RedeemerTag::Propose => "Propose",
RedeemerTag::Vote => "Vote",
}
.to_string()
}

View File

@ -2,6 +2,7 @@ use super::{
error::Error, error::Error,
script_context::{sort_voters, DataLookupTable, ResolvedInput, ScriptPurpose, ScriptVersion}, script_context::{sort_voters, DataLookupTable, ResolvedInput, ScriptPurpose, ScriptVersion},
}; };
use crate::tx::script_context::sort_reward_accounts;
use itertools::Itertools; use itertools::Itertools;
use pallas_addresses::{Address, ScriptHash, ShelleyPaymentPart, StakePayload}; use pallas_addresses::{Address, ScriptHash, ShelleyPaymentPart, StakePayload};
use pallas_codec::utils::Nullable; use pallas_codec::utils::Nullable;
@ -234,13 +235,20 @@ pub fn has_exact_set_of_redeemers(
let missing: Vec<_> = redeemers_needed let missing: Vec<_> = redeemers_needed
.into_iter() .into_iter()
.filter(|x| !wits_redeemer_keys.contains(&&x.0)) .filter(|x| !wits_redeemer_keys.contains(&&x.0))
.map(|x| format!("{:?}[{:?}] -> {}", x.0.tag, x.0.index, x.2)) .map(|x| {
format!(
"{}[{:?}] -> {}",
redeemer_tag_to_string(&x.0.tag),
x.0.index,
x.2
)
})
.collect(); .collect();
let extra: Vec<_> = wits_redeemer_keys let extra: Vec<_> = wits_redeemer_keys
.into_iter() .into_iter()
.filter(|x| !needed_redeemer_keys.contains(x)) .filter(|x| !needed_redeemer_keys.contains(x))
.map(|x| format!("{:?}[{:?}]", x.tag, x.index)) .map(|x| format!("{}[{:?}]", redeemer_tag_to_string(&x.tag), x.index))
.collect(); .collect();
if !missing.is_empty() || !extra.is_empty() { if !missing.is_empty() || !extra.is_empty() {
@ -306,7 +314,7 @@ fn build_redeemer_key(
.map(|m| m.iter().map(|(acnt, _)| acnt).collect()) .map(|m| m.iter().map(|(acnt, _)| acnt).collect())
.unwrap_or_default(); .unwrap_or_default();
reward_accounts.sort(); reward_accounts.sort_by(|acnt_a, acnt_b| sort_reward_accounts(acnt_a, acnt_b));
let mut redeemer_key = None; let mut redeemer_key = None;
@ -377,3 +385,15 @@ fn build_redeemer_key(
} }
} }
} }
pub fn redeemer_tag_to_string(redeemer_tag: &RedeemerTag) -> String {
match redeemer_tag {
RedeemerTag::Spend => "Spend",
RedeemerTag::Mint => "Mint",
RedeemerTag::Reward => "Withdraw",
RedeemerTag::Cert => "Publish",
RedeemerTag::Propose => "Propose",
RedeemerTag::Vote => "Vote",
}
.to_string()
}

View File

@ -1,8 +1,8 @@
use super::{to_plutus_data::MintValue, Error}; use super::{to_plutus_data::MintValue, Error};
use itertools::Itertools; use itertools::Itertools;
use pallas_addresses::{Address, StakePayload}; use pallas_addresses::{Address, Network, StakePayload};
use pallas_codec::utils::{ use pallas_codec::utils::{
KeyValuePairs, NonEmptyKeyValuePairs, NonEmptySet, Nullable, PositiveCoin, Bytes, KeyValuePairs, NonEmptyKeyValuePairs, NonEmptySet, Nullable, PositiveCoin,
}; };
use pallas_crypto::hash::Hash; use pallas_crypto::hash::Hash;
use pallas_primitives::{ use pallas_primitives::{
@ -217,7 +217,7 @@ impl TxInfoV1 {
let inputs = get_tx_in_info_v1(&tx.transaction_body.inputs, utxos)?; let inputs = get_tx_in_info_v1(&tx.transaction_body.inputs, utxos)?;
let certificates = get_certificates_info(&tx.transaction_body.certificates); let certificates = get_certificates_info(&tx.transaction_body.certificates);
let withdrawals = let withdrawals =
KeyValuePairs::from(get_withdrawal_info(&tx.transaction_body.withdrawals)); KeyValuePairs::from(get_withdrawals_info(&tx.transaction_body.withdrawals));
let mint = get_mint_info(&tx.transaction_body.mint); let mint = get_mint_info(&tx.transaction_body.mint);
let redeemers = get_redeemers_info( let redeemers = get_redeemers_info(
@ -232,7 +232,7 @@ impl TxInfoV1 {
mint, mint,
certificates, certificates,
withdrawals: withdrawals.into(), withdrawals: withdrawals.into(),
valid_range: get_validity_range_info(&tx.transaction_body, slot_config), valid_range: get_validity_range_info(&tx.transaction_body, slot_config)?,
signatories: get_signatories_info(&tx.transaction_body.required_signers), signatories: get_signatories_info(&tx.transaction_body.required_signers),
data: get_data_info(&tx.transaction_witness_set), data: get_data_info(&tx.transaction_witness_set),
redeemers, redeemers,
@ -266,7 +266,7 @@ impl TxInfoV2 {
let inputs = get_tx_in_info_v2(&tx.transaction_body.inputs, utxos)?; let inputs = get_tx_in_info_v2(&tx.transaction_body.inputs, utxos)?;
let certificates = get_certificates_info(&tx.transaction_body.certificates); let certificates = get_certificates_info(&tx.transaction_body.certificates);
let withdrawals = let withdrawals =
KeyValuePairs::from(get_withdrawal_info(&tx.transaction_body.withdrawals)); KeyValuePairs::from(get_withdrawals_info(&tx.transaction_body.withdrawals));
let mint = get_mint_info(&tx.transaction_body.mint); let mint = get_mint_info(&tx.transaction_body.mint);
let redeemers = get_redeemers_info( let redeemers = get_redeemers_info(
@ -290,7 +290,7 @@ impl TxInfoV2 {
mint, mint,
certificates, certificates,
withdrawals, withdrawals,
valid_range: get_validity_range_info(&tx.transaction_body, slot_config), valid_range: get_validity_range_info(&tx.transaction_body, slot_config)?,
signatories: get_signatories_info(&tx.transaction_body.required_signers), signatories: get_signatories_info(&tx.transaction_body.required_signers),
data: KeyValuePairs::from(get_data_info(&tx.transaction_witness_set)), data: KeyValuePairs::from(get_data_info(&tx.transaction_witness_set)),
redeemers, redeemers,
@ -330,7 +330,7 @@ impl TxInfoV3 {
let certificates = get_certificates_info(&tx.transaction_body.certificates); let certificates = get_certificates_info(&tx.transaction_body.certificates);
let withdrawals = let withdrawals =
KeyValuePairs::from(get_withdrawal_info(&tx.transaction_body.withdrawals)); KeyValuePairs::from(get_withdrawals_info(&tx.transaction_body.withdrawals));
let mint = get_mint_info(&tx.transaction_body.mint); let mint = get_mint_info(&tx.transaction_body.mint);
@ -367,7 +367,7 @@ impl TxInfoV3 {
mint, mint,
certificates, certificates,
withdrawals, withdrawals,
valid_range: get_validity_range_info(&tx.transaction_body, slot_config), valid_range: get_validity_range_info(&tx.transaction_body, slot_config)?,
signatories: get_signatories_info(&tx.transaction_body.required_signers), signatories: get_signatories_info(&tx.transaction_body.required_signers),
data: KeyValuePairs::from(get_data_info(&tx.transaction_witness_set)), data: KeyValuePairs::from(get_data_info(&tx.transaction_witness_set)),
redeemers, redeemers,
@ -626,14 +626,14 @@ pub fn get_proposal_procedures_info(
.unwrap_or_default() .unwrap_or_default()
} }
pub fn get_withdrawal_info( pub fn get_withdrawals_info(
withdrawals: &Option<NonEmptyKeyValuePairs<RewardAccount, Coin>>, withdrawals: &Option<NonEmptyKeyValuePairs<RewardAccount, Coin>>,
) -> Vec<(Address, Coin)> { ) -> Vec<(Address, Coin)> {
withdrawals withdrawals
.clone() .clone()
.map(|w| { .map(|w| {
w.into_iter() w.into_iter()
.sorted() .sorted_by(|(accnt_a, _), (accnt_b, _)| sort_reward_accounts(accnt_a, accnt_b))
.map(|(reward_account, coin)| (Address::from_bytes(&reward_account).unwrap(), coin)) .map(|(reward_account, coin)| (Address::from_bytes(&reward_account).unwrap(), coin))
.collect() .collect()
}) })
@ -643,21 +643,31 @@ pub fn get_withdrawal_info(
pub fn get_validity_range_info( pub fn get_validity_range_info(
body: &MintedTransactionBody, body: &MintedTransactionBody,
slot_config: &SlotConfig, slot_config: &SlotConfig,
) -> TimeRange { ) -> Result<TimeRange, Error> {
fn slot_to_begin_posix_time(slot: u64, sc: &SlotConfig) -> u64 { fn slot_to_begin_posix_time(slot: u64, sc: &SlotConfig) -> Result<u64, Error> {
if slot < sc.zero_slot {
return Err(Error::SlotTooFarInThePast {
oldest_allowed: sc.zero_slot,
});
}
let ms_after_begin = (slot - sc.zero_slot) * sc.slot_length as u64; let ms_after_begin = (slot - sc.zero_slot) * sc.slot_length as u64;
sc.zero_time + ms_after_begin Ok(sc.zero_time + ms_after_begin)
} }
fn slot_range_to_posix_time_range(slot_range: TimeRange, sc: &SlotConfig) -> TimeRange { fn slot_range_to_posix_time_range(
TimeRange { slot_range: TimeRange,
sc: &SlotConfig,
) -> Result<TimeRange, Error> {
Ok(TimeRange {
lower_bound: slot_range lower_bound: slot_range
.lower_bound .lower_bound
.map(|lower_bound| slot_to_begin_posix_time(lower_bound, sc)), .map(|lower_bound| slot_to_begin_posix_time(lower_bound, sc))
.transpose()?,
upper_bound: slot_range upper_bound: slot_range
.upper_bound .upper_bound
.map(|upper_bound| slot_to_begin_posix_time(upper_bound, sc)), .map(|upper_bound| slot_to_begin_posix_time(upper_bound, sc))
} .transpose()?,
})
} }
slot_range_to_posix_time_range( slot_range_to_posix_time_range(
@ -841,7 +851,7 @@ pub fn find_script(
lookup_script(&hash) lookup_script(&hash)
}), }),
RedeemerTag::Reward => get_withdrawal_info(&tx.transaction_body.withdrawals) RedeemerTag::Reward => get_withdrawals_info(&tx.transaction_body.withdrawals)
.get(redeemer.index as usize) .get(redeemer.index as usize)
.ok_or(Error::MissingScriptForRedeemer) .ok_or(Error::MissingScriptForRedeemer)
.and_then(|(addr, _)| { .and_then(|(addr, _)| {
@ -1086,6 +1096,34 @@ fn sort_gov_action_id(a: &GovActionId, b: &GovActionId) -> Ordering {
} }
} }
pub fn sort_reward_accounts(a: &Bytes, b: &Bytes) -> Ordering {
let addr_a = Address::from_bytes(a).expect("invalid reward address in withdrawals.");
let addr_b = Address::from_bytes(b).expect("invalid reward address in withdrawals.");
fn network_tag(network: Network) -> u8 {
match network {
Network::Testnet => 0,
Network::Mainnet => 1,
Network::Other(tag) => tag,
}
}
if let (Address::Stake(accnt_a), Address::Stake(accnt_b)) = (addr_a, addr_b) {
if accnt_a.network() != accnt_b.network() {
return network_tag(accnt_a.network()).cmp(&network_tag(accnt_b.network()));
}
match (accnt_a.payload(), accnt_b.payload()) {
(StakePayload::Script(..), StakePayload::Stake(..)) => Ordering::Less,
(StakePayload::Stake(..), StakePayload::Script(..)) => Ordering::Greater,
(StakePayload::Script(hash_a), StakePayload::Script(hash_b)) => hash_a.cmp(hash_b),
(StakePayload::Stake(hash_a), StakePayload::Stake(hash_b)) => hash_a.cmp(hash_b),
}
} else {
unreachable!("invalid reward address in withdrawals.");
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::{ use crate::{
@ -1479,4 +1517,62 @@ mod tests {
// from the Haskell ledger / cardano node. // from the Haskell ledger / cardano node.
insta::assert_debug_snapshot!(script_context.to_plutus_data()); insta::assert_debug_snapshot!(script_context.to_plutus_data());
} }
#[test]
fn script_context_withdraw() {
let redeemer = Redeemer {
tag: RedeemerTag::Reward,
index: 0,
data: Data::constr(0, vec![]),
ex_units: ExUnits {
mem: 1000000,
steps: 100000000,
},
};
// NOTE: The transaction also contains treasury donation and current treasury amount
let script_context = fixture_tx_info(
"84a7008182582000000000000000000000000000000000000000000000000000\
00000000000000000183a2005839200000000000000000000000000000000000\
0000000000000000000000111111111111111111111111111111111111111111\
11111111111111011a000f4240a2005823400000000000000000000000000000\
00000000000000000000000000008198bd431b03011a000f4240a20058235011\
1111111111111111111111111111111111111111111111111111118198bd431b\
03011a000f424002182a031a00448e0105a1581df004036eecadc2f19e95f831\
b4bc08919cde1d1088d74602bd3dcd78a2000e81581c00000000000000000000\
0000000000000000000000000000000000001601a10582840000d87a81d87980\
821a000f42401a05f5e100840300d87980821a000f42401a05f5e100f5f6",
"8182582000000000000000000000000000000000000000000000000000000000\
0000000000",
"81a40058393004036eecadc2f19e95f831b4bc08919cde1d1088d74602bd3dcd\
78a204036eecadc2f19e95f831b4bc08919cde1d1088d74602bd3dcd78a2011a\
000f4240028201d81843d8798003d818590221820359021c5902190101003232\
323232323232322232533333300c00215323330073001300937540062a660109\
211c52756e6e696e672032206172672076616c696461746f72206d696e740013\
533333300d004153330073001300937540082a66601660146ea8010494ccc021\
288a4c2a660129211856616c696461746f722072657475726e65642066616c73\
65001365600600600600600600600315330084911d52756e6e696e6720332061\
72672076616c696461746f72207370656e640013533333300d00415333007300\
1300937540082a66601660146ea8010494cccccc03800454ccc020c008c028dd\
50008a99980618059baa0011253330094a22930a998052491856616c69646174\
6f722072657475726e65642066616c7365001365600600600600600600600600\
6006006006006300c300a37540066e1d20001533007001161533007001161533\
00700116153300700116490191496e636f72726563742072656465656d657220\
7479706520666f722076616c696461746f72207370656e642e0a202020202020\
2020202020202020202020202020446f75626c6520636865636b20796f752068\
6176652077726170706564207468652072656465656d65722074797065206173\
2073706563696669656420696e20796f757220706c757475732e6a736f6e0015\
330034910b5f746d70313a20566f6964001615330024910b5f746d70303a2056\
6f696400165734ae7155ceaab9e5573eae855d21",
)
.into_script_context(&redeemer, None)
.unwrap();
// NOTE: The initial snapshot has been generated using the Haskell
// implementation of the ledger library for that same serialized
// transactions. It is meant to control that our construction of the
// script context and its serialization matches exactly those
// from the Haskell ledger / cardano node.
insta::assert_debug_snapshot!(script_context.to_plutus_data());
}
} }

File diff suppressed because it is too large Load Diff

View File

@ -736,127 +736,34 @@ impl ToPlutusData for PlutusData {
impl ToPlutusData for TimeRange { impl ToPlutusData for TimeRange {
fn to_plutus_data(&self) -> PlutusData { fn to_plutus_data(&self) -> PlutusData {
match &self { fn bound(bound: Option<u64>, is_lower: bool) -> PlutusData {
TimeRange { match bound {
lower_bound: Some(lower_bound), Some(x) => wrap_multiple_with_constr(
upper_bound: None,
} => {
wrap_multiple_with_constr(
0, 0,
vec![ vec![
// LowerBound wrap_with_constr(1, x.to_plutus_data()),
wrap_multiple_with_constr( // NOTE: Finite lower bounds are always inclusive, unlike upper bounds.
0, is_lower.to_plutus_data(),
vec![
// Finite
wrap_with_constr(1, lower_bound.to_plutus_data()),
// Closure
true.to_plutus_data(),
],
), //UpperBound
wrap_multiple_with_constr(
0,
vec![
// PosInf
empty_constr(2),
// Closure
true.to_plutus_data(),
],
),
], ],
) ),
} None => wrap_multiple_with_constr(
TimeRange {
lower_bound: None,
upper_bound: Some(upper_bound),
} => {
wrap_multiple_with_constr(
0, 0,
vec![ vec![
// LowerBound empty_constr(if is_lower { 0 } else { 2 }),
wrap_multiple_with_constr( // NOTE: Infinite bounds are always exclusive, by convention.
0, true.to_plutus_data(),
vec![
// NegInf
empty_constr(0),
// Closure
true.to_plutus_data(),
],
),
//UpperBound
wrap_multiple_with_constr(
0,
vec![
// Finite
wrap_with_constr(1, upper_bound.to_plutus_data()),
// Closure
true.to_plutus_data(),
],
),
], ],
) ),
}
TimeRange {
lower_bound: Some(lower_bound),
upper_bound: Some(upper_bound),
} => {
wrap_multiple_with_constr(
0,
vec![
// LowerBound
wrap_multiple_with_constr(
0,
vec![
// Finite
wrap_with_constr(1, lower_bound.to_plutus_data()),
// Closure
true.to_plutus_data(),
],
),
//UpperBound
wrap_multiple_with_constr(
0,
vec![
// Finite
wrap_with_constr(1, upper_bound.to_plutus_data()),
// Closure
false.to_plutus_data(),
],
),
],
)
}
TimeRange {
lower_bound: None,
upper_bound: None,
} => {
wrap_multiple_with_constr(
0,
vec![
// LowerBound
wrap_multiple_with_constr(
0,
vec![
// NegInf
empty_constr(0),
// Closure
true.to_plutus_data(),
],
),
//UpperBound
wrap_multiple_with_constr(
0,
vec![
// PosInf
empty_constr(2),
// Closure
true.to_plutus_data(),
],
),
],
)
} }
} }
wrap_multiple_with_constr(
0,
vec![
bound(self.lower_bound, true),
bound(self.upper_bound, false),
],
)
} }
} }

View File

@ -8,23 +8,22 @@ for lang in $(ls script_context); do
title=$(basename $interaction) title=$(basename $interaction)
title="${title%.*}" title="${title%.*}"
cd script_context/$lang cd script_context/$lang
./test.sh $title "$AIKEN" & echo "running $lang/$title..."
TESTS+=("$title,$lang,$!") ./test.sh $title "$AIKEN"
TESTS+=("$title,$lang,$?")
cd - 1>/dev/null cd - 1>/dev/null
done done
done done
for args in ${TESTS[@]}; do for args in ${TESTS[@]}; do
IFS=',' read title lang pid <<< "${args}" IFS=',' read title lang code <<< "${args}"
wait $pid
code=("$?")
log="script_context/$lang/$title.log" log="script_context/$lang/$title.log"
if [ $code -ne 0 ]; then if [ $code -ne 0 ]; then
echo "=== $title ❌ (code=$code)" echo "=== $lang/$title ❌ (code=$code)"
cat $log && rm -f $log cat $log && rm -f $log
exit $code exit $code
else else
echo "=== $title ✅" echo "=== $lang/$title ✅"
cat $log && rm -f $log cat $log && rm -f $log
fi fi
echo "" echo ""

View File

@ -13,4 +13,4 @@ requirements = []
source = "github" source = "github"
[etags] [etags]
"aiken-lang/stdlib@main" = [{ secs_since_epoch = 1723324201, nanos_since_epoch = 743234000 }, "5e58899446492a704d0927a43299139856bef746e697b55895ba34206fa28452"] "aiken-lang/stdlib@main" = [{ secs_since_epoch = 1723583483, nanos_since_epoch = 18378000 }, "5e58899446492a704d0927a43299139856bef746e697b55895ba34206fa28452"]

View File

@ -1 +1 @@
84A80081825820000000000000000000000000000000000000000000000000000000000000000000018182581D60111111111111111111111111111111111111111111111111111111111A3B9ACA0002182A05A2581DE022222222222222222222222222222222222222222222222222222222182A581DF0AFDDC16C18E7D8DE379FB9AAD39B3D1B5AFD27603E5EBAC818432A720E0B5820FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0D818258200000000000000000000000000000000000000000000000000000000000000000001082581D60000000000000000000000000000000000000000000000000000000001A3B9ACA001101A20582840000D87980821A000F42401A05F5E100840301D87980821A000F42401A05F5E1000682{{ VALIDATOR }}583D583B010000323232323232322253330054A22930B180080091129998030010A4C26600A6002600E0046660060066010004002AE695CDAAB9F5742AE881F5F6 84A80081825820000000000000000000000000000000000000000000000000000000000000000000018182581D60111111111111111111111111111111111111111111111111111111111A3B9ACA0002182A05A2581DE022222222222222222222222222222222222222222222222222222222182A581DF0AFDDC16C18E7D8DE379FB9AAD39B3D1B5AFD27603E5EBAC818432A720E0B5820FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0D818258200000000000000000000000000000000000000000000000000000000000000000001082581D60000000000000000000000000000000000000000000000000000000001A3B9ACA001101A20582840000D87980821A000F42401A05F5E100840300D87980821A000F42401A05F5E1000682{{ VALIDATOR }}583D583B010000323232323232322253330054A22930B180080091129998030010A4C26600A6002600E0046660060066010004002AE695CDAAB9F5742AE881F5F6

View File

@ -29,7 +29,7 @@
{ 5: { 5:
[ [0, 0, 121([]), [1000000, 100000000]] [ [0, 0, 121([]), [1000000, 100000000]]
, [3, 1, 121([]), [1000000, 100000000]] , [3, 0, 121([]), [1000000, 100000000]]
] ]
, 6: [ {{ VALIDATOR }}, h'583b010000323232323232322253330054a22930b180080091129998030010a4c26600a6002600e0046660060066010004002ae695cdaab9f5742ae881' ] , 6: [ {{ VALIDATOR }}, h'583b010000323232323232322253330054a22930b180080091129998030010a4c26600a6002600e0046660060066010004002ae695cdaab9f5742ae881' ]

View File

@ -6,7 +6,7 @@
"plutusVersion": "v2", "plutusVersion": "v2",
"compiler": { "compiler": {
"name": "Aiken", "name": "Aiken",
"version": "v1.0.31-alpha+81c0152" "version": "v1.0.31-alpha+fe5c565"
}, },
"license": "Apache-2.0" "license": "Apache-2.0"
}, },
@ -25,8 +25,8 @@
"$ref": "#/definitions/Void" "$ref": "#/definitions/Void"
} }
}, },
"compiledCode": "5903280100003232323232323223232232253330073253330083330083375e601a601c601c601c601c601c601c601c601c601c601c601c60146ea8c004c028dd5001260126d8799f58200000000000000000000000000000000000000000000000000000000000000000ff004a09444c94ccc024c94ccc028cdc3a400460166ea80044c94ccc02ccdd7980218069baa0014c0126d8799f58200000000000000000000000000000000000000000000000000000000000000000ff0013009375a6006601a6ea8004528180798061baa001163001300b375400626464a6660166464a6660200022c2a6660206026002264a66601c66ebcc018c040dd50009ba6300448202a35ae41c54ccc038cdd7980398081baa30073010375400298122d8799f581c11111111111111111111111111111111111111111111111111111111ff001533300e533300e300c300f3754600c60206ea8c01cc040dd50008a5014a22a66601c66ebcc00cc040dd5000a60103d879800013375e600a60206ea800530103d87a800014a029405280a5030120011637586002601c6ea8c014c038dd50031180898091809000899baf3002300d37546008601a6ea8014dd31800a40a8294094ccc02cc02400452f5bded8c0264646600200297adef6c6022533301100113301233760981014000374c00697adef6c60132323232533301233720910100002133016337609801014000374c00e00a2a66602466e3d22100002133016337609801014000374c00e00626602c66ec0dd48011ba600133006006003375660260066eb8c044008c054008c04c004c8cc0040052f5bded8c044a66602000226602266ec13001014000375000697adef6c60132323232533301133720910100002133015337609801014000375000e00a2a66602266e3d22100002133015337609801014000375000e00626602a66ec0dd48011ba800133006006003375a60240066eb8c040008c050008c0480048c03cc040c040c0400045281180718078008a502300d00114984d9594ccc014c00cc018dd50008a99980418039baa001149858594ccc00cc004c010dd50010a99980318029baa00214985858dc3a4000ae6955ceaab9e5573eae815d0aba201", "compiledCode": "5903fb01000032323232323232323232322533333300c00115332330053001300737540042a66601260106ea8008494cccccc03800454ccc018c008c020dd50008a99980518049baa0011253330073253330083330083375e601c601e601e601e601e601e601e601e601e601e601e601e60166ea8c004c02cdd500126126d8799f58200000000000000000000000000000000000000000000000000000000000000000ff004a09444c94ccc024c94ccc028cdc3a400460186ea80044c94ccc02ccdd7980218071baa0014c0126d8799f58200000000000000000000000000000000000000000000000000000000000000000ff0013007375a6006601c6ea8004528180818069baa001153300b4911c73637269707420707572706f73652069736e277420275370656e642700163001300c375400626464a6660166464a6660220022a6601c92011c756e6578706563746564206e756d626572206f66206f7574707574730016153330113014001132533300e3375e600c60226ea8004dd318022410151ad720e2a66601c66ebcc01cc044dd5180398089baa0014c0122d8799f581c11111111111111111111111111111111111111111111111111111111ff001533300e533300e300a30103754600c60226ea8c01cc044dd50008a5014a22a66601c66ebcc00cc044dd5000a60103d879800013375e600a60226ea800530103d87a800014a029405280a503013001153300e4911c756e6578706563746564206e756d626572206f66206f757470757473001637586002601e6ea8c014c03cdd50031180918099809800899baf3002300e37546008601c6ea8014dd31800a40a8294094ccc02cc01c00452f5bded8c0264646600200297adef6c6022533301200113301333760981014000374c00697adef6c60132323232533301233720910100002133017337609801014000374c00e00a2a66602466e3d22100002133017337609801014000374c00e00626602e66ec0dd48011ba600133006006003375660280066eb8c048008c058008c050004c8cc0040052f5bded8c044a66602200226602466ec13001014000375000697adef6c60132323232533301133720910100002133016337609801014000375000e00a2a66602266e3d22100002133016337609801014000375000e00626602c66ec0dd48011ba800133006006003375a60260066eb8c044008c054008c04c0048c040c044c044c0440045281180798080008a502300e001149854cc0212411856616c696461746f722072657475726e65642066616c73650013656004004004004004004004370e90000018018018018018a99801a4810f5f72656465656d65723a20566f6964001615330024910c5f646174756d3a20566f696400165734ae7155ceaab9e5573eae815d0aba257481",
"hash": "759c4c40f04fe27a816fbe04c522ac00c710762e979ebe09ed276362" "hash": "1c6c13a9a56cbcb9ed18c312c9e9e9996b0545b7230b7cf81cbe012d"
}, },
{ {
"title": "deploy.spend", "title": "deploy.spend",
@ -42,8 +42,8 @@
"$ref": "#/definitions/Data" "$ref": "#/definitions/Data"
} }
}, },
"compiledCode": "5902520100003232323232323232222533300453330043375e00698103d879800013253330053323223253330093370e900018051baa001132533300a3370e900018059baa001132533300e001161325333333013001161616132533301030130031533300d3375e980106d8799f182aff0000413370e600e00c90020a5016375a0022c602000260186ea800458c038c02cdd50008b1919198008008019129998070008a6103d87a8000132323232533300f3372200e0042a66601e66e3c01c0084cdd2a40006602600297ae014c0103d87a80001330060060033010003375c601c004602400460200026e50dd9a6106d8799f182aff00300100122533300a0011480004cdc02400466004004601a0026eacc028c02cc02cc02cc02cc02cc02cc02cc02cc02cc02cc01cdd5180098039baa00213232533300a00116132533300b00116132533300932533300a3375e600a60186ea800530126d87a9f5820fcaa61fb85676101d9e3398a484674e71c45c3fd41b492682f3b0054f4cf3273ff0013375e601e60206020602060186ea800530122d8799f581ce37db487fbd58c45d059bcbf5cd6b1604d3bec16cf888f1395a4ebc4ff0014a0601c0062a66601266ebcc038c03cc02cdd5180298059baa0014c012ad8799fd8799fd8799f581c66666666666666666666666666666666666666666666666666666666ffffff00153330093370e900218051baa3004300b37540022944585280a50300d001300d0013758600260106ea8c008c020dd500191805980618060008a502300a00114a029309b2b2b9a5573aaae7955cfaba05742ae895d201", "compiledCode": "59039801000032323232323232323232222533300553330053375e00698103d8798000132533300633232232533300a3370e900018061baa00113253333330130011533300b3370e900018069baa001132533301000100b132533333301500100c00c00c132533301230150031533300e3375e980106d8799f182aff0000413370e600e00c90020a5000d375a0020186024002601c6ea8004028028028028028c040c034dd50008a99805a495865787065637420536f6d6528646174756d29203d0a20202020646963742e67657428646174756d732c20626c616b6532625f323536286275696c74696e2e73657269616c6973655f64617461286d795f646174756d292929001632323300100100322533301000114c0103d87a800013232323253330103372200e0042a66602066e3c01c0084cdd2a40006602a00297ae014c0103d87a80001330060060033012003375c6020004602800460240026e50dd9a6106d8799f182aff00300100122533300c0011480004cdc02400466004004601e0026eacc030c034c034c034c034c034c034c034c034c034c034c024dd5180098049baa00213232533300c00115330094901316578706563746564207472616e73616374696f6e20746f206861766520286174206c65617374292032206f7574707574730016132533300d001153300a4901316578706563746564207472616e73616374696f6e20746f206861766520286174206c65617374292032206f7574707574730016132533300a32533300b3375e600a601c6ea800530126d87a9f5820fcaa61fb85676101d9e3398a484674e71c45c3fd41b492682f3b0054f4cf3273ff0013375e6022602460246024601c6ea800530122d8799f581ce37db487fbd58c45d059bcbf5cd6b1604d3bec16cf888f1395a4ebc4ff0014a060200062a66601466ebcc040c044c034dd5180298069baa0014c012ad8799fd8799fd8799f581c66666666666666666666666666666666666666666666666666666666ffffff001533300a3370e900218061baa3004300d3754002294454cc02d24115657870656374656420696e6c696e6520646174756d001614a02940c03c004c03c004dd6180098051baa3002300a37540064601a601c601c00229408c0300045280a4c2a6600c92011856616c696461746f722072657475726e65642066616c73650013656153300249011d65787065637420646174756d3a204d79446174756d203d20646174756d00165734ae7155ceaab9e5573eae815d0aba257481",
"hash": "d593ff2c1db29ce9a9a392280895f03d00705203dc4a0ea15870a0b1" "hash": "66a5272eb58aed0097083185588ef1e8b3888a3bc2e03c061f09c898"
}, },
{ {
"title": "mint.mint", "title": "mint.mint",
@ -53,8 +53,8 @@
"$ref": "#/definitions/Data" "$ref": "#/definitions/Data"
} }
}, },
"compiledCode": "590300010000323232323232322253330033232323232533233009323232533300f3012002132533300d3005300e3754002266e3c008dd7180918079baa001163008300e37540142c6eb8c040004cc004004cc010c00cdd5980298061baa3007300c37540109110022533300e00114bd70099807980618080009980100118088008a999191980599912999806980298071baa002132533300e3005300f37540022c266e1cdd6980998081baa001483c850c8cc004004c94ccc03cc018c040dd50008a5eb7bdb1804dd5980a18089baa00132323300100130093756601660246ea8010894ccc0500045300103d87a800013232323253330153372200e0042a66602a66e3c01c0084c02ccc064dd3000a5eb80530103d87a80001330060060033756602c0066eb8c050008c060008c058004dd7180998081baa00322533301200114c103d87a800013232323253330133372291103666f6f00002153330133371e910103666f6f000021300933017375000297ae014c0103d87a8000133006006003375a60280066eb8c048008c058008c05000458c01cc034dd5004980418069baa009132323232533300f3007301037540022a66601e66ebc038c044c8cdd8180a800980a980b0009bac3014301137540022600c60046eacc010c044dd5180618089baa00d14a02c64660020026eacc010c044dd5180618089baa00d22533301300114c103d87a80001323253330123375e6026004601c60286ea80404c020cc058dd39980b18098011980b180a00125eb812f5c0266008008002602e004602a002600200244a66602200229000099b8048008cc008008c0500048c044c048c048c048c048c048c048c048c048c048004dd2a40006e1d200214a06e1d200014a046600400291010022323300100100322533300d00114bd6f7b630099191919299980719b910070021533300e3371e00e0042006200a26602466ec0dd48011ba6001330060060033756601e0066eb8c034008c044008c03c0048c02cc030c030c030c0300048c028c02c0048c024004526136565734aae7555cf2ab9f5740ae855d101", "compiledCode": "590496010000323232323232323232225333004323232323253323300a3232533301000100b13253330113014002132533300e300530103754002266e3c008dd7180a18089baa001153300f49124657870656374204d696e7428706f6c6963795f696429203d206374782e707572706f736500163008301037540140186eb8c048004cc004004cc010c00cdd5980298071baa3007300e375401091010022533301000114bd70099808980718090009980100118098008a999191980619912999807180298081baa002132533300f3005301137540022a6602092010f746f6b656e206e6f7420666f756e64001613370e6eb4c054c048dd5000a41e428646600200264a666020600c60246ea800452f5bded8c026eacc058c04cdd500099191980080098049bab300b3014375400844a66602c002298103d87a800013232323253330163372200e0042a66602c66e3c01c0084c02ccc06cdd3000a5eb80530103d87a8000133006006003375660300066eb8c058008c068008c060004dd7180a98091baa00322533301400114c103d87a800013232323253330143372291103666f6f00002153330143371e910103666f6f000021300933019375000297ae014c0103d87a8000133006006003375a602c0066eb8c050008c060008c05800454cc03d24120657870656374204d696e7428706f6c6963795f696429203d20707572706f736500163007300f37540126010601e6ea80244c8c8c8c94ccc040c01cc048dd50008a99980819baf00e30133233760602e002602e60300026eb0c058c04cdd50008980318011bab300430133754601860266ea80345280a99808a496b65787065637420536f6d652850616972285f2c2072656465656d65722929203d0a202020206c6973742e66696e64286374782e7472616e73616374696f6e2e72656465656d6572732c20666e286b7629207b206b762e317374203d3d206374782e707572706f7365207d29001632330010013756600860266ea8c030c04cdd500691299980a8008a6103d87a80001323253330133375e602a004601c602c6ea80404c020cc060dd39980c180a8011980c180b00125eb812f5c02660080080026032004602e002600200244a66602600229000099b8048008cc008008c0580048c04cc050c050c050c050c050c050c050c050c050004dd2a40006e1d200214a06e1d200014a046600400291010022323300100100322533300f00114bd6f7b630099191919299980799b910070021533300f3371e00e0042006200a26602866ec0dd48011ba600133006006003375660220066eb8c03c008c04c008c0440048c034c038c038c038c0380048c030c0340048c02c00452615330054911856616c696461746f722072657475726e65642066616c736500136561533002490189657870656374205b6d795f706f6c6963795f69645d203d0a202020206374782e7472616e73616374696f6e2e6d696e740a2020202020207c3e2076616c75652e66726f6d5f6d696e7465645f76616c75650a2020202020207c3e2076616c75652e776974686f75745f6c6f76656c6163650a2020202020207c3e2076616c75652e706f6c696369657300165734ae7155ceaab9e5573eae815d0aba21",
"hash": "f557530d177449d0609a60cbe4f48b221c04a6ca7f9f235fcdc8c741" "hash": "8372367de2b0391b1bec0489dc72cb65de1a791f4e9712b9149d6392"
}, },
{ {
"title": "withdrawals.spend", "title": "withdrawals.spend",
@ -70,8 +70,8 @@
"$ref": "#/definitions/Void" "$ref": "#/definitions/Void"
} }
}, },
"compiledCode": "5902300100003232323232323223223225333006323232533300932533300a3370e900118059baa0011613370e6eb4c030c8cdd81808000980818088009bac300f300c3754002902a198009bab3002300b3754600660166ea80108cdd79805800a6126d8799fd8799f581c22222222222222222222222222222222222222222222222222222222ffff001533300932533300a3370e900118059baa0011613370e6eb4c030c8cdd81808000980818088009bac300f300c3754002900e198009bab3002300b3754600660166ea80108cdd79805800a60126d8799fd87a9f581cafddc16c18e7d8de379fb9aad39b3d1b5afd27603e5ebac818432a72ffff0013375e6e9cc8cc004004dd5980198061baa3004300c375400a44a66601c002297ae013300f300c3010001330020023011001374e6601a98126d8799fd8799f581c22222222222222222222222222222222222222222222222222222222ffff003300d4c126d8799fd87a9f581cafddc16c18e7d8de379fb9aad39b3d1b5afd27603e5ebac818432a72ffff004bd700a5014a044646600200200644a66601e002298103d87a800013232533300e300500213374a9000198091ba733012300f0023301230100024bd7025eb804cc010010004c04c008c0440048c034c038c038c038c038c038c0380048c0300045261365653330043370e900018029baa00115333007300637540022930b0b299980119b8748000c00cdd50008a99980298021baa001149858595cd2ab9d5573caae7d5d02ba157441", "compiledCode": "5902de01000032323232323232323232322533333300c001153330043370e900018031baa001153330083007375400224a66666601a0022a66600a66e1d2000300737540022a66601260106ea8004494ccc018c8c8c94ccc024c94ccc028cdc3a400460186ea800454cc02d2411c616c6963652773207769746864726177616c206e6f7420666f756e64001613370e6eb4c034c8cdd81808800980898090009bac3010300d3754002902a198009bab3002300c3754600660186ea80108cdd79806000a6126d8799fd8799f581c22222222222222222222222222222222222222222222222222222222ffff001533300932533300a3370e900118061baa001153300b49011a626f622773207769746864726177616c206e6f7420666f756e64001613370e6eb4c034c8cdd81808800980898090009bac3010300d3754002900e198009bab3002300c3754600660186ea80108cdd79806000a6126d8799fd87a9f581cafddc16c18e7d8de379fb9aad39b3d1b5afd27603e5ebac818432a72ffff0013375e6e9cc8cc004004dd5980198069baa3004300d375400a44a66601e002297ae0133010300d3011001330020023012001374e6601c98126d8799fd87a9f581cafddc16c18e7d8de379fb9aad39b3d1b5afd27603e5ebac818432a72ffff003300e4c126d8799fd8799f581c22222222222222222222222222222222222222222222222222222222ffff004bd700a5014a044646600200200644a666020002298103d87a800013232533300e300500213374a9000198099ba73301330100023301330110024bd7025eb804cc010010004c050008c0480048c038c03cc03cc03cc03cc03cc03c0048c03400452615330074911856616c696461746f722072657475726e65642066616c73650013656003003003003003003003003003003003003153300349010f5f72656465656d65723a20566f6964001615330024910c5f646174756d3a20566f696400165734ae7155ceaab9e5573eae815d0aba257481",
"hash": "06f1f9df4be68a65cd55a921e3e7ec1eb4104906c53e0e564c726faa" "hash": "4f44caf93e36ee884b6d03b1e1c93bf8cda516fd39f7113823508571"
} }
], ],
"definitions": { "definitions": {

View File

@ -26,7 +26,7 @@ then
exit 1 exit 1
fi fi
$AIKEN build 2>/dev/null $AIKEN build --filter-traces all -t verbose
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
exit $? exit $?
fi fi
@ -41,4 +41,7 @@ cp ctx/$TITLE/inputs.cbor.template ctx/$TITLE/inputs.cbor
sed "s/{{ VALIDATOR_HASH }}/$VALIDATOR_HASH/" ctx/$TITLE/outputs.cbor.template > ctx/$TITLE/outputs.cbor sed "s/{{ VALIDATOR_HASH }}/$VALIDATOR_HASH/" ctx/$TITLE/outputs.cbor.template > ctx/$TITLE/outputs.cbor
sed "s/{{ VALIDATOR }}/$VALIDATOR/" ctx/$TITLE/tx.cbor.template | sed "s/{{ VALIDATOR_HASH }}/$VALIDATOR_HASH/" > ctx/$TITLE/tx.cbor sed "s/{{ VALIDATOR }}/$VALIDATOR/" ctx/$TITLE/tx.cbor.template | sed "s/{{ VALIDATOR_HASH }}/$VALIDATOR_HASH/" > ctx/$TITLE/tx.cbor
$AIKEN tx simulate 1>$TITLE.log 2>&1 ctx/$TITLE/tx.cbor ctx/$TITLE/inputs.cbor ctx/$TITLE/outputs.cbor $AIKEN tx simulate 1>$TITLE.log 2>&1 \
ctx/$TITLE/tx.cbor \
ctx/$TITLE/inputs.cbor \
ctx/$TITLE/outputs.cbor

View File

@ -31,7 +31,7 @@ validator {
None -> fail @"bob's withdrawal not found" None -> fail @"bob's withdrawal not found"
Some(value) -> value.2nd == 14 Some(value) -> value.2nd == 14
}, },
list.map(ctx.transaction.withdrawals, fn(kv) { kv.1st }) == [alice, bob], list.map(ctx.transaction.withdrawals, fn(kv) { kv.1st }) == [bob, alice],
} }
} }
} }

View File

@ -44,7 +44,7 @@ for convenience. The test still assumes a few things. For any
- Purpose - Purpose
- [x] spend - [x] spend
- [x] mint - [x] mint
- [ ] withdraw - [x] withdraw
- [x] publish - [x] publish
- [x] voting - [x] voting
- [x] proposing - [x] proposing
@ -79,11 +79,11 @@ for convenience. The test still assumes a few things. For any
- [x] Retire CC - [x] Retire CC
- withdrawals - withdrawals
- [x] none - [x] none
- [ ] some - [x] some
- [ ] validity range - [x] validity range
- extra signatories - extra signatories
- [x] none - [x] none
- [ ] some - [x] some
- [x] redeemers - [x] redeemers
- [x] datums - [x] datums
- votes - votes
@ -102,10 +102,10 @@ for convenience. The test still assumes a few things. For any
- Address - Address
- [x] type-0 (key | key) - [x] type-0 (key | key)
- [x] type-1 (script | key) - [x] type-1 (script | key)
- [ ] type-2 (key | script) - [x] type-2 (key | script)
- [ ] type-3 (script | script) - [x] type-3 (script | script)
- [ ] type-4 (key | ptr) - [x] type-4 (key | ptr)
- [ ] type-5 (script | ptr) - [x] type-5 (script | ptr)
- [x] type-6 (key | ø) - [x] type-6 (key | ø)
- [x] type-7 (key | ø) - [x] type-7 (key | ø)
@ -205,5 +205,5 @@ for convenience. The test still assumes a few things. For any
- [x] no confidence - [x] no confidence
- Boundary - Boundary
- [ ] closed - [x] closed
- [ ] open - [x] open

View File

@ -2,15 +2,15 @@
# You typically do not need to edit this file # You typically do not need to edit this file
[[requirements]] [[requirements]]
name = "logicalmechanism/stdlib" name = "aiken-lang/stdlib"
version = "plutus-v3" version = "v2"
source = "github" source = "github"
[[packages]] [[packages]]
name = "logicalmechanism/stdlib" name = "aiken-lang/stdlib"
version = "plutus-v3" version = "v2"
requirements = [] requirements = []
source = "github" source = "github"
[etags] [etags]
"logicalmechanism/stdlib@plutus-v3" = [{ secs_since_epoch = 1723394635, nanos_since_epoch = 36770000 }, "097396ab7dedd5e38c558f35b2fb34a2d0f058bb0da0635949f5fcbb36f1310e"] "aiken-lang/stdlib@v2" = [{ secs_since_epoch = 1723583491, nanos_since_epoch = 208977000 }, "cdbbce58b61deb385e7ea787a2e0fc2dc8fe94db9999e0e6275bc9c70e5796be"]

View File

@ -3,9 +3,9 @@ version = "0.0.0"
compiler = "v1.0.31-alpha" compiler = "v1.0.31-alpha"
plutus = "v3" plutus = "v3"
license = "Apache-2.0" license = "Apache-2.0"
description = "Aiken contracts for project 'script_context/v3'" description = "End-to-end testing of standard lib script context, for Plutus v3"
[[dependencies]] [[dependencies]]
name = "logicalmechanism/stdlib" name = "aiken-lang/stdlib"
version = "plutus-v3" version = "v2"
source = "github" source = "github"

View File

@ -0,0 +1,7 @@
[
{ 0: h'30{{ withdraw.spend.hash }}{{ withdraw.spend.hash }}'
, 1: 1000000
, 2: [1, 24(h'd87980')]
, 3: 24(h'8203{{ withdraw.spend.cbor }}')
}
]

View File

@ -0,0 +1,42 @@
[
{ 0:
[ [h'0000000000000000000000000000000000000000000000000000000000000000', 0]
]
, 1:
[ { 0: h'200000000000000000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111'
, 1: 1000000
}
, { 0: h'40000000000000000000000000000000000000000000000000000000008198bd431b03'
, 1: 1000000
}
, { 0: h'50111111111111111111111111111111111111111111111111111111118198bd431b03'
, 1: 1000000
}
]
, 2: 42
, 3: 4492801
, 5:
{ h'E000000000000000000000000000000000000000000000000000000000': 14
, h'F0{{ withdraw.withdraw.hash }}': 0
}
, 14:
[ h'00000000000000000000000000000000000000000000000000000000'
]
},
{ 5: [ [0, 0, 122([121([])]), [1000000, 100000000]]
, [3, 0, 121([]), [1000000, 100000000]]
]
},
true,
null
]

File diff suppressed because one or more lines are too long

View File

@ -45,9 +45,10 @@ for ITEM in ${VALIDATORS[@]}; do
VALIDATOR_NAME=$(echo $ITEM | jq -r .title) VALIDATOR_NAME=$(echo $ITEM | jq -r .title)
VALIDATOR_HASH=$(echo $ITEM | jq -r .hash) VALIDATOR_HASH=$(echo $ITEM | jq -r .hash)
VALIDATOR=$(echo $ITEM | jq -r .compiledCode) VALIDATOR=$(echo $ITEM | jq -r .compiledCode)
VALIDATOR_CBOR=$(echo "h'$VALIDATOR'" | cbor-diag --to hex --from diag)
RESOLVED_INPUTS=$(echo $RESOLVED_INPUTS \ RESOLVED_INPUTS=$(echo $RESOLVED_INPUTS \
| sed "s/{{ $VALIDATOR_NAME.cbor }}/$VALIDATOR/g" \ | sed "s/{{ $VALIDATOR_NAME.cbor }}/$VALIDATOR_CBOR/g" \
| sed "s/{{ $VALIDATOR_NAME.hash }}/$VALIDATOR_HASH/g") | sed "s/{{ $VALIDATOR_NAME.hash }}/$VALIDATOR_HASH/g")
TRANSACTION=$(echo $TRANSACTION \ TRANSACTION=$(echo $TRANSACTION \
@ -59,9 +60,7 @@ echo $RESOLVED_INPUTS | cbor-diag --to hex --from diag > ctx/$TITLE/resolved_inp
echo $TRANSACTION | cbor-diag --to hex --from diag > ctx/$TITLE/tx.cbor echo $TRANSACTION | cbor-diag --to hex --from diag > ctx/$TITLE/tx.cbor
# ogmios inspect transaction $(cat ctx/$TITLE/tx.cbor) | jq ".votes" $AIKEN tx simulate 1>$TITLE.log 2>&1 \
$AIKEN tx simulate \
ctx/$TITLE/tx.cbor \ ctx/$TITLE/tx.cbor \
ctx/inputs.cbor \ ctx/inputs.cbor \
ctx/$TITLE/resolved_inputs.cbor ctx/$TITLE/resolved_inputs.cbor

View File

@ -16,7 +16,7 @@ const void_hash =
#"923918e403bf43c34b4ef6b48eb2ee04babed17320d8d1b9ff9ad086e86f44ec" #"923918e403bf43c34b4ef6b48eb2ee04babed17320d8d1b9ff9ad086e86f44ec"
validator { validator {
fn mint_1(_tmp2: Void, ctx: ScriptContext) { fn mint_1(_tmp2: Data, ctx: ScriptContext) {
let our_policy_id = assert_script_info(ctx.info) let our_policy_id = assert_script_info(ctx.info)
let other_policy_id = assert_redeemers(ctx.transaction.redeemers) let other_policy_id = assert_redeemers(ctx.transaction.redeemers)
assert_outputs(ctx.transaction.outputs, our_policy_id, other_policy_id) assert_outputs(ctx.transaction.outputs, our_policy_id, other_policy_id)

View File

@ -22,7 +22,7 @@ const only9s =
#"9999999999999999999999999999999999999999999999999999999999999999" #"9999999999999999999999999999999999999999999999999999999999999999"
validator { validator {
fn script(_tmp0: Void, ctx: ScriptContext) { fn script(_tmp0: Data, ctx: ScriptContext) {
assert_redeemer(ctx.redeemer) assert_redeemer(ctx.redeemer)
let votes = ctx.transaction.votes let votes = ctx.transaction.votes
@ -35,18 +35,14 @@ validator {
expect expect
Some( Some(
Pair( Pair(ConstitutionalCommitteeMember(VerificationKey(only0s)),
ConstitutionalCommitteeMember(VerificationKey(only0s)), [
[ Pair(GovernanceActionId {
Pair( transaction: only9s,
GovernanceActionId { proposal_procedure: 152,
transaction: only9s, },
proposal_procedure: 152, No),
}, ]),
No,
),
],
),
) == list.at(votes, 1) ) == list.at(votes, 1)
expect Some(Pair(DelegateRepresentative(Script(..)), [_, ..])) = expect Some(Pair(DelegateRepresentative(Script(..)), [_, ..])) =
@ -54,23 +50,15 @@ validator {
expect expect
Some( Some(
Pair( Pair(DelegateRepresentative(VerificationKey(only0s)),
DelegateRepresentative(VerificationKey(only0s)), [
[ Pair(GovernanceActionId { transaction: only7s, proposal_procedure: 2 },
Pair( Abstain),
GovernanceActionId { transaction: only7s, proposal_procedure: 2 }, Pair(GovernanceActionId { transaction: only8s, proposal_procedure: 1 },
Abstain, Abstain),
), Pair(GovernanceActionId { transaction: only9s, proposal_procedure: 0 },
Pair( Abstain),
GovernanceActionId { transaction: only8s, proposal_procedure: 1 }, ]),
Abstain,
),
Pair(
GovernanceActionId { transaction: only9s, proposal_procedure: 0 },
Abstain,
),
],
),
) == list.at(votes, 3) ) == list.at(votes, 3)
expect Some(Pair(StakePool(pool_id), [_, ..])) = list.at(votes, 4) expect Some(Pair(StakePool(pool_id), [_, ..])) = list.at(votes, 4)
@ -83,8 +71,10 @@ validator {
fn assert_redeemer(data: Data) { fn assert_redeemer(data: Data) {
let is_valid = let is_valid =
if data is Foo(42): Foo { if data is Foo(42): Foo {
trace data
True True
} else if data is Void { } else if data is Void {
trace data
True True
} else { } else {
False False

View File

@ -0,0 +1,52 @@
use aiken/collection/list
use aiken/interval
use cardano/credential.{Address, Inline, Pointer, Script, VerificationKey}
use cardano/transaction.{ScriptContext, Withdrawing}
const only0s = #"00000000000000000000000000000000000000000000000000000000"
const only1s = #"11111111111111111111111111111111111111111111111111111111"
validator {
fn spend(_tmp0: Void, _tmp1: Void, _ctx: Data) {
True
}
fn withdraw(_tmp0: Void, ctx: ScriptContext) {
expect Withdrawing(Script(my_script_hash)) = ctx.info
expect
interval.entirely_before(1596059092000) == ctx.transaction.validity_range
let addresses = list.map(ctx.transaction.outputs, fn(out) { out.address })
expect
Some(
Address {
payment_credential: VerificationKey(only0s),
stake_credential: Some(Inline(Script(only1s))),
},
) == list.at(addresses, 0)
expect
Some(
Address {
payment_credential: VerificationKey(only0s),
stake_credential: Some(Pointer(2498243, 27, 3)),
},
) == list.at(addresses, 1)
expect
Some(
Address {
payment_credential: Script(only1s),
stake_credential: Some(Pointer(2498243, 27, 3)),
},
) == list.at(addresses, 2)
expect
[Pair(Script(my_script_hash), 0), Pair(VerificationKey(only0s), 14)] == ctx.transaction.withdrawals
True
}
}