fix: Plutus V3 NoDatum - Error: missing required inline datum or datum hash in script input

This commit is contained in:
solidsnakedev 2024-09-11 15:25:20 -06:00
parent 0905146140
commit defce9be4e
4 changed files with 157 additions and 7 deletions

View File

@ -1,4 +1,7 @@
use super::{to_plutus_data::MintValue, Error}; use super::{
to_plutus_data::{MintValue, ToPlutusData},
Error,
};
use itertools::Itertools; use itertools::Itertools;
use pallas_addresses::{Address, Network, StakePayload}; use pallas_addresses::{Address, Network, StakePayload};
use pallas_codec::utils::{ use pallas_codec::utils::{
@ -839,6 +842,16 @@ pub fn find_script(
Some(DatumOption::Data(data)) => Ok(data.0.clone()), Some(DatumOption::Data(data)) => Ok(data.0.clone()),
_ => Err(Error::MissingRequiredInlineDatumOrHash), _ => Err(Error::MissingRequiredInlineDatumOrHash),
}; };
let lookup_datum_v3 = |datum: Option<DatumOption>| match datum {
Some(DatumOption::Hash(hash)) => match lookup_table.datum.get(&hash) {
Some(d) => Ok(d.clone()),
None => Err(Error::MissingRequiredDatum {
hash: hash.to_string(),
}),
},
Some(DatumOption::Data(data)) => Ok(data.0.clone()),
_ => Ok(None::<PlutusData>.to_plutus_data()),
};
match redeemer.tag { match redeemer.tag {
RedeemerTag::Mint => get_mint_info(&tx.transaction_body.mint) RedeemerTag::Mint => get_mint_info(&tx.transaction_body.mint)
@ -908,12 +921,12 @@ pub fn find_script(
.and_then(|input| match output_address(&input.resolved) { .and_then(|input| match output_address(&input.resolved) {
Address::Shelley(shelley_address) => { Address::Shelley(shelley_address) => {
let hash = shelley_address.payment().as_hash(); let hash = shelley_address.payment().as_hash();
let (script, _) = lookup_script(hash)?;
let script = lookup_script(hash); let datum = match script {
ScriptVersion::V3(_) => lookup_datum_v3(output_datum(&input.resolved)),
let datum = lookup_datum(output_datum(&input.resolved)); _ => lookup_datum(output_datum(&input.resolved)),
}?;
script.and_then(|(script, _)| Ok((script, Some(datum?)))) Ok((script, Some(datum)))
} }
_ => Err(Error::NonScriptStakeCredential), _ => Err(Error::NonScriptStakeCredential),
}), }),

View File

@ -0,0 +1,5 @@
[
{ 0: h'70{{ simple_spend_no_datum.simple_spend.spend.hash }}'
, 1: 1000000000
}
]

View File

@ -0,0 +1,33 @@
[
{ 0:
[ [h'0000000000000000000000000000000000000000000000000000000000000000', 0]
]
, 1:
[]
, 2: 42
, 11: h'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF'
, 13:
[ [h'0000000000000000000000000000000000000000000000000000000000000000', 0]
]
, 16:
[ h'6000000000000000000000000000000000000000000000000000000000', 1000000000
]
, 17: 1
},
{ 5: [[0, 0, 121([]), [1000000, 100000000]]]
, 7: [h'{{ simple_spend_no_datum.simple_spend.spend.cbor }}']
},
true,
null
]

View File

@ -0,0 +1,99 @@
use aiken/collection/dict
use cardano/address.{Address, Script}
use cardano/assets
use cardano/transaction.{
Input, NoDatum, Output, OutputReference, ScriptPurpose, Spend, Transaction,
}
validator simple_spend {
spend(
_datum: Option<Void>,
_redeemer: Void,
output_ref: OutputReference,
transaction: Transaction,
) {
assert_transaction_id(transaction.id)
assert_script_info(output_ref)
assert_inputs(transaction.inputs)
expect [] = transaction.outputs
expect [] = transaction.reference_inputs
expect [] = transaction.extra_signatories
expect 42 == transaction.fee
assert_redeemers(transaction.redeemers)
expect [] == dict.to_pairs(transaction.datums)
True
}
else(_ctx) {
fail
}
}
fn assert_transaction_id(id: ByteArray) {
expect
#"c6fbd346681a8f8337f6b3e51e6ec973f1509367eabc3a44c849af58a1d8471b" == id
Void
}
fn assert_script_info(info: OutputReference) {
expect
OutputReference {
transaction_id: #"0000000000000000000000000000000000000000000000000000000000000000",
output_index: 0,
} == info
Void
}
fn assert_inputs(inputs: List<Input>) {
expect [
Input {
output_reference: OutputReference { transaction_id, output_index: 0 },
output: Output {
address,
value: resolved_input_value,
datum: NoDatum,
reference_script: None,
},
},
] = inputs
expect
transaction_id == #"0000000000000000000000000000000000000000000000000000000000000000"
expect resolved_input_value == assets.from_lovelace(1000000000)
expect Address { payment_credential: Script(_), stake_credential: None } =
address
Void
}
fn assert_redeemers(redeemers: Pairs<ScriptPurpose, Data>) {
expect
[
Pair(
Spend(
OutputReference {
transaction_id: #"0000000000000000000000000000000000000000000000000000000000000000",
output_index: 0,
},
),
void(),
),
] == redeemers
Void
}
fn void() -> Data {
let void: Data = Void
void
}