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.lock linguist-generated=true merge=binary linguist-vendored
Cargo.nix 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 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" walkdir = "2.3.2"
insta = { version = "1.30.0", features = ["yaml", "json", "redactions"] } insta = { version = "1.30.0", features = ["yaml", "json", "redactions"] }
miette = { version = "7.2.0", features = ["fancy"] } miette = { version = "7.2.0", features = ["fancy"] }
pallas-addresses = "0.22.0" pallas-addresses = { git = "https://github.com/KtorZ/pallas.git", rev = "454b3bcf32cdc238aba65e4c3e4656a352480ec1" }
pallas-codec = { version = "0.22.0", features = ["num-bigint"] } pallas-codec = { git = "https://github.com/KtorZ/pallas.git", rev = "454b3bcf32cdc238aba65e4c3e4656a352480ec1", features = ["num-bigint"] }
pallas-crypto = "0.22.0" pallas-crypto = { git = "https://github.com/KtorZ/pallas.git", rev = "454b3bcf32cdc238aba65e4c3e4656a352480ec1" }
pallas-primitives = "0.22.0" pallas-primitives = { git = "https://github.com/KtorZ/pallas.git", rev = "454b3bcf32cdc238aba65e4c3e4656a352480ec1" }
pallas-traverse = "0.22.0" pallas-traverse = { git = "https://github.com/KtorZ/pallas.git", rev = "454b3bcf32cdc238aba65e4c3e4656a352480ec1" }
[profile.dev.package.insta] [profile.dev.package.insta]
opt-level = 3 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() wrap_args(elems.iter().map(|e| (self.wrap_expr(e), false))).group()
} }
UntypedExpr::Pair { fst, snd, .. } => "Pair" UntypedExpr::Pair { fst, snd, .. } => {
.to_doc() let elems = [fst, snd];
.append("(") "Pair"
.append(self.expr(fst, false)) .to_doc()
.append(break_(",", ", ")) .append(wrap_args(elems.iter().map(|e| (self.wrap_expr(e), false))).group())
.append(self.expr(snd, false)) }
.append(")")
.group(),
UntypedExpr::TupleIndex { index, tuple, .. } => { UntypedExpr::TupleIndex { index, tuple, .. } => {
let suffix = Ordinal(*index + 1).suffix().to_doc(); let suffix = Ordinal(*index + 1).suffix().to_doc();

View File

@ -6,10 +6,10 @@ use crate::{
}; };
pub fn parser( pub fn parser(
expression: Recursive<'_, Token, UntypedPattern, ParseError>, pattern: Recursive<'_, Token, UntypedPattern, ParseError>,
) -> impl Parser<Token, UntypedPattern, Error = ParseError> + '_ { ) -> impl Parser<Token, UntypedPattern, Error = ParseError> + '_ {
select! {Token::UpName { name } => name} select! {Token::UpName { name } => name}
.then(args(expression)) .then(args(pattern))
.map_with_span( .map_with_span(
|(name, (arguments, spread_location, is_record)), location| { |(name, (arguments, spread_location, is_record)), location| {
UntypedPattern::Constructor { UntypedPattern::Constructor {
@ -27,13 +27,13 @@ pub fn parser(
} }
pub(crate) fn args( 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> + '_ ) -> impl Parser<Token, (Vec<CallArg<UntypedPattern>>, Option<Span>, bool), Error = ParseError> + '_
{ {
let record_constructor_pattern_arg_parser = choice(( let record_constructor_pattern_arg_parser = choice((
select! {Token::Name {name} => name} select! {Token::Name {name} => name}
.then_ignore(just(Token::Colon)) .then_ignore(just(Token::Colon))
.then(expression.clone()) .then(pattern.clone())
.map_with_span(|(name, pattern), span| CallArg { .map_with_span(|(name, pattern), span| CallArg {
location: span, location: span,
label: Some(name), label: Some(name),
@ -59,7 +59,7 @@ pub(crate) fn args(
) )
.delimited_by(just(Token::LeftBrace), just(Token::RightBrace)); .delimited_by(just(Token::LeftBrace), just(Token::RightBrace));
let tuple_constructor_pattern_arg_parser = expression let tuple_constructor_pattern_arg_parser = pattern
.clone() .clone()
.map(|pattern| CallArg { .map(|pattern| CallArg {
location: pattern.location(), 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 schema;
pub mod validator; pub mod validator;
pub use error::Error;
use crate::{ use crate::{
config::{self, Config, PlutusVersion}, config::{self, Config, PlutusVersion},
module::CheckedModules, module::CheckedModules,
}; };
use aiken_lang::gen_uplc::CodeGenerator; use aiken_lang::gen_uplc::CodeGenerator;
use definitions::Definitions; use definitions::Definitions;
pub use error::Error;
use schema::{Annotated, Schema}; use schema::{Annotated, Schema};
use std::fmt::Debug; use std::fmt::Debug;
use validator::Validator; use validator::Validator;
@ -70,7 +69,7 @@ impl Blueprint {
let validators: Result<Vec<_>, Error> = modules let validators: Result<Vec<_>, Error> = modules
.validators() .validators()
.flat_map(|(validator, def)| { .flat_map(|(validator, def)| {
Validator::from_checked_module(modules, generator, validator, def) Validator::from_checked_module(modules, generator, validator, def, &config.plutus)
.into_iter() .into_iter()
.map(|result| { .map(|result| {
result.map(|mut schema| { result.map(|mut schema| {

View File

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

View File

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

View File

@ -83,7 +83,7 @@ pub fn exec(
let result = let result =
blueprint.with_validator(title, when_too_many, when_missing, |validator| match to { blueprint.with_validator(title, when_too_many, when_missing, |validator| match to {
Format::CardanoCli => { 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(); let mut double_cbor_bytes = Vec::new();

View File

@ -1,7 +1,7 @@
use miette::IntoDiagnostic; use miette::IntoDiagnostic;
use owo_colors::{OwoColorize, Stream::Stderr}; use owo_colors::{OwoColorize, Stream::Stderr};
use pallas_primitives::{ use pallas_primitives::{
babbage::{Redeemer, TransactionInput, TransactionOutput}, conway::{Redeemer, TransactionInput, TransactionOutput},
Fragment, Fragment,
}; };
use pallas_traverse::{Era, MultiEraTx}; use pallas_traverse::{Era, MultiEraTx};
@ -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},
}, },
}; };
@ -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!( eprintln!(
"{} {}", "{} {}",
@ -101,7 +101,7 @@ pub fn exec(
}) })
.collect(); .collect();
if let Some(tx_babbage) = tx.as_babbage() { if let Some(tx_conway) = tx.as_conway() {
let slot_config = SlotConfig { let slot_config = SlotConfig {
zero_time, zero_time,
zero_slot, zero_slot,
@ -110,17 +110,17 @@ pub fn exec(
let with_redeemer = |redeemer: &Redeemer| { let with_redeemer = |redeemer: &Redeemer| {
eprintln!( eprintln!(
"{} {:?} → {}", "{} {}[{}]",
" Redeemer" " 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
) )
}; };
let result = tx::eval_phase_two( let result = tx::eval_phase_two(
tx_babbage, tx_conway,
&resolved_inputs, &resolved_inputs,
None, None,
None, None,
@ -149,7 +149,14 @@ pub fn exec(
); );
} }
Err(err) => { 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); process::exit(1);
} }
} }
@ -157,46 +164,3 @@ pub fn exec(
Ok(()) 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] [dev-dependencies]
hex = "0.4.3" hex = "0.4.3"
indoc = "2.0.1" indoc = "2.0.1"
insta.workspace = true
pretty_assertions = "1.3.0" pretty_assertions = "1.3.0"
walkdir.workspace = true 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> { 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)?; let mut s = serializer.serialize_struct("Program<DeBruijn>", 2)?;
s.serialize_field("compiledCode", &hex::encode(&cbor))?; s.serialize_field("compiledCode", &compiled_code)?;
s.serialize_field("hash", &conway::PlutusV2Script(cbor.into()).compute_hash())?; s.serialize_field("hash", &hash)?;
s.end() 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> { fn deserialize<D: Deserializer<'a>>(deserializer: D) -> Result<Self, D::Error> {
#[derive(serde::Deserialize)] #[derive(serde::Deserialize)]
#[serde(field_identifier, rename_all = "camelCase")] #[serde(field_identifier, rename_all = "camelCase")]
enum Fields { enum Fields {
CompiledCode, CompiledCode,
Hash,
} }
struct ProgramVisitor; struct ProgramVisitor;
impl<'a> Visitor<'a> for ProgramVisitor { impl<'a> Visitor<'a> for ProgramVisitor {
type Value = Program<DeBruijn>; type Value = SerializableProgram;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 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 where
V: MapAccess<'a>, V: MapAccess<'a>,
{ {
let mut compiled_code: Option<String> = None; let mut compiled_code: Option<String> = None;
let mut hash: Option<String> = None;
while let Some(key) = map.next_key()? { while let Some(key) = map.next_key()? {
match key { match key {
Fields::CompiledCode => { Fields::CompiledCode => {
@ -151,11 +212,20 @@ impl<'a> Deserialize<'a> for Program<DeBruijn> {
} }
compiled_code = Some(map.next_value()?); 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 = let compiled_code =
compiled_code.ok_or_else(|| de::Error::missing_field("compiledCode"))?; 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 cbor_buffer = Vec::new();
let mut flat_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", &"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) deserializer.deserialize_struct("Program<DeBruijn>", FIELDS, ProgramVisitor)
} }
} }
@ -789,9 +878,13 @@ impl Program<NamedDeBruijn> {
impl Program<DeBruijn> { impl Program<DeBruijn> {
pub fn eval(&self, initial_budget: ExBudget) -> EvalResult { pub fn eval(&self, initial_budget: ExBudget) -> EvalResult {
let program: Program<NamedDeBruijn> = self.clone().into(); let program: Program<NamedDeBruijn> = self.clone().into();
program.eval(initial_budget) 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> { 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::{ use crate::{
ast::{ ast::{
Constant, DeBruijn, FakeNamedDeBruijn, Name, NamedDeBruijn, Program, Term, Type, Unique, Constant, DeBruijn, FakeNamedDeBruijn, Name, NamedDeBruijn, Program, Term, Type, Unique,
@ -15,6 +5,14 @@ use crate::{
builtins::DefaultFunction, builtins::DefaultFunction,
machine::runtime::Compressable, 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 BUILTIN_TAG_WIDTH: u32 = 7;
const CONST_TAG_WIDTH: u32 = 4; const CONST_TAG_WIDTH: u32 = 4;

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)

File diff suppressed because it is too large Load Diff

View File

@ -11,11 +11,21 @@ pub enum Error {
InvalidStepKind(u8), InvalidStepKind(u8),
#[error("Cannot evaluate an open term:\\n\\n{}", .0.to_pretty())] #[error("Cannot evaluate an open term:\\n\\n{}", .0.to_pretty())]
OpenTermEvaluated(Term<NamedDeBruijn>), OpenTermEvaluated(Term<NamedDeBruijn>),
#[error("The provided Plutus code called 'error'.")] #[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),
@ -29,9 +39,13 @@ pub enum Error {
PairTypeMismatch(Type), PairTypeMismatch(Type),
#[error("Empty List:\n\n{0:#?}")] #[error("Empty List:\n\n{0:#?}")]
EmptyList(Value), 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>), 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>), BuiltinTermArgumentExpected(Term<NamedDeBruijn>),
#[error("Unable to unlift value because it is not a constant:\n\n{0:#?}")] #[error("Unable to unlift value because it is not a constant:\n\n{0:#?}")]
NotAConstant(Value), NotAConstant(Value),
@ -49,15 +63,18 @@ pub enum Error {
Utf8(#[from] FromUtf8Error), Utf8(#[from] FromUtf8Error),
#[error("Out of Bounds\n\nindex: {}\nbytestring: {}\npossible: 0 - {}", .0, hex::encode(.1), .1.len() - 1)] #[error("Out of Bounds\n\nindex: {}\nbytestring: {}\npossible: 0 - {}", .0, hex::encode(.1), .1.len() - 1)]
ByteStringOutOfBounds(BigInt, Vec<u8>), ByteStringOutOfBounds(BigInt, Vec<u8>),
#[error("Attempt to consByteString something bigger than one byte {0}")] #[error("Attempt to consByteString something than isn't a byte between [0-255]: {0}")]
ByteStringConsBiggerThanOneByte(BigInt), ByteStringConsNotAByte(BigInt),
#[error("Divide By Zero\n\n{0} / {1}")] #[error("Divide By Zero\n\n{0} / {1}")]
DivideByZero(BigInt, BigInt), DivideByZero(BigInt, BigInt),
#[error("Ed25519S PublicKey should be 32 bytes but it was {0}")] #[error("Ed25519S PublicKey should be 32 bytes but it was {0}")]
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,
@ -79,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

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

View File

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

View File

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

View File

@ -1,10 +1,12 @@
use crate::{ use crate::{
ast::{Constant, Program, Term, Type}, ast::{Constant, Program, Term, Type},
flat::Binder, flat::Binder,
machine::runtime::{convert_tag_to_constr, Compressable}, machine::{
machine::value::from_pallas_bigint, 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 pretty::RcDoc;
use std::ascii::escape_default; 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::{ use crate::{
ast::{DeBruijn, Program}, ast::{DeBruijn, Program},
machine::cost_model::ExBudget, machine::cost_model::ExBudget,
PlutusData, PlutusData,
}; };
use error::Error;
use eval::get_script_and_datum_lookup_table; 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 error;
pub mod eval; pub mod eval;
@ -40,7 +36,7 @@ pub fn eval_phase_two(
) -> Result<Vec<Redeemer>, Error> { ) -> Result<Vec<Redeemer>, Error> {
let redeemers = tx.transaction_witness_set.redeemer.as_ref(); 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 { if run_phase_one {
// subset of phase 1 check on redeemers and scripts // 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()); let mut remaining_budget = *initial_budget.unwrap_or(&ExBudget::default());
for redeemer in rs.iter() { for (redeemer_key, redeemer_value) in rs.iter() {
with_redeemer(redeemer); 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( let redeemer = eval::eval_redeemer(
tx, tx,
utxos, utxos,
slot_config, slot_config,
redeemer, &redeemer,
&lookup_table, &lookup_table,
cost_mdls, cost_mdls,
&remaining_budget, &remaining_budget,
@ -93,7 +96,8 @@ pub fn eval_phase_two_raw(
run_phase_one: bool, run_phase_one: bool,
with_redeemer: fn(&Redeemer) -> (), with_redeemer: fn(&Redeemer) -> (),
) -> Result<Vec<Vec<u8>>, Error> { ) -> 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))?; .or_else(|_| MultiEraTx::decode_for_era(Era::Alonzo, tx_bytes))?;
let cost_mdls = CostMdls::decode_fragment(cost_mdls_bytes)?; let cost_mdls = CostMdls::decode_fragment(cost_mdls_bytes)?;
@ -119,7 +123,7 @@ pub fn eval_phase_two_raw(
}; };
match multi_era_tx { match multi_era_tx {
MultiEraTx::Babbage(tx) => { MultiEraTx::Conway(tx) => {
match eval_phase_two( match eval_phase_two(
&tx, &tx,
&utxos, &utxos,
@ -136,15 +140,12 @@ pub fn eval_phase_two_raw(
Err(err) => Err(err), Err(err) => Err(err),
} }
} }
// MultiEraTx::AlonzoCompatible(tx, _) => match eval_tx(&tx, &utxos, &sc) { _ => unimplemented!(
// Ok(redeemers) => Ok(redeemers r#"The transaction is serialized in an old era format. Because we're slightly lazy to
// .iter() maintain backward compatibility with every possible transaction format AND, because
// .map(|r| r.encode_fragment().unwrap()) those formats are mostly forward-compatible, you are kindly expected to provide a
// .collect()), transaction in a format suitable for the Conway era."#
// 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"),
} }
} }

View File

@ -2,62 +2,103 @@ use crate::{
machine::{self, cost_model::ExBudget}, machine::{self, cost_model::ExBudget},
TransactionInput, TransactionInput,
}; };
use pallas_primitives::conway::Language;
#[derive(thiserror::Error, Debug, miette::Diagnostic)] #[derive(thiserror::Error, Debug, miette::Diagnostic)]
pub enum Error { pub enum Error {
#[error("{0}")] #[error("{0}")]
Address(#[from] pallas_addresses::Error), 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, BadWithdrawalAddress,
#[error("{0}")] #[error("{0}")]
FlatDecode(#[from] pallas_codec::flat::de::Error), FlatDecode(#[from] pallas_codec::flat::de::Error),
#[error("{0}")] #[error("{0}")]
FragmentDecode(#[from] pallas_primitives::Error), 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>), 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, NativeScriptPhaseTwo,
#[error("Can't eval without redeemers")] #[error("can't eval without redeemers")]
NoRedeemers, 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 { RequiredRedeemersMismatch {
missing: Vec<String>, missing: Vec<String>,
extra: Vec<String>, extra: Vec<String>,
}, },
#[error("Extraneous redeemer")] #[error("extraneous redeemer")]
ExtraneousRedeemer, ExtraneousRedeemer,
#[error("Resolved Input not found.")] #[error("resolved Input not found")]
ResolvedInputNotFound(TransactionInput), ResolvedInputNotFound(TransactionInput),
#[error("A key hash cannot be the hash of a script.")] #[error("redeemer points to a non-script withdrawal")]
ScriptKeyHash, NonScriptWithdrawal,
#[error("PlutusV1 cost model not found.")] #[error("stake credential points to a non-script withdrawal")]
V1CostModelNotFound, NonScriptStakeCredential,
#[error("PlutusV2 cost model not found.")] #[error("the designated procedure defines no guardrail script")]
V2CostModelNotFound, NoGuardrailScriptForProcedure,
#[error("Wrong era, Please use Babbage or Alonzo: {0}")] #[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), 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, ByronAddressNotAllowed,
#[error("Inline datum not allowed in PlutusV1.")] #[error("inline datum not allowed when PlutusV1 scripts are present")]
InlineDatumNotAllowed, InlineDatumNotAllowed,
#[error("Script and input reference not allowed in PlutusV1.")] #[error("script and input reference not allowed in PlutusV1")]
ScriptAndInputRefNotAllowed, ScriptAndInputRefNotAllowed,
#[error("Address doesn't contain a payment credential.")] #[error("address doesn't contain a payment credential")]
NoPaymentCredential, NoPaymentCredential,
#[error("Missing required datum: {}", hash)] #[error("missing required datum\n{:>13} {}", "Datum", hash)]
MissingRequiredDatum { hash: String }, MissingRequiredDatum { hash: String },
#[error("Missing required script: {}", hash)] #[error("missing required script\n{:>13} {}", "Script", hash)]
MissingRequiredScript { hash: String }, 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, MissingRequiredInlineDatumOrHash,
#[error("Only stake deregistration and delegation are valid certificate script purposes.")] #[error("redeemer points to an unsupported certificate type")]
OnlyStakeDeregAndDelegAllowed, UnsupportedCertificateType,
#[error("Redeemer ({}, {}): {}", tag, index, err)] #[error("failed script execution\n{:>13} {}", format!("{}[{}]", tag, index), err)]
RedeemerError { RedeemerError {
tag: String, tag: String,
index: u32, index: u32,
err: Box<Error>, 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, 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::{ use super::{
error::Error, error::Error,
eval::{DataLookupTable, ScriptVersion}, script_context::{sort_voters, DataLookupTable, ResolvedInput, ScriptPurpose, ScriptVersion},
script_context::{ResolvedInput, ScriptPurpose},
}; };
use crate::tx::script_context::sort_reward_accounts;
use itertools::Itertools;
use pallas_addresses::{Address, ScriptHash, ShelleyPaymentPart, StakePayload}; use pallas_addresses::{Address, ScriptHash, ShelleyPaymentPart, StakePayload};
use pallas_codec::utils::{KeyValuePairs, MaybeIndefArray}; use pallas_codec::utils::Nullable;
use pallas_primitives::babbage::{ use pallas_primitives::conway::{
Certificate, MintedTx, PolicyId, RedeemerTag, RewardAccount, StakeCredential, TransactionOutput, Certificate, GovAction, MintedTx, PolicyId, RedeemerTag, RedeemersKey, RewardAccount,
StakeCredential, TransactionOutput, Voter,
}; };
use std::collections::HashMap; use std::collections::HashMap;
// TODO: include in pallas eventually? type ScriptsNeeded = Vec<(ScriptPurpose, ScriptHash)>;
#[derive(Debug, PartialEq, Clone)]
struct RedeemerPtr {
tag: RedeemerTag,
index: u32,
}
type AlonzoScriptsNeeded = Vec<(ScriptPurpose, ScriptHash)>;
// subset of phase-1 ledger checks related to scripts // subset of phase-1 ledger checks related to scripts
pub fn eval_phase_one( pub fn eval_phase_one(
@ -35,7 +30,7 @@ pub fn eval_phase_one(
} }
pub fn validate_missing_scripts( pub fn validate_missing_scripts(
needed: &AlonzoScriptsNeeded, needed: &ScriptsNeeded,
txscripts: HashMap<ScriptHash, ScriptVersion>, txscripts: HashMap<ScriptHash, ScriptVersion>,
) -> Result<(), Error> { ) -> Result<(), Error> {
let received_hashes = txscripts.keys().copied().collect::<Vec<ScriptHash>>(); let received_hashes = txscripts.keys().copied().collect::<Vec<ScriptHash>>();
@ -46,32 +41,23 @@ pub fn validate_missing_scripts(
.clone() .clone()
.into_iter() .into_iter()
.filter(|x| !received_hashes.contains(x)) .filter(|x| !received_hashes.contains(x))
.map(|x| format!("[Missing (sh: {x})]")) .map(|x| x.to_string())
.collect(); .collect();
let extra: Vec<_> = received_hashes let extra: Vec<_> = received_hashes
.into_iter() .into_iter()
.filter(|x| !needed_hashes.contains(x)) .filter(|x| !needed_hashes.contains(x))
.map(|x| format!("[Extraneous (sh: {x:?})]")) .map(|x| x.to_string())
.collect(); .collect();
if !missing.is_empty() || !extra.is_empty() { if !missing.is_empty() || !extra.is_empty() {
let missing_errors = missing.join(" "); return Err(Error::RequiredRedeemersMismatch { missing, extra });
let extra_errors = extra.join(" ");
unreachable!(
"Mismatch in required scripts: {} {}",
missing_errors, extra_errors
);
} }
Ok(()) Ok(())
} }
pub fn scripts_needed( pub fn scripts_needed(tx: &MintedTx, utxos: &[ResolvedInput]) -> Result<ScriptsNeeded, Error> {
tx: &MintedTx,
utxos: &[ResolvedInput],
) -> Result<AlonzoScriptsNeeded, Error> {
let mut needed = Vec::new(); let mut needed = Vec::new();
let txb = tx.transaction_body.clone(); let txb = tx.transaction_body.clone();
@ -91,61 +77,119 @@ pub fn scripts_needed(
if let Address::Shelley(a) = address { if let Address::Shelley(a) = address {
if let ShelleyPaymentPart::Script(h) = a.payment() { 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 let mut reward = txb
.withdrawals .withdrawals
.as_ref() .as_deref()
.unwrap_or(&KeyValuePairs::Indef(vec![])) .map(|w| {
.iter() w.iter()
.filter_map(|(acnt, _)| { .filter_map(|(acnt, _)| {
let address = Address::from_bytes(acnt).unwrap(); let address = Address::from_bytes(acnt).unwrap();
if let Address::Stake(a) = address { if let Address::Stake(a) = address {
if let StakePayload::Script(h) = a.payload() { if let StakePayload::Script(h) = a.payload() {
let cred = StakeCredential::Scripthash(*h); let cred = StakeCredential::Scripthash(*h);
return Some((ScriptPurpose::Rewarding(cred), *h)); return Some((ScriptPurpose::Rewarding(cred), *h));
} }
} }
None None
})
.collect::<ScriptsNeeded>()
}) })
.collect::<AlonzoScriptsNeeded>(); .unwrap_or_default();
let mut cert = txb let mut cert = txb
.certificates .certificates
.clone() .as_deref()
.unwrap_or_default() .map(|m| {
.iter() m.iter()
.filter_map(|cert| { .enumerate()
// only Dereg and Deleg certs can require scripts .filter_map(|(ix, cert)| match cert {
match cert { Certificate::StakeDeregistration(StakeCredential::Scripthash(h))
Certificate::StakeDeregistration(StakeCredential::Scripthash(h)) => { | Certificate::UnReg(StakeCredential::Scripthash(h), _)
Some((ScriptPurpose::Certifying(cert.clone()), *h)) | Certificate::VoteDeleg(StakeCredential::Scripthash(h), _)
} | Certificate::VoteRegDeleg(StakeCredential::Scripthash(h), _, _)
Certificate::StakeDelegation(StakeCredential::Scripthash(h), _) => { | Certificate::StakeVoteDeleg(StakeCredential::Scripthash(h), _, _)
Some((ScriptPurpose::Certifying(cert.clone()), *h)) | Certificate::StakeRegDeleg(StakeCredential::Scripthash(h), _, _)
} | Certificate::StakeVoteRegDeleg(StakeCredential::Scripthash(h), _, _, _)
_ => None, | 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 let mut mint = txb
.mint .mint
.as_ref() .as_deref()
.unwrap_or(&KeyValuePairs::Indef(vec![])) .map(|m| {
.iter() m.iter()
.map(|(policy_id, _)| (ScriptPurpose::Minting(*policy_id), *policy_id)) .map(|(policy_id, _)| (ScriptPurpose::Minting(*policy_id), *policy_id))
.collect::<AlonzoScriptsNeeded>(); .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 spend);
needed.append(&mut reward); needed.append(&mut reward);
needed.append(&mut cert); needed.append(&mut cert);
needed.append(&mut mint); needed.append(&mut mint);
needed.append(&mut propose);
needed.append(&mut voting);
Ok(needed) Ok(needed)
} }
@ -153,58 +197,58 @@ pub fn scripts_needed(
/// hasExactSetOfRedeemers in Ledger Spec, but we pass `txscripts` directly /// hasExactSetOfRedeemers in Ledger Spec, but we pass `txscripts` directly
pub fn has_exact_set_of_redeemers( pub fn has_exact_set_of_redeemers(
tx: &MintedTx, tx: &MintedTx,
needed: &AlonzoScriptsNeeded, needed: &ScriptsNeeded,
tx_scripts: HashMap<ScriptHash, ScriptVersion>, tx_scripts: HashMap<ScriptHash, ScriptVersion>,
) -> Result<(), Error> { ) -> Result<(), Error> {
let mut redeemers_needed = Vec::new(); let mut redeemers_needed = Vec::new();
for (script_purpose, script_hash) in needed { 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); 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 { match script {
ScriptVersion::V1(_) => { ScriptVersion::V1(_) => {
redeemers_needed.push((ptr, script_purpose.clone(), *script_hash)) redeemers_needed.push((key, script_purpose.clone(), *script_hash))
} }
ScriptVersion::V2(_) => { 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(_) => (), ScriptVersion::Native(_) => (),
} }
} }
} }
let wits_redeemer_ptrs: Vec<RedeemerPtr> = tx let wits_redeemer_keys: Vec<&RedeemersKey> = tx
.transaction_witness_set .transaction_witness_set
.redeemer .redeemer
.as_ref() .as_deref()
.unwrap_or(&MaybeIndefArray::Indef(vec![])) .map(|m| m.iter().map(|(k, _)| k).collect())
.iter() .unwrap_or_default();
.map(|r| RedeemerPtr {
tag: r.tag.clone(),
index: r.index,
})
.collect();
let needed_redeemer_ptrs: Vec<RedeemerPtr> = let needed_redeemer_keys: Vec<RedeemersKey> =
redeemers_needed.iter().map(|x| x.0.clone()).collect(); redeemers_needed.iter().map(|x| x.0.clone()).collect();
let missing: Vec<_> = redeemers_needed let missing: Vec<_> = redeemers_needed
.into_iter() .into_iter()
.filter(|x| !wits_redeemer_ptrs.contains(&x.0)) .filter(|x| !wits_redeemer_keys.contains(&&x.0))
.map(|x| { .map(|x| {
format!( 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(); .collect();
let extra: Vec<_> = wits_redeemer_ptrs let extra: Vec<_> = wits_redeemer_keys
.into_iter() .into_iter()
.filter(|x| !needed_redeemer_ptrs.contains(x)) .filter(|x| !needed_redeemer_keys.contains(x))
.map(|x| format!("[Extraneous (redeemer_ptr: {x:?})]")) .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() {
@ -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 /// 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 /// according to the type of the script purpose, and the index according to the
/// placement of script purpose inside its container. /// placement of script purpose inside its container.
fn build_redeemer_ptr( fn build_redeemer_key(
tx: &MintedTx, tx: &MintedTx,
script_purpose: &ScriptPurpose, script_purpose: &ScriptPurpose,
) -> Result<Option<RedeemerPtr>, Error> { ) -> Result<Option<RedeemersKey>, Error> {
let tx_body = tx.transaction_body.clone(); let tx_body = tx.transaction_body.clone();
match script_purpose { match script_purpose {
ScriptPurpose::Minting(hash) => { ScriptPurpose::Minting(hash) => {
let mut policy_ids = tx_body let policy_ids: Vec<&PolicyId> = tx_body
.mint .mint
.as_ref() .as_deref()
.unwrap_or(&KeyValuePairs::Indef(vec![])) .map(|m| m.iter().map(|(policy_id, _)| policy_id).sorted().collect())
.iter() .unwrap_or_default();
.map(|(policy_id, _)| *policy_id)
.collect::<Vec<PolicyId>>();
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); Ok(redeemer_key)
match maybe_idx {
Some(idx) => Ok(Some(RedeemerPtr {
tag: RedeemerTag::Mint,
index: idx as u32,
})),
None => Ok(None),
}
} }
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); ScriptPurpose::Spending(txin, ()) => {
let redeemer_key = tx_body
match maybe_idx { .inputs
Some(idx) => Ok(Some(RedeemerPtr { .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, tag: RedeemerTag::Spend,
index: idx as u32, index: index as u32,
})), });
None => Ok(None),
} Ok(redeemer_key)
} }
ScriptPurpose::Rewarding(racnt) => { ScriptPurpose::Rewarding(racnt) => {
let mut reward_accounts = tx_body let mut reward_accounts: Vec<&RewardAccount> = tx_body
.withdrawals .withdrawals
.as_ref() .as_deref()
.unwrap_or(&KeyValuePairs::Indef(vec![])) .map(|m| m.iter().map(|(acnt, _)| acnt).collect())
.iter() .unwrap_or_default();
.map(|(acnt, _)| acnt.clone())
.collect::<Vec<RewardAccount>>();
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() { for (idx, x) in reward_accounts.iter().enumerate() {
let cred = match Address::from_bytes(x).unwrap() { let cred = match Address::from_bytes(x).unwrap() {
@ -288,33 +328,72 @@ fn build_redeemer_ptr(
}; };
if cred == Some(racnt.to_owned()) { if cred == Some(racnt.to_owned()) {
maybe_idx = Some(idx); redeemer_key = Some(RedeemersKey {
tag: RedeemerTag::Reward,
index: idx as u32,
});
} }
} }
match maybe_idx { Ok(redeemer_key)
Some(idx) => Ok(Some(RedeemerPtr {
tag: RedeemerTag::Reward,
index: idx as u32,
})),
None => Ok(None),
}
} }
ScriptPurpose::Certifying(d) => {
let maybe_idx = tx_body
.certificates
.as_ref()
.unwrap_or(&MaybeIndefArray::Indef(vec![]))
.iter()
.position(|x| x == d);
match maybe_idx { ScriptPurpose::Certifying(_, d) => {
Some(idx) => Ok(Some(RedeemerPtr { 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, tag: RedeemerTag::Cert,
index: idx as u32, index: index as u32,
})), });
None => Ok(None),
} 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_codec::utils::MaybeIndefArray;
use pallas_primitives::{ use pallas_primitives::{
babbage::{CostMdls, TransactionInput, TransactionOutput}, conway::{CostMdls, TransactionInput, TransactionOutput},
Fragment, Fragment,
}; };
use pallas_traverse::{Era, MultiEraTx}; use pallas_traverse::{Era, MultiEraTx};
use crate::machine::cost_model::ExBudget;
use super::{eval_phase_two, ResolvedInput, SlotConfig};
#[test] #[test]
fn test_eval_0() { fn test_eval_0() {
/* /*
@ -227,6 +225,7 @@ fn test_eval_0() {
let cost_mdl = CostMdls { let cost_mdl = CostMdls {
plutus_v1: None, plutus_v1: None,
plutus_v2: Some(costs), plutus_v2: Some(costs),
plutus_v3: None,
}; };
let initial_budget = ExBudget { let initial_budget = ExBudget {
@ -234,11 +233,12 @@ fn test_eval_0() {
mem: 14000000, 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)) .or_else(|_| MultiEraTx::decode_for_era(Era::Alonzo, &tx_bytes))
.unwrap(); .unwrap();
match multi_era_tx { match multi_era_tx {
MultiEraTx::Babbage(tx) => { MultiEraTx::Conway(tx) => {
let redeemers = eval_phase_two( let redeemers = eval_phase_two(
&tx, &tx,
&utxos, &utxos,
@ -497,6 +497,7 @@ fn test_eval_1() {
let cost_mdl = CostMdls { let cost_mdl = CostMdls {
plutus_v1: None, plutus_v1: None,
plutus_v2: Some(costs), plutus_v2: Some(costs),
plutus_v3: None,
}; };
let initial_budget = ExBudget { let initial_budget = ExBudget {
@ -504,11 +505,13 @@ fn test_eval_1() {
mem: 14000000, 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)) .or_else(|_| MultiEraTx::decode_for_era(Era::Alonzo, &tx_bytes))
.unwrap(); .unwrap();
match multi_era_tx { match multi_era_tx {
MultiEraTx::Babbage(tx) => { MultiEraTx::Conway(tx) => {
let redeemers = eval_phase_two( let redeemers = eval_phase_two(
&tx, &tx,
&utxos, &utxos,
@ -606,6 +609,7 @@ fn test_eval_2() {
let cost_mdl = CostMdls { let cost_mdl = CostMdls {
plutus_v1: Some(costs), plutus_v1: Some(costs),
plutus_v2: None, plutus_v2: None,
plutus_v3: None,
}; };
let initial_budget = ExBudget { let initial_budget = ExBudget {
@ -613,11 +617,12 @@ fn test_eval_2() {
mem: 14000000, 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)) .or_else(|_| MultiEraTx::decode_for_era(Era::Alonzo, &tx_bytes))
.unwrap(); .unwrap();
match multi_era_tx { match multi_era_tx {
MultiEraTx::Babbage(tx) => { MultiEraTx::Conway(tx) => {
let redeemers = eval_phase_two( let redeemers = eval_phase_two(
&tx, &tx,
&utxos, &utxos,
@ -874,6 +879,7 @@ fn test_eval_3() {
let cost_mdl = CostMdls { let cost_mdl = CostMdls {
plutus_v1: None, plutus_v1: None,
plutus_v2: Some(costs), plutus_v2: Some(costs),
plutus_v3: None,
}; };
let initial_budget = ExBudget { let initial_budget = ExBudget {
@ -881,11 +887,12 @@ fn test_eval_3() {
mem: 14000000, 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)) .or_else(|_| MultiEraTx::decode_for_era(Era::Alonzo, &tx_bytes))
.unwrap(); .unwrap();
match multi_era_tx { match multi_era_tx {
MultiEraTx::Babbage(tx) => { MultiEraTx::Conway(tx) => {
let redeemers = eval_phase_two( let redeemers = eval_phase_two(
&tx, &tx,
&utxos, &utxos,
@ -980,6 +987,7 @@ fn test_eval_4() {
let cost_mdl = CostMdls { let cost_mdl = CostMdls {
plutus_v1: Some(costs), plutus_v1: Some(costs),
plutus_v2: None, plutus_v2: None,
plutus_v3: None,
}; };
let initial_budget = ExBudget { let initial_budget = ExBudget {
@ -987,11 +995,12 @@ fn test_eval_4() {
mem: 14000000, 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)) .or_else(|_| MultiEraTx::decode_for_era(Era::Alonzo, &tx_bytes))
.unwrap(); .unwrap();
match multi_era_tx { match multi_era_tx {
MultiEraTx::Babbage(tx) => { MultiEraTx::Conway(tx) => {
assert!(eval_phase_two( assert!(eval_phase_two(
&tx, &tx,
&utxos, &utxos,
@ -1063,6 +1072,7 @@ fn test_eval_5() {
let cost_mdl = CostMdls { let cost_mdl = CostMdls {
plutus_v1: Some(costs), plutus_v1: Some(costs),
plutus_v2: None, plutus_v2: None,
plutus_v3: None,
}; };
let initial_budget = ExBudget { let initial_budget = ExBudget {
@ -1070,11 +1080,12 @@ fn test_eval_5() {
mem: 14000000, 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)) .or_else(|_| MultiEraTx::decode_for_era(Era::Alonzo, &tx_bytes))
.unwrap(); .unwrap();
match multi_era_tx { match multi_era_tx {
MultiEraTx::Babbage(tx) => { MultiEraTx::Conway(tx) => {
let redeemers = eval_phase_two( let redeemers = eval_phase_two(
&tx, &tx,
&utxos, &utxos,
@ -1171,6 +1182,7 @@ fn test_eval_6() {
let cost_mdl = CostMdls { let cost_mdl = CostMdls {
plutus_v1: Some(costs), plutus_v1: Some(costs),
plutus_v2: None, plutus_v2: None,
plutus_v3: None,
}; };
let initial_budget = ExBudget { let initial_budget = ExBudget {
@ -1178,11 +1190,12 @@ fn test_eval_6() {
mem: 14000000, 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)) .or_else(|_| MultiEraTx::decode_for_era(Era::Alonzo, &tx_bytes))
.unwrap(); .unwrap();
match multi_era_tx { match multi_era_tx {
MultiEraTx::Babbage(tx) => { MultiEraTx::Conway(tx) => {
let redeemers = eval_phase_two( let redeemers = eval_phase_two(
&tx, &tx,
&utxos, &utxos,
@ -1279,6 +1292,7 @@ fn test_eval_7() {
let cost_mdl = CostMdls { let cost_mdl = CostMdls {
plutus_v1: Some(costs), plutus_v1: Some(costs),
plutus_v2: None, plutus_v2: None,
plutus_v3: None,
}; };
let initial_budget = ExBudget { let initial_budget = ExBudget {
@ -1286,11 +1300,12 @@ fn test_eval_7() {
mem: 14000000, 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)) .or_else(|_| MultiEraTx::decode_for_era(Era::Alonzo, &tx_bytes))
.unwrap(); .unwrap();
match multi_era_tx { match multi_era_tx {
MultiEraTx::Babbage(tx) => { MultiEraTx::Conway(tx) => {
let redeemers = eval_phase_two( let redeemers = eval_phase_two(
&tx, &tx,
&utxos, &utxos,
@ -1538,6 +1553,7 @@ fn test_eval_8() {
let cost_mdl = CostMdls { let cost_mdl = CostMdls {
plutus_v1: None, plutus_v1: None,
plutus_v2: Some(costs), plutus_v2: Some(costs),
plutus_v3: None,
}; };
let initial_budget = ExBudget { let initial_budget = ExBudget {
@ -1545,11 +1561,12 @@ fn test_eval_8() {
mem: 14000000, 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)) .or_else(|_| MultiEraTx::decode_for_era(Era::Alonzo, &tx_bytes))
.unwrap(); .unwrap();
match multi_era_tx { match multi_era_tx {
MultiEraTx::Babbage(tx) => { MultiEraTx::Conway(tx) => {
let redeemers = eval_phase_two( let redeemers = eval_phase_two(
&tx, &tx,
&utxos, &utxos,
@ -1593,12 +1610,13 @@ fn test_eval_8() {
fn eval_missing_redeemer() { fn eval_missing_redeemer() {
let tx_bytes = hex::decode("84a30082825820275b5da338c8b899035081eb34bfa950b634911a5dd3271b3ad6cf4c2bba0c5000825820275b5da338c8b899035081eb34bfa950b634911a5dd3271b3ad6cf4c2bba0c50010181825839000af00cc47500bb64cfffb783e8c42f746b4e8b8a70ede9c08c7113acf3bde34d1041f5a2076ef9aa6cf4539ab1a96ed462a0300acbdb65d51a02cf47c8021a00028d89a1068149480100002221200101f5f6").unwrap(); 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)) .or_else(|_| MultiEraTx::decode_for_era(Era::Alonzo, &tx_bytes))
.unwrap(); .unwrap();
let inputs = multi_era_tx let inputs = multi_era_tx
.as_babbage() .as_conway()
.unwrap() .unwrap()
.transaction_body .transaction_body
.inputs .inputs
@ -1641,6 +1659,7 @@ fn eval_missing_redeemer() {
let cost_mdl = CostMdls { let cost_mdl = CostMdls {
plutus_v1: Some(costs), plutus_v1: Some(costs),
plutus_v2: None, plutus_v2: None,
plutus_v3: None,
}; };
let initial_budget = ExBudget { let initial_budget = ExBudget {
@ -1648,12 +1667,13 @@ fn eval_missing_redeemer() {
mem: 14000000, 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)) .or_else(|_| MultiEraTx::decode_for_era(Era::Alonzo, &tx_bytes))
.unwrap(); .unwrap();
match multi_era_tx { match multi_era_tx {
MultiEraTx::Babbage(tx) => { MultiEraTx::Conway(tx) => {
eval_phase_two( eval_phase_two(
&tx, &tx,
&utxos, &utxos,
@ -1673,12 +1693,13 @@ fn eval_missing_redeemer() {
fn eval_extraneous_redeemer() { fn eval_extraneous_redeemer() {
let tx_bytes = hex::decode("84a70082825820275b5da338c8b899035081eb34bfa950b634911a5dd3271b3ad6cf4c2bba0c5000825820275b5da338c8b899035081eb34bfa950b634911a5dd3271b3ad6cf4c2bba0c50010181825839000af00cc47500bb64cfffb783e8c42f746b4e8b8a70ede9c08c7113acf3bde34d1041f5a2076ef9aa6cf4539ab1a96ed462a0300acbdb65d51a02cf2b47021a0002aa0a0b5820fc54f302cff3a8a1cb374f5e4979e18a1d3627dcf4539637b03f5959eb8565bf0d81825820275b5da338c8b899035081eb34bfa950b634911a5dd3271b3ad6cf4c2bba0c500110825839000af00cc47500bb64cfffb783e8c42f746b4e8b8a70ede9c08c7113acf3bde34d1041f5a2076ef9aa6cf4539ab1a96ed462a0300acbdb65d51a02af51c2111a0003ff0fa40081825820065dd553fbe4e240a8f819bb9e333a7483de4a22b65c7fb6a95ce9450f84dff758402c26125a057a696079d08f2c8c9d2b8ccda9fe7cf7360c1a86712b85a91db82a3b80996b30ba6f4b2f969c93eb50694e0f6ea0bcf129080dcc07ecd9e605f00a049fd87980ff0582840000d879808219044c1a000382d48401001864821903e81903e8068149480100002221200101f5f6").unwrap(); 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)) .or_else(|_| MultiEraTx::decode_for_era(Era::Alonzo, &tx_bytes))
.unwrap(); .unwrap();
let inputs = multi_era_tx let inputs = multi_era_tx
.as_babbage() .as_conway()
.unwrap() .unwrap()
.transaction_body .transaction_body
.inputs .inputs
@ -1721,6 +1742,7 @@ fn eval_extraneous_redeemer() {
let cost_mdl = CostMdls { let cost_mdl = CostMdls {
plutus_v1: Some(costs), plutus_v1: Some(costs),
plutus_v2: None, plutus_v2: None,
plutus_v3: None,
}; };
let initial_budget = ExBudget { let initial_budget = ExBudget {
@ -1728,12 +1750,13 @@ fn eval_extraneous_redeemer() {
mem: 14000000, 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)) .or_else(|_| MultiEraTx::decode_for_era(Era::Alonzo, &tx_bytes))
.unwrap(); .unwrap();
match multi_era_tx { match multi_era_tx {
MultiEraTx::Babbage(tx) => { MultiEraTx::Conway(tx) => {
assert!(eval_phase_two( assert!(eval_phase_two(
&tx, &tx,
&utxos, &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