Skip to main content

Hydra Team Update

· 6 min read
Noon van der Silk
Software Engineering Lead

What did the team achieve?

  • Released 2.3.0, headlined by the reapplyTx snapshot-processing speedup, node configuration via YAML file, native PaymentExtendedKey (HD wallet) key support #2583, and the batch of rotation, Blockfrost and network-layer resilience fixes from the last two updates. Note that all the subsequently listed work has not yet been released
  • Merged the performance stack #2776-#2780, in five reviewable pieces:
    • accumulator commitments are now computed through the rust-accumulator FFI (bit-identical, pinned by equivalence and golden tests) and updated incrementally from the previous confirmed snapshot, taking the 4k-UTxO commitment from 2.13s to 25ms #2780
    • BREAKING: broadcast messages are batched into a single etcd value, one Raft commit per batch over a reused gRPC connection. This bumps the network protocol version to 2, so all members of a head must upgrade together #2778
    • maxTxsPerSnapshot raised from 100 to 1000, leader-side only so no coordinated upgrade is needed #2777
    • SQLite event encoding moved onto the write-behind thread, keeping serialisation of large SnapshotRequested events off the node loop between processing a ReqSn and broadcasting the AckSn #2779
    • plus the measurement and benchmark infrastructure the whole stack was driven from #2776
  • Implemented selective partial fanout: a new PartialFanout client input lets you distribute a chosen subset of the closed head's UTxO, with a HeadPartiallyFannedOut server output telling clients whether the node keeps draining or awaits the next selection, a FanningOut head status, and a matching TUI flow. Only the node that issued the command drives the step, so observers can't steamroll UTxO another party deliberately left behind #2750, #2333, with a docs page to go with it #2794
  • BREAKING: --deposit-period is now embedded in the on-chain OpenDatum at Init time, so all nodes in a head must agree on it; a mismatch emits IgnoredHeadInitializing and the node ignores the head, the same way contestation period mismatches already worked #2734
  • Added --deposit-activation to decouple activation from the deadline calculation: it controls only the Inactive -> Active transition while --deposit-period keeps its deadline and expiry role, giving three independent windows (maturity, active, recovery). The default of 3600s reproduces the old behaviour exactly #2802, #2744
  • POST /commit now rejects deposits that could never be claimed. A dry-run increment is checked against the L1 maximum transaction and serialized value sizes, returning a new DepositTooLarge error. Previously the deposit would land on-chain and the increment claiming it could never be submitted, wedging further incremental commits and locking the funds until recovery after the deadline #2807
  • Fixed long-running nodes rejecting every layer 2 Plutus transaction carrying a validity bound: the era history queried at startup has a forecast horizon (36 hours on mainnet), and once past it those transactions failed with PastHorizon until restart. The last era is now unbounded for L2 ledger time conversions #2803, #2798
  • BREAKING (WebSocket API): removed the SyncedStatusReport server output, which the node pushed on every block. Sync status is now edge-triggered via NodeUnsynced/NodeSynced and Greetings.chainSyncedStatus, and the continuous drift value became a hydra_chain_drift_seconds metric alongside a new hydra_chain_last_block_timestamp_seconds so a stalled chain backend is detectable even while drift is frozen #2769, #2749
  • Made hydra-chain-observer version-aware: it detects which protocol version an observed transaction belongs to by matching head and deposit script hashes against a registry in networks.json covering 0.13.0 through 2.2.0, removing the compile-time coupling to a single version and the hydra-plutus dependency altogether #2740
  • Fixed pasting into hydra-tui text fields (bracketed paste mode, so a paste arrives as one event and typing c into an address no longer cancels the dialog) and stopped it submitting stale form values when the entered address or amount was invalid #2770
  • Made the mac release binaries runnable without nix: they were hard-linking libraries out of /nix/store and simply wouldn't launch on a plain machine #2795, #2461
  • Bumped Mithril to 2630.0 and switched to the v2 database backend, since the aggregator no longer certifies v1 #2808
  • Docs fixes: the transaction-cost benchmark page is now generated by the docs build instead of being dropped in as raw markdown afterwards, so it renders with the current theme and stops listing removed transactions #2799, and the fanout cost table now sweeps party counts #2796

What's next?

  • Complete the typst + Agda specification work, split into a reviewable stack: a protocol fix forbidding a commit and a decommit in flight simultaneously #2784, the prose migration from LaTeX to Typst #2785, the Agda formalisation itself #2786, a hydra-agda package extracted via MAlonzo with a CI gate #2787, and differential tests checking the node and validator against that reference #2788
  • Switch the event store to CBOR #2767 and offer an opt-in binary encoding on the client API #2762
  • Iterate on ADR 34, covering the separation of hydra-chain-observer into a service shared by several nodes #2771
  • Make rejectLowDeposits a single pass rather than quadratic #2805
  • Get a release out with the performance stack and selective partial fanout