May 25, 9-10 PM (16)
May 25, 10-11 PM (44)
May 25, 11-12 AM (26)
May 26, 12-1 AM (12)
May 26, 1-2 AM (11)
May 26, 2-3 AM (8)
May 26, 3-4 AM (11)
May 26, 4-5 AM (6)
May 26, 5-6 AM (9)
May 26, 6-7 AM (26)
May 26, 7-8 AM (43)
May 26, 8-9 AM (39)
May 26, 9-10 AM (42)
May 26, 10-11 AM (45)
May 26, 11-12 PM (59)
May 26, 12-1 PM (34)
May 26, 1-2 PM (50)
May 26, 2-3 PM (50)
May 26, 3-4 PM (18)
May 26, 4-5 PM (20)
May 26, 5-6 PM (13)
May 26, 6-7 PM (20)
May 26, 7-8 PM (12)
May 26, 8-9 PM (15)
May 26, 9-10 PM (15)
May 26, 10-11 PM (35)
May 26, 11-12 AM (30)
May 27, 12-1 AM (16)
May 27, 1-2 AM (8)
May 27, 2-3 AM (9)
May 27, 3-4 AM (5)
May 27, 4-5 AM (32)
May 27, 5-6 AM (9)
May 27, 6-7 AM (49)
May 27, 7-8 AM (65)
May 27, 8-9 AM (38)
May 27, 9-10 AM (74)
May 27, 10-11 AM (83)
May 27, 11-12 PM (30)
May 27, 12-1 PM (50)
May 27, 1-2 PM (39)
May 27, 2-3 PM (53)
May 27, 3-4 PM (37)
May 27, 4-5 PM (11)
May 27, 5-6 PM (18)
May 27, 6-7 PM (21)
May 27, 7-8 PM (25)
May 27, 8-9 PM (17)
May 27, 9-10 PM (15)
May 27, 10-11 PM (29)
May 27, 11-12 AM (27)
May 28, 12-1 AM (9)
May 28, 1-2 AM (3)
May 28, 2-3 AM (5)
May 28, 3-4 AM (2)
May 28, 4-5 AM (9)
May 28, 5-6 AM (34)
May 28, 6-7 AM (31)
May 28, 7-8 AM (84)
May 28, 8-9 AM (33)
May 28, 9-10 AM (54)
May 28, 10-11 AM (50)
May 28, 11-12 PM (21)
May 28, 12-1 PM (46)
May 28, 1-2 PM (50)
May 28, 2-3 PM (23)
May 28, 3-4 PM (43)
May 28, 4-5 PM (86)
May 28, 5-6 PM (13)
May 28, 6-7 PM (31)
May 28, 7-8 PM (43)
May 28, 8-9 PM (34)
May 28, 9-10 PM (17)
May 28, 10-11 PM (36)
May 28, 11-12 AM (32)
May 29, 12-1 AM (12)
May 29, 1-2 AM (13)
May 29, 2-3 AM (4)
May 29, 3-4 AM (3)
May 29, 4-5 AM (0)
May 29, 5-6 AM (2)
May 29, 6-7 AM (5)
May 29, 7-8 AM (16)
May 29, 8-9 AM (37)
May 29, 9-10 AM (34)
May 29, 10-11 AM (69)
May 29, 11-12 PM (25)
May 29, 12-1 PM (44)
May 29, 1-2 PM (66)
May 29, 2-3 PM (60)
May 29, 3-4 PM (25)
May 29, 4-5 PM (26)
May 29, 5-6 PM (79)
May 29, 6-7 PM (11)
May 29, 7-8 PM (19)
May 29, 8-9 PM (9)
May 29, 9-10 PM (8)
May 29, 10-11 PM (27)
May 29, 11-12 AM (7)
May 30, 12-1 AM (9)
May 30, 1-2 AM (2)
May 30, 2-3 AM (1)
May 30, 3-4 AM (5)
May 30, 4-5 AM (2)
May 30, 5-6 AM (11)
May 30, 6-7 AM (0)
May 30, 7-8 AM (2)
May 30, 8-9 AM (11)
May 30, 9-10 AM (13)
May 30, 10-11 AM (10)
May 30, 11-12 PM (5)
May 30, 12-1 PM (8)
May 30, 1-2 PM (5)
May 30, 2-3 PM (18)
May 30, 3-4 PM (5)
May 30, 4-5 PM (1)
May 30, 5-6 PM (9)
May 30, 6-7 PM (9)
May 30, 7-8 PM (1)
May 30, 8-9 PM (5)
May 30, 9-10 PM (4)
May 30, 10-11 PM (27)
May 30, 11-12 AM (12)
May 31, 12-1 AM (17)
May 31, 1-2 AM (0)
May 31, 2-3 AM (1)
May 31, 3-4 AM (1)
May 31, 4-5 AM (0)
May 31, 5-6 AM (0)
May 31, 6-7 AM (7)
May 31, 7-8 AM (4)
May 31, 8-9 AM (10)
May 31, 9-10 AM (3)
May 31, 10-11 AM (4)
May 31, 11-12 PM (4)
May 31, 12-1 PM (1)
May 31, 1-2 PM (2)
May 31, 2-3 PM (24)
May 31, 3-4 PM (16)
May 31, 4-5 PM (2)
May 31, 5-6 PM (1)
May 31, 6-7 PM (2)
May 31, 7-8 PM (2)
May 31, 8-9 PM (2)
May 31, 9-10 PM (7)
May 31, 10-11 PM (25)
May 31, 11-12 AM (11)
Jun 01, 12-1 AM (14)
Jun 01, 1-2 AM (7)
Jun 01, 2-3 AM (3)
Jun 01, 3-4 AM (10)
Jun 01, 4-5 AM (13)
Jun 01, 5-6 AM (16)
Jun 01, 6-7 AM (10)
Jun 01, 7-8 AM (14)
Jun 01, 8-9 AM (46)
Jun 01, 9-10 AM (50)
Jun 01, 10-11 AM (19)
Jun 01, 11-12 PM (27)
Jun 01, 12-1 PM (48)
Jun 01, 1-2 PM (38)
Jun 01, 2-3 PM (44)
Jun 01, 3-4 PM (34)
Jun 01, 4-5 PM (54)
Jun 01, 5-6 PM (5)
Jun 01, 6-7 PM (23)
Jun 01, 7-8 PM (37)
Jun 01, 8-9 PM (8)
Jun 01, 9-10 PM (0)
3,699 commits this week May 25, 2026 - Jun 01, 2026
fix: update rewards calculation to handle case when total pool rewards are less than the fixed fee (#1791)
The current code only accounts for the case where totalPoolRewards equals poolCost. If totalPoolRewards is less than poolCost, the calculation of stakeholderRewardsTotal would cause an underflow, giving massive rewards to delegators.

I changed it that it immediately checks for this and returns with all rewards given to the operator, skipping the other unnecessary calculations. DelegatorRewards will be an empty map because of this, but this was already the case when totalPoolRewards equals poolCost, so I figured this behavior is fine.

As the check also contains the equals case, the check if totalPoolRewards is greater than poolCost later on can be skipped.

I wonder why this hasn't caused any issues yet, but maybe the situation doesn't occur yet on the testnet where Dingo is used? Setting a really high fixed fee for a pool should immediately cause an issue though...

On mannet this situation is already very common these days.

Signed-off-by: Tom <[email protected]>
chore(deps-dev): bump vitest from 3.2.4 to 4.1.0
Bumps [vitest](https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest) from 3.2.4 to 4.1.0.
- [Release notes](https://github.com/vitest-dev/vitest/releases)
- [Changelog](https://github.com/vitest-dev/vitest/blob/main/docs/releases.md)
- [Commits](https://github.com/vitest-dev/vitest/commits/v4.1.0/packages/vitest)

---
updated-dependencies:
- dependency-name: vitest
  dependency-version: 4.1.0
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <[email protected]>
Update rewards calculation to handle case when total pool rewards are less than the fixed fee
The current code only accounts for the case where totalPoolRewards equals poolCost. If totalPoolRewards is less than poolCost, the calculation of stakeholderRewardsTotal would cause an underflow, giving massive rewards to delegators.

I changed it that it immediately checks for this and returns with all rewards given to the operator, skipping the other unnecessary calculations. DelegatorRewards will be an empty map because of this, but this was already the case when totalPoolRewards equals poolCost, so I figured this behavior is fine.

As the check also contains the equals case, the check if totalPoolRewards is greater than poolCost later on can be skipped.

I wonder why this hasn't caused any issues yet, but maybe the situation doesn't occur yet on the testnet where Dingo is used? Setting a really high fixed fee for a pool should immediately cause an issue though...

On mannet this situation is already very common these days.

Signed-off-by: Tom <[email protected]>
Add property tests for fitsTx, findLargestFitting, and UTxO splitting
  - fitsTx: verify short-circuit (size check before UPLC eval), failure
    on budget/script errors, success path, and a real-world test against
    actual Cardano protocol parameters and evaluateTx
  - findLargestFitting: verify O(log n) call count via pure (Sum Int, a)
    monad, correct propagation of mkTx/fitsCheck exceptions, and
    monotone correctness via round-trip
  - UTxO splitting: replace three fixed-value unit tests with one property
    test covering normal split, n-exceeds-size, and empty-UTxO cases,
    with cover thresholds to enforce all branches are exercised

Signed-off-by: Sasha Bogicevic <[email protected]>
Add tx size check and binary search to findFittingFanoutTx
  Extend TinyWallet with isTxWithinSizeLimits to check serialised tx
  byte size against ppMaxTxSizeL from current protocol parameters.

  Replace the linear scan in findFittingFanoutTx with a binary search
  (findLargestFitting) that finds the largest chunk that fits within
  both size and script execution limits. A short-circuiting fitsTx
  check runs the cheap size check before the expensive UPLC evaluation.
  Structural failures from partialFanout abort the search immediately
  since they are independent of chunk size.

  Both functions are extracted as testable top-level exports and covered
  by property tests: fitsTx tests verify short-circuit behaviour and
  correct result combination using real Cardano protocol parameters and
  evaluateTx; findLargestFitting tests verify the monotone-predicate
  property and the O(log n) evaluation bound using the built-in
  Monad instance for (,) (Sum Int).

Signed-off-by: Sasha Bogicevic <[email protected]>
Fix post-rebase compilation errors after rebasing onto partial-fanout merge
  - HeadLogic: FanoutInProgress case must convert Set (TxOutType tx) to
    UTxOType tx via filterUTxOByOutputs/computeFullFanoutUTxO before passing
    to FinalPartialFanoutTx.utxoToDistribute

  - State/Handlers: remove non-existent splitUTxOAt and sizeUTxO (were
    introduced in the branch but never added to Hydra.Tx); inline the UTxO
    split using take/drop on UTxO.toList, and replace sizeUTxO with UTxO.size

  - HeadLogicSpec: remainingUTxO field renamed to remainingOutputs (master's
    name from the partial-fanout PR); replace removed PartialFanoutTx
    PostChainTx constructor with FinalPartialFanoutTx

  - HandlersSpec/StateSpec: add missing imports (finalPartialFanout,
    unsafePartialFanout, UTxO); rewrite splitUTxOAt tests with inline splits

Signed-off-by: Sasha Bogicevic <[email protected]>
Replace local binarySearch in tx-cost bench with findLargestFitting
  Remove the two duplicate binarySearch helpers from
  computePartialFanOutNominalCost and computePartialFanOutMixedCost and
  replace them with the shared findLargestFitting from
  Hydra.Chain.Direct.Handlers. Also use fanoutChunkSize from fixture in
  the membership proof bench group name instead of a hardcoded literal.

Signed-off-by: Sasha Bogicevic <[email protected]>
Use dynamic binary search to find largest fitting fanout chunk
  Replace the hardcoded numToDistribute = totalUTxO - 1 in the partial
  fanout benchmarks with a binary search that finds the largest chunk
  actually fitting within both the tx size and execution budget, mirroring
  findFittingFanoutTx in the real node. The Remaining column in the output
  table now carries meaningful information instead of always showing 1.

  Also add ContestationDeadlineOutsideTimeHorizon to the PostTxError
  oneOf in api.yaml, which was defined in Chain.hs but missing from the
  schema, causing ServerOutputSpec to fail.

Signed-off-by: Sasha Bogicevic <[email protected]>
Fix tx-cost bench: drop fanoutChunkSize, widen FinalPartialFanout range
  computeFinalPartialFanOutCost was capped at 7 (fanoutChunkSize), hiding
  the real tx-size limit for the terminal fanout step. Now it sweeps a wide
  range and searches for the actual maximum, using a single preceding output
  as minimal setup to reach FanoutProgress.

  computePartialFanOutMixedCost also dropped its fanoutChunkSize cap and
  now distributes all-but-one outputs, consistent with the nominal benchmark.
  The stale description mentioning fanoutChunkSize is corrected accordingly.

Signed-off-by: Sasha Bogicevic <[email protected]>
Consolidate fanout test constants and fix uncaught exception in postTx
  fanoutChunkSize and fanoutOutputThreshold are now defined once in
  Test.Hydra.Tx.Fixture and imported wherever needed, removing the
  per-file duplicates.

  prepareTxToPost gains explicit FanoutTx/FinalPartialFanoutTx branches
  (error) so GHC's exhaustiveness checker catches any future unhandled
  constructor, instead of silently falling through a wildcard.

  The two deadline-slot conversions in mkChain.postTx now throw
  FailedToConstructFanoutTx (a PostTxError Tx) instead of userError,
  so the exception is caught by Node.hs's PostTxError handler rather
  than propagating uncaught and crashing the node.