implement a strict subset of PlutusV3 transaction info

More specifically, that is simply mimicking the script context from
  v2, minus the new governance features.
This commit is contained in:
KtorZ 2024-08-08 23:01:17 +02:00
parent c454dc72eb
commit fdf7a81288
No known key found for this signature in database
GPG Key ID: 33173CB6F77F4277
5 changed files with 135 additions and 24 deletions

View File

@ -96,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)?;

View File

@ -6,7 +6,7 @@ use super::{
use crate::{ use crate::{
ast::{FakeNamedDeBruijn, NamedDeBruijn, Program}, ast::{FakeNamedDeBruijn, NamedDeBruijn, Program},
machine::cost_model::ExBudget, machine::cost_model::ExBudget,
tx::script_context::{DataLookupTable, ScriptVersion, TxInfoV1, TxInfoV2}, tx::script_context::{DataLookupTable, ScriptVersion, TxInfoV1, TxInfoV2, TxInfoV3},
PlutusData, PlutusData,
}; };
use pallas_codec::utils::Bytes; use pallas_codec::utils::Bytes;
@ -116,7 +116,22 @@ pub fn eval_redeemer(
program(script.0)?, program(script.0)?,
), ),
(ScriptVersion::V3(_script), _datum) => todo!(), (ScriptVersion::V3(script), datum) => do_eval_redeemer(
cost_mdls_opt
.map(|cost_mdls| {
cost_mdls
.plutus_v3
.as_ref()
.ok_or(Error::CostModelNotFound(Language::PlutusV3))
})
.transpose()?,
initial_budget,
&Language::PlutusV3,
datum,
redeemer,
TxInfoV3::from_transaction(tx, utxos, slot_config)?,
program(script.0)?,
),
} }
.map_err(|err| Error::RedeemerError { .map_err(|err| Error::RedeemerError {
tag: redeemer_tag_to_string(&redeemer.tag), tag: redeemer_tag_to_string(&redeemer.tag),

View File

@ -10,7 +10,7 @@ use pallas_primitives::conway::{
}; };
use std::collections::HashMap; use std::collections::HashMap;
type AlonzoScriptsNeeded = Vec<(ScriptPurpose, ScriptHash)>; type ScriptsNeeded = 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(
@ -28,7 +28,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>>();
@ -61,10 +61,7 @@ pub fn validate_missing_scripts(
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();
@ -106,7 +103,7 @@ pub fn scripts_needed(
None None
}) })
.collect::<AlonzoScriptsNeeded>() .collect::<ScriptsNeeded>()
}) })
.unwrap_or_default(); .unwrap_or_default();
@ -127,7 +124,7 @@ pub fn scripts_needed(
_ => None, _ => None,
} }
}) })
.collect::<AlonzoScriptsNeeded>() .collect::<ScriptsNeeded>()
}) })
.unwrap_or_default(); .unwrap_or_default();
@ -137,7 +134,7 @@ pub fn scripts_needed(
.map(|m| { .map(|m| {
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(); .unwrap_or_default();
@ -156,7 +153,7 @@ 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();

View File

@ -27,6 +27,7 @@ pub struct TxInInfo {
pub out_ref: TransactionInput, pub out_ref: TransactionInput,
pub resolved: TxOut, pub resolved: TxOut,
} }
#[derive(Debug, PartialEq, Clone)] #[derive(Debug, PartialEq, Clone)]
pub enum TxOut { pub enum TxOut {
V1(TransactionOutput), V1(TransactionOutput),
@ -290,15 +291,51 @@ impl TxInfoV2 {
} }
} }
pub struct TxInfoV3 {} #[derive(Debug, PartialEq, Clone)]
pub struct TxInfoV3 {
pub inputs: Vec<TxInInfo>,
pub reference_inputs: Vec<TxInInfo>,
pub outputs: Vec<TxOut>,
pub fee: Value,
pub mint: MintValue,
pub certificates: Vec<Certificate>,
pub withdrawals: KeyValuePairs<Address, Coin>,
pub valid_range: TimeRange,
pub signatories: Vec<AddrKeyhash>,
pub redeemers: KeyValuePairs<ScriptPurpose, Redeemer>,
pub data: KeyValuePairs<DatumHash, PlutusData>,
// TODO:
// votes : KeyValuePairs<Voter, KeyValuePairs<GovernanceActionId, Vote>>
// proposalProcedures : Vec<ProposalProcedure>
// currentTreasuryAmount : Option<Coin>
// treasuryDonation : Option<Coin>
pub id: Hash<32>,
}
impl TxInfoV3 { impl TxInfoV3 {
pub fn from_transaction( pub fn from_transaction(
_tx: &MintedTx, tx: &MintedTx,
_utxos: &[ResolvedInput], utxos: &[ResolvedInput],
_slot_config: &SlotConfig, slot_config: &SlotConfig,
) -> Result<TxInfo, Error> { ) -> Result<TxInfo, Error> {
todo!("TxInfoV3") if let TxInfo::V2(tx_info_v2) = TxInfoV2::from_transaction(tx, utxos, slot_config)? {
Ok(TxInfo::V3(TxInfoV3 {
inputs: tx_info_v2.inputs,
reference_inputs: tx_info_v2.reference_inputs,
outputs: tx_info_v2.outputs,
fee: tx_info_v2.fee,
mint: tx_info_v2.mint,
certificates: tx_info_v2.certificates,
withdrawals: tx_info_v2.withdrawals,
valid_range: tx_info_v2.valid_range,
signatories: tx_info_v2.signatories,
redeemers: tx_info_v2.redeemers,
data: tx_info_v2.data,
id: tx_info_v2.id,
}))
} else {
unreachable!()
}
} }
} }
@ -306,12 +343,15 @@ impl TxInfoV3 {
pub enum TxInfo { pub enum TxInfo {
V1(TxInfoV1), V1(TxInfoV1),
V2(TxInfoV2), V2(TxInfoV2),
V3(TxInfoV3),
} }
impl TxInfo { impl TxInfo {
pub fn purpose(&self, needle: &Redeemer) -> Option<ScriptPurpose> { pub fn purpose(&self, needle: &Redeemer) -> Option<ScriptPurpose> {
match self { match self {
TxInfo::V1(TxInfoV1 { redeemers, .. }) | TxInfo::V2(TxInfoV2 { redeemers, .. }) => { TxInfo::V1(TxInfoV1 { redeemers, .. })
| TxInfo::V2(TxInfoV2 { redeemers, .. })
| TxInfo::V3(TxInfoV3 { redeemers, .. }) => {
redeemers.iter().find_map(|(purpose, redeemer)| { redeemers.iter().find_map(|(purpose, redeemer)| {
if redeemer == needle { if redeemer == needle {
Some(purpose.clone()) Some(purpose.clone())
@ -327,6 +367,7 @@ impl TxInfo {
match self { match self {
TxInfo::V1(info) => &info.inputs, TxInfo::V1(info) => &info.inputs,
TxInfo::V2(info) => &info.inputs, TxInfo::V2(info) => &info.inputs,
TxInfo::V3(info) => &info.inputs,
} }
} }
@ -334,6 +375,7 @@ impl TxInfo {
match self { match self {
TxInfo::V1(info) => &info.mint, TxInfo::V1(info) => &info.mint,
TxInfo::V2(info) => &info.mint, TxInfo::V2(info) => &info.mint,
TxInfo::V3(info) => &info.mint,
} }
} }
@ -341,6 +383,7 @@ impl TxInfo {
match self { match self {
TxInfo::V1(info) => &info.withdrawals[..], TxInfo::V1(info) => &info.withdrawals[..],
TxInfo::V2(info) => &info.withdrawals[..], TxInfo::V2(info) => &info.withdrawals[..],
TxInfo::V3(info) => &info.withdrawals[..],
} }
} }
@ -348,6 +391,7 @@ impl TxInfo {
match self { match self {
TxInfo::V1(info) => &info.certificates[..], TxInfo::V1(info) => &info.certificates[..],
TxInfo::V2(info) => &info.certificates[..], TxInfo::V2(info) => &info.certificates[..],
TxInfo::V3(info) => &info.certificates[..],
} }
} }
} }

View File

@ -36,6 +36,8 @@ fn empty_constr(index: u64) -> PlutusData {
}) })
} }
struct WithWrappedTransactionId<'a, T>(&'a T);
pub trait ToPlutusData { pub trait ToPlutusData {
fn to_plutus_data(&self) -> PlutusData; fn to_plutus_data(&self) -> PlutusData;
} }
@ -98,12 +100,24 @@ impl ToPlutusData for Address {
} }
} }
impl<'a> ToPlutusData for WithWrappedTransactionId<'a, TransactionInput> {
fn to_plutus_data(&self) -> PlutusData {
wrap_multiple_with_constr(
0,
vec![
wrap_with_constr(0, self.0.transaction_id.to_plutus_data()),
PlutusData::BigInt(BigInt::Int((self.0.index as i128).try_into().unwrap())),
],
)
}
}
impl ToPlutusData for TransactionInput { impl ToPlutusData for TransactionInput {
fn to_plutus_data(&self) -> PlutusData { fn to_plutus_data(&self) -> PlutusData {
wrap_multiple_with_constr( wrap_multiple_with_constr(
0, 0,
vec![ vec![
wrap_with_constr(0, self.transaction_id.to_plutus_data()), self.transaction_id.to_plutus_data(),
PlutusData::BigInt(BigInt::Int((self.index as i128).try_into().unwrap())), PlutusData::BigInt(BigInt::Int((self.index as i128).try_into().unwrap())),
], ],
) )
@ -299,7 +313,7 @@ impl ToPlutusData for TxOut {
// legacy_output.datum_hash.to_plutus_data(), // legacy_output.datum_hash.to_plutus_data(),
// ], // ],
// ), // ),
TransactionOutput::Legacy(..) => todo!("TransactionOutput::Legacy"), TransactionOutput::Legacy(..) => unimplemented!("TransactionOutput::Legacy"),
TransactionOutput::PostAlonzo(post_alonzo_output) => wrap_multiple_with_constr( TransactionOutput::PostAlonzo(post_alonzo_output) => wrap_multiple_with_constr(
0, 0,
vec![ vec![
@ -329,7 +343,7 @@ impl ToPlutusData for TxOut {
// None::<ScriptRef>.to_plutus_data(), // None::<ScriptRef>.to_plutus_data(),
// ], // ],
// ), // ),
TransactionOutput::Legacy(..) => todo!("TransactionOutput::Legacy"), TransactionOutput::Legacy(..) => unimplemented!("TransactionOutput::Legacy"),
TransactionOutput::PostAlonzo(post_alonzo_output) => wrap_multiple_with_constr( TransactionOutput::PostAlonzo(post_alonzo_output) => wrap_multiple_with_constr(
0, 0,
vec![ vec![
@ -556,6 +570,29 @@ impl ToPlutusData for TimeRange {
} }
} }
impl<'a> ToPlutusData for WithWrappedTransactionId<'a, Vec<TxInInfo>> {
fn to_plutus_data(&self) -> PlutusData {
PlutusData::Array(
self.0
.iter()
.map(|p| WithWrappedTransactionId(p).to_plutus_data())
.collect(),
)
}
}
impl<'a> ToPlutusData for WithWrappedTransactionId<'a, TxInInfo> {
fn to_plutus_data(&self) -> PlutusData {
wrap_multiple_with_constr(
0,
vec![
WithWrappedTransactionId(&self.0.out_ref).to_plutus_data(),
self.0.resolved.to_plutus_data(),
],
)
}
}
impl ToPlutusData for TxInInfo { impl ToPlutusData for TxInInfo {
fn to_plutus_data(&self) -> PlutusData { fn to_plutus_data(&self) -> PlutusData {
wrap_multiple_with_constr( wrap_multiple_with_constr(
@ -587,7 +624,7 @@ impl ToPlutusData for TxInfo {
TxInfo::V1(tx_info) => wrap_multiple_with_constr( TxInfo::V1(tx_info) => wrap_multiple_with_constr(
0, 0,
vec![ vec![
tx_info.inputs.to_plutus_data(), WithWrappedTransactionId(&tx_info.inputs).to_plutus_data(),
tx_info.outputs.to_plutus_data(), tx_info.outputs.to_plutus_data(),
tx_info.fee.to_plutus_data(), tx_info.fee.to_plutus_data(),
tx_info.mint.to_plutus_data(), tx_info.mint.to_plutus_data(),
@ -600,6 +637,23 @@ impl ToPlutusData for TxInfo {
], ],
), ),
TxInfo::V2(tx_info) => wrap_multiple_with_constr( TxInfo::V2(tx_info) => wrap_multiple_with_constr(
0,
vec![
WithWrappedTransactionId(&tx_info.inputs).to_plutus_data(),
WithWrappedTransactionId(&tx_info.reference_inputs).to_plutus_data(),
tx_info.outputs.to_plutus_data(),
tx_info.fee.to_plutus_data(),
tx_info.mint.to_plutus_data(),
tx_info.certificates.to_plutus_data(),
tx_info.withdrawals.to_plutus_data(),
tx_info.valid_range.to_plutus_data(),
tx_info.signatories.to_plutus_data(),
tx_info.redeemers.to_plutus_data(),
tx_info.data.to_plutus_data(),
wrap_with_constr(0, tx_info.id.to_plutus_data()),
],
),
TxInfo::V3(tx_info) => wrap_multiple_with_constr(
0, 0,
vec![ vec![
tx_info.inputs.to_plutus_data(), tx_info.inputs.to_plutus_data(),
@ -613,7 +667,7 @@ impl ToPlutusData for TxInfo {
tx_info.signatories.to_plutus_data(), tx_info.signatories.to_plutus_data(),
tx_info.redeemers.to_plutus_data(), tx_info.redeemers.to_plutus_data(),
tx_info.data.to_plutus_data(), tx_info.data.to_plutus_data(),
wrap_with_constr(0, tx_info.id.to_plutus_data()), tx_info.id.to_plutus_data(),
], ],
), ),
} }