Home / Input Output / hydra-poc
Mar 23, 12-1 PM (1)
Mar 23, 1-2 PM (2)
Mar 23, 2-3 PM (0)
Mar 23, 3-4 PM (0)
Mar 23, 4-5 PM (0)
Mar 23, 5-6 PM (0)
Mar 23, 6-7 PM (0)
Mar 23, 7-8 PM (0)
Mar 23, 8-9 PM (0)
Mar 23, 9-10 PM (0)
Mar 23, 10-11 PM (0)
Mar 23, 11-12 AM (0)
Mar 24, 12-1 AM (0)
Mar 24, 1-2 AM (0)
Mar 24, 2-3 AM (0)
Mar 24, 3-4 AM (0)
Mar 24, 4-5 AM (0)
Mar 24, 5-6 AM (0)
Mar 24, 6-7 AM (0)
Mar 24, 7-8 AM (0)
Mar 24, 8-9 AM (0)
Mar 24, 9-10 AM (1)
Mar 24, 10-11 AM (0)
Mar 24, 11-12 PM (0)
Mar 24, 12-1 PM (2)
Mar 24, 1-2 PM (0)
Mar 24, 2-3 PM (0)
Mar 24, 3-4 PM (0)
Mar 24, 4-5 PM (0)
Mar 24, 5-6 PM (0)
Mar 24, 6-7 PM (0)
Mar 24, 7-8 PM (0)
Mar 24, 8-9 PM (0)
Mar 24, 9-10 PM (0)
Mar 24, 10-11 PM (0)
Mar 24, 11-12 AM (0)
Mar 25, 12-1 AM (0)
Mar 25, 1-2 AM (0)
Mar 25, 2-3 AM (0)
Mar 25, 3-4 AM (0)
Mar 25, 4-5 AM (0)
Mar 25, 5-6 AM (0)
Mar 25, 6-7 AM (0)
Mar 25, 7-8 AM (0)
Mar 25, 8-9 AM (0)
Mar 25, 9-10 AM (0)
Mar 25, 10-11 AM (0)
Mar 25, 11-12 PM (0)
Mar 25, 12-1 PM (0)
Mar 25, 1-2 PM (1)
Mar 25, 2-3 PM (0)
Mar 25, 3-4 PM (0)
Mar 25, 4-5 PM (0)
Mar 25, 5-6 PM (0)
Mar 25, 6-7 PM (1)
Mar 25, 7-8 PM (0)
Mar 25, 8-9 PM (0)
Mar 25, 9-10 PM (0)
Mar 25, 10-11 PM (0)
Mar 25, 11-12 AM (0)
Mar 26, 12-1 AM (0)
Mar 26, 1-2 AM (0)
Mar 26, 2-3 AM (0)
Mar 26, 3-4 AM (0)
Mar 26, 4-5 AM (0)
Mar 26, 5-6 AM (0)
Mar 26, 6-7 AM (0)
Mar 26, 7-8 AM (0)
Mar 26, 8-9 AM (0)
Mar 26, 9-10 AM (1)
Mar 26, 10-11 AM (0)
Mar 26, 11-12 PM (0)
Mar 26, 12-1 PM (0)
Mar 26, 1-2 PM (0)
Mar 26, 2-3 PM (0)
Mar 26, 3-4 PM (0)
Mar 26, 4-5 PM (0)
Mar 26, 5-6 PM (0)
Mar 26, 6-7 PM (0)
Mar 26, 7-8 PM (0)
Mar 26, 8-9 PM (0)
Mar 26, 9-10 PM (0)
Mar 26, 10-11 PM (0)
Mar 26, 11-12 AM (0)
Mar 27, 12-1 AM (0)
Mar 27, 1-2 AM (0)
Mar 27, 2-3 AM (0)
Mar 27, 3-4 AM (0)
Mar 27, 4-5 AM (0)
Mar 27, 5-6 AM (0)
Mar 27, 6-7 AM (0)
Mar 27, 7-8 AM (0)
Mar 27, 8-9 AM (0)
Mar 27, 9-10 AM (0)
Mar 27, 10-11 AM (0)
Mar 27, 11-12 PM (0)
Mar 27, 12-1 PM (0)
Mar 27, 1-2 PM (1)
Mar 27, 2-3 PM (0)
Mar 27, 3-4 PM (2)
Mar 27, 4-5 PM (0)
Mar 27, 5-6 PM (0)
Mar 27, 6-7 PM (0)
Mar 27, 7-8 PM (0)
Mar 27, 8-9 PM (0)
Mar 27, 9-10 PM (0)
Mar 27, 10-11 PM (0)
Mar 27, 11-12 AM (0)
Mar 28, 12-1 AM (0)
Mar 28, 1-2 AM (0)
Mar 28, 2-3 AM (0)
Mar 28, 3-4 AM (0)
Mar 28, 4-5 AM (0)
Mar 28, 5-6 AM (0)
Mar 28, 6-7 AM (0)
Mar 28, 7-8 AM (0)
Mar 28, 8-9 AM (0)
Mar 28, 9-10 AM (0)
Mar 28, 10-11 AM (0)
Mar 28, 11-12 PM (0)
Mar 28, 12-1 PM (0)
Mar 28, 1-2 PM (0)
Mar 28, 2-3 PM (0)
Mar 28, 3-4 PM (0)
Mar 28, 4-5 PM (0)
Mar 28, 5-6 PM (0)
Mar 28, 6-7 PM (0)
Mar 28, 7-8 PM (0)
Mar 28, 8-9 PM (0)
Mar 28, 9-10 PM (0)
Mar 28, 10-11 PM (0)
Mar 28, 11-12 AM (0)
Mar 29, 12-1 AM (0)
Mar 29, 1-2 AM (0)
Mar 29, 2-3 AM (0)
Mar 29, 3-4 AM (0)
Mar 29, 4-5 AM (0)
Mar 29, 5-6 AM (0)
Mar 29, 6-7 AM (0)
Mar 29, 7-8 AM (0)
Mar 29, 8-9 AM (0)
Mar 29, 9-10 AM (0)
Mar 29, 10-11 AM (0)
Mar 29, 11-12 PM (0)
Mar 29, 12-1 PM (0)
Mar 29, 1-2 PM (0)
Mar 29, 2-3 PM (0)
Mar 29, 3-4 PM (0)
Mar 29, 4-5 PM (0)
Mar 29, 5-6 PM (0)
Mar 29, 6-7 PM (0)
Mar 29, 7-8 PM (0)
Mar 29, 8-9 PM (0)
Mar 29, 9-10 PM (0)
Mar 29, 10-11 PM (0)
Mar 29, 11-12 AM (0)
Mar 30, 12-1 AM (0)
Mar 30, 1-2 AM (0)
Mar 30, 2-3 AM (0)
Mar 30, 3-4 AM (0)
Mar 30, 4-5 AM (0)
Mar 30, 5-6 AM (1)
Mar 30, 6-7 AM (0)
Mar 30, 7-8 AM (1)
Mar 30, 8-9 AM (0)
Mar 30, 9-10 AM (0)
Mar 30, 10-11 AM (0)
Mar 30, 11-12 PM (1)
Mar 30, 12-1 PM (3)
17 commits this week Mar 23, 2026 - Mar 30, 2026
Fix Plutus script evaluation using era-aware EpochInfo on mainnet/testnet
  On multi-era chains, Byron slots are 20s each while Shelley+ slots are 1s.
  Using fixedEpochInfo for L2 Globals produces wrong POSIXTime values in the
  Plutus ScriptContext, which can cause time-sensitive scripts (Close, Contest,
  Fanout) to fail. For online (Cardano) mode, query the chain's EraHistory and
  use it to build an era-aware EpochInfo via newGlobalsWithEraHistory. Offline
  mode keeps fixedEpochInfo since it runs a single-era devnet.

