Merge branch 'tx-simulate-plutus-v3'

This commit is contained in:
KtorZ 2024-08-14 03:17:14 +02:00
commit 32e6705423
No known key found for this signature in database
GPG Key ID: 33173CB6F77F4277
2990 changed files with 26237 additions and 2341 deletions

1
.gitattributes vendored
View File

@ -1,3 +1,4 @@
Cargo.lock linguist-generated=true merge=binary linguist-vendored
Cargo.nix linguist-generated=true merge=binary linguist-vendored
flake.lock linguist-generated=true merge=binary linguist-vendored
**/*.snap merge=binary linguist-vendored

608
Cargo.lock generated vendored

File diff suppressed because it is too large Load Diff

View File

@ -49,11 +49,11 @@ x86_64-unknown-linux-gnu = "ubuntu-22.04"
walkdir = "2.3.2"
insta = { version = "1.30.0", features = ["yaml", "json", "redactions"] }
miette = { version = "7.2.0", features = ["fancy"] }
pallas-addresses = "0.22.0"
pallas-codec = { version = "0.22.0", features = ["num-bigint"] }
pallas-crypto = "0.22.0"
pallas-primitives = "0.22.0"
pallas-traverse = "0.22.0"
pallas-addresses = { git = "https://github.com/KtorZ/pallas.git", rev = "454b3bcf32cdc238aba65e4c3e4656a352480ec1" }
pallas-codec = { git = "https://github.com/KtorZ/pallas.git", rev = "454b3bcf32cdc238aba65e4c3e4656a352480ec1", features = ["num-bigint"] }
pallas-crypto = { git = "https://github.com/KtorZ/pallas.git", rev = "454b3bcf32cdc238aba65e4c3e4656a352480ec1" }
pallas-primitives = { git = "https://github.com/KtorZ/pallas.git", rev = "454b3bcf32cdc238aba65e4c3e4656a352480ec1" }
pallas-traverse = { git = "https://github.com/KtorZ/pallas.git", rev = "454b3bcf32cdc238aba65e4c3e4656a352480ec1" }
[profile.dev.package.insta]
opt-level = 3

View File

@ -998,14 +998,12 @@ impl<'comments> Formatter<'comments> {
wrap_args(elems.iter().map(|e| (self.wrap_expr(e), false))).group()
}
UntypedExpr::Pair { fst, snd, .. } => "Pair"
.to_doc()
.append("(")
.append(self.expr(fst, false))
.append(break_(",", ", "))
.append(self.expr(snd, false))
.append(")")
.group(),
UntypedExpr::Pair { fst, snd, .. } => {
let elems = [fst, snd];
"Pair"
.to_doc()
.append(wrap_args(elems.iter().map(|e| (self.wrap_expr(e), false))).group())
}
UntypedExpr::TupleIndex { index, tuple, .. } => {
let suffix = Ordinal(*index + 1).suffix().to_doc();

View File

@ -6,10 +6,10 @@ use crate::{
};
pub fn parser(
expression: Recursive<'_, Token, UntypedPattern, ParseError>,
pattern: Recursive<'_, Token, UntypedPattern, ParseError>,
) -> impl Parser<Token, UntypedPattern, Error = ParseError> + '_ {
select! {Token::UpName { name } => name}
.then(args(expression))
.then(args(pattern))
.map_with_span(
|(name, (arguments, spread_location, is_record)), location| {
UntypedPattern::Constructor {
@ -27,13 +27,13 @@ pub fn parser(
}
pub(crate) fn args(
expression: Recursive<'_, Token, UntypedPattern, ParseError>,
pattern: Recursive<'_, Token, UntypedPattern, ParseError>,
) -> impl Parser<Token, (Vec<CallArg<UntypedPattern>>, Option<Span>, bool), Error = ParseError> + '_
{
let record_constructor_pattern_arg_parser = choice((
select! {Token::Name {name} => name}
.then_ignore(just(Token::Colon))
.then(expression.clone())
.then(pattern.clone())
.map_with_span(|(name, pattern), span| CallArg {
location: span,
label: Some(name),
@ -59,7 +59,7 @@ pub(crate) fn args(
)
.delimited_by(just(Token::LeftBrace), just(Token::RightBrace));
let tuple_constructor_pattern_arg_parser = expression
let tuple_constructor_pattern_arg_parser = pattern
.clone()
.map(|pattern| CallArg {
location: pattern.location(),

View File

@ -1116,3 +1116,27 @@ fn format_long_imports() {
"#
);
}
#[test]
fn format_long_pair() {
assert_format!(
r#"
test foo() {
expect(Some([
Pair(GovernanceActionId { transaction: only7s, proposal_procedure: 2 },
Abstain),
])) == whatever
expect(Some([
Foo(GovernanceActionId { transaction: only7s, proposal_procedure: 2 },
Abstain),
])) == whatever
expect(Some([
(GovernanceActionId { transaction: only7s, proposal_procedure: 2 },
Abstain),
])) == whatever
}
"#
);
}

View File

@ -0,0 +1,35 @@
---
source: crates/aiken-lang/src/tests/format.rs
description: "Code:\n\ntest foo() {\n expect(Some([\n Pair(GovernanceActionId { transaction: only7s, proposal_procedure: 2 },\n Abstain),\n ])) == whatever\n\n expect(Some([\n Foo(GovernanceActionId { transaction: only7s, proposal_procedure: 2 },\n Abstain),\n ])) == whatever\n\n expect(Some([\n (GovernanceActionId { transaction: only7s, proposal_procedure: 2 },\n Abstain),\n ])) == whatever\n}\n"
---
test foo() {
expect
Some(
[
Pair(
GovernanceActionId { transaction: only7s, proposal_procedure: 2 },
Abstain,
),
],
) == whatever
expect
Some(
[
Foo(
GovernanceActionId { transaction: only7s, proposal_procedure: 2 },
Abstain,
),
],
) == whatever
expect
Some(
[
(
GovernanceActionId { transaction: only7s, proposal_procedure: 2 },
Abstain,
),
],
) == whatever
}

View File

@ -5,14 +5,13 @@ pub mod parameter;
pub mod schema;
pub mod validator;
pub use error::Error;
use crate::{
config::{self, Config, PlutusVersion},
module::CheckedModules,
};
use aiken_lang::gen_uplc::CodeGenerator;
use definitions::Definitions;
pub use error::Error;
use schema::{Annotated, Schema};
use std::fmt::Debug;
use validator::Validator;
@ -70,7 +69,7 @@ impl Blueprint {
let validators: Result<Vec<_>, Error> = modules
.validators()
.flat_map(|(validator, def)| {
Validator::from_checked_module(modules, generator, validator, def)
Validator::from_checked_module(modules, generator, validator, def, &config.plutus)
.into_iter()
.map(|result| {
result.map(|mut schema| {

View File

@ -9,13 +9,14 @@ use crate::module::{CheckedModule, CheckedModules};
use aiken_lang::{
ast::{Annotation, TypedArg, TypedFunction, TypedValidator},
gen_uplc::CodeGenerator,
plutus_version::PlutusVersion,
tipo::Type,
};
use miette::NamedSource;
use serde;
use std::borrow::Borrow;
use uplc::{
ast::{Constant, DeBruijn, Program},
ast::{Constant, SerializableProgram},
PlutusData,
};
@ -36,7 +37,7 @@ pub struct Validator {
pub parameters: Vec<Parameter>,
#[serde(flatten)]
pub program: Program<DeBruijn>,
pub program: SerializableProgram,
#[serde(skip_serializing_if = "Definitions::is_empty")]
#[serde(default)]
@ -49,6 +50,7 @@ impl Validator {
generator: &mut CodeGenerator,
module: &CheckedModule,
def: &TypedValidator,
plutus_version: &PlutusVersion,
) -> Vec<Result<Validator, Error>> {
let is_multi_validator = def.other_fun.is_some();
@ -62,6 +64,7 @@ impl Validator {
&def.fun,
is_multi_validator,
&mut program,
plutus_version,
)];
if let Some(ref other_func) = def.other_fun {
@ -73,12 +76,14 @@ impl Validator {
other_func,
is_multi_validator,
&mut program,
plutus_version,
));
}
validators
}
#[allow(clippy::too_many_arguments)]
fn create_validator_blueprint(
generator: &mut CodeGenerator,
modules: &CheckedModules,
@ -87,6 +92,7 @@ impl Validator {
func: &TypedFunction,
is_multi_validator: bool,
program: &mut MemoProgram,
plutus_version: &PlutusVersion,
) -> Result<Validator, Error> {
let mut args = func.arguments.iter().rev();
let (_, redeemer, datum) = (args.next(), args.next().unwrap(), args.next());
@ -168,7 +174,11 @@ impl Validator {
parameters,
datum,
redeemer,
program: program.get(generator, def, &module.name),
program: match plutus_version {
PlutusVersion::V1 => SerializableProgram::PlutusV1Program,
PlutusVersion::V2 => SerializableProgram::PlutusV2Program,
PlutusVersion::V3 => SerializableProgram::PlutusV3Program,
}(program.get(generator, def, &module.name)),
definitions,
})
}
@ -208,7 +218,7 @@ impl Validator {
Some((head, tail)) => {
head.validate(definitions, &Constant::Data(arg.clone()))?;
Ok(Self {
program: self.program.apply_data(arg.clone()),
program: self.program.map(|program| program.apply_data(arg.clone())),
parameters: tail.to_vec(),
..self
})
@ -284,7 +294,7 @@ mod tests {
.next()
.expect("source code did no yield any validator");
let validators = Validator::from_checked_module(&modules, &mut generator, validator, def);
let validators = Validator::from_checked_module(&modules, &mut generator, validator, def, &PlutusVersion::default());
if validators.len() > 1 {
panic!("Multi-validator given to test bench. Don't do that.")

View File

@ -1,7 +1,3 @@
use aiken_lang::{ast::TypedFunction, gen_uplc::CodeGenerator};
use miette::NamedSource;
use uplc::ast::{DeBruijn, Program};
use crate::{
blueprint::{
self,
@ -11,6 +7,9 @@ use crate::{
},
module::{CheckedModule, CheckedModules},
};
use aiken_lang::{ast::TypedFunction, gen_uplc::CodeGenerator, plutus_version::PlutusVersion};
use miette::NamedSource;
use uplc::ast::SerializableProgram;
#[derive(Debug, PartialEq, Clone, serde::Serialize, serde::Deserialize)]
pub struct Export {
@ -24,7 +23,7 @@ pub struct Export {
pub parameters: Vec<Parameter>,
#[serde(flatten)]
pub program: Program<DeBruijn>,
pub program: SerializableProgram,
#[serde(skip_serializing_if = "Definitions::is_empty")]
#[serde(default)]
@ -37,6 +36,7 @@ impl Export {
module: &CheckedModule,
generator: &mut CodeGenerator,
modules: &CheckedModules,
plutus_version: &PlutusVersion,
) -> Result<Export, blueprint::Error> {
let mut definitions = Definitions::new();
@ -64,10 +64,16 @@ impl Export {
})
.collect::<Result<_, _>>()?;
let program = generator
.generate_raw(&func.body, &func.arguments, &module.name)
.to_debruijn()
.unwrap();
let program = match plutus_version {
PlutusVersion::V1 => SerializableProgram::PlutusV1Program,
PlutusVersion::V2 => SerializableProgram::PlutusV2Program,
PlutusVersion::V3 => SerializableProgram::PlutusV3Program,
}(
generator
.generate_raw(&func.body, &func.arguments, &module.name)
.to_debruijn()
.unwrap(),
);
Ok(Export {
name: format!("{}.{}", &module.name, &func.name),
@ -86,6 +92,7 @@ mod tests {
use aiken_lang::{
self,
ast::{TraceLevel, Tracing},
plutus_version::PlutusVersion,
};
macro_rules! assert_export {
@ -103,7 +110,7 @@ mod tests {
.next()
.expect("source code did no yield any exports");
let export = Export::from_function(func, module, &mut generator, &modules);
let export = Export::from_function(func, module, &mut generator, &modules, &PlutusVersion::default());
match export {
Err(e) => insta::with_settings!({

View File

@ -40,7 +40,6 @@ use aiken_lang::{
format::{Formatter, MAX_COLUMNS},
gen_uplc::CodeGenerator,
line_numbers::LineNumbers,
plutus_version::PlutusVersion,
tipo::{Type, TypeInfo},
IdGenerator,
};
@ -50,8 +49,7 @@ use miette::NamedSource;
use options::{CodeGenMode, Options};
use package_name::PackageName;
use pallas_addresses::{Address, Network, ShelleyAddress, ShelleyDelegationPart, StakePayload};
use pallas_primitives::conway::{self as cardano, PolicyId};
use pallas_traverse::ComputeHash;
use pallas_primitives::conway::PolicyId;
use std::{
collections::{BTreeSet, HashMap},
fs::{self, File},
@ -298,7 +296,7 @@ where
let path = dir.clone().join(format!("{}.uplc", validator.title));
let program = &validator.program;
let program: Program<Name> = program.try_into().unwrap();
let program: Program<Name> = program.inner().try_into().unwrap();
fs::write(&path, program.to_pretty()).map_err(|error| Error::FileIo { error, path })?;
}
@ -490,7 +488,7 @@ where
Network::Testnet
};
Ok(validator.program.address(
Ok(validator.program.inner().address(
network,
delegation_part.to_owned(),
&self.config.plutus.into(),
@ -520,15 +518,7 @@ where
if n > 0 {
Err(blueprint::error::Error::ParameterizedValidator { n }.into())
} else {
let cbor = validator.program.to_cbor().unwrap();
let validator_hash = match self.config.plutus {
PlutusVersion::V1 => cardano::PlutusV1Script(cbor.into()).compute_hash(),
PlutusVersion::V2 => cardano::PlutusV2Script(cbor.into()).compute_hash(),
PlutusVersion::V3 => cardano::PlutusV3Script(cbor.into()).compute_hash(),
};
Ok(validator_hash)
Ok(validator.program.compiled_code_and_hash().1)
}
})
}
@ -552,7 +542,13 @@ where
.map(|(checked_module, func)| {
let mut generator = self.new_generator(tracing);
Export::from_function(func, checked_module, &mut generator, &self.checked_modules)
Export::from_function(
func,
checked_module,
&mut generator,
&self.checked_modules,
&self.config.plutus,
)
})
.transpose()?
.ok_or_else(|| Error::ExportNotFound {

View File

@ -83,7 +83,7 @@ pub fn exec(
let result =
blueprint.with_validator(title, when_too_many, when_missing, |validator| match to {
Format::CardanoCli => {
let cbor_bytes = validator.program.to_cbor().unwrap();
let cbor_bytes = validator.program.inner().to_cbor().unwrap();
let mut double_cbor_bytes = Vec::new();

View File

@ -1,7 +1,7 @@
use miette::IntoDiagnostic;
use owo_colors::{OwoColorize, Stream::Stderr};
use pallas_primitives::{
babbage::{Redeemer, TransactionInput, TransactionOutput},
conway::{Redeemer, TransactionInput, TransactionOutput},
Fragment,
};
use pallas_traverse::{Era, MultiEraTx};
@ -9,7 +9,7 @@ use std::{fmt, fs, path::PathBuf, process};
use uplc::{
machine::cost_model::ExBudget,
tx::{
self,
self, redeemer_tag_to_string,
script_context::{ResolvedInput, SlotConfig},
},
};
@ -79,7 +79,7 @@ pub fn exec(
)
};
let tx = MultiEraTx::decode_for_era(Era::Babbage, &tx_bytes).into_diagnostic()?;
let tx = MultiEraTx::decode_for_era(Era::Conway, &tx_bytes).into_diagnostic()?;
eprintln!(
"{} {}",
@ -101,7 +101,7 @@ pub fn exec(
})
.collect();
if let Some(tx_babbage) = tx.as_babbage() {
if let Some(tx_conway) = tx.as_conway() {
let slot_config = SlotConfig {
zero_time,
zero_slot,
@ -110,17 +110,17 @@ pub fn exec(
let with_redeemer = |redeemer: &Redeemer| {
eprintln!(
"{} {:?} → {}",
" Redeemer"
"{} {}[{}]",
" Evaluating"
.if_supports_color(Stderr, |s| s.purple())
.if_supports_color(Stderr, |s| s.bold()),
redeemer.tag,
redeemer_tag_to_string(&redeemer.tag),
redeemer.index
)
};
let result = tx::eval_phase_two(
tx_babbage,
tx_conway,
&resolved_inputs,
None,
None,
@ -149,7 +149,14 @@ pub fn exec(
);
}
Err(err) => {
eprintln!("{}", display_tx_error(&err));
eprintln!(
"{} {}",
" Error"
.if_supports_color(Stderr, |s| s.red())
.if_supports_color(Stderr, |s| s.bold()),
err.red()
);
process::exit(1);
}
}
@ -157,46 +164,3 @@ pub fn exec(
Ok(())
}
fn display_tx_error(err: &tx::error::Error) -> String {
let mut msg = format!(
"{} {}",
" Error"
.if_supports_color(Stderr, |s| s.red())
.if_supports_color(Stderr, |s| s.bold()),
err.red()
);
match err {
tx::error::Error::RedeemerError { err, .. } => {
msg.push_str(&format!(
"\n{}",
display_tx_error(err)
.lines()
.skip(1)
.collect::<Vec<_>>()
.join("\n"),
));
msg
}
tx::error::Error::Machine(_, _, traces) => {
msg.push_str(
traces
.iter()
.map(|s| {
format!(
"\n{} {}",
" Trace"
.if_supports_color(Stderr, |s| s.yellow())
.if_supports_color(Stderr, |s| s.bold()),
s.if_supports_color(Stderr, |s| s.yellow())
)
})
.collect::<Vec<_>>()
.join("")
.as_str(),
);
msg
}
_ => msg,
}
}

View File

@ -42,5 +42,6 @@ k256 = { version = "0.13.0" }
[dev-dependencies]
hex = "0.4.3"
indoc = "2.0.1"
insta.workspace = true
pretty_assertions = "1.3.0"
walkdir.workspace = true

View File

@ -111,38 +111,99 @@ where
}
}
impl Serialize for Program<DeBruijn> {
#[derive(Debug, Clone, PartialEq)]
pub enum SerializableProgram {
PlutusV1Program(Program<DeBruijn>),
PlutusV2Program(Program<DeBruijn>),
PlutusV3Program(Program<DeBruijn>),
}
impl SerializableProgram {
pub fn inner(&self) -> &Program<DeBruijn> {
use SerializableProgram::*;
match self {
PlutusV1Program(program) => program,
PlutusV2Program(program) => program,
PlutusV3Program(program) => program,
}
}
pub fn map<F>(self, f: F) -> Self
where
F: FnOnce(Program<DeBruijn>) -> Program<DeBruijn>,
{
use SerializableProgram::*;
match self {
PlutusV1Program(program) => PlutusV1Program(f(program)),
PlutusV2Program(program) => PlutusV2Program(f(program)),
PlutusV3Program(program) => PlutusV3Program(f(program)),
}
}
pub fn compiled_code_and_hash(&self) -> (String, pallas_crypto::hash::Hash<28>) {
use SerializableProgram::*;
match self {
PlutusV1Program(pgrm) => {
let cbor = pgrm.to_cbor().unwrap();
let compiled_code = hex::encode(&cbor);
let hash = conway::PlutusV1Script(cbor.into()).compute_hash();
(compiled_code, hash)
}
PlutusV2Program(pgrm) => {
let cbor = pgrm.to_cbor().unwrap();
let compiled_code = hex::encode(&cbor);
let hash = conway::PlutusV2Script(cbor.into()).compute_hash();
(compiled_code, hash)
}
PlutusV3Program(pgrm) => {
let cbor = pgrm.to_cbor().unwrap();
let compiled_code = hex::encode(&cbor);
let hash = conway::PlutusV3Script(cbor.into()).compute_hash();
(compiled_code, hash)
}
}
}
}
impl Serialize for SerializableProgram {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let cbor = self.to_cbor().unwrap();
let (compiled_code, hash) = self.compiled_code_and_hash();
let mut s = serializer.serialize_struct("Program<DeBruijn>", 2)?;
s.serialize_field("compiledCode", &hex::encode(&cbor))?;
s.serialize_field("hash", &conway::PlutusV2Script(cbor.into()).compute_hash())?;
s.serialize_field("compiledCode", &compiled_code)?;
s.serialize_field("hash", &hash)?;
s.end()
}
}
impl<'a> Deserialize<'a> for Program<DeBruijn> {
impl<'a> Deserialize<'a> for SerializableProgram {
fn deserialize<D: Deserializer<'a>>(deserializer: D) -> Result<Self, D::Error> {
#[derive(serde::Deserialize)]
#[serde(field_identifier, rename_all = "camelCase")]
enum Fields {
CompiledCode,
Hash,
}
struct ProgramVisitor;
impl<'a> Visitor<'a> for ProgramVisitor {
type Value = Program<DeBruijn>;
type Value = SerializableProgram;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("Program<Visitor>")
formatter.write_str("validator")
}
fn visit_map<V>(self, mut map: V) -> Result<Program<DeBruijn>, V::Error>
fn visit_map<V>(self, mut map: V) -> Result<SerializableProgram, V::Error>
where
V: MapAccess<'a>,
{
let mut compiled_code: Option<String> = None;
let mut hash: Option<String> = None;
while let Some(key) = map.next_key()? {
match key {
Fields::CompiledCode => {
@ -151,11 +212,20 @@ impl<'a> Deserialize<'a> for Program<DeBruijn> {
}
compiled_code = Some(map.next_value()?);
}
Fields::Hash => {
if hash.is_some() {
return Err(de::Error::duplicate_field("hash"));
}
hash = Some(map.next_value()?);
}
}
}
let compiled_code =
compiled_code.ok_or_else(|| de::Error::missing_field("compiledCode"))?;
let hash = hash.ok_or_else(|| de::Error::missing_field("hash"))?;
let mut cbor_buffer = Vec::new();
let mut flat_buffer = Vec::new();
@ -166,10 +236,29 @@ impl<'a> Deserialize<'a> for Program<DeBruijn> {
&"a base16-encoded CBOR-serialized UPLC program",
)
})
.and_then(|program| {
let cbor = || program.to_cbor().unwrap().into();
if conway::PlutusV3Script(cbor()).compute_hash().to_string() == hash {
return Ok(SerializableProgram::PlutusV3Program(program));
}
if conway::PlutusV2Script(cbor()).compute_hash().to_string() == hash {
return Ok(SerializableProgram::PlutusV2Program(program));
}
if conway::PlutusV1Script(cbor()).compute_hash().to_string() == hash {
return Ok(SerializableProgram::PlutusV1Program(program));
}
Err(de::Error::custom(
"hash doesn't match any recognisable Plutus version.",
))
})
}
}
const FIELDS: &[&str] = &["compiledCode"];
const FIELDS: &[&str] = &["compiledCode", "hash"];
deserializer.deserialize_struct("Program<DeBruijn>", FIELDS, ProgramVisitor)
}
}
@ -789,9 +878,13 @@ impl Program<NamedDeBruijn> {
impl Program<DeBruijn> {
pub fn eval(&self, initial_budget: ExBudget) -> EvalResult {
let program: Program<NamedDeBruijn> = self.clone().into();
program.eval(initial_budget)
}
pub fn eval_version(self, initial_budget: ExBudget, version: &Language) -> EvalResult {
let program: Program<NamedDeBruijn> = self.clone().into();
program.eval_version(initial_budget, version)
}
}
impl Term<NamedDeBruijn> {

View File

@ -1,13 +1,3 @@
use num_bigint::BigInt;
use pallas_codec::flat::{
de::{self, Decode, Decoder},
en::{self, Encode, Encoder},
Flat,
};
use pallas_primitives::{babbage::PlutusData, Fragment};
use std::{collections::VecDeque, fmt::Debug, rc::Rc};
use crate::{
ast::{
Constant, DeBruijn, FakeNamedDeBruijn, Name, NamedDeBruijn, Program, Term, Type, Unique,
@ -15,6 +5,14 @@ use crate::{
builtins::DefaultFunction,
machine::runtime::Compressable,
};
use num_bigint::BigInt;
use pallas_codec::flat::{
de::{self, Decode, Decoder},
en::{self, Encode, Encoder},
Flat,
};
use pallas_primitives::{conway::PlutusData, Fragment};
use std::{collections::VecDeque, fmt::Debug, rc::Rc};
const BUILTIN_TAG_WIDTH: u32 = 7;
const CONST_TAG_WIDTH: u32 = 4;

View File

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

File diff suppressed because it is too large Load Diff

View File

@ -11,11 +11,21 @@ pub enum Error {
InvalidStepKind(u8),
#[error("Cannot evaluate an open term:\\n\\n{}", .0.to_pretty())]
OpenTermEvaluated(Term<NamedDeBruijn>),
#[error("The provided Plutus code called 'error'.")]
#[error("The validator crashed / exited prematurely")]
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),
#[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),
#[error("Attempted to case a non-const:\n\n{0:#?}")]
NonConstrScrutinized(Value),
@ -29,9 +39,13 @@ pub enum Error {
PairTypeMismatch(Type),
#[error("Empty List:\n\n{0:#?}")]
EmptyList(Value),
#[error("A builtin received a term argument when something else was expected:\n\n{0}\n\nYou probably forgot to wrap the builtin with a force.")]
#[error(
"A builtin received a term argument when something else was expected:\n\n{0}\n\nYou probably forgot to wrap the builtin with a force."
)]
UnexpectedBuiltinTermArgument(Term<NamedDeBruijn>),
#[error("A builtin expected a term argument, but something else was received:\n\n{0}\n\nYou probably have an extra force wrapped around a builtin")]
#[error(
"A builtin expected a term argument, but something else was received:\n\n{0}\n\nYou probably have an extra force wrapped around a builtin"
)]
BuiltinTermArgumentExpected(Term<NamedDeBruijn>),
#[error("Unable to unlift value because it is not a constant:\n\n{0:#?}")]
NotAConstant(Value),
@ -49,15 +63,18 @@ pub enum Error {
Utf8(#[from] FromUtf8Error),
#[error("Out of Bounds\n\nindex: {}\nbytestring: {}\npossible: 0 - {}", .0, hex::encode(.1), .1.len() - 1)]
ByteStringOutOfBounds(BigInt, Vec<u8>),
#[error("Attempt to consByteString something bigger than one byte {0}")]
ByteStringConsBiggerThanOneByte(BigInt),
#[error("Attempt to consByteString something than isn't a byte between [0-255]: {0}")]
ByteStringConsNotAByte(BigInt),
#[error("Divide By Zero\n\n{0} / {1}")]
DivideByZero(BigInt, BigInt),
#[error("Ed25519S PublicKey should be 32 bytes but it was {0}")]
UnexpectedEd25519PublicKeyLength(usize),
#[error("Ed25519S Signature should be 64 bytes but it was {0}")]
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),
#[error("Integer overflow")]
OverflowError,
@ -79,3 +96,21 @@ impl From<k256::ecdsa::Error> for 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

@ -485,8 +485,8 @@ impl DefaultFunction {
wrap.try_into().unwrap()
}
BuiltinSemantics::V2 => {
if *arg1 > 255.into() {
return Err(Error::ByteStringConsBiggerThanOneByte(arg1.clone()));
if *arg1 > 255.into() || *arg1 < 0.into() {
return Err(Error::ByteStringConsNotAByte(arg1.clone()));
}
arg1.try_into().unwrap()

View File

@ -1,14 +1,12 @@
use std::{collections::VecDeque, mem::size_of, ops::Deref, rc::Rc};
use super::{runtime::BuiltinRuntime, Error};
use crate::{
ast::{Constant, NamedDeBruijn, Term, Type},
builtins::DefaultFunction,
};
use num_bigint::BigInt;
use num_traits::{Signed, ToPrimitive, Zero};
use pallas_primitives::babbage::{self, PlutusData};
use super::{runtime::BuiltinRuntime, Error};
use pallas_primitives::conway::{self, PlutusData};
use std::{collections::VecDeque, mem::size_of, ops::Deref, rc::Rc};
pub(super) type Env = Rc<Vec<Value>>;
@ -398,44 +396,41 @@ pub fn integer_log2(i: BigInt) -> i64 {
}
}
pub fn from_pallas_bigint(n: &babbage::BigInt) -> BigInt {
pub fn from_pallas_bigint(n: &conway::BigInt) -> BigInt {
match n {
babbage::BigInt::Int(i) => i128::from(*i).into(),
babbage::BigInt::BigUInt(bytes) => BigInt::from_bytes_be(num_bigint::Sign::Plus, bytes),
babbage::BigInt::BigNInt(bytes) => {
BigInt::from_bytes_be(num_bigint::Sign::Minus, bytes) - 1
}
conway::BigInt::Int(i) => i128::from(*i).into(),
conway::BigInt::BigUInt(bytes) => BigInt::from_bytes_be(num_bigint::Sign::Plus, bytes),
conway::BigInt::BigNInt(bytes) => BigInt::from_bytes_be(num_bigint::Sign::Minus, bytes) - 1,
}
}
pub fn to_pallas_bigint(n: &BigInt) -> babbage::BigInt {
pub fn to_pallas_bigint(n: &BigInt) -> conway::BigInt {
if let Some(i) = n.to_i128() {
if let Ok(i) = i.try_into() {
let pallas_int: pallas_codec::utils::Int = i;
return babbage::BigInt::Int(pallas_int);
return conway::BigInt::Int(pallas_int);
}
}
if n.is_positive() {
let (_, bytes) = n.to_bytes_be();
babbage::BigInt::BigUInt(bytes.into())
conway::BigInt::BigUInt(bytes.into())
} else {
// Note that this would break if n == 0
// BUT n == 0 always fits into 64bits and hence would end up in the first branch.
let n: BigInt = n + 1;
let (_, bytes) = n.to_bytes_be();
babbage::BigInt::BigNInt(bytes.into())
conway::BigInt::BigNInt(bytes.into())
}
}
#[cfg(test)]
mod tests {
use num_bigint::BigInt;
use crate::{
ast::Constant,
machine::value::{integer_log2, Value},
};
use num_bigint::BigInt;
#[test]
fn to_ex_mem_bigint() {

View File

@ -1,18 +1,14 @@
use std::{cmp::Ordering, iter, ops::Neg, rc::Rc, vec};
use indexmap::IndexMap;
use itertools::Itertools;
use pallas_primitives::babbage::{BigInt, PlutusData};
use super::interner::CodeGenInterner;
use crate::{
ast::{Constant, Data, Name, NamedDeBruijn, Program, Term, Type},
builder::{CONSTR_FIELDS_EXPOSER, CONSTR_INDEX_EXPOSER},
builtins::DefaultFunction,
machine::cost_model::ExBudget,
};
use super::interner::CodeGenInterner;
use indexmap::IndexMap;
use itertools::Itertools;
use pallas_primitives::conway::{BigInt, PlutusData};
use std::{cmp::Ordering, iter, ops::Neg, rc::Rc, vec};
#[derive(Eq, Hash, PartialEq, Clone, Debug, PartialOrd)]
pub enum ScopePath {
@ -1981,18 +1977,15 @@ fn pop_lambdas_and_get_names(term: &Term<Name>) -> (Vec<Rc<Name>>, &Term<Name>)
#[cfg(test)]
mod tests {
use pallas_primitives::babbage::{BigInt, PlutusData};
use pretty_assertions::assert_eq;
use super::NO_INLINE;
use crate::{
ast::{Constant, Data, Name, NamedDeBruijn, Program, Term},
builder::{CONSTR_FIELDS_EXPOSER, CONSTR_INDEX_EXPOSER},
builtins::DefaultFunction,
optimize::interner::CodeGenInterner,
};
use super::NO_INLINE;
use pallas_primitives::conway::{BigInt, PlutusData};
use pretty_assertions::assert_eq;
fn compare_optimization(
mut expected: Program<Name>,

View File

@ -1,16 +1,13 @@
use std::{ops::Neg, rc::Rc, str::FromStr};
use crate::{
ast::{Constant, Name, Program, Term, Type},
builtins::DefaultFunction,
machine::runtime::Compressable,
machine::value::to_pallas_bigint,
machine::{runtime::Compressable, value::to_pallas_bigint},
};
use interner::Interner;
use num_bigint::BigInt;
use pallas_primitives::alonzo::PlutusData;
use peg::{error::ParseError, str::LineCol};
use std::{ops::Neg, rc::Rc, str::FromStr};
pub mod interner;
@ -195,10 +192,10 @@ peg::parser! {
= n:$(['0'..='9']+) {? n.parse().or(Err("usize")) }
rule number() -> isize
= n:$("-"* ['0'..='9']+) {? n.parse().or(Err("isize")) }
= n:$(("-"/"+")* ['0'..='9']+) {? n.parse().or(Err("isize")) }
rule big_number() -> BigInt
= n:$("-"* ['0'..='9']+) {? (if n.starts_with('-') { BigInt::parse_bytes(&n.as_bytes()[1..], 10).map(|i| i.neg()) } else { BigInt::parse_bytes(n.as_bytes(), 10) }).ok_or("BigInt") }
= n:$(("-"/"+")* ['0'..='9']+) {? (if n.starts_with('-') { BigInt::parse_bytes(&n.as_bytes()[1..], 10).map(|i| i.neg()) } else { BigInt::parse_bytes(n.as_bytes(), 10) }).ok_or("BigInt") }
rule boolean() -> bool
= b:$("True" / "False") { b == "True" }
@ -375,11 +372,12 @@ peg::parser! {
#[cfg(test)]
mod tests {
use crate::{
ast::{Constant, Name, Program, Term, Type, Unique},
builtins::DefaultFunction,
};
use num_bigint::BigInt;
use pretty_assertions::assert_eq;
use crate::ast::{Constant, Name, Program, Term, Type, Unique};
use crate::builtins::DefaultFunction;
use std::rc::Rc;
#[test]

View File

@ -1,10 +1,12 @@
use crate::{
ast::{Constant, Program, Term, Type},
flat::Binder,
machine::runtime::{convert_tag_to_constr, Compressable},
machine::value::from_pallas_bigint,
machine::{
runtime::{convert_tag_to_constr, Compressable},
value::from_pallas_bigint,
},
};
use pallas_primitives::babbage::{Constr, PlutusData};
use pallas_primitives::conway::{Constr, PlutusData};
use pretty::RcDoc;
use std::ascii::escape_default;

View File

@ -1,20 +1,16 @@
use pallas_primitives::{
babbage::{CostMdls, MintedTx, Redeemer, TransactionInput, TransactionOutput},
Fragment,
};
use pallas_traverse::{Era, MultiEraTx};
use error::Error;
pub use phase_one::eval_phase_one;
pub use script_context::{ResolvedInput, SlotConfig};
use crate::{
ast::{DeBruijn, Program},
machine::cost_model::ExBudget,
PlutusData,
};
use eval::get_script_and_datum_lookup_table;
use error::Error;
use pallas_primitives::{
conway::{CostMdls, MintedTx, Redeemer, TransactionInput, TransactionOutput},
Fragment,
};
use pallas_traverse::{Era, MultiEraTx};
pub use phase_one::{eval_phase_one, redeemer_tag_to_string};
pub use script_context::{DataLookupTable, ResolvedInput, SlotConfig};
pub mod error;
pub mod eval;
@ -40,7 +36,7 @@ pub fn eval_phase_two(
) -> Result<Vec<Redeemer>, Error> {
let redeemers = tx.transaction_witness_set.redeemer.as_ref();
let lookup_table = get_script_and_datum_lookup_table(tx, utxos);
let lookup_table = DataLookupTable::from_transaction(tx, utxos);
if run_phase_one {
// subset of phase 1 check on redeemers and scripts
@ -53,14 +49,21 @@ pub fn eval_phase_two(
let mut remaining_budget = *initial_budget.unwrap_or(&ExBudget::default());
for redeemer in rs.iter() {
with_redeemer(redeemer);
for (redeemer_key, redeemer_value) in rs.iter() {
let redeemer = Redeemer {
tag: redeemer_key.tag,
index: redeemer_key.index,
data: redeemer_value.data.clone(),
ex_units: redeemer_value.ex_units,
};
with_redeemer(&redeemer);
let redeemer = eval::eval_redeemer(
tx,
utxos,
slot_config,
redeemer,
&redeemer,
&lookup_table,
cost_mdls,
&remaining_budget,
@ -93,7 +96,8 @@ pub fn eval_phase_two_raw(
run_phase_one: bool,
with_redeemer: fn(&Redeemer) -> (),
) -> Result<Vec<Vec<u8>>, Error> {
let multi_era_tx = MultiEraTx::decode_for_era(Era::Babbage, tx_bytes)
let multi_era_tx = MultiEraTx::decode_for_era(Era::Conway, tx_bytes)
.or_else(|_| MultiEraTx::decode_for_era(Era::Babbage, tx_bytes))
.or_else(|_| MultiEraTx::decode_for_era(Era::Alonzo, tx_bytes))?;
let cost_mdls = CostMdls::decode_fragment(cost_mdls_bytes)?;
@ -119,7 +123,7 @@ pub fn eval_phase_two_raw(
};
match multi_era_tx {
MultiEraTx::Babbage(tx) => {
MultiEraTx::Conway(tx) => {
match eval_phase_two(
&tx,
&utxos,
@ -136,15 +140,12 @@ pub fn eval_phase_two_raw(
Err(err) => Err(err),
}
}
// MultiEraTx::AlonzoCompatible(tx, _) => match eval_tx(&tx, &utxos, &sc) {
// Ok(redeemers) => Ok(redeemers
// .iter()
// .map(|r| r.encode_fragment().unwrap())
// .collect()),
// Err(_) => Err(()),
// },
// TODO: I probably did a mistake here with using MintedTx which is only compatible with Babbage tx.
_ => todo!("Wrong era. Please use babbage"),
_ => unimplemented!(
r#"The transaction is serialized in an old era format. Because we're slightly lazy to
maintain backward compatibility with every possible transaction format AND, because
those formats are mostly forward-compatible, you are kindly expected to provide a
transaction in a format suitable for the Conway era."#
),
}
}

View File

@ -2,62 +2,103 @@ use crate::{
machine::{self, cost_model::ExBudget},
TransactionInput,
};
use pallas_primitives::conway::Language;
#[derive(thiserror::Error, Debug, miette::Diagnostic)]
pub enum Error {
#[error("{0}")]
Address(#[from] pallas_addresses::Error),
#[error("Only shelley reward addresses can be a part of withdrawals")]
#[error("only shelley reward addresses can be a part of withdrawals")]
BadWithdrawalAddress,
#[error("{0}")]
FlatDecode(#[from] pallas_codec::flat::de::Error),
#[error("{0}")]
FragmentDecode(#[from] pallas_primitives::Error),
#[error("{}\n\n{:#?}\n\n{}", .0, .1, .2.join("\n"))]
#[error("{}{}", .0, .2.iter()
.map(|trace| {
format!(
"\n{:>13} {}",
"Trace",
if trace.contains("\n") {
trace.lines()
.enumerate()
.map(|(ix, row)| {
if ix == 0 {
row.to_string()
} else {
format!("{:>13} {}", "",
row
)
}
})
.collect::<Vec<_>>()
.join("\n")
} else {
trace.to_string()
}
)
})
.collect::<Vec<_>>()
.join("")
.as_str()
)]
Machine(machine::Error, ExBudget, Vec<String>),
#[error("Native script can't be executed in phase-two")]
#[error("native script can't be executed in phase-two")]
NativeScriptPhaseTwo,
#[error("Can't eval without redeemers")]
#[error("can't eval without redeemers")]
NoRedeemers,
#[error("Mismatch in required redeemers: {} {}", .missing.join(" "), .extra.join(" "))]
#[error(
"missing and/or unexpected validator(s) and/or redeemer(s)\n{:>13} {}\n{:>13} {}",
"Missing",
if .missing.is_empty() { "ø".to_string() } else { .missing.join(&format!("\n{:>14}", "")) },
"Unexpected",
if .extra.is_empty() { "ø".to_string() } else { .extra.join(&format!("\n{:>14}", "")) },
)]
RequiredRedeemersMismatch {
missing: Vec<String>,
extra: Vec<String>,
},
#[error("Extraneous redeemer")]
#[error("extraneous redeemer")]
ExtraneousRedeemer,
#[error("Resolved Input not found.")]
#[error("resolved Input not found")]
ResolvedInputNotFound(TransactionInput),
#[error("A key hash cannot be the hash of a script.")]
ScriptKeyHash,
#[error("PlutusV1 cost model not found.")]
V1CostModelNotFound,
#[error("PlutusV2 cost model not found.")]
V2CostModelNotFound,
#[error("Wrong era, Please use Babbage or Alonzo: {0}")]
#[error("redeemer points to a non-script withdrawal")]
NonScriptWithdrawal,
#[error("stake credential points to a non-script withdrawal")]
NonScriptStakeCredential,
#[error("the designated procedure defines no guardrail script")]
NoGuardrailScriptForProcedure,
#[error("cost model not found for language\n{:>13} {:?}", "Language", .0)]
CostModelNotFound(Language),
#[error("unsupported era, please use Conway\n{:>13} {0}", "Decoder error")]
WrongEra(#[from] pallas_codec::minicbor::decode::Error),
#[error("Byron address not allowed in Plutus.")]
#[error("byron address not allowed when PlutusV2 scripts are present")]
ByronAddressNotAllowed,
#[error("Inline datum not allowed in PlutusV1.")]
#[error("inline datum not allowed when PlutusV1 scripts are present")]
InlineDatumNotAllowed,
#[error("Script and input reference not allowed in PlutusV1.")]
#[error("script and input reference not allowed in PlutusV1")]
ScriptAndInputRefNotAllowed,
#[error("Address doesn't contain a payment credential.")]
#[error("address doesn't contain a payment credential")]
NoPaymentCredential,
#[error("Missing required datum: {}", hash)]
#[error("missing required datum\n{:>13} {}", "Datum", hash)]
MissingRequiredDatum { hash: String },
#[error("Missing required script: {}", hash)]
#[error("missing required script\n{:>13} {}", "Script", hash)]
MissingRequiredScript { hash: String },
#[error("Missing required inline datum or datum hash in script input.")]
#[error("missing required inline datum or datum hash in script input")]
MissingRequiredInlineDatumOrHash,
#[error("Only stake deregistration and delegation are valid certificate script purposes.")]
OnlyStakeDeregAndDelegAllowed,
#[error("Redeemer ({}, {}): {}", tag, index, err)]
#[error("redeemer points to an unsupported certificate type")]
UnsupportedCertificateType,
#[error("failed script execution\n{:>13} {}", format!("{}[{}]", tag, index), err)]
RedeemerError {
tag: String,
index: u32,
err: Box<Error>,
},
#[error("Failed to apply parameters to Plutus script.")]
#[error("missing script for redeemer")]
MissingScriptForRedeemer,
#[error("failed to apply parameters to Plutus script")]
ApplyParamsError,
#[error("validity start or end too far in the past")]
SlotTooFarInThePast { oldest_allowed: u64 },
}

File diff suppressed because it is too large Load Diff

View File

@ -1,23 +1,18 @@
use super::{
error::Error,
eval::{DataLookupTable, ScriptVersion},
script_context::{ResolvedInput, ScriptPurpose},
script_context::{sort_voters, DataLookupTable, ResolvedInput, ScriptPurpose, ScriptVersion},
};
use crate::tx::script_context::sort_reward_accounts;
use itertools::Itertools;
use pallas_addresses::{Address, ScriptHash, ShelleyPaymentPart, StakePayload};
use pallas_codec::utils::{KeyValuePairs, MaybeIndefArray};
use pallas_primitives::babbage::{
Certificate, MintedTx, PolicyId, RedeemerTag, RewardAccount, StakeCredential, TransactionOutput,
use pallas_codec::utils::Nullable;
use pallas_primitives::conway::{
Certificate, GovAction, MintedTx, PolicyId, RedeemerTag, RedeemersKey, RewardAccount,
StakeCredential, TransactionOutput, Voter,
};
use std::collections::HashMap;
// TODO: include in pallas eventually?
#[derive(Debug, PartialEq, Clone)]
struct RedeemerPtr {
tag: RedeemerTag,
index: u32,
}
type AlonzoScriptsNeeded = Vec<(ScriptPurpose, ScriptHash)>;
type ScriptsNeeded = Vec<(ScriptPurpose, ScriptHash)>;
// subset of phase-1 ledger checks related to scripts
pub fn eval_phase_one(
@ -35,7 +30,7 @@ pub fn eval_phase_one(
}
pub fn validate_missing_scripts(
needed: &AlonzoScriptsNeeded,
needed: &ScriptsNeeded,
txscripts: HashMap<ScriptHash, ScriptVersion>,
) -> Result<(), Error> {
let received_hashes = txscripts.keys().copied().collect::<Vec<ScriptHash>>();
@ -46,32 +41,23 @@ pub fn validate_missing_scripts(
.clone()
.into_iter()
.filter(|x| !received_hashes.contains(x))
.map(|x| format!("[Missing (sh: {x})]"))
.map(|x| x.to_string())
.collect();
let extra: Vec<_> = received_hashes
.into_iter()
.filter(|x| !needed_hashes.contains(x))
.map(|x| format!("[Extraneous (sh: {x:?})]"))
.map(|x| x.to_string())
.collect();
if !missing.is_empty() || !extra.is_empty() {
let missing_errors = missing.join(" ");
let extra_errors = extra.join(" ");
unreachable!(
"Mismatch in required scripts: {} {}",
missing_errors, extra_errors
);
return Err(Error::RequiredRedeemersMismatch { missing, extra });
}
Ok(())
}
pub fn scripts_needed(
tx: &MintedTx,
utxos: &[ResolvedInput],
) -> Result<AlonzoScriptsNeeded, Error> {
pub fn scripts_needed(tx: &MintedTx, utxos: &[ResolvedInput]) -> Result<ScriptsNeeded, Error> {
let mut needed = Vec::new();
let txb = tx.transaction_body.clone();
@ -91,61 +77,119 @@ pub fn scripts_needed(
if let Address::Shelley(a) = address {
if let ShelleyPaymentPart::Script(h) = a.payment() {
spend.push((ScriptPurpose::Spending(input.clone()), *h));
spend.push((ScriptPurpose::Spending(input.clone(), ()), *h));
}
}
}
let mut reward = txb
.withdrawals
.as_ref()
.unwrap_or(&KeyValuePairs::Indef(vec![]))
.iter()
.filter_map(|(acnt, _)| {
let address = Address::from_bytes(acnt).unwrap();
.as_deref()
.map(|w| {
w.iter()
.filter_map(|(acnt, _)| {
let address = Address::from_bytes(acnt).unwrap();
if let Address::Stake(a) = address {
if let StakePayload::Script(h) = a.payload() {
let cred = StakeCredential::Scripthash(*h);
return Some((ScriptPurpose::Rewarding(cred), *h));
}
}
if let Address::Stake(a) = address {
if let StakePayload::Script(h) = a.payload() {
let cred = StakeCredential::Scripthash(*h);
return Some((ScriptPurpose::Rewarding(cred), *h));
}
}
None
None
})
.collect::<ScriptsNeeded>()
})
.collect::<AlonzoScriptsNeeded>();
.unwrap_or_default();
let mut cert = txb
.certificates
.clone()
.unwrap_or_default()
.iter()
.filter_map(|cert| {
// only Dereg and Deleg certs can require scripts
match cert {
Certificate::StakeDeregistration(StakeCredential::Scripthash(h)) => {
Some((ScriptPurpose::Certifying(cert.clone()), *h))
}
Certificate::StakeDelegation(StakeCredential::Scripthash(h), _) => {
Some((ScriptPurpose::Certifying(cert.clone()), *h))
}
_ => None,
}
.as_deref()
.map(|m| {
m.iter()
.enumerate()
.filter_map(|(ix, cert)| match cert {
Certificate::StakeDeregistration(StakeCredential::Scripthash(h))
| Certificate::UnReg(StakeCredential::Scripthash(h), _)
| Certificate::VoteDeleg(StakeCredential::Scripthash(h), _)
| Certificate::VoteRegDeleg(StakeCredential::Scripthash(h), _, _)
| Certificate::StakeVoteDeleg(StakeCredential::Scripthash(h), _, _)
| Certificate::StakeRegDeleg(StakeCredential::Scripthash(h), _, _)
| Certificate::StakeVoteRegDeleg(StakeCredential::Scripthash(h), _, _, _)
| Certificate::RegDRepCert(StakeCredential::Scripthash(h), _, _)
| Certificate::UnRegDRepCert(StakeCredential::Scripthash(h), _)
| Certificate::UpdateDRepCert(StakeCredential::Scripthash(h), _)
| Certificate::AuthCommitteeHot(StakeCredential::Scripthash(h), _)
| Certificate::ResignCommitteeCold(StakeCredential::Scripthash(h), _)
| Certificate::StakeDelegation(StakeCredential::Scripthash(h), _) => {
Some((ScriptPurpose::Certifying(ix, cert.clone()), *h))
}
_ => None,
})
.collect::<ScriptsNeeded>()
})
.collect::<AlonzoScriptsNeeded>();
.unwrap_or_default();
let mut mint = txb
.mint
.as_ref()
.unwrap_or(&KeyValuePairs::Indef(vec![]))
.iter()
.map(|(policy_id, _)| (ScriptPurpose::Minting(*policy_id), *policy_id))
.collect::<AlonzoScriptsNeeded>();
.as_deref()
.map(|m| {
m.iter()
.map(|(policy_id, _)| (ScriptPurpose::Minting(*policy_id), *policy_id))
.collect::<ScriptsNeeded>()
})
.unwrap_or_default();
let mut propose = txb
.proposal_procedures
.as_deref()
.map(|m| {
m.iter()
.enumerate()
.filter_map(|(ix, procedure)| match procedure.gov_action {
GovAction::ParameterChange(_, _, Nullable::Some(hash)) => {
Some((ScriptPurpose::Proposing(ix, procedure.clone()), hash))
}
GovAction::TreasuryWithdrawals(_, Nullable::Some(hash)) => {
Some((ScriptPurpose::Proposing(ix, procedure.clone()), hash))
}
GovAction::HardForkInitiation(..)
| GovAction::Information
| GovAction::NewConstitution(..)
| GovAction::TreasuryWithdrawals(..)
| GovAction::ParameterChange(..)
| GovAction::NoConfidence(..)
| GovAction::UpdateCommittee(..) => None,
})
.collect::<ScriptsNeeded>()
})
.unwrap_or_default();
let mut voting = txb
.voting_procedures
.as_deref()
.map(|m| {
m.iter()
.filter_map(|(voter, _)| match voter {
Voter::ConstitutionalCommitteeScript(hash) | Voter::DRepScript(hash) => {
Some((ScriptPurpose::Voting(voter.clone()), *hash))
}
Voter::ConstitutionalCommitteeKey(_)
| Voter::DRepKey(_)
| Voter::StakePoolKey(_) => None,
})
.collect::<ScriptsNeeded>()
})
.unwrap_or_default();
needed.append(&mut spend);
needed.append(&mut reward);
needed.append(&mut cert);
needed.append(&mut mint);
needed.append(&mut propose);
needed.append(&mut voting);
Ok(needed)
}
@ -153,58 +197,58 @@ pub fn scripts_needed(
/// hasExactSetOfRedeemers in Ledger Spec, but we pass `txscripts` directly
pub fn has_exact_set_of_redeemers(
tx: &MintedTx,
needed: &AlonzoScriptsNeeded,
needed: &ScriptsNeeded,
tx_scripts: HashMap<ScriptHash, ScriptVersion>,
) -> Result<(), Error> {
let mut redeemers_needed = Vec::new();
for (script_purpose, script_hash) in needed {
let redeemer_ptr = build_redeemer_ptr(tx, script_purpose)?;
let redeemer_key = build_redeemer_key(tx, script_purpose)?;
let script = tx_scripts.get(script_hash);
if let (Some(ptr), Some(script)) = (redeemer_ptr, script) {
if let (Some(key), Some(script)) = (redeemer_key, script) {
match script {
ScriptVersion::V1(_) => {
redeemers_needed.push((ptr, script_purpose.clone(), *script_hash))
redeemers_needed.push((key, script_purpose.clone(), *script_hash))
}
ScriptVersion::V2(_) => {
redeemers_needed.push((ptr, script_purpose.clone(), *script_hash))
redeemers_needed.push((key, script_purpose.clone(), *script_hash))
}
ScriptVersion::V3(_) => {
redeemers_needed.push((key, script_purpose.clone(), *script_hash))
}
ScriptVersion::Native(_) => (),
}
}
}
let wits_redeemer_ptrs: Vec<RedeemerPtr> = tx
let wits_redeemer_keys: Vec<&RedeemersKey> = tx
.transaction_witness_set
.redeemer
.as_ref()
.unwrap_or(&MaybeIndefArray::Indef(vec![]))
.iter()
.map(|r| RedeemerPtr {
tag: r.tag.clone(),
index: r.index,
})
.collect();
.as_deref()
.map(|m| m.iter().map(|(k, _)| k).collect())
.unwrap_or_default();
let needed_redeemer_ptrs: Vec<RedeemerPtr> =
let needed_redeemer_keys: Vec<RedeemersKey> =
redeemers_needed.iter().map(|x| x.0.clone()).collect();
let missing: Vec<_> = redeemers_needed
.into_iter()
.filter(|x| !wits_redeemer_ptrs.contains(&x.0))
.filter(|x| !wits_redeemer_keys.contains(&&x.0))
.map(|x| {
format!(
"[Missing (redeemer_ptr: {:?}, script_purpose: {:?}, script_hash: {})]",
x.0, x.1, x.2,
"{}[{:?}] -> {}",
redeemer_tag_to_string(&x.0.tag),
x.0.index,
x.2
)
})
.collect();
let extra: Vec<_> = wits_redeemer_ptrs
let extra: Vec<_> = wits_redeemer_keys
.into_iter()
.filter(|x| !needed_redeemer_ptrs.contains(x))
.map(|x| format!("[Extraneous (redeemer_ptr: {x:?})]"))
.filter(|x| !needed_redeemer_keys.contains(x))
.map(|x| format!("{}[{:?}]", redeemer_tag_to_string(&x.tag), x.index))
.collect();
if !missing.is_empty() || !extra.is_empty() {
@ -217,66 +261,62 @@ pub fn has_exact_set_of_redeemers(
/// builds a redeemer pointer (tag, index) from a script purpose by setting the tag
/// according to the type of the script purpose, and the index according to the
/// placement of script purpose inside its container.
fn build_redeemer_ptr(
fn build_redeemer_key(
tx: &MintedTx,
script_purpose: &ScriptPurpose,
) -> Result<Option<RedeemerPtr>, Error> {
) -> Result<Option<RedeemersKey>, Error> {
let tx_body = tx.transaction_body.clone();
match script_purpose {
ScriptPurpose::Minting(hash) => {
let mut policy_ids = tx_body
let policy_ids: Vec<&PolicyId> = tx_body
.mint
.as_ref()
.unwrap_or(&KeyValuePairs::Indef(vec![]))
.iter()
.map(|(policy_id, _)| *policy_id)
.collect::<Vec<PolicyId>>();
.as_deref()
.map(|m| m.iter().map(|(policy_id, _)| policy_id).sorted().collect())
.unwrap_or_default();
policy_ids.sort();
let redeemer_key =
policy_ids
.iter()
.position(|x| x == &hash)
.map(|index| RedeemersKey {
tag: RedeemerTag::Mint,
index: index as u32,
});
let maybe_idx = policy_ids.iter().position(|x| x == hash);
match maybe_idx {
Some(idx) => Ok(Some(RedeemerPtr {
tag: RedeemerTag::Mint,
index: idx as u32,
})),
None => Ok(None),
}
Ok(redeemer_key)
}
ScriptPurpose::Spending(txin) => {
let mut inputs = tx_body.inputs.to_vec();
inputs.sort_by(
|i_a, i_b| match i_a.transaction_id.cmp(&i_b.transaction_id) {
std::cmp::Ordering::Less => std::cmp::Ordering::Less,
std::cmp::Ordering::Equal => i_a.index.cmp(&i_b.index),
std::cmp::Ordering::Greater => std::cmp::Ordering::Greater,
},
);
let maybe_idx = inputs.iter().position(|x| x == txin);
match maybe_idx {
Some(idx) => Ok(Some(RedeemerPtr {
ScriptPurpose::Spending(txin, ()) => {
let redeemer_key = tx_body
.inputs
.iter()
.sorted_by(
|i_a, i_b| match i_a.transaction_id.cmp(&i_b.transaction_id) {
std::cmp::Ordering::Less => std::cmp::Ordering::Less,
std::cmp::Ordering::Equal => i_a.index.cmp(&i_b.index),
std::cmp::Ordering::Greater => std::cmp::Ordering::Greater,
},
)
.position(|x| x == txin)
.map(|index| RedeemersKey {
tag: RedeemerTag::Spend,
index: idx as u32,
})),
None => Ok(None),
}
index: index as u32,
});
Ok(redeemer_key)
}
ScriptPurpose::Rewarding(racnt) => {
let mut reward_accounts = tx_body
let mut reward_accounts: Vec<&RewardAccount> = tx_body
.withdrawals
.as_ref()
.unwrap_or(&KeyValuePairs::Indef(vec![]))
.iter()
.map(|(acnt, _)| acnt.clone())
.collect::<Vec<RewardAccount>>();
.as_deref()
.map(|m| m.iter().map(|(acnt, _)| acnt).collect())
.unwrap_or_default();
reward_accounts.sort();
reward_accounts.sort_by(|acnt_a, acnt_b| sort_reward_accounts(acnt_a, acnt_b));
let mut maybe_idx = None;
let mut redeemer_key = None;
for (idx, x) in reward_accounts.iter().enumerate() {
let cred = match Address::from_bytes(x).unwrap() {
@ -288,33 +328,72 @@ fn build_redeemer_ptr(
};
if cred == Some(racnt.to_owned()) {
maybe_idx = Some(idx);
redeemer_key = Some(RedeemersKey {
tag: RedeemerTag::Reward,
index: idx as u32,
});
}
}
match maybe_idx {
Some(idx) => Ok(Some(RedeemerPtr {
tag: RedeemerTag::Reward,
index: idx as u32,
})),
None => Ok(None),
}
Ok(redeemer_key)
}
ScriptPurpose::Certifying(d) => {
let maybe_idx = tx_body
.certificates
.as_ref()
.unwrap_or(&MaybeIndefArray::Indef(vec![]))
.iter()
.position(|x| x == d);
match maybe_idx {
Some(idx) => Ok(Some(RedeemerPtr {
ScriptPurpose::Certifying(_, d) => {
let redeemer_key = tx_body
.certificates
.as_deref()
.map(|m| m.iter().position(|x| x == d))
.unwrap_or_default()
.map(|index| RedeemersKey {
tag: RedeemerTag::Cert,
index: idx as u32,
})),
None => Ok(None),
}
index: index as u32,
});
Ok(redeemer_key)
}
ScriptPurpose::Voting(v) => {
let redeemer_key = tx_body
.voting_procedures
.as_deref()
.map(|m| {
m.iter()
.sorted_by(|(a, _), (b, _)| sort_voters(a, b))
.position(|x| &x.0 == v)
})
.unwrap_or_default()
.map(|index| RedeemersKey {
tag: RedeemerTag::Vote,
index: index as u32,
});
Ok(redeemer_key)
}
ScriptPurpose::Proposing(_, procedure) => {
let redeemer_key = tx_body
.proposal_procedures
.as_deref()
.map(|m| m.iter().position(|x| x == procedure))
.unwrap_or_default()
.map(|index| RedeemersKey {
tag: RedeemerTag::Propose,
index: index as u32,
});
Ok(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()
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,641 @@
---
source: crates/uplc/src/tx/script_context.rs
expression: script_context.to_plutus_data()
---
Constr(
Constr {
tag: 121,
any_constructor: None,
fields: [
Constr(
Constr {
tag: 121,
any_constructor: None,
fields: [
Array(
[
Constr(
Constr {
tag: 121,
any_constructor: None,
fields: [
Constr(
Constr {
tag: 121,
any_constructor: None,
fields: [
BoundedBytes(
BoundedBytes(
[
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
],
),
),
BigInt(
Int(
Int(
Int {
neg: false,
val: 0,
},
),
),
),
],
},
),
Constr(
Constr {
tag: 121,
any_constructor: None,
fields: [
Constr(
Constr {
tag: 121,
any_constructor: None,
fields: [
Constr(
Constr {
tag: 122,
any_constructor: None,
fields: [
BoundedBytes(
BoundedBytes(
[
57,
244,
127,
211,
179,
136,
239,
83,
196,
143,
8,
222,
36,
118,
109,
62,
85,
218,
222,
108,
174,
144,
140,
194,
78,
15,
79,
62,
],
),
),
],
},
),
Constr(
Constr {
tag: 122,
any_constructor: None,
fields: [],
},
),
],
},
),
Map(
Def(
[
(
BoundedBytes(
BoundedBytes(
[],
),
),
Map(
Def(
[
(
BoundedBytes(
BoundedBytes(
[],
),
),
BigInt(
Int(
Int(
Int {
neg: false,
val: 1000000000,
},
),
),
),
),
],
),
),
),
],
),
),
Constr(
Constr {
tag: 123,
any_constructor: None,
fields: [
Constr(
Constr {
tag: 121,
any_constructor: None,
fields: [],
},
),
],
},
),
Constr(
Constr {
tag: 122,
any_constructor: None,
fields: [],
},
),
],
},
),
],
},
),
],
),
Array(
[],
),
Array(
[
Constr(
Constr {
tag: 121,
any_constructor: None,
fields: [
Constr(
Constr {
tag: 121,
any_constructor: None,
fields: [
Constr(
Constr {
tag: 121,
any_constructor: None,
fields: [
BoundedBytes(
BoundedBytes(
[
17,
17,
17,
17,
17,
17,
17,
17,
17,
17,
17,
17,
17,
17,
17,
17,
17,
17,
17,
17,
17,
17,
17,
17,
17,
17,
17,
17,
],
),
),
],
},
),
Constr(
Constr {
tag: 122,
any_constructor: None,
fields: [],
},
),
],
},
),
Map(
Def(
[
(
BoundedBytes(
BoundedBytes(
[],
),
),
Map(
Def(
[
(
BoundedBytes(
BoundedBytes(
[],
),
),
BigInt(
Int(
Int(
Int {
neg: false,
val: 1000000000,
},
),
),
),
),
],
),
),
),
],
),
),
Constr(
Constr {
tag: 121,
any_constructor: None,
fields: [],
},
),
Constr(
Constr {
tag: 122,
any_constructor: None,
fields: [],
},
),
],
},
),
],
),
BigInt(
Int(
Int(
Int {
neg: false,
val: 42,
},
),
),
),
Map(
Def(
[],
),
),
Array(
[],
),
Map(
Def(
[],
),
),
Constr(
Constr {
tag: 121,
any_constructor: None,
fields: [
Constr(
Constr {
tag: 121,
any_constructor: None,
fields: [
Constr(
Constr {
tag: 121,
any_constructor: None,
fields: [],
},
),
Constr(
Constr {
tag: 122,
any_constructor: None,
fields: [],
},
),
],
},
),
Constr(
Constr {
tag: 121,
any_constructor: None,
fields: [
Constr(
Constr {
tag: 123,
any_constructor: None,
fields: [],
},
),
Constr(
Constr {
tag: 122,
any_constructor: None,
fields: [],
},
),
],
},
),
],
},
),
Array(
[],
),
Map(
Def(
[
(
Constr(
Constr {
tag: 122,
any_constructor: None,
fields: [
Constr(
Constr {
tag: 121,
any_constructor: None,
fields: [
BoundedBytes(
BoundedBytes(
[
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
],
),
),
BigInt(
Int(
Int(
Int {
neg: false,
val: 0,
},
),
),
),
],
},
),
],
},
),
Constr(
Constr {
tag: 121,
any_constructor: None,
fields: [],
},
),
),
],
),
),
Map(
Def(
[],
),
),
BoundedBytes(
BoundedBytes(
[
120,
236,
20,
142,
166,
71,
207,
153,
105,
68,
104,
145,
175,
49,
147,
156,
93,
87,
178,
117,
162,
69,
87,
6,
120,
44,
97,
131,
239,
11,
98,
241,
],
),
),
Map(
Def(
[],
),
),
Array(
[],
),
Constr(
Constr {
tag: 122,
any_constructor: None,
fields: [],
},
),
Constr(
Constr {
tag: 122,
any_constructor: None,
fields: [],
},
),
],
},
),
Constr(
Constr {
tag: 121,
any_constructor: None,
fields: [],
},
),
Constr(
Constr {
tag: 122,
any_constructor: None,
fields: [
Constr(
Constr {
tag: 121,
any_constructor: None,
fields: [
BoundedBytes(
BoundedBytes(
[
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
],
),
),
BigInt(
Int(
Int(
Int {
neg: false,
val: 0,
},
),
),
),
],
},
),
Constr(
Constr {
tag: 121,
any_constructor: None,
fields: [
Constr(
Constr {
tag: 121,
any_constructor: None,
fields: [],
},
),
],
},
),
],
},
),
],
},
)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,14 +1,12 @@
use super::{eval_phase_two, ResolvedInput, SlotConfig};
use crate::machine::cost_model::ExBudget;
use pallas_codec::utils::MaybeIndefArray;
use pallas_primitives::{
babbage::{CostMdls, TransactionInput, TransactionOutput},
conway::{CostMdls, TransactionInput, TransactionOutput},
Fragment,
};
use pallas_traverse::{Era, MultiEraTx};
use crate::machine::cost_model::ExBudget;
use super::{eval_phase_two, ResolvedInput, SlotConfig};
#[test]
fn test_eval_0() {
/*
@ -227,6 +225,7 @@ fn test_eval_0() {
let cost_mdl = CostMdls {
plutus_v1: None,
plutus_v2: Some(costs),
plutus_v3: None,
};
let initial_budget = ExBudget {
@ -234,11 +233,12 @@ fn test_eval_0() {
mem: 14000000,
};
let multi_era_tx = MultiEraTx::decode_for_era(Era::Babbage, &tx_bytes)
let multi_era_tx = MultiEraTx::decode_for_era(Era::Conway, &tx_bytes)
.or_else(|_| MultiEraTx::decode_for_era(Era::Babbage, &tx_bytes))
.or_else(|_| MultiEraTx::decode_for_era(Era::Alonzo, &tx_bytes))
.unwrap();
match multi_era_tx {
MultiEraTx::Babbage(tx) => {
MultiEraTx::Conway(tx) => {
let redeemers = eval_phase_two(
&tx,
&utxos,
@ -497,6 +497,7 @@ fn test_eval_1() {
let cost_mdl = CostMdls {
plutus_v1: None,
plutus_v2: Some(costs),
plutus_v3: None,
};
let initial_budget = ExBudget {
@ -504,11 +505,13 @@ fn test_eval_1() {
mem: 14000000,
};
let multi_era_tx = MultiEraTx::decode_for_era(Era::Babbage, &tx_bytes)
let multi_era_tx = MultiEraTx::decode_for_era(Era::Conway, &tx_bytes)
.or_else(|_| MultiEraTx::decode_for_era(Era::Babbage, &tx_bytes))
.or_else(|_| MultiEraTx::decode_for_era(Era::Alonzo, &tx_bytes))
.unwrap();
match multi_era_tx {
MultiEraTx::Babbage(tx) => {
MultiEraTx::Conway(tx) => {
let redeemers = eval_phase_two(
&tx,
&utxos,
@ -606,6 +609,7 @@ fn test_eval_2() {
let cost_mdl = CostMdls {
plutus_v1: Some(costs),
plutus_v2: None,
plutus_v3: None,
};
let initial_budget = ExBudget {
@ -613,11 +617,12 @@ fn test_eval_2() {
mem: 14000000,
};
let multi_era_tx = MultiEraTx::decode_for_era(Era::Babbage, &tx_bytes)
let multi_era_tx = MultiEraTx::decode_for_era(Era::Conway, &tx_bytes)
.or_else(|_| MultiEraTx::decode_for_era(Era::Babbage, &tx_bytes))
.or_else(|_| MultiEraTx::decode_for_era(Era::Alonzo, &tx_bytes))
.unwrap();
match multi_era_tx {
MultiEraTx::Babbage(tx) => {
MultiEraTx::Conway(tx) => {
let redeemers = eval_phase_two(
&tx,
&utxos,
@ -874,6 +879,7 @@ fn test_eval_3() {
let cost_mdl = CostMdls {
plutus_v1: None,
plutus_v2: Some(costs),
plutus_v3: None,
};
let initial_budget = ExBudget {
@ -881,11 +887,12 @@ fn test_eval_3() {
mem: 14000000,
};
let multi_era_tx = MultiEraTx::decode_for_era(Era::Babbage, &tx_bytes)
let multi_era_tx = MultiEraTx::decode_for_era(Era::Conway, &tx_bytes)
.or_else(|_| MultiEraTx::decode_for_era(Era::Babbage, &tx_bytes))
.or_else(|_| MultiEraTx::decode_for_era(Era::Alonzo, &tx_bytes))
.unwrap();
match multi_era_tx {
MultiEraTx::Babbage(tx) => {
MultiEraTx::Conway(tx) => {
let redeemers = eval_phase_two(
&tx,
&utxos,
@ -980,6 +987,7 @@ fn test_eval_4() {
let cost_mdl = CostMdls {
plutus_v1: Some(costs),
plutus_v2: None,
plutus_v3: None,
};
let initial_budget = ExBudget {
@ -987,11 +995,12 @@ fn test_eval_4() {
mem: 14000000,
};
let multi_era_tx = MultiEraTx::decode_for_era(Era::Babbage, &tx_bytes)
let multi_era_tx = MultiEraTx::decode_for_era(Era::Conway, &tx_bytes)
.or_else(|_| MultiEraTx::decode_for_era(Era::Babbage, &tx_bytes))
.or_else(|_| MultiEraTx::decode_for_era(Era::Alonzo, &tx_bytes))
.unwrap();
match multi_era_tx {
MultiEraTx::Babbage(tx) => {
MultiEraTx::Conway(tx) => {
assert!(eval_phase_two(
&tx,
&utxos,
@ -1063,6 +1072,7 @@ fn test_eval_5() {
let cost_mdl = CostMdls {
plutus_v1: Some(costs),
plutus_v2: None,
plutus_v3: None,
};
let initial_budget = ExBudget {
@ -1070,11 +1080,12 @@ fn test_eval_5() {
mem: 14000000,
};
let multi_era_tx = MultiEraTx::decode_for_era(Era::Babbage, &tx_bytes)
let multi_era_tx = MultiEraTx::decode_for_era(Era::Conway, &tx_bytes)
.or_else(|_| MultiEraTx::decode_for_era(Era::Babbage, &tx_bytes))
.or_else(|_| MultiEraTx::decode_for_era(Era::Alonzo, &tx_bytes))
.unwrap();
match multi_era_tx {
MultiEraTx::Babbage(tx) => {
MultiEraTx::Conway(tx) => {
let redeemers = eval_phase_two(
&tx,
&utxos,
@ -1171,6 +1182,7 @@ fn test_eval_6() {
let cost_mdl = CostMdls {
plutus_v1: Some(costs),
plutus_v2: None,
plutus_v3: None,
};
let initial_budget = ExBudget {
@ -1178,11 +1190,12 @@ fn test_eval_6() {
mem: 14000000,
};
let multi_era_tx = MultiEraTx::decode_for_era(Era::Babbage, &tx_bytes)
let multi_era_tx = MultiEraTx::decode_for_era(Era::Conway, &tx_bytes)
.or_else(|_| MultiEraTx::decode_for_era(Era::Babbage, &tx_bytes))
.or_else(|_| MultiEraTx::decode_for_era(Era::Alonzo, &tx_bytes))
.unwrap();
match multi_era_tx {
MultiEraTx::Babbage(tx) => {
MultiEraTx::Conway(tx) => {
let redeemers = eval_phase_two(
&tx,
&utxos,
@ -1279,6 +1292,7 @@ fn test_eval_7() {
let cost_mdl = CostMdls {
plutus_v1: Some(costs),
plutus_v2: None,
plutus_v3: None,
};
let initial_budget = ExBudget {
@ -1286,11 +1300,12 @@ fn test_eval_7() {
mem: 14000000,
};
let multi_era_tx = MultiEraTx::decode_for_era(Era::Babbage, &tx_bytes)
let multi_era_tx = MultiEraTx::decode_for_era(Era::Conway, &tx_bytes)
.or_else(|_| MultiEraTx::decode_for_era(Era::Babbage, &tx_bytes))
.or_else(|_| MultiEraTx::decode_for_era(Era::Alonzo, &tx_bytes))
.unwrap();
match multi_era_tx {
MultiEraTx::Babbage(tx) => {
MultiEraTx::Conway(tx) => {
let redeemers = eval_phase_two(
&tx,
&utxos,
@ -1538,6 +1553,7 @@ fn test_eval_8() {
let cost_mdl = CostMdls {
plutus_v1: None,
plutus_v2: Some(costs),
plutus_v3: None,
};
let initial_budget = ExBudget {
@ -1545,11 +1561,12 @@ fn test_eval_8() {
mem: 14000000,
};
let multi_era_tx = MultiEraTx::decode_for_era(Era::Babbage, &tx_bytes)
let multi_era_tx = MultiEraTx::decode_for_era(Era::Conway, &tx_bytes)
.or_else(|_| MultiEraTx::decode_for_era(Era::Babbage, &tx_bytes))
.or_else(|_| MultiEraTx::decode_for_era(Era::Alonzo, &tx_bytes))
.unwrap();
match multi_era_tx {
MultiEraTx::Babbage(tx) => {
MultiEraTx::Conway(tx) => {
let redeemers = eval_phase_two(
&tx,
&utxos,
@ -1593,12 +1610,13 @@ fn test_eval_8() {
fn eval_missing_redeemer() {
let tx_bytes = hex::decode("84a30082825820275b5da338c8b899035081eb34bfa950b634911a5dd3271b3ad6cf4c2bba0c5000825820275b5da338c8b899035081eb34bfa950b634911a5dd3271b3ad6cf4c2bba0c50010181825839000af00cc47500bb64cfffb783e8c42f746b4e8b8a70ede9c08c7113acf3bde34d1041f5a2076ef9aa6cf4539ab1a96ed462a0300acbdb65d51a02cf47c8021a00028d89a1068149480100002221200101f5f6").unwrap();
let multi_era_tx = MultiEraTx::decode_for_era(Era::Babbage, &tx_bytes)
let multi_era_tx = MultiEraTx::decode_for_era(Era::Conway, &tx_bytes)
.or_else(|_| MultiEraTx::decode_for_era(Era::Babbage, &tx_bytes))
.or_else(|_| MultiEraTx::decode_for_era(Era::Alonzo, &tx_bytes))
.unwrap();
let inputs = multi_era_tx
.as_babbage()
.as_conway()
.unwrap()
.transaction_body
.inputs
@ -1641,6 +1659,7 @@ fn eval_missing_redeemer() {
let cost_mdl = CostMdls {
plutus_v1: Some(costs),
plutus_v2: None,
plutus_v3: None,
};
let initial_budget = ExBudget {
@ -1648,12 +1667,13 @@ fn eval_missing_redeemer() {
mem: 14000000,
};
let multi_era_tx = MultiEraTx::decode_for_era(Era::Babbage, &tx_bytes)
let multi_era_tx = MultiEraTx::decode_for_era(Era::Conway, &tx_bytes)
.or_else(|_| MultiEraTx::decode_for_era(Era::Babbage, &tx_bytes))
.or_else(|_| MultiEraTx::decode_for_era(Era::Alonzo, &tx_bytes))
.unwrap();
match multi_era_tx {
MultiEraTx::Babbage(tx) => {
MultiEraTx::Conway(tx) => {
eval_phase_two(
&tx,
&utxos,
@ -1673,12 +1693,13 @@ fn eval_missing_redeemer() {
fn eval_extraneous_redeemer() {
let tx_bytes = hex::decode("84a70082825820275b5da338c8b899035081eb34bfa950b634911a5dd3271b3ad6cf4c2bba0c5000825820275b5da338c8b899035081eb34bfa950b634911a5dd3271b3ad6cf4c2bba0c50010181825839000af00cc47500bb64cfffb783e8c42f746b4e8b8a70ede9c08c7113acf3bde34d1041f5a2076ef9aa6cf4539ab1a96ed462a0300acbdb65d51a02cf2b47021a0002aa0a0b5820fc54f302cff3a8a1cb374f5e4979e18a1d3627dcf4539637b03f5959eb8565bf0d81825820275b5da338c8b899035081eb34bfa950b634911a5dd3271b3ad6cf4c2bba0c500110825839000af00cc47500bb64cfffb783e8c42f746b4e8b8a70ede9c08c7113acf3bde34d1041f5a2076ef9aa6cf4539ab1a96ed462a0300acbdb65d51a02af51c2111a0003ff0fa40081825820065dd553fbe4e240a8f819bb9e333a7483de4a22b65c7fb6a95ce9450f84dff758402c26125a057a696079d08f2c8c9d2b8ccda9fe7cf7360c1a86712b85a91db82a3b80996b30ba6f4b2f969c93eb50694e0f6ea0bcf129080dcc07ecd9e605f00a049fd87980ff0582840000d879808219044c1a000382d48401001864821903e81903e8068149480100002221200101f5f6").unwrap();
let multi_era_tx = MultiEraTx::decode_for_era(Era::Babbage, &tx_bytes)
let multi_era_tx = MultiEraTx::decode_for_era(Era::Conway, &tx_bytes)
.or_else(|_| MultiEraTx::decode_for_era(Era::Babbage, &tx_bytes))
.or_else(|_| MultiEraTx::decode_for_era(Era::Alonzo, &tx_bytes))
.unwrap();
let inputs = multi_era_tx
.as_babbage()
.as_conway()
.unwrap()
.transaction_body
.inputs
@ -1721,6 +1742,7 @@ fn eval_extraneous_redeemer() {
let cost_mdl = CostMdls {
plutus_v1: Some(costs),
plutus_v2: None,
plutus_v3: None,
};
let initial_budget = ExBudget {
@ -1728,12 +1750,13 @@ fn eval_extraneous_redeemer() {
mem: 14000000,
};
let multi_era_tx = MultiEraTx::decode_for_era(Era::Babbage, &tx_bytes)
let multi_era_tx = MultiEraTx::decode_for_era(Era::Conway, &tx_bytes)
.or_else(|_| MultiEraTx::decode_for_era(Era::Babbage, &tx_bytes))
.or_else(|_| MultiEraTx::decode_for_era(Era::Alonzo, &tx_bytes))
.unwrap();
match multi_era_tx {
MultiEraTx::Babbage(tx) => {
MultiEraTx::Conway(tx) => {
assert!(eval_phase_two(
&tx,
&utxos,

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More