diff --git a/crates/uplc/src/tx/script_context.rs b/crates/uplc/src/tx/script_context.rs index 992b86e2e..a5f4c1cda 100644 --- a/crates/uplc/src/tx/script_context.rs +++ b/crates/uplc/src/tx/script_context.rs @@ -831,13 +831,13 @@ pub fn find_script( let lookup_datum = |datum: Option| match datum { Some(DatumOption::Hash(hash)) => match lookup_table.datum.get(&hash) { - Some(d) => Ok(d.clone()), + Some(d) => Ok(Some(d.clone())), None => Err(Error::MissingRequiredDatum { hash: hash.to_string(), }), }, - Some(DatumOption::Data(data)) => Ok(data.0.clone()), - _ => Err(Error::MissingRequiredInlineDatumOrHash), + Some(DatumOption::Data(data)) => Ok(Some(data.0.clone())), + None => Ok(None), }; match redeemer.tag { @@ -908,12 +908,16 @@ pub fn find_script( .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(output_datum(&input.resolved))?; - let script = lookup_script(hash); - - let datum = lookup_datum(output_datum(&input.resolved)); + if datum.is_none() + && matches!(script, ScriptVersion::V1(..) | ScriptVersion::V2(..)) + { + return Err(Error::MissingRequiredInlineDatumOrHash); + } - script.and_then(|(script, _)| Ok((script, Some(datum?)))) + Ok((script, datum)) } _ => Err(Error::NonScriptStakeCredential), }), diff --git a/examples/acceptance_tests/script_context/v3/ctx/simple_spend_no_datum/resolved_inputs.template b/examples/acceptance_tests/script_context/v3/ctx/simple_spend_no_datum/resolved_inputs.template new file mode 100644 index 000000000..ab2915ce8 --- /dev/null +++ b/examples/acceptance_tests/script_context/v3/ctx/simple_spend_no_datum/resolved_inputs.template @@ -0,0 +1,5 @@ +[ + { 0: h'70{{ simple_spend_no_datum.simple_spend.spend.hash }}' + , 1: 1000000000 + } +] diff --git a/examples/acceptance_tests/script_context/v3/ctx/simple_spend_no_datum/tx.template b/examples/acceptance_tests/script_context/v3/ctx/simple_spend_no_datum/tx.template new file mode 100644 index 000000000..7a4775016 --- /dev/null +++ b/examples/acceptance_tests/script_context/v3/ctx/simple_spend_no_datum/tx.template @@ -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 +] diff --git a/examples/acceptance_tests/script_context/v3/validators/simple_spend_no_datum.ak b/examples/acceptance_tests/script_context/v3/validators/simple_spend_no_datum.ak new file mode 100644 index 000000000..94c457e78 --- /dev/null +++ b/examples/acceptance_tests/script_context/v3/validators/simple_spend_no_datum.ak @@ -0,0 +1,49 @@ +use aiken/collection/dict +use cardano/address.{Address, Script} +use cardano/assets +use cardano/transaction.{Input, NoDatum, Output, OutputReference, Transaction} + +validator simple_spend { + spend( + datum: Option, + _redeemer: Void, + _output_ref: OutputReference, + transaction: Transaction, + ) { + expect None = datum + + assert_inputs(transaction.inputs) + + expect [] == dict.to_pairs(transaction.datums) + + True + } + + else(_ctx) { + fail + } +} + +fn assert_inputs(inputs: List) { + 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 +}