Signed-off-by: Sasha Bogicevic <[email protected]>
Filter pending deposits by HeadId when processing ReqTx (#2559)
## Summary
- Fix `RequestedDepositNotFoundLocally` error when submitting L2
transactions while deposits from other heads exist
- Apply `depositsForHead` filter to `pendingDeposits` in ReqTx handler,
consistent with ReqSn and AckSn handlers
- Prevents `selectNextDeposit` from picking deposits belonging to other
heads

## Problem
When processing a `ReqTx` (new L2 transaction), `onOpenNetworkReqTx`
received unfiltered `pendingDeposits`. This allowed `selectNextDeposit`
to
pick a deposit from another head, include it in the `ReqSn`, and cause
`RequestedDepositNotFoundLocally` errors when peers couldn't find the
deposit in their filtered list.

## Test plan
- [ ] Verify existing deposit-related tests pass
- [ ] Test L2 transaction submission while deposits from other heads are
observed on chain
Filter pending deposits by HeadId in all head-level handlers
The following handlers were passing unfiltered pendingDeposits, causing
them to potentially pick deposits from other heads:

1. ReqTx handler (line 1739): Could select wrong deposit for ReqSn,
   causing RequestedDepositNotFoundLocally errors on peers.

2. OnDecrementTx handler (line 1666): Could include wrong deposit in
   subsequent ReqSn via setExistingDeposit.

3. Rollback handler (line 1707): maybeRepostIncrementTx could find
   and repost for wrong head's deposit.

Other handlers (ReqSn, AckSn, onOpenChainTick) already correctly used
depositsForHead to filter deposits by the current head's ID.

Note: onChainTick intentionally processes ALL deposits as it handles
node-level deposit status tracking (DepositActivated/DepositExpired),
not head-specific logic.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Directly open heads (#2536)
Resolves #1329
Fix https://github.com/cardano-scaling/hydra/issues/2534 
Fix https://github.com/cardano-scaling/hydra/issues/2557

This is a monumental list of changes .. but what a pleasant one
(removing code = :lotus_position:)

Implements ADR-33 (new `docs/adr/2026-03-10_033-directly-open-head.md`):
the Hydra head initialization phase is removed. Init now opens the head
directly with an empty UTxO set, eliminating the old Commit → CollectCom
→ Open flow entirely.

- :lotus_position: Remove the initialization phase: Init creates the
head in Open state immediately — no more Commit, CollectCom, or Abort
transactions: **Greatly reduces cost and simplifies coordination** to
open a head
- :lotus_position: This gets rid of most known issues around abort and
only #1468 remains
- :lotus_position: Remove vInitial and vCommit on-chain validators,
reducing the script surface and may allow a single publishing txs again?
These were also the bottle necks and we _could_ **support ~50 party
heads** now
  - Not done in this PR, should I change it?
- :lotus_position: Remove Initial off-chain state and all associated
HeadLogic event handlers (HeadIsInitializing, Committed, HeadIsAborted,
Abort client input)
- :lotus_position: Unify fund ingestion under the existing
deposit/increment mechanism — POST /commit now always drafts a deposit
tx into an open head
- :lotus_position: Fix snapshot sideloading of deposit snapshots:
LocalStateCleared now correctly includes utxoToCommit in localUTxO when
the corresponding on-chain increment has been finalized
- :lotus_position: More behavior tests where possible
- :lotus_position: Consolidate and simplify E2E deposit tests:
single-party integrations for plain UTxO and script blueprint,
multi-party concurrent deposits with mkTestTiming' N for correct deposit
period sizing
- :lotus_position: Check deposits for Byron addresses and mainnet ADA
limit in draftDepositTx (previously only checked for commits)

This is so radically different that this will be HydraV2, hence I bumped
versions accordingly. We should use the chance to clean up the API (in
follow-up PRs).

TODO:
- [x] Scripts in `hydra-plutus`
- [x] L1 tx construction, observation and mutation tests in `hydra-tx`
- [x] L2 protocol types
- [x] `tx-cost` benchmark
  - [x] Cost diffences github workflow
- [x] L2 protocol logic
- [x] E2E tests in `hydra-cluster`
- [x] `hydra-tui`
- [x] Formal spec updated
https://github.com/cardano-scaling/hydra-formal-specification/pull/24
- [x] ADR for this change written
---

<!-- Consider each and tick it off one way or the other -->
* [x] CHANGELOG updated
* [x] Documentation updated
* [x] Haddocks updated
* [ ] ~~No new TODOs introduced~~ All follow-ups:
  - Rename `/commit` -> `/deposits` + rename everything
  - Drop `/head-initialization`
  - Unify `HeadSeed`/`HeadId`
- Make deposits / increment not require `==` but `>=` on the value (to
allow smaller than minUTxO deposits)
  - Use script reference on v_deposit in increment tx
Add deposit/decommit to full life cycle test and fix historical message replay
  singlePartyHeadFullLifeCycle now exercises the deposit (commit) flow
  using timing-derived deposit period instead of a hardcoded value, so the
  deposit activates within the test timeout on both devnet and real networks.

  waitForNodesSynced now waits for the Greetings message before declaring
  the node ready. Greetings is always sent after the full historical event
  replay, making it a reliable separator between replayed and live messages.
  This prevents tests from matching on historical HeadIsOpen or NodeSynced
  events from a previous run's persisted state — which caused the smoke test
  to proceed with a stale headId and then fail with "Head is not open" when
  posting to /commit.

Signed-off-by: Sasha Bogicevic <[email protected]>
Fix stuck snapshot when CommitFinalized races with RequestedSnapshot
  When CommitFinalized (or DecommitFinalized) arrives while a snapshot is
  in RequestedSnapshot state, the in-flight ReqSn carries the old version
  and will be rejected with ReqSvNumberInvalid once the version bumps.
  Since nothing re-triggers a fresh request, the head gets permanently
  stuck with pending localTxs.

  The guard added in ef0762bd5 used snapshotInFlight which returns True
  for both RequestedSnapshot and SeenSnapshot. This was correct for
  SeenSnapshot (AckSns in-flight, snapshot will complete naturally) but
  too broad for RequestedSnapshot (stale echo will be rejected).

  Replace the guard with isCollectingAcks which only blocks SeenSnapshot,
  allowing CommitFinalized/DecommitFinalized to immediately re-request
  with the new version when in RequestedSnapshot state.

Signed-off-by: Sasha Bogicevic <[email protected]>
Write IOSim trace to file instead of stdout on test failure
  The old dumpTrace used say which in IO context dumps the entire IOSim
  trace (potentially thousands of JSON lines) to stdout on test failure.
  With slow-network tests generating much larger traces, this was very
  noisy. Now the trace is written to a temp file and only the path is
  printed.

Signed-off-by: Sasha Bogicevic <[email protected]>
Pick up active deposits in chained snapshots when currentDepositTxId is unset
  When a deposit activates while a snapshot is in-flight, the tick cannot
  request a snapshot (blocked by snapshotInFlight). After the in-flight
  snapshot confirms, LocalStateCleared resets currentDepositTxId to Nothing,
  so setExistingDeposit returns Nothing and the deposit is never included in
  subsequent chained snapshots — eventually expiring unused.

  Fix by introducing selectNextDeposit which falls back to scanning
  pendingDeposits for the oldest active deposit when currentDepositTxId is
  unset, guarded by: no pending decommit and the last confirmed snapshot did
  not already include a deposit (to avoid double-posting IncrementTx before
  CommitFinalized removes the deposit). This fallback is used in both
  maybeRequestNextSnapshot and maybeRequestSnapshot in onOpenNetworkReqTx.

Signed-off-by: Sasha Bogicevic <[email protected]>
Pick up active deposits in chained snapshots when currentDepositTxId is unset
  When a deposit activates while a snapshot is in-flight, the tick cannot
  request a snapshot (blocked by snapshotInFlight). After the in-flight
  snapshot confirms, LocalStateCleared resets currentDepositTxId to Nothing,
  so setExistingDeposit returns Nothing and the deposit is never included in
  subsequent chained snapshots — eventually expiring unused.

  Fix by introducing selectNextDeposit which falls back to scanning
  pendingDeposits for the oldest active deposit when currentDepositTxId is
  unset, guarded by: no pending decommit and the last confirmed snapshot did
  not already include a deposit (to avoid double-posting IncrementTx before
  CommitFinalized removes the deposit). This fallback is used in both
  maybeRequestNextSnapshot and maybeRequestSnapshot in onOpenNetworkReqTx.

Signed-off-by: Sasha Bogicevic <[email protected]>