cardano-serialization-lib
cardano-serialization-lib copied to clipboard
How to spend multiple script outputs with inline-datum - MissingRedeemers Error
Hi, I am using the latest CSL 11.1.0 version on the preview network and I am trying to spend 2 script outputs that hold an inline datum like so:
for (let i = 0; i < sortedScriptTxInputs.length; i++) {
const o = sortedScriptTxInputs[i];
const txIn = TransactionInput.new(TransactionHash.from_bytes(Buffer.from(o.txId, 'hex')), o.idx);
const redeemer = wallet.withdrawRedeemer(i);
const plutusWitness = PlutusWitness.new_with_ref(PlutusScriptSource.new(spendingContract), DatumSource.new_ref_input(txIn), redeemer);
const amt = Value.new(BigNum.from_str(`${o.value.coins}`));
txBuilder.add_plutus_script_input(plutusWitness, txIn, amt);
}
console.log(`Number of script inputs: ${sortedScriptTxInputs.length}`); // prints 2
console.log(txBuilder.get_plutus_input_scripts()?.len()); // prints 1
I've tried both PlutusWitness
constructors: new
and new_with_ref
. The new
constructor attaches a datum to the Tx which causes a NonOutputSupplimentaryDatums
error. Using the new_with_ref
constructor seems to add a reference_input
and no datum witnesses, but it also only attaches 1
redeemer to the transaction even though I am adding 2
.
Hi @will991 ! Which version of plutus script do you use ?
Plutus V2
@will991 Could you try to spend 1 script input instead all ? It might help to localize the error. Are the datums the same for all inputs ?
Ok, I am getting a PPViewHashesDontMatch
error. That is the only error in the log.
Here is what I am doing:
- Add script input:
for (let i = 0; i < sortedScriptTxInputs.length; i++) {
const o = sortedScriptTxInputs[i];
const txIn = TransactionInput.new(TransactionHash.from_bytes(Buffer.from(o.txId, 'hex')), o.idx);
const redeemer = wallet.withdrawRedeemer(i);
const plutusWitness = PlutusWitness.new_with_ref(PlutusScriptSource.new(spendingContract), DatumSource.new_ref_input(txIn), redeemer);
const amt = Value.new(BigNum.from_str(`${o.value.coins}`));
scriptInputs.add_plutus_script_input(plutusWitness, txIn, amt);
}
txBuilder.set_inputs(scriptInputs);
- Setting collateral
- Adding required vkey signature
- Adding v2 costmodel & calculating
script data hash
:
const costModel = TxBuilderConstants.plutus_vasil_cost_models().get(Language.new_plutus_v2());
if (!costModel)
throw new Error('Missing vasil plutus v2 cost model');
const costModels = Costmdls.new();
costModels.insert(Language.new_plutus_v2(), costModel);
txBuilder.calc_script_data_hash(costModels);
- Add change output, Build Tx:
txBuilder.add_change_if_needed(changeAddress);
const tx = txBuilder.build_tx();
- Sign, extract vKey witness and add it to Tx witness set.
Here is shortened json of the signed Tx:
{
"body": {
"inputs": [
{
"transaction_id": "39246caa36df6944b4fb01d1d73d6c9a3a7b59e112e60517861b83253ccdabd1",
"index": 0
}
],
"outputs": [
{
"address": "addr_test1qrqcwuw9ju33z2l0zayt38wsthsldyrgyt82p2p3trccucffejwnp8afwa8v58aw7dpj7hpf9dh8txr0qlksqtcsxheqhekxra",
"amount": {
"coin": "3967503",
"multiasset": null
},
"plutus_data": null,
"script_ref": null
}
],
"fee": "1032497",
"ttl": null,
"certs": null,
"withdrawals": null,
"update": null,
"auxiliary_data_hash": null,
"validity_start_interval": null,
"mint": null,
"script_data_hash": "59eb6669a57d8d273b627c0f92cc55b5ebadc2a1e163973ddea981a0c402d5e3",
"collateral": [
{
"transaction_id": "8ae1f95340f665cc3eb84855c6654b95f3f8a956ed63b787b48686ebe08328ed",
"index": 0
}
],
"required_signers": [
"c18771c59723112bef1748b89dd05de1f6906822cea0a83158f18e61"
],
"network_id": null,
"collateral_return": null,
"total_collateral": "5000000",
"reference_inputs": [
{
"transaction_id": "39246caa36df6944b4fb01d1d73d6c9a3a7b59e112e60517861b83253ccdabd1",
"index": 0
}
]
},
"witness_set": {
"vkeys": [
{
"vkey": "ed25519_pk15g8dhxed0u4c4y8a4nwv5wvcpksx6mya2drzqjfuj2a0z3q2vlxsey056m",
"signature": "5182c8ca3086f2f9a6d4e0d2e8ab5ead02ef99afb0c16675f3f90ee850525abc1080c232e94c83cdffc700d32703948143725383527b4ad49e31dbc8a92ed708"
}
],
"native_scripts": null,
"bootstraps": null,
"plutus_scripts": [
"59153c01000033... some long script"
],
"plutus_data": {
"elems": [],
"definite_encoding": null
},
"redeemers": [
{
"tag": "Spend",
"index": "0",
"data": "{\"constructor\":0,\"fields\":[]}",
"ex_units": {
"mem": "7000000",
"steps": "3000000000"
}
}
]
},
"is_valid": true,
"auxiliary_data": null
}
From the error, I suppose the calculated hash of the script_data_hash
field does not match whatever is expected. But not sure how I get that resolved.
Exact Error:
""transaction submit error ShelleyTxValidationError ShelleyBasedEraBabbage (ApplyTxError [UtxowFailure (FromAlonzoUtxowFail (PPViewHashesDontMatch (SJust (SafeHash \"59eb6669a57d8d273b627c0f92cc55b5ebadc2a1e163973ddea981a0c402d5e3\")) (SJust (SafeHash \"45c67dd3aec5a66ddd3e0470d05923ad9b5cc4617ceb6aa94141e6b1abb4ee5d\"))))])""
> Are the datums the same for all inputs ?
Yes the datums are the same for all script inputs in this example. They only contain the PubKeyHash. The redeemer is also the same (Unit) but indexed in the case of spending multiple script outputs.
I am getting a similar error and currently working on resolving this, I will update here if I make progress
@will991 thanks! We will investigate it soon.
@NicholasMaselli could you provide information about your case ?
Current calc_script_data_hash
function has some issues when it comes to ref datums and it also has some trouble including the right cost models. The workaround I've been using is simply to calculate and set the script_data_hash
manually.
@will991 for your case, could you try
const redeemers = Redeemers.new()
redeemers.add(txBuilder.get_plutus_input_scripts().get(0).redeemer())
redeemers.add(txBuilder.get_plutus_input_scripts().get(1).redeemer())
const plutusWitnessHash = hash_script_data(redeemers, costModels, undefined)
txBuilder.set_script_data_hash(plutusWitnessHash)
@twwu123 thanks! This worked for me as well but only for a single script input. If I have multiple I still get:
""transaction submit error ShelleyTxValidationError ShelleyBasedEraBabbage (ApplyTxError [UtxowFailure (FromAlonzoUtxowFail (MissingRedeemers [(Spending (TxIn (TxId {_unTxId = SafeHash \"23e874d6549250c6d845031974212f87edb7f1b1d0f676afdf03cbddaf0ae9ad\"}) (TxIx 0)),ScriptHash \"d8feffeeee5fe079055719280d2a9603d93dc1289c2dff9912378d51\")])),UtxowFailure (FromAlonzoUtxowFail (PPViewHashesDontMatch (SJust (SafeHash \"ef6fdbc10a2566ba69e4ab9b8f4834c5392df30f7f7b07c216ffc059c613d569\")) (SJust (SafeHash \"8a180f238eb3cdbf8e8ef3bb7e512712fba6be0c51d25a9dc2c27a3f468c27a2\")))),UtxowFailure (UtxoFailure (FromAlonzoUtxoFail (UtxosFailure (CollectErrors [NoRedeemer (Spending (TxIn (TxId {_unTxId = SafeHash \"23e874d6549250c6d845031974212f87edb7f1b1d0f676afdf03cbddaf0ae9ad\"}) (TxIx 0)))]))))])""
It seems that the redeemers array only contains a single entry instead of 2 (for 2 script inputs)
"redeemers": [
{
"tag": "Spend",
"index": "1",
"data": "{\"constructor\":0,\"fields\":[]}",
"ex_units": {
"mem": "7000000",
"steps": "3000000000"
}
}
]
I suppose this may have to do with using txBuilder#build_tx
.
So I think there are some issues with multiple inputs from the same script due to the current implementation. @lisicky and I will do some more investigation, thanks a lot for the details.
Fix will be in the next CSL release