Skip to content

Witness datums are written in one layout and hashed in another #604

Description

@solidsnakedev

Summary

A witness datum is written in one layout and hashed in another. TransactionWitnessSet writes plutus_data with the transaction codec options (CML_DEFAULT_OPTIONS, every array and map definite). Data.toDatumHash and Redeemers.toScriptDataHash hash the same datum with the data default (CML_DATA_DEFAULT_OPTIONS, indefinite lists, maps and constructor fields). For any datum with constructor fields, a list or a map, the bytes in the transaction hash to neither value, so the node rejects a spend that supplies the datum in the witness set.

Evidence

Devnet on main (833d25e): lock at an always-succeeding script address under Data.toDatumHash(datum), then spend it with the datum in the witness set and the script data hash from toScriptDataHash(redeemers, costModels, [datum]), encoded with Transaction.toCBORHex and witnessed with addVKeyWitnessesBytes.

Datum Witness set writes Hashes use Node
Constr 0 [{1: 2}, [3]] d87982a101028103 d8799fbf0102ff9f03ffff 3113, script integrity hash mismatch
Constr 0 [1] d8798101 d8799f01ff 3113

With the script data hash computed over the written bytes, the node moves on to 3111 (missing datum), because the written datum does not hash to the locked datum hash. Only a transaction where all three agree on one layout was accepted.

The transaction builder does not attach witness datums yet (txBuilder.ts L858-863 is a TODO), so today only hand-built transactions hit this. It will block datum hash spends once the builder supports them.

Fix

Write new witness datums in the data layout used for hashing, and keep decoded witness datums in their original bytes (the OriginalBytes approach from #581, as #603 did for inline datums). After that, the data default can follow the node (#395).

Regression test

  • Devnet: the spend above is accepted for both datums.
  • The witness datum bytes hash to Data.toDatumHash(datum), and toScriptDataHash equals CML.hash_script_data over the written witness set.
  • A decoded transaction keeps its witness datum bytes in every layout, including maps with byte-string keys, through addVKeyWitnessesBytes.

Must FAIL on main today and PASS after the fix.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions