refactor(validate): extract phase2 evaluator and surface failure context
Move the amaru-uplc invocation out of `tx.rs` into a dedicated
`phase2::evaluator` module exposing `eval_script` -> `ScriptEvalResult`.
This isolates the script-evaluation surface from the rest of phase-two
plumbing and makes it directly testable.
Promote machine failures from a silently-discarded `Err` on
`result.term` into structured data: `MachineFailure { message, budget,
logs }` is propagated up and surfaced on `TxEvalResult` via a new
`failure_message: Option<String>` field. Previously a failing script
would yield `success: false` with no diagnostic; callers now receive
the evaluator's error message and the same line is emitted at debug
level via `tracing`.
Restructure `Error::Machine` from an opaque tuple wrapping the
arena-borrowed `MachineError` into a `{ message, budget, logs }` struct
with a clean `Display` impl backed by free `format_machine_traces` and
`indent_trace` helpers. The previous variant could never actually be
constructed (the arena lifetime didn't permit it) and was dead.
Drop the `* 11 / 10` budget inflation hack in `tx.rs` — the evaluator's
reported `consumed_budget` is now passed through verbatim. Callers
that relied on the old margin will see slightly lower numbers.
Add unit tests in `evaluator.rs` covering: CBOR decode failure typing,
flat decode failure typing, machine failure capturing logs and a
non-empty message, V2 application order (datum -> redeemer -> context),
V2 with missing datum, and a regression test confirming `serialiseData`
on V3 evaluates without panicking.
Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>