Fix ToPlutusData serializer for V3
This is intense, as we still want to preserve the serializer for V1 & V2, and I've tried as much as possible to avoid polluting the application layer with many enum types such as: ``` pub enum TxOut { V1(TransactionOutput), V2(TransactionOutput), V3(TransactionOutput), } ``` Those types make working with the script context cumbersome, and are only truly required to provide different serialisation strategies. So instead, we keep one top-level `TxInfo V1/V2/V3` type, and we ensure to pass serialization strategies as type wrappers. This way, the strategy propagates through the structure up until it's eliminated when it reaches the relevant types. All-in-all, this strikes a correct balance between maintainability and repetition; and it makes it possible to define _different but mostly identical_ encoders for the various versions. With it, I've been able to successfully encode a V3 script context and match it against one produced using the Haskell libraries. More to come.
This commit is contained in:
parent
f848bad3f2
commit
821f7bd8c7
|
@ -1942,7 +1942,6 @@ checksum = "caff54706df99d2a78a5a4e3455ff45448d81ef1bb63c22cd14052ca0e993a3f"
|
|||
[[package]]
|
||||
name = "pallas-addresses"
|
||||
version = "0.29.0"
|
||||
source = "git+https://github.com/KtorZ/pallas.git?rev=8ea5a1adc9919b70b213dfe597e920d6e113120c#8ea5a1adc9919b70b213dfe597e920d6e113120c"
|
||||
dependencies = [
|
||||
"base58",
|
||||
"bech32",
|
||||
|
@ -1957,7 +1956,6 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "pallas-codec"
|
||||
version = "0.29.0"
|
||||
source = "git+https://github.com/KtorZ/pallas.git?rev=8ea5a1adc9919b70b213dfe597e920d6e113120c#8ea5a1adc9919b70b213dfe597e920d6e113120c"
|
||||
dependencies = [
|
||||
"hex",
|
||||
"minicbor",
|
||||
|
@ -1969,7 +1967,6 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "pallas-crypto"
|
||||
version = "0.29.0"
|
||||
source = "git+https://github.com/KtorZ/pallas.git?rev=8ea5a1adc9919b70b213dfe597e920d6e113120c#8ea5a1adc9919b70b213dfe597e920d6e113120c"
|
||||
dependencies = [
|
||||
"cryptoxide",
|
||||
"hex",
|
||||
|
@ -1982,7 +1979,6 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "pallas-primitives"
|
||||
version = "0.29.0"
|
||||
source = "git+https://github.com/KtorZ/pallas.git?rev=8ea5a1adc9919b70b213dfe597e920d6e113120c#8ea5a1adc9919b70b213dfe597e920d6e113120c"
|
||||
dependencies = [
|
||||
"base58",
|
||||
"bech32",
|
||||
|
@ -1997,7 +1993,6 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "pallas-traverse"
|
||||
version = "0.29.0"
|
||||
source = "git+https://github.com/KtorZ/pallas.git?rev=8ea5a1adc9919b70b213dfe597e920d6e113120c#8ea5a1adc9919b70b213dfe597e920d6e113120c"
|
||||
dependencies = [
|
||||
"hex",
|
||||
"itertools 0.13.0",
|
||||
|
@ -3209,6 +3204,7 @@ dependencies = [
|
|||
"hex",
|
||||
"indexmap 1.9.3",
|
||||
"indoc",
|
||||
"insta",
|
||||
"itertools 0.10.5",
|
||||
"k256",
|
||||
"miette 5.10.0",
|
||||
|
|
|
@ -42,5 +42,6 @@ k256 = { version = "0.13.0" }
|
|||
[dev-dependencies]
|
||||
hex = "0.4.3"
|
||||
indoc = "2.0.1"
|
||||
insta.workspace = true
|
||||
pretty_assertions = "1.3.0"
|
||||
walkdir.workspace = true
|
||||
|
|
|
@ -32,19 +32,20 @@ pub fn eval_redeemer(
|
|||
tx_info: TxInfo,
|
||||
program: Program<NamedDeBruijn>,
|
||||
) -> Result<Redeemer, Error> {
|
||||
let purpose = tx_info
|
||||
.purpose(redeemer)
|
||||
.expect("redeemer's purpose shall be known by this point.");
|
||||
let script_context = tx_info
|
||||
.into_script_context(redeemer, datum.as_ref())
|
||||
.expect("couldn't create script context from transaction?");
|
||||
|
||||
let script_context = ScriptContext { tx_info, purpose };
|
||||
|
||||
let program = if let Some(datum) = datum {
|
||||
let program = match script_context {
|
||||
ScriptContext::V1V2 { .. } => if let Some(datum) = datum {
|
||||
program.apply_data(datum)
|
||||
} else {
|
||||
program
|
||||
}
|
||||
.apply_data(redeemer.data.clone())
|
||||
.apply_data(script_context.to_plutus_data());
|
||||
.apply_data(script_context.to_plutus_data()),
|
||||
ScriptContext::V3 { .. } => program.apply_data(script_context.to_plutus_data()),
|
||||
};
|
||||
|
||||
let mut eval_result = if let Some(costs) = cost_mdl_opt {
|
||||
program.eval_as(lang, costs, Some(initial_budget))
|
||||
|
|
|
@ -81,7 +81,7 @@ pub fn scripts_needed(tx: &MintedTx, utxos: &[ResolvedInput]) -> Result<ScriptsN
|
|||
|
||||
if let Address::Shelley(a) = address {
|
||||
if let ShelleyPaymentPart::Script(h) = a.payment() {
|
||||
spend.push((ScriptPurpose::Spending(input.clone()), *h));
|
||||
spend.push((ScriptPurpose::Spending(input.clone(), ()), *h));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -241,7 +241,7 @@ fn build_redeemer_key(
|
|||
Ok(redeemer_key)
|
||||
}
|
||||
|
||||
ScriptPurpose::Spending(txin) => {
|
||||
ScriptPurpose::Spending(txin, ()) => {
|
||||
let redeemer_key = tx_body
|
||||
.inputs
|
||||
.iter()
|
||||
|
|
|
@ -25,47 +25,48 @@ pub struct ResolvedInput {
|
|||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub struct TxInInfo {
|
||||
pub out_ref: TransactionInput,
|
||||
pub resolved: TxOut,
|
||||
pub resolved: TransactionOutput,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub enum TxOut {
|
||||
V1(TransactionOutput),
|
||||
V2(TransactionOutput),
|
||||
}
|
||||
|
||||
impl TxOut {
|
||||
pub fn address(&self) -> Address {
|
||||
let address_from_output = |output: &TransactionOutput| match output {
|
||||
pub fn output_address(output: &TransactionOutput) -> Address {
|
||||
match output {
|
||||
TransactionOutput::Legacy(x) => Address::from_bytes(&x.address).unwrap(),
|
||||
TransactionOutput::PostAlonzo(x) => Address::from_bytes(&x.address).unwrap(),
|
||||
};
|
||||
match self {
|
||||
TxOut::V1(output) => address_from_output(output),
|
||||
TxOut::V2(output) => address_from_output(output),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn datum(&self) -> Option<DatumOption> {
|
||||
let datum_from_output = |output: &TransactionOutput| match output {
|
||||
pub fn output_datum(output: &TransactionOutput) -> Option<DatumOption> {
|
||||
match output {
|
||||
TransactionOutput::Legacy(x) => x.datum_hash.map(DatumOption::Hash),
|
||||
TransactionOutput::PostAlonzo(x) => x.datum_option.clone(),
|
||||
};
|
||||
match self {
|
||||
TxOut::V1(output) => datum_from_output(output),
|
||||
TxOut::V2(output) => datum_from_output(output),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The ScriptPurpose is part of the ScriptContext is the case of Plutus V1 and V2.
|
||||
/// It is superseded by the ScriptInfo in PlutusV3.
|
||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||
pub enum ScriptPurpose {
|
||||
pub enum ScriptInfo<T> {
|
||||
Minting(PolicyId),
|
||||
Spending(TransactionInput),
|
||||
Spending(TransactionInput, T),
|
||||
Rewarding(StakeCredential),
|
||||
Certifying(Certificate),
|
||||
}
|
||||
|
||||
pub type ScriptPurpose = ScriptInfo<()>;
|
||||
|
||||
impl ScriptPurpose {
|
||||
pub fn into_script_info<T>(self, datum: T) -> ScriptInfo<T> {
|
||||
match self {
|
||||
Self::Minting(policy_id) => ScriptInfo::Minting(policy_id),
|
||||
Self::Spending(transaction_output, ()) => {
|
||||
ScriptInfo::Spending(transaction_output, datum)
|
||||
}
|
||||
Self::Rewarding(stake_credential) => ScriptInfo::Rewarding(stake_credential),
|
||||
Self::Certifying(certificate) => ScriptInfo::Certifying(certificate),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub enum ScriptVersion {
|
||||
Native(NativeScript),
|
||||
|
@ -184,7 +185,7 @@ impl DataLookupTable {
|
|||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub struct TxInfoV1 {
|
||||
pub inputs: Vec<TxInInfo>,
|
||||
pub outputs: Vec<TxOut>,
|
||||
pub outputs: Vec<TransactionOutput>,
|
||||
pub fee: Value,
|
||||
pub mint: MintValue,
|
||||
pub certificates: Vec<Certificate>,
|
||||
|
@ -219,8 +220,8 @@ impl TxInfoV1 {
|
|||
|
||||
Ok(TxInfo::V1(TxInfoV1 {
|
||||
inputs,
|
||||
outputs: get_outputs_info(TxOut::V1, &tx.transaction_body.outputs[..]),
|
||||
fee: get_fee_info(&tx.transaction_body.fee),
|
||||
outputs: get_outputs_info(&tx.transaction_body.outputs[..]),
|
||||
fee: Value::Coin(get_fee_info(&tx.transaction_body.fee)),
|
||||
mint,
|
||||
certificates,
|
||||
withdrawals: withdrawals.into(),
|
||||
|
@ -237,7 +238,7 @@ impl TxInfoV1 {
|
|||
pub struct TxInfoV2 {
|
||||
pub inputs: Vec<TxInInfo>,
|
||||
pub reference_inputs: Vec<TxInInfo>,
|
||||
pub outputs: Vec<TxOut>,
|
||||
pub outputs: Vec<TransactionOutput>,
|
||||
pub fee: Value,
|
||||
pub mint: MintValue,
|
||||
pub certificates: Vec<Certificate>,
|
||||
|
@ -277,8 +278,8 @@ impl TxInfoV2 {
|
|||
Ok(TxInfo::V2(TxInfoV2 {
|
||||
inputs,
|
||||
reference_inputs,
|
||||
outputs: get_outputs_info(TxOut::V2, &tx.transaction_body.outputs[..]),
|
||||
fee: get_fee_info(&tx.transaction_body.fee),
|
||||
outputs: get_outputs_info(&tx.transaction_body.outputs[..]),
|
||||
fee: Value::Coin(get_fee_info(&tx.transaction_body.fee)),
|
||||
mint,
|
||||
certificates,
|
||||
withdrawals,
|
||||
|
@ -295,8 +296,8 @@ impl TxInfoV2 {
|
|||
pub struct TxInfoV3 {
|
||||
pub inputs: Vec<TxInInfo>,
|
||||
pub reference_inputs: Vec<TxInInfo>,
|
||||
pub outputs: Vec<TxOut>,
|
||||
pub fee: Value,
|
||||
pub outputs: Vec<TransactionOutput>,
|
||||
pub fee: Coin,
|
||||
pub mint: MintValue,
|
||||
pub certificates: Vec<Certificate>,
|
||||
pub withdrawals: KeyValuePairs<Address, Coin>,
|
||||
|
@ -323,7 +324,7 @@ impl TxInfoV3 {
|
|||
inputs: tx_info_v2.inputs,
|
||||
reference_inputs: tx_info_v2.reference_inputs,
|
||||
outputs: tx_info_v2.outputs,
|
||||
fee: tx_info_v2.fee,
|
||||
fee: get_fee_info(&tx.transaction_body.fee),
|
||||
mint: tx_info_v2.mint,
|
||||
certificates: tx_info_v2.certificates,
|
||||
withdrawals: tx_info_v2.withdrawals,
|
||||
|
@ -347,19 +348,41 @@ pub enum TxInfo {
|
|||
}
|
||||
|
||||
impl TxInfo {
|
||||
pub fn purpose(&self, needle: &Redeemer) -> Option<ScriptPurpose> {
|
||||
pub fn into_script_context(
|
||||
self,
|
||||
redeemer: &Redeemer,
|
||||
datum: Option<&PlutusData>,
|
||||
) -> Option<ScriptContext> {
|
||||
match self {
|
||||
TxInfo::V1(TxInfoV1 { redeemers, .. })
|
||||
| TxInfo::V2(TxInfoV2 { redeemers, .. })
|
||||
| TxInfo::V3(TxInfoV3 { redeemers, .. }) => {
|
||||
redeemers.iter().find_map(|(purpose, redeemer)| {
|
||||
if redeemer == needle {
|
||||
TxInfo::V1(TxInfoV1 { ref redeemers, .. })
|
||||
| TxInfo::V2(TxInfoV2 { ref redeemers, .. }) => redeemers
|
||||
.iter()
|
||||
.find_map(move |(purpose, some_redeemer)| {
|
||||
if redeemer == some_redeemer {
|
||||
Some(purpose.clone())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.map(move |purpose| ScriptContext::V1V2 {
|
||||
tx_info: self,
|
||||
purpose: purpose.clone().into(),
|
||||
}),
|
||||
|
||||
TxInfo::V3(TxInfoV3 { ref redeemers, .. }) => redeemers
|
||||
.iter()
|
||||
.find_map(move |(purpose, some_redeemer)| {
|
||||
if redeemer == some_redeemer {
|
||||
Some(purpose.clone())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.map(move |purpose| ScriptContext::V3 {
|
||||
tx_info: self,
|
||||
redeemer: redeemer.data.clone(),
|
||||
purpose: purpose.clone().into_script_info(datum.cloned()),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -397,9 +420,16 @@ impl TxInfo {
|
|||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub struct ScriptContext {
|
||||
pub tx_info: TxInfo,
|
||||
pub purpose: ScriptPurpose,
|
||||
pub enum ScriptContext {
|
||||
V1V2 {
|
||||
tx_info: TxInfo,
|
||||
purpose: Box<ScriptPurpose>,
|
||||
},
|
||||
V3 {
|
||||
tx_info: TxInfo,
|
||||
redeemer: PlutusData,
|
||||
purpose: ScriptInfo<Option<PlutusData>>,
|
||||
},
|
||||
}
|
||||
|
||||
//---- Time conversion: slot range => posix time range
|
||||
|
@ -470,7 +500,7 @@ pub fn get_tx_in_info_v1(
|
|||
|
||||
Ok(TxInInfo {
|
||||
out_ref: utxo.input.clone(),
|
||||
resolved: TxOut::V1(sort_tx_out_value(&utxo.output)),
|
||||
resolved: sort_tx_out_value(&utxo.output),
|
||||
})
|
||||
})
|
||||
.collect()
|
||||
|
@ -506,7 +536,7 @@ pub fn get_tx_in_info_v2(
|
|||
|
||||
Ok(TxInInfo {
|
||||
out_ref: utxo.input.clone(),
|
||||
resolved: TxOut::V2(sort_tx_out_value(&utxo.output)),
|
||||
resolved: sort_tx_out_value(&utxo.output),
|
||||
})
|
||||
})
|
||||
.collect()
|
||||
|
@ -521,19 +551,16 @@ pub fn get_mint_info(mint: &Option<Mint>) -> MintValue {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn get_outputs_info(
|
||||
to_tx_out: fn(TransactionOutput) -> TxOut,
|
||||
outputs: &[MintedTransactionOutput],
|
||||
) -> Vec<TxOut> {
|
||||
pub fn get_outputs_info(outputs: &[MintedTransactionOutput]) -> Vec<TransactionOutput> {
|
||||
outputs
|
||||
.iter()
|
||||
.cloned()
|
||||
.map(|output| to_tx_out(sort_tx_out_value(&output.into())))
|
||||
.map(|output| sort_tx_out_value(&output.into()))
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn get_fee_info(fee: &Coin) -> Value {
|
||||
Value::Coin(*fee)
|
||||
pub fn get_fee_info(fee: &Coin) -> Coin {
|
||||
*fee
|
||||
}
|
||||
|
||||
pub fn get_certificates_info(certificates: &Option<NonEmptySet<Certificate>>) -> Vec<Certificate> {
|
||||
|
@ -649,7 +676,7 @@ fn script_purpose_builder<'a>(
|
|||
RedeemerTag::Spend => inputs
|
||||
.get(index)
|
||||
.cloned()
|
||||
.map(|i| ScriptPurpose::Spending(i.out_ref)),
|
||||
.map(|i| ScriptPurpose::Spending(i.out_ref, ())),
|
||||
RedeemerTag::Cert => certificates
|
||||
.get(index)
|
||||
.cloned()
|
||||
|
@ -756,13 +783,13 @@ pub fn find_script(
|
|||
})?
|
||||
.get(redeemer.index as usize)
|
||||
.ok_or(Error::MissingScriptForRedeemer)
|
||||
.and_then(|input| match input.resolved.address() {
|
||||
.and_then(|input| match output_address(&input.resolved) {
|
||||
Address::Shelley(shelley_address) => {
|
||||
let hash = shelley_address.payment().as_hash();
|
||||
|
||||
let script = lookup_script(hash);
|
||||
|
||||
let datum = lookup_datum(input.resolved.datum());
|
||||
let datum = lookup_datum(output_datum(&input.resolved));
|
||||
|
||||
script.and_then(|(script, _)| Ok((script, Some(datum?))))
|
||||
}
|
||||
|
@ -775,7 +802,7 @@ pub fn find_script(
|
|||
}
|
||||
}
|
||||
|
||||
fn from_alonzo_value(value: &alonzo::Value) -> Value {
|
||||
pub fn from_alonzo_value(value: &alonzo::Value) -> Value {
|
||||
match value {
|
||||
alonzo::Value::Coin(coin) => Value::Coin(*coin),
|
||||
alonzo::Value::Multiasset(coin, assets) if assets.is_empty() => Value::Coin(*coin),
|
||||
|
@ -810,6 +837,15 @@ fn from_alonzo_value(value: &alonzo::Value) -> Value {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn from_alonzo_output(output: &alonzo::TransactionOutput) -> TransactionOutput {
|
||||
TransactionOutput::PostAlonzo(PostAlonzoTransactionOutput {
|
||||
address: output.address.clone(),
|
||||
value: from_alonzo_value(&output.amount),
|
||||
datum_option: output.datum_hash.map(DatumOption::Hash),
|
||||
script_ref: None,
|
||||
})
|
||||
}
|
||||
|
||||
// --------------------- Sorting
|
||||
|
||||
fn sort_tx_out_value(tx_output: &TransactionOutput) -> TransactionOutput {
|
||||
|
@ -882,3 +918,91 @@ fn sort_redeemers(a: &RedeemersKey, b: &RedeemersKey) -> Ordering {
|
|||
redeemer_tag_as_usize(&a.tag).cmp(&redeemer_tag_as_usize(&b.tag))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::{
|
||||
ast::Data,
|
||||
tx::{
|
||||
script_context::{TxInfo, TxInfoV3},
|
||||
to_plutus_data::ToPlutusData,
|
||||
ResolvedInput, SlotConfig,
|
||||
},
|
||||
};
|
||||
use pallas_primitives::{
|
||||
conway::{ExUnits, PlutusData, Redeemer, RedeemerTag, TransactionInput, TransactionOutput},
|
||||
Fragment,
|
||||
};
|
||||
use pallas_traverse::{Era, MultiEraTx};
|
||||
|
||||
fn fixture_tx_info(transaction: &str, inputs: &str, outputs: &str) -> TxInfo {
|
||||
let transaction_bytes = hex::decode(transaction).unwrap();
|
||||
let inputs_bytes = hex::decode(inputs).unwrap();
|
||||
let outputs_bytes = hex::decode(outputs).unwrap();
|
||||
|
||||
let inputs = Vec::<TransactionInput>::decode_fragment(inputs_bytes.as_slice()).unwrap();
|
||||
let outputs = Vec::<TransactionOutput>::decode_fragment(outputs_bytes.as_slice()).unwrap();
|
||||
let resolved_inputs: Vec<ResolvedInput> = inputs
|
||||
.iter()
|
||||
.zip(outputs.iter())
|
||||
.map(|(input, output)| ResolvedInput {
|
||||
input: input.clone(),
|
||||
output: output.clone(),
|
||||
})
|
||||
.collect();
|
||||
|
||||
TxInfoV3::from_transaction(
|
||||
MultiEraTx::decode_for_era(Era::Conway, transaction_bytes.as_slice())
|
||||
.unwrap()
|
||||
.as_conway()
|
||||
.unwrap(),
|
||||
&resolved_inputs,
|
||||
&SlotConfig::default(),
|
||||
)
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn from_haskell(data: &str) -> PlutusData {
|
||||
PlutusData::decode_fragment(hex::decode(data).unwrap().as_slice()).unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tx_to_plutus_data() {
|
||||
let datum = Some(Data::constr(0, Vec::new()));
|
||||
|
||||
let redeemer = Redeemer {
|
||||
tag: RedeemerTag::Spend,
|
||||
index: 0,
|
||||
data: Data::constr(0, Vec::new()),
|
||||
ex_units: ExUnits {
|
||||
mem: 1000000,
|
||||
steps: 100000000,
|
||||
},
|
||||
};
|
||||
|
||||
let script_context = fixture_tx_info(
|
||||
"84a7008182582000000000000000000000000000000000000000000000000000\
|
||||
0000000000000000018182581d60111111111111111111111111111111111111\
|
||||
111111111111111111111a3b9aca0002182a0b5820ffffffffffffffffffffff\
|
||||
ffffffffffffffffffffffffffffffffffffffffff0d81825820000000000000\
|
||||
0000000000000000000000000000000000000000000000000000001082581d60\
|
||||
000000000000000000000000000000000000000000000000000000001a3b9aca\
|
||||
001101a20581840000d87980821a000f42401a05f5e100078152510101003222\
|
||||
253330044a229309b2b2b9a1f5f6",
|
||||
"8182582000000000000000000000000000000000000000000000000000000000\
|
||||
0000000000",
|
||||
"81a300581d7039f47fd3b388ef53c48f08de24766d3e55dade6cae908cc24e0f\
|
||||
4f3e011a3b9aca00028201d81843d87980",
|
||||
)
|
||||
.into_script_context(&redeemer, datum.as_ref())
|
||||
.unwrap();
|
||||
|
||||
// NOTE: The initial snapshot has been generated using the Haskell
|
||||
// implementation of the ledger library for that same serialized
|
||||
// transactions. It is meant to control that our construction of the
|
||||
// script context and its serialization matches exactly those
|
||||
// from the Haskell ledger / cardano node.
|
||||
insta::assert_debug_snapshot!(script_context.to_plutus_data())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,23 +1,20 @@
|
|||
use super::script_context::{ScriptContext, ScriptPurpose, TimeRange, TxInInfo, TxInfo, TxOut};
|
||||
use crate::machine::runtime::{convert_constr_to_tag, ANY_TAG};
|
||||
use super::script_context::{
|
||||
ScriptContext, ScriptInfo, ScriptPurpose, TimeRange, TxInInfo, TxInfo,
|
||||
};
|
||||
use crate::{
|
||||
ast::Data,
|
||||
machine::runtime::{convert_constr_to_tag, ANY_TAG},
|
||||
tx::script_context::from_alonzo_output,
|
||||
};
|
||||
use pallas_addresses::{Address, ShelleyDelegationPart, ShelleyPaymentPart, StakePayload};
|
||||
use pallas_codec::utils::{AnyUInt, Bytes, Int, KeyValuePairs};
|
||||
use pallas_codec::utils::{AnyUInt, Bytes, Int, KeyValuePairs, NonEmptyKeyValuePairs};
|
||||
use pallas_crypto::hash::Hash;
|
||||
use pallas_primitives::conway::{
|
||||
AssetName, BigInt, Certificate, Constr, DatumOption, Mint, PlutusData, PseudoScript, Redeemer,
|
||||
ScriptRef, StakeCredential, TransactionInput, TransactionOutput, Value,
|
||||
AssetName, BigInt, Certificate, Coin, Constr, DatumOption, Mint, PlutusData, PolicyId,
|
||||
PseudoScript, Redeemer, ScriptRef, StakeCredential, TransactionInput, TransactionOutput, Value,
|
||||
};
|
||||
use pallas_traverse::ComputeHash;
|
||||
|
||||
fn wrap_with_constr(index: u64, data: PlutusData) -> PlutusData {
|
||||
let converted = convert_constr_to_tag(index);
|
||||
PlutusData::Constr(Constr {
|
||||
tag: converted.unwrap_or(ANY_TAG),
|
||||
any_constructor: converted.map_or(Some(index), |_| None),
|
||||
fields: vec![data],
|
||||
})
|
||||
}
|
||||
|
||||
fn wrap_multiple_with_constr(index: u64, data: Vec<PlutusData>) -> PlutusData {
|
||||
let converted = convert_constr_to_tag(index);
|
||||
PlutusData::Constr(Constr {
|
||||
|
@ -27,17 +24,20 @@ fn wrap_multiple_with_constr(index: u64, data: Vec<PlutusData>) -> PlutusData {
|
|||
})
|
||||
}
|
||||
|
||||
fn wrap_with_constr(index: u64, data: PlutusData) -> PlutusData {
|
||||
wrap_multiple_with_constr(index, vec![data])
|
||||
}
|
||||
|
||||
fn empty_constr(index: u64) -> PlutusData {
|
||||
let converted = convert_constr_to_tag(index);
|
||||
PlutusData::Constr(Constr {
|
||||
tag: converted.unwrap_or(ANY_TAG),
|
||||
any_constructor: converted.map_or(Some(index), |_| None),
|
||||
fields: vec![],
|
||||
})
|
||||
wrap_multiple_with_constr(index, vec![])
|
||||
}
|
||||
|
||||
struct WithWrappedTransactionId<'a, T>(&'a T);
|
||||
|
||||
struct WithZeroAdaAsset<'a, T>(&'a T);
|
||||
|
||||
struct WithOptionDatum<'a, T>(&'a T);
|
||||
|
||||
pub trait ToPlutusData {
|
||||
fn to_plutus_data(&self) -> PlutusData;
|
||||
}
|
||||
|
@ -165,6 +165,19 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> ToPlutusData for WithWrappedTransactionId<'a, KeyValuePairs<ScriptPurpose, Redeemer>> {
|
||||
fn to_plutus_data(&self) -> PlutusData {
|
||||
let mut data_vec: Vec<(PlutusData, PlutusData)> = vec![];
|
||||
for (key, value) in self.0.iter() {
|
||||
data_vec.push((
|
||||
WithWrappedTransactionId(key).to_plutus_data(),
|
||||
value.to_plutus_data(),
|
||||
))
|
||||
}
|
||||
PlutusData::Map(KeyValuePairs::Def(data_vec))
|
||||
}
|
||||
}
|
||||
|
||||
impl<A: ToPlutusData> ToPlutusData for Option<A> {
|
||||
fn to_plutus_data(&self) -> PlutusData {
|
||||
match self {
|
||||
|
@ -174,7 +187,6 @@ impl<A: ToPlutusData> ToPlutusData for Option<A> {
|
|||
}
|
||||
}
|
||||
|
||||
// Does this here surely overwrite Option from above for DatumOption?
|
||||
impl ToPlutusData for Option<DatumOption> {
|
||||
// NoOutputDatum = 0 | OutputDatumHash = 1 | OutputDatum = 2
|
||||
fn to_plutus_data(&self) -> PlutusData {
|
||||
|
@ -224,57 +236,81 @@ impl ToPlutusData for u64 {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> ToPlutusData for WithZeroAdaAsset<'a, Value> {
|
||||
fn to_plutus_data(&self) -> PlutusData {
|
||||
match self.0 {
|
||||
Value::Coin(coin) => {
|
||||
PlutusData::Map(KeyValuePairs::Def(vec![coin_to_plutus_data(coin)]))
|
||||
}
|
||||
Value::Multiasset(coin, multiassets) => value_to_plutus_data(
|
||||
multiassets.iter(),
|
||||
|amount| u64::from(amount).to_plutus_data(),
|
||||
vec![coin_to_plutus_data(coin)],
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ToPlutusData for Value {
|
||||
fn to_plutus_data(&self) -> PlutusData {
|
||||
match self {
|
||||
Value::Coin(coin) => PlutusData::Map(KeyValuePairs::Def(vec![(
|
||||
Bytes::from(vec![]).to_plutus_data(),
|
||||
PlutusData::Map(KeyValuePairs::Def(vec![(
|
||||
AssetName::from(vec![]).to_plutus_data(),
|
||||
coin.to_plutus_data(),
|
||||
)])),
|
||||
)])),
|
||||
Value::Multiasset(coin, multiassets) => {
|
||||
let mut data_vec: Vec<(PlutusData, PlutusData)> = vec![(
|
||||
Bytes::from(vec![]).to_plutus_data(),
|
||||
PlutusData::Map(KeyValuePairs::Def(vec![(
|
||||
AssetName::from(vec![]).to_plutus_data(),
|
||||
coin.to_plutus_data(),
|
||||
)])),
|
||||
)];
|
||||
|
||||
for (policy_id, assets) in multiassets.iter() {
|
||||
let mut assets_vec = vec![];
|
||||
for (asset, amount) in assets.iter() {
|
||||
assets_vec
|
||||
.push((asset.to_plutus_data(), u64::from(amount).to_plutus_data()));
|
||||
}
|
||||
data_vec.push((
|
||||
policy_id.to_plutus_data(),
|
||||
PlutusData::Map(KeyValuePairs::Def(assets_vec)),
|
||||
));
|
||||
}
|
||||
|
||||
PlutusData::Map(KeyValuePairs::Def(data_vec))
|
||||
}
|
||||
Value::Coin(coin) => PlutusData::Map(KeyValuePairs::Def(if *coin > 0 {
|
||||
vec![coin_to_plutus_data(coin)]
|
||||
} else {
|
||||
vec![]
|
||||
})),
|
||||
Value::Multiasset(coin, multiassets) => value_to_plutus_data(
|
||||
multiassets.iter(),
|
||||
|amount| u64::from(amount).to_plutus_data(),
|
||||
if *coin > 0 {
|
||||
vec![coin_to_plutus_data(coin)]
|
||||
} else {
|
||||
vec![]
|
||||
},
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ToPlutusData for MintValue {
|
||||
impl<'a> ToPlutusData for WithZeroAdaAsset<'a, MintValue> {
|
||||
fn to_plutus_data(&self) -> PlutusData {
|
||||
let mut data_vec: Vec<(PlutusData, PlutusData)> = vec![(
|
||||
value_to_plutus_data(
|
||||
self.0.mint_value.iter(),
|
||||
|amount| i64::from(amount).to_plutus_data(),
|
||||
vec![(
|
||||
Bytes::from(vec![]).to_plutus_data(),
|
||||
PlutusData::Map(KeyValuePairs::Def(vec![(
|
||||
AssetName::from(vec![]).to_plutus_data(),
|
||||
0_i64.to_plutus_data(),
|
||||
)])),
|
||||
)];
|
||||
)],
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
for (policy_id, assets) in self.mint_value.iter() {
|
||||
impl ToPlutusData for MintValue {
|
||||
fn to_plutus_data(&self) -> PlutusData {
|
||||
value_to_plutus_data(
|
||||
self.mint_value.iter(),
|
||||
|amount| i64::from(amount).to_plutus_data(),
|
||||
vec![],
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn value_to_plutus_data<'a, I, Q>(
|
||||
mint: I,
|
||||
from_quantity: fn(&'a Q) -> PlutusData,
|
||||
mut data_vec: Vec<(PlutusData, PlutusData)>,
|
||||
) -> PlutusData
|
||||
where
|
||||
I: Iterator<Item = &'a (PolicyId, NonEmptyKeyValuePairs<AssetName, Q>)>,
|
||||
Q: Clone,
|
||||
{
|
||||
for (policy_id, assets) in mint {
|
||||
let mut assets_vec = vec![];
|
||||
for (asset, amount) in assets.iter() {
|
||||
assets_vec.push((asset.to_plutus_data(), i64::from(amount).to_plutus_data()));
|
||||
assets_vec.push((asset.to_plutus_data(), from_quantity(amount)));
|
||||
}
|
||||
data_vec.push((
|
||||
policy_id.to_plutus_data(),
|
||||
|
@ -284,6 +320,15 @@ impl ToPlutusData for MintValue {
|
|||
|
||||
PlutusData::Map(KeyValuePairs::Def(data_vec))
|
||||
}
|
||||
|
||||
fn coin_to_plutus_data(coin: &Coin) -> (PlutusData, PlutusData) {
|
||||
(
|
||||
Bytes::from(vec![]).to_plutus_data(),
|
||||
PlutusData::Map(KeyValuePairs::Def(vec![(
|
||||
AssetName::from(vec![]).to_plutus_data(),
|
||||
coin.to_plutus_data(),
|
||||
)])),
|
||||
)
|
||||
}
|
||||
|
||||
impl ToPlutusData for ScriptRef {
|
||||
|
@ -299,51 +344,85 @@ impl ToPlutusData for ScriptRef {
|
|||
}
|
||||
}
|
||||
|
||||
impl ToPlutusData for TxOut {
|
||||
impl<'a> ToPlutusData for WithOptionDatum<'a, WithZeroAdaAsset<'a, Vec<TransactionOutput>>> {
|
||||
fn to_plutus_data(&self) -> PlutusData {
|
||||
match self {
|
||||
TxOut::V1(output) => match output {
|
||||
// TransactionOutput::Legacy(legacy_output) => wrap_multiple_with_constr(
|
||||
// 0,
|
||||
// vec![
|
||||
// Address::from_bytes(&legacy_output.address)
|
||||
// .unwrap()
|
||||
// .to_plutus_data(),
|
||||
// legacy_output.amount.to_plutus_data(),
|
||||
// legacy_output.datum_hash.to_plutus_data(),
|
||||
// ],
|
||||
// ),
|
||||
TransactionOutput::Legacy(..) => unimplemented!("TransactionOutput::Legacy"),
|
||||
PlutusData::Array(
|
||||
self.0
|
||||
.0
|
||||
.iter()
|
||||
.map(|p| WithOptionDatum(&WithZeroAdaAsset(p)).to_plutus_data())
|
||||
.collect(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ToPlutusData for WithZeroAdaAsset<'a, Vec<TransactionOutput>> {
|
||||
fn to_plutus_data(&self) -> PlutusData {
|
||||
PlutusData::Array(
|
||||
self.0
|
||||
.iter()
|
||||
.map(|p| WithZeroAdaAsset(p).to_plutus_data())
|
||||
.collect(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ToPlutusData for WithOptionDatum<'a, WithZeroAdaAsset<'a, TransactionOutput>> {
|
||||
fn to_plutus_data(&self) -> PlutusData {
|
||||
match self.0 .0 {
|
||||
TransactionOutput::Legacy(legacy_output) => {
|
||||
WithOptionDatum(&WithZeroAdaAsset(&from_alonzo_output(legacy_output)))
|
||||
.to_plutus_data()
|
||||
}
|
||||
|
||||
TransactionOutput::PostAlonzo(post_alonzo_output) => wrap_multiple_with_constr(
|
||||
0,
|
||||
vec![
|
||||
Address::from_bytes(&post_alonzo_output.address)
|
||||
.unwrap()
|
||||
.to_plutus_data(),
|
||||
post_alonzo_output.value.to_plutus_data(),
|
||||
WithZeroAdaAsset(&post_alonzo_output.value).to_plutus_data(),
|
||||
match post_alonzo_output.datum_option {
|
||||
Some(DatumOption::Hash(hash)) => Some(hash).to_plutus_data(),
|
||||
_ => None::<Hash<32>>.to_plutus_data(),
|
||||
},
|
||||
],
|
||||
),
|
||||
},
|
||||
TxOut::V2(output) => match output {
|
||||
// TransactionOutput::Legacy(legacy_output) => wrap_multiple_with_constr(
|
||||
// 0,
|
||||
// vec![
|
||||
// Address::from_bytes(&legacy_output.address)
|
||||
// .unwrap()
|
||||
// .to_plutus_data(),
|
||||
// legacy_output.amount.to_plutus_data(),
|
||||
// match legacy_output.datum_hash {
|
||||
// Some(hash) => wrap_with_constr(1, hash.to_plutus_data()),
|
||||
// _ => empty_constr(0),
|
||||
// },
|
||||
// None::<ScriptRef>.to_plutus_data(),
|
||||
// ],
|
||||
// ),
|
||||
TransactionOutput::Legacy(..) => unimplemented!("TransactionOutput::Legacy"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ToPlutusData for WithZeroAdaAsset<'a, TransactionOutput> {
|
||||
fn to_plutus_data(&self) -> PlutusData {
|
||||
match self.0 {
|
||||
TransactionOutput::Legacy(legacy_output) => {
|
||||
WithZeroAdaAsset(&from_alonzo_output(legacy_output)).to_plutus_data()
|
||||
}
|
||||
TransactionOutput::PostAlonzo(post_alonzo_output) => wrap_multiple_with_constr(
|
||||
0,
|
||||
vec![
|
||||
Address::from_bytes(&post_alonzo_output.address)
|
||||
.unwrap()
|
||||
.to_plutus_data(),
|
||||
WithZeroAdaAsset(&post_alonzo_output.value).to_plutus_data(),
|
||||
post_alonzo_output.datum_option.to_plutus_data(),
|
||||
post_alonzo_output
|
||||
.script_ref
|
||||
.as_ref()
|
||||
.map(|s| s.clone().unwrap())
|
||||
.to_plutus_data(),
|
||||
],
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ToPlutusData for TransactionOutput {
|
||||
fn to_plutus_data(&self) -> PlutusData {
|
||||
match self {
|
||||
TransactionOutput::Legacy(legacy_output) => {
|
||||
from_alonzo_output(legacy_output).to_plutus_data()
|
||||
}
|
||||
TransactionOutput::PostAlonzo(post_alonzo_output) => wrap_multiple_with_constr(
|
||||
0,
|
||||
vec![
|
||||
|
@ -359,7 +438,6 @@ impl ToPlutusData for TxOut {
|
|||
.to_plutus_data(),
|
||||
],
|
||||
),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -570,24 +648,57 @@ impl ToPlutusData for TimeRange {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> ToPlutusData for WithWrappedTransactionId<'a, Vec<TxInInfo>> {
|
||||
impl<'a> ToPlutusData
|
||||
for WithOptionDatum<'a, WithZeroAdaAsset<'a, WithWrappedTransactionId<'a, Vec<TxInInfo>>>>
|
||||
{
|
||||
fn to_plutus_data(&self) -> PlutusData {
|
||||
PlutusData::Array(
|
||||
self.0
|
||||
.0
|
||||
.0
|
||||
.iter()
|
||||
.map(|p| WithWrappedTransactionId(p).to_plutus_data())
|
||||
.map(|p| {
|
||||
WithOptionDatum(&WithZeroAdaAsset(&WithWrappedTransactionId(p)))
|
||||
.to_plutus_data()
|
||||
})
|
||||
.collect(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ToPlutusData for WithWrappedTransactionId<'a, TxInInfo> {
|
||||
impl<'a> ToPlutusData for WithZeroAdaAsset<'a, WithWrappedTransactionId<'a, Vec<TxInInfo>>> {
|
||||
fn to_plutus_data(&self) -> PlutusData {
|
||||
PlutusData::Array(
|
||||
self.0
|
||||
.0
|
||||
.iter()
|
||||
.map(|p| WithZeroAdaAsset(&WithWrappedTransactionId(p)).to_plutus_data())
|
||||
.collect(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ToPlutusData for WithZeroAdaAsset<'a, 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(),
|
||||
WithWrappedTransactionId(&self.0 .0.out_ref).to_plutus_data(),
|
||||
WithZeroAdaAsset(&self.0 .0.resolved).to_plutus_data(),
|
||||
],
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ToPlutusData
|
||||
for WithOptionDatum<'a, WithZeroAdaAsset<'a, WithWrappedTransactionId<'a, TxInInfo>>>
|
||||
{
|
||||
fn to_plutus_data(&self) -> PlutusData {
|
||||
wrap_multiple_with_constr(
|
||||
0,
|
||||
vec![
|
||||
WithWrappedTransactionId(&self.0 .0 .0.out_ref).to_plutus_data(),
|
||||
WithOptionDatum(&WithZeroAdaAsset(&self.0 .0 .0.resolved)).to_plutus_data(),
|
||||
],
|
||||
)
|
||||
}
|
||||
|
@ -605,11 +716,22 @@ impl ToPlutusData for TxInInfo {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> ToPlutusData for WithWrappedTransactionId<'a, ScriptPurpose> {
|
||||
fn to_plutus_data(&self) -> PlutusData {
|
||||
match self.0 {
|
||||
ScriptPurpose::Spending(out_ref, ()) => {
|
||||
wrap_with_constr(1, WithWrappedTransactionId(out_ref).to_plutus_data())
|
||||
}
|
||||
otherwise => otherwise.to_plutus_data(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ToPlutusData for ScriptPurpose {
|
||||
fn to_plutus_data(&self) -> PlutusData {
|
||||
match self {
|
||||
ScriptPurpose::Minting(policy_id) => wrap_with_constr(0, policy_id.to_plutus_data()),
|
||||
ScriptPurpose::Spending(out_ref) => wrap_with_constr(1, out_ref.to_plutus_data()),
|
||||
ScriptPurpose::Spending(out_ref, ()) => wrap_with_constr(1, out_ref.to_plutus_data()),
|
||||
ScriptPurpose::Rewarding(stake_credential) => {
|
||||
wrap_with_constr(2, stake_credential.to_plutus_data())
|
||||
}
|
||||
|
@ -618,16 +740,37 @@ impl ToPlutusData for ScriptPurpose {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T> ToPlutusData for ScriptInfo<T>
|
||||
where
|
||||
T: ToPlutusData,
|
||||
{
|
||||
fn to_plutus_data(&self) -> PlutusData {
|
||||
match self {
|
||||
ScriptInfo::Minting(policy_id) => wrap_with_constr(0, policy_id.to_plutus_data()),
|
||||
ScriptInfo::Spending(out_ref, datum) => {
|
||||
wrap_multiple_with_constr(1, vec![out_ref.to_plutus_data(), datum.to_plutus_data()])
|
||||
}
|
||||
ScriptInfo::Rewarding(stake_credential) => {
|
||||
wrap_with_constr(2, stake_credential.to_plutus_data())
|
||||
}
|
||||
ScriptInfo::Certifying(dcert) => wrap_with_constr(3, dcert.to_plutus_data()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ToPlutusData for TxInfo {
|
||||
fn to_plutus_data(&self) -> PlutusData {
|
||||
match self {
|
||||
TxInfo::V1(tx_info) => wrap_multiple_with_constr(
|
||||
0,
|
||||
vec![
|
||||
WithWrappedTransactionId(&tx_info.inputs).to_plutus_data(),
|
||||
tx_info.outputs.to_plutus_data(),
|
||||
tx_info.fee.to_plutus_data(),
|
||||
tx_info.mint.to_plutus_data(),
|
||||
WithOptionDatum(&WithZeroAdaAsset(&WithWrappedTransactionId(
|
||||
&tx_info.inputs,
|
||||
)))
|
||||
.to_plutus_data(),
|
||||
WithOptionDatum(&WithZeroAdaAsset(&tx_info.outputs)).to_plutus_data(),
|
||||
WithZeroAdaAsset(&tx_info.fee).to_plutus_data(),
|
||||
WithZeroAdaAsset(&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(),
|
||||
|
@ -639,16 +782,17 @@ impl ToPlutusData for TxInfo {
|
|||
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(),
|
||||
WithZeroAdaAsset(&WithWrappedTransactionId(&tx_info.inputs)).to_plutus_data(),
|
||||
WithZeroAdaAsset(&WithWrappedTransactionId(&tx_info.reference_inputs))
|
||||
.to_plutus_data(),
|
||||
WithZeroAdaAsset(&tx_info.outputs).to_plutus_data(),
|
||||
WithZeroAdaAsset(&tx_info.fee).to_plutus_data(),
|
||||
WithZeroAdaAsset(&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(),
|
||||
WithWrappedTransactionId(&tx_info.redeemers).to_plutus_data(),
|
||||
tx_info.data.to_plutus_data(),
|
||||
wrap_with_constr(0, tx_info.id.to_plutus_data()),
|
||||
],
|
||||
|
@ -668,6 +812,10 @@ impl ToPlutusData for TxInfo {
|
|||
tx_info.redeemers.to_plutus_data(),
|
||||
tx_info.data.to_plutus_data(),
|
||||
tx_info.id.to_plutus_data(),
|
||||
Data::map(vec![]), // TODO tx_info.votes :: Map Voter (Map GovernanceActionId Vote)
|
||||
Data::list(vec![]), // TODO tx_info.proposal_procedures :: [ProposalProcedure]
|
||||
empty_constr(1), // TODO tx_info.current_treasury_amount :: Haskell.Maybe V2.Lovelace
|
||||
empty_constr(1), // TODO tx_info.treasury_donation :: Haskell.Maybe V2.Lovelace
|
||||
],
|
||||
),
|
||||
}
|
||||
|
@ -676,10 +824,27 @@ impl ToPlutusData for TxInfo {
|
|||
|
||||
impl ToPlutusData for ScriptContext {
|
||||
fn to_plutus_data(&self) -> PlutusData {
|
||||
wrap_multiple_with_constr(
|
||||
match self {
|
||||
ScriptContext::V1V2 { tx_info, purpose } => wrap_multiple_with_constr(
|
||||
0,
|
||||
vec![self.tx_info.to_plutus_data(), self.purpose.to_plutus_data()],
|
||||
)
|
||||
vec![
|
||||
tx_info.to_plutus_data(),
|
||||
WithWrappedTransactionId(purpose.as_ref()).to_plutus_data(),
|
||||
],
|
||||
),
|
||||
ScriptContext::V3 {
|
||||
tx_info,
|
||||
redeemer,
|
||||
purpose,
|
||||
} => wrap_multiple_with_constr(
|
||||
0,
|
||||
vec![
|
||||
tx_info.to_plutus_data(),
|
||||
redeemer.to_plutus_data(),
|
||||
purpose.to_plutus_data(),
|
||||
],
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
AIKEN=${1:-"cargo run -r --quiet --"}
|
||||
|
||||
TESTS=()
|
||||
for lang in $(ls script_context); do
|
||||
for interaction in $(find script_context/$lang/validators -type f); do
|
||||
title=$(basename $interaction)
|
||||
title="${title%.*}"
|
||||
cd script_context/$lang
|
||||
./test.sh $title &
|
||||
./test.sh $title "$AIKEN" &
|
||||
TESTS+=("$title,$lang,$!")
|
||||
cd - 1>/dev/null
|
||||
done
|
||||
|
|
|
@ -13,4 +13,4 @@ requirements = []
|
|||
source = "github"
|
||||
|
||||
[etags]
|
||||
"aiken-lang/stdlib@main" = [{ secs_since_epoch = 1723298787, nanos_since_epoch = 494542000 }, "5e58899446492a704d0927a43299139856bef746e697b55895ba34206fa28452"]
|
||||
"aiken-lang/stdlib@main" = [{ secs_since_epoch = 1723298816, nanos_since_epoch = 935691000 }, "5e58899446492a704d0927a43299139856bef746e697b55895ba34206fa28452"]
|
||||
|
|
|
@ -12,6 +12,8 @@ if [ -z $TITLE ]; then
|
|||
exit 1
|
||||
fi
|
||||
|
||||
AIKEN=${2:-"cargo run -r --quiet --"}
|
||||
|
||||
if ! command -v jq &> /dev/null
|
||||
then
|
||||
echo "\033[1mjq\033[0m missing from system but required."
|
||||
|
@ -24,7 +26,7 @@ then
|
|||
exit 1
|
||||
fi
|
||||
|
||||
cargo run -r --quiet -- build 2>/dev/null
|
||||
$AIKEN build 2>/dev/null
|
||||
if [ $? -ne 0 ]; then
|
||||
exit $?
|
||||
fi
|
||||
|
@ -39,4 +41,4 @@ cp ctx/$TITLE/inputs.cbor.template ctx/$TITLE/inputs.cbor
|
|||
sed "s/{{ VALIDATOR_HASH }}/$VALIDATOR_HASH/" ctx/$TITLE/outputs.cbor.template > ctx/$TITLE/outputs.cbor
|
||||
sed "s/{{ VALIDATOR }}/$VALIDATOR/" ctx/$TITLE/tx.cbor.template | sed "s/{{ VALIDATOR_HASH }}/$VALIDATOR_HASH/" > ctx/$TITLE/tx.cbor
|
||||
|
||||
cargo run -r --quiet -- tx simulate 1>$TITLE.log 2>&1 ctx/$TITLE/tx.cbor ctx/$TITLE/inputs.cbor ctx/$TITLE/outputs.cbor
|
||||
$AIKEN tx simulate 1>$TITLE.log 2>&1 ctx/$TITLE/tx.cbor ctx/$TITLE/inputs.cbor ctx/$TITLE/outputs.cbor
|
||||
|
|
Loading…
Reference in New Issue