Skip to content

Leios prototype tx-firehose: dynamically allow for txs with more outputs - #6658

Merged
ch1bo merged 1 commit into
leios-prototypefrom
ch1bo/firehose-outputs
Aug 22, 2026
Merged

Leios prototype tx-firehose: dynamically allow for txs with more outputs#6658
ch1bo merged 1 commit into
leios-prototypefrom
ch1bo/firehose-outputs

Conversation

@ch1bo

@ch1bo ch1bo commented Aug 22, 2026

Copy link
Copy Markdown
Contributor

Two bugs stopped --outputs-per-tx > 1 from running for more than a few seconds, both showing up as "insufficient funds - total inputs (364400 lovelace) do not cover fee (1000000)".

takeInputs picks by TxIn order, i.e. effectively at random, so it could select target dust entries and split their sum target ways — producing finer dust, and repeating. 364,400 lovelace sits exactly in the divide-by-5 sequence down from the original 30M ADA, with the value itself untouched (29,999,924,000,000 across 305 UTxOs) simply because it was never selected. takeLargest instead takes the target largest funds, extending with the next largest until they cover fee + target * outputFloor, so an output is never created too small to spend again and stranded dust gets consolidated rather than sharpened. That also subsumes the fan-out case, so takeFattest goes.

Separately, keeping the inputs on a reject is right for a transient failure but wrong when the ledger says they are gone: takeInputs is deterministic, so the retry rebuilt the same tx and earned the same rejection until max-consecutive-errors. Worse at startup with a single UTxO and a fan-out target, where that one tx is the only one buildable.

Measured on dozen-devnet: --outputs-per-tx 5 gives 648 B transactions, 5 in / 5 out, no failures.

Description

Add your description here, if it fixes a particular issue please provide a
link
to the issue.

Checklist

  • Commit sequence broadly makes sense and commits have useful messages
  • New tests are added if needed and existing tests are updated. These may include:
    • golden tests
    • property tests
    • roundtrip tests
    • integration tests
      See Running tests for more details
  • Any changes are noted in the CHANGELOG.md for affected package
    • cardano-node-chairman, cardano-submit-api and cardano-testnet instead need a
      changelog fragment in <package>/.changes/, because their CHANGELOG.md is generated
      from fragments at release time. Copy _TEMPLATE.yml from that directory, or run
      nix run github:input-output-hk/cardano-dev#herald -- new
  • The version bounds in .cabal files are updated
  • CI passes. See note on CI. The following CI checks are required:
    • Code is linted with hlint. See .github/workflows/check-hlint.yml to get the hlint version
    • Code is formatted with stylish-haskell. See .github/workflows/stylish-haskell.yml to get the stylish-haskell version
    • Code builds on Linux, MacOS and Windows for ghc-9.6 and ghc-9.12
  • Self-reviewed the diff

Note on CI

If your PR is from a fork, the necessary CI jobs won't trigger automatically for security reasons.
You will need to get someone with write privileges. Please contact IOG node developers to do this
for you.

…are gone

Two bugs stopped --outputs-per-tx > 1 from running for more than a few
seconds, both showing up as "insufficient funds - total inputs (364400
lovelace) do not cover fee (1000000)".

takeInputs picks by TxIn order, i.e. effectively at random, so it could
select `target` dust entries and split their sum `target` ways — producing
finer dust, and repeating. 364,400 lovelace sits exactly in the divide-by-5
sequence down from the original 30M ADA, with the value itself untouched
(29,999,924,000,000 across 305 UTxOs) simply because it was never selected.
takeLargest instead takes the `target` largest funds, extending with the next
largest until they cover fee + target * outputFloor, so an output is never
created too small to spend again and stranded dust gets consolidated rather
than sharpened. That also subsumes the fan-out case, so takeFattest goes.

Separately, keeping the inputs on a reject is right for a transient failure
but wrong when the ledger says they are gone: takeInputs is deterministic, so
the retry rebuilt the same tx and earned the same rejection until
max-consecutive-errors. Worse at startup with a single UTxO and a fan-out
target, where that one tx is the only one buildable.

Measured on dozen-devnet: --outputs-per-tx 5 gives 648 B transactions, 5 in /
5 out, no failures.
@ch1bo
ch1bo requested a review from a team as a code owner August 22, 2026 17:27
@ch1bo ch1bo added the leios Means that this tickets is related to the implementation of ouroboros leios. label Aug 22, 2026
@ch1bo
ch1bo merged commit 11cd5ba into leios-prototype Aug 22, 2026
9 of 15 checks passed
@ch1bo
ch1bo deleted the ch1bo/firehose-outputs branch August 22, 2026 17:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

leios Means that this tickets is related to the implementation of ouroboros leios.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant