Skip to content

Blockfrost speedup - #2821

Merged
noonio merged 6 commits into
masterfrom
blockfrost-speedup
Aug 14, 2026
Merged

Blockfrost speedup#2821
noonio merged 6 commits into
masterfrom
blockfrost-speedup

Conversation

@v0d1ch

@v0d1ch v0d1ch commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

fixes #2753

Improvements in this PR:

  • lifecycle >1h before, ~13.5 min now (~8 min net of build and contestation);
  • publish ~10 min → ~32s;
  • first seeding ~30 min → ~40s.

https://github.com/cardano-scaling/hydra/actions/runs/31692829527/job/94423784389


  • CHANGELOG updated or not needed
  • Documentation updated or not needed
  • Haddocks updated or not needed
  • No new TODOs introduced or explained herafter

@v0d1ch v0d1ch self-assigned this Aug 13, 2026
v0d1ch added 6 commits August 13, 2026 12:44
Also await on the utxo to become available at the address since
tx inclusion does not update address query immediately.

Signed-off-by: Sasha Bogicevic <sasha.bogicevic@iohk.io>
- Report PostTxError immediately instead of sleeping one block time first.
- Keep serving the queue after a failed submission. Previously the client
  thread exited, which cancelled the race in blockfrostChain and restarted
  the follower from the startup point: one failed post triggered a full
  re-sync and re-observation of every block since node start.
- Actually inspect the API-level result. tryError only caught IOExceptions,
  so an API rejection (the inner Either from runBlockfrost) fell into the
  success branch and was reported as PostedTx. Rejected transactions were
  invisible to the caller.
- Inject the submit action (submitViaBlockfrost adapter) to make the client
  unit-testable, and add a regression test for immediate reporting and
  queue continuity after failure.

Signed-off-by: Sasha Bogicevic <sasha.bogicevic@iohk.io>
The follower slept one block time and then processed exactly one block
per iteration, so it could never advance faster than the chain grows and
any lag became permanent. At the tip it was slower still: fetching the
unconfirmed tip block threw NotEnoughBlockConfirmations into the retry
wrapper, doubling the effective poll period to two block times.

Fetch successors with getNextBlocks' (up to 100 full block records per
request) instead of chasing _blockNextBlock with one getBlock per block:

- catch up any distance in bounded batches without sleeping, and sleep
  one block time only once caught up to the tip
- skip the per-block transaction fetch when the header says tx_count is
  zero, which is most testnet blocks
- keep the one-confirmation policy by only processing blocks that
  already have a successor, via the confirmations field instead of
  exception control flow
- startup catch-up is no longer a special case and no longer re-observes
  the block at the persisted start point, matching the direct backend

Removes the now-unthrown NotEnoughBlockConfirmations and
MissingNextBlockHash error constructors.

Signed-off-by: Sasha Bogicevic <sasha.bogicevic@iohk.io>
The test was parked behind pendingWith and rotted: it closed with a
hand-signed snapshot claiming a UTxO that was never deposited into the
head, which the head validator now correctly rejects with H65
(ChangedHeadAdaOverhead). The DirectChainSpec version of the same test
closes with an empty snapshot; apply the same shape here and drop the
then-unused second seeding and external key.

Exercising a real deposit through Blockfrost remains future coverage
work.

Signed-off-by: Sasha Bogicevic <sasha.bogicevic@iohk.io>
Nothing handled HTTP 429 responses: runBlockfrostM collapsed every API
error into a rendered string and all retry paths treated them alike.
Worse, the retry policy used for startup queries had a units bug: the
comment promised exponential backoff of 1s..60s, but fullJitterBackoff
takes microseconds, so the base was 2ms with no cap and all retries
fired within about two seconds.

- Distinguish 429 as BlockfrostRateLimited and retry it inside
  runBlockfrostM with capped exponential backoff (1s, 2s, 4s ... max
  60s, at most 6 attempts) before giving up. blockfrost-client does not
  expose the Retry-After header, so the delay is blind.
- Fix the startup retry policy to an actual 1s-base full-jitter backoff
  capped at 60s, and take the policy as a parameter so tests can use a
  delay-free one.
- Route transaction submission through runBlockfrostM so it inherits
  the backoff.
- Share the backoff constants with hydra-chain-observer's Blockfrost
  client, which gained the same 429 handling, instead of keeping a
  drifting copy there.

Signed-off-by: Sasha Bogicevic <sasha.bogicevic@iohk.io>
With the Blockfrost backend now polling verifiable conditions, the
remaining fixed-delay machinery had no purpose:

- Remove the --blockfrost-query-timeout option, its query-timeout
  config key and api.yaml schema entry; it configured the deleted
  unconditional pre-query sleep.
- Remove getQueryDelay from the ChainBackend class and the 30s settle
  before each Blockfrost cluster test; reactive rate-limit backoff
  replaced the only reason they existed.
- Shrink the blanket Blockfrost test timeout multiplier from 30x to 3x,
  since the follower now observes about one block behind the tip.

Un-park "can open, close & fanout a Head using Blockfrost": tag it
@requiresBlockfrost so the nightly filter actually selects it, and size
observation deadlines as 6 block times instead of a fixed 30s. During
development on preview, publishing took ~32s and a seeding ~40s, versus
roughly 10 and 30 minutes before.

Signed-off-by: Sasha Bogicevic <sasha.bogicevic@iohk.io>
@v0d1ch
v0d1ch force-pushed the blockfrost-speedup branch from e4011a0 to 1d4fe81 Compare August 13, 2026 10:45
@github-actions

Copy link
Copy Markdown

Transaction cost differences

No cost or size differences found

@github-actions

Copy link
Copy Markdown

End-to-end benchmark differences

Comparing this PR (new) against master (old). Numbers come from cloud VMs, so changes under 5% are shown as and are likely run-to-run noise rather than a real regression or improvement. 🟢 = improvement, 🔴 = regression; uncolored rows are neutral measures reported for context.

Sustained load (3 nodes, 3x5000 txs)

Metric master PR Δ
End-to-end TPS (tx/s) 477.61 464.31 ≈ -13.30 (-2.8%)
Sustained TPS (tx/s) 890.09 841.52 🔴 -48.57 (-5.5%)
Backlog drain time (s) 30.20 29.90 ≈ -0.30 (-1.0%)
Snapshots per second (/s) 0.54 0.53 ≈ -0.01 (-1.9%)
Avg txs per snapshot 882.40 882.40 ≈ +0.00 (+0.0%)
Avg. Confirmation Time (s) 24.971 26.050 ≈ +1.079 (+4.3%)
P50 confirmation (s) 26.851 27.085 ≈ +0.234 (+0.9%)
P95 confirmation (s) 30.245 31.769 🔴 +1.524 (+5.0%)
P99 confirmation (s) 30.290 31.929 🔴 +1.639 (+5.4%)
Tx validation time p50 (s) 9.058 9.402 ≈ +0.345 (+3.8%)
Peak node RSS (MB) 425.20 429.00 ≈ +3.80 (+0.9%)
Invalid txs 0.00 0.00 ≈ +0.00 (n/a%)

Plateau 1000 UTxO (1 node, 4000 txs)

Metric master PR Δ
End-to-end TPS (tx/s) 231.34 195.80 🔴 -35.54 (-15.4%)
Backlog drain time (s) 17.20 20.30 🔴 +3.10 (+18.0%)
Snapshots per second (/s) 0.40 0.34 -0.06 (-15.0%)
Avg txs per snapshot 571.40 571.40 ≈ +0.00 (+0.0%)
Avg. Confirmation Time (s) 11.171 13.000 🔴 +1.829 (+16.4%)
P50 confirmation (s) 10.356 11.908 🔴 +1.552 (+15.0%)
P95 confirmation (s) 17.208 20.326 🔴 +3.118 (+18.1%)
P99 confirmation (s) 17.210 20.329 🔴 +3.120 (+18.1%)
Tx validation time p50 (s) 5.385 6.305 🔴 +0.919 (+17.1%)
Peak node RSS (MB) 403.70 425.40 +21.70 (+5.4%)
Invalid txs 0.00 0.00 ≈ +0.00 (n/a%)

Round-trip latency (3 nodes, closed-loop, 3x250 txs)

Metric master PR Δ
End-to-end TPS (tx/s) 116.37 103.24 🔴 -13.13 (-11.3%)
Sustained TPS (tx/s) 116.63 103.07 🔴 -13.56 (-11.6%)
Backlog drain time (s) 0.00 0.00 ≈ +0.00 (n/a%)
Snapshots per second (/s) 78.66 69.93 -8.73 (-11.1%)
Avg txs per snapshot 1.50 1.50 ≈ +0.00 (+0.0%)
Avg. Confirmation Time (s) 0.026 0.029 🔴 +0.003 (+12.5%)
P50 confirmation (s) 0.025 0.028 🔴 +0.003 (+13.3%)
P95 confirmation (s) 0.034 0.038 🔴 +0.004 (+11.8%)
P99 confirmation (s) 0.039 0.043 🔴 +0.004 (+11.3%)
Tx validation time p50 (s) 0.007 0.008 🔴 +0.001 (+13.0%)
Peak node RSS (MB) 149.00 149.00 ≈ +0.00 (+0.0%)
Invalid txs 0.00 0.00 ≈ +0.00 (n/a%)

@github-actions

Copy link
Copy Markdown

Transaction costs

Sizes and execution budgets for Hydra protocol transactions. Note that unlisted parameters are currently using arbitrary values and results are not fully deterministic and comparable to previous runs.

Metadata
Generated at 2026-08-13 10:53:09.542986755 UTC
Max. memory units 14000000
Max. CPU units 10000000000
Max. tx size (kB) 16384

Script summary

Name Hash Size (Bytes)
νHead f2dd4ade71e19c2310a86215aa78aea06463aca2d8b818af8dc1b8a4 12805
μHead 4abb8dedbcd6a6f03f4fe227300e2713d73b7680d47baa898b60d27a* 4971
νDeposit c78e8c9205721eb3ef4410f3db9c6169fa6db497c24641d29c20529c 1615
νCRS 09db7ee6cf7a4b358dd5c8a2f19d2c048336ffc5a01ef35a47ca7072 2736
  • The minting policy hash is only usable for comparison. As the script is parameterized, the actual script is unique per head.

Init transaction costs

Parties Tx size % max Mem % max CPU Min fee ₳
1 5477 9.85 3.25 0.49
2 5571 9.62 3.15 0.50
3 5668 10.61 3.48 0.51
5 5861 11.42 3.73 0.53
10 6340 13.83 4.50 0.57
50 10183 35.60 11.31 0.97
100 14983 62.17 19.63 1.45
114 16331 69.49 21.89 1.59

Cost of Increment Transaction

Parties Tx size % max Mem % max CPU Min fee ₳
1 2321 20.59 7.33 0.47
2 2452 21.75 8.37 0.49
3 2581 23.20 9.50 0.52
5 2846 24.46 11.23 0.55
10 3503 29.84 16.27 0.66
50 8742 71.36 55.93 1.51
75 12018 97.94 80.93 2.05

Cost of Decrement Transaction

Parties Tx size % max Mem % max CPU Min fee ₳
1 641 18.46 6.68 0.38
2 773 19.40 7.64 0.40
3 903 20.35 8.61 0.42
5 1167 22.35 10.58 0.46
10 1825 27.17 15.44 0.56
50 7067 67.53 54.73 1.40
75 10338 93.89 79.60 1.94

Close transaction costs

Parties Tx size % max Mem % max CPU Min fee ₳
2 800 18.76 12.65 0.43
3 931 19.72 13.62 0.45
50 7090 68.07 60.18 1.45
74 10238 92.64 83.90 1.95

Contest transaction costs

Parties Tx size % max Mem % max CPU Min fee ₳
1 704 21.50 14.91 0.46
2 828 22.64 15.93 0.48
3 964 23.75 16.95 0.51
5 1226 26.07 19.02 0.55
10 1881 31.72 24.14 0.66
50 7121 80.17 65.91 1.59
66 9217 98.64 82.36 1.95

FanOut transaction costs

Involves spending head output and burning head tokens. Uses ada-only UTXO for better comparability.
Rows first grow the UTxO set at a fixed 10 parties, then show the largest set that still fits per number of parties (burning more participation tokens leaves less room for outputs).

Parties UTxO UTxO (bytes) Tx size % max Mem % max CPU Min fee ₳
10 0 0 5644 23.29 42.87 0.90
10 1 57 5679 25.63 45.39 0.93
10 5 285 5814 35.88 55.71 1.10
10 10 570 5984 49.89 68.99 1.31
10 20 1140 6324 82.42 96.97 1.79
1 20 1138 6043 76.20 95.00 1.72
5 20 1140 6169 78.96 95.88 1.75
10 20 1140 6325 82.42 96.97 1.79
20 20 1139 6633 89.74 99.26 1.88
50 15 855 7396 94.70 91.88 1.90

PartialFanOut transaction costs

Largest chunk of ada-only outputs that can be distributed in one partial fanout step, computed dynamically. The last row is the maximum total UTxO count where at least one output can still be distributed.

Total UTxO Distributed UTxO (bytes) Tx size % max Mem % max CPU Min fee ₳
11 10 570 983 34.91 66.33 0.95
25 23 1310 1429 68.24 99.40 1.48
30 23 1308 1427 68.24 99.40 1.48
40 23 1309 1428 68.24 99.40 1.48
50 23 1309 1428 68.24 99.40 1.48
100 23 1307 1426 68.24 99.40 1.48
150 23 1309 1428 68.24 99.40 1.48
200 23 1310 1429 68.24 99.40 1.48
200 23 1310 1425 68.24 99.40 1.48

PartialFanOut transaction costs (with native tokens)

Largest chunk of native-token outputs that can be distributed in one partial fanout step, computed dynamically. The last row is the maximum total UTxO count where at least one output can still be distributed.

Total UTxO Distributed UTxO (bytes) Tx size % max Mem % max CPU Min fee ₳
11 10 1000 1473 42.00 68.83 1.05
25 21 2058 2302 76.56 99.12 1.58
30 21 2142 2390 76.59 99.17 1.59
40 21 1995 2236 76.56 99.11 1.58
50 21 2079 2325 76.59 99.12 1.59
100 21 2163 2413 76.59 99.17 1.59
150 21 2478 2743 76.56 99.22 1.60
200 21 1974 2215 76.56 99.11 1.58
200 21 2373 2629 76.59 99.22 1.60

FinalPartialFanOut transaction costs (with native tokens)

Terminal partial fanout step (FanoutProgress → Final) with outputs carrying a native token. Burns all head tokens and proves accumulator exhaustion via BLS proof.

Distributed UTxO (bytes) Tx size % max Mem % max CPU Min fee ₳
1 100 5519 22.10 44.30 0.89
5 490 5825 35.58 55.79 1.10
10 1020 6251 53.90 70.62 1.37
10 1010 6241 53.90 70.60 1.37

End-to-end benchmark results

This page is intended to collect the latest end-to-end benchmark results produced by Hydra's continuous integration (CI) system from the latest master code.

Please note that these results are approximate as they are currently produced from limited cloud VMs and not controlled hardware. Rather than focusing on the absolute results, the emphasis should be on relative results, such as how the timings for a scenario evolve as the code changes.

Generated at 2026-08-13 10:54:05.311075051 UTC

Baseline Scenario

Number of nodes 1
Number of txs 300
Avg. Confirmation Time (ms) 202.5
P99 204.7ms
P95 204.4ms
P50 202.6ms
Tx validation time p50 (ms) 124.6
End-to-end TPS 1431.84 tx/s
Backlog drain time (s) 0.2
Snapshots observed 3
Snapshots per second 14.32 /s
Avg txs per snapshot 100.0
Peak node RSS (MB) 144.4
Number of Invalid txs 0
Fanout outputs 2

Three local nodes

Number of nodes 3
Number of txs 900
Avg. Confirmation Time (ms) 1006.0
P99 1060.1ms
P95 1058.8ms
P50 1045.3ms
Tx validation time p50 (ms) 489.8
End-to-end TPS 836.15 tx/s
Backlog drain time (s) 1.0
Snapshots observed 3
Snapshots per second 2.79 /s
Avg txs per snapshot 300.0
Peak node RSS (MB) 146.2
Number of Invalid txs 0
Fanout outputs 4

Scenario benchmark results

This page collects results from the scenario matrix: every combination of cluster size, UTxO shape, and incremental-ops mode is exercised by CI from the latest master code and reported below.

Numbers are approximate. They come from cloud VMs rather than controlled hardware, so the useful signal is the relative change between cells and between commits, not the absolute throughput.

Generated at 2026-08-13 11:06:27.336454208 UTC

Summary across cells

TPS columns are rates (transactions per second); Wall clock (s) is the measured elapsed time from the first tx submission to the last confirmation. Times are rounded to one decimal.

Scenario Txs Wall clock (s) End-to-end TPS (tx/s) Sustained TPS (tx/s) Avg conf (ms) P95 conf (ms)
Nodes=1, Constant, fire and forget 30 0.0 1250.03 n/a 23.3 23.7
Nodes=1, Constant, wait for tx valid 30 0.1 210.34 206.74 4.7 6.2
Nodes=1, Growing, fire and forget 30 0.0 1036.73 n/a 28.2 28.7
Nodes=1, Growing, wait for tx valid 30 0.2 151.38 158.82 6.5 9.9
Nodes=1, Mixed, fire and forget 30 0.0 820.13 n/a 35.8 36.3
Nodes=1, Mixed, wait for tx valid 30 0.2 176.97 179.39 5.6 7.5
Nodes=2, Constant, fire and forget 60 0.1 941.88 n/a 61.4 62.5
Nodes=2, Constant, wait for tx valid 60 0.4 139.29 134.94 14.2 20.7
Nodes=2, Growing, fire and forget 60 0.1 804.07 n/a 72.3 73.1
Nodes=2, Growing, wait for tx valid 60 0.6 92.86 92.98 21.3 32.0
Nodes=2, Mixed, fire and forget 60 0.1 924.13 n/a 63.1 64.7
Nodes=2, Mixed, wait for tx valid 60 0.6 100.21 94.71 19.7 29.3
Nodes=3, Constant, fire and forget 90 0.1 650.22 n/a 135.8 138.1
Nodes=3, Constant, wait for tx valid 90 0.8 113.20 111.56 25.9 37.5
Nodes=3, Growing, fire and forget 90 0.2 563.87 n/a 156.4 159.3
Nodes=3, Growing, wait for tx valid 90 1.2 72.15 72.03 40.8 54.8
Nodes=3, Mixed, fire and forget 90 0.2 516.36 n/a 170.9 172.8
Nodes=3, Mixed, wait for tx valid 90 1.0 86.07 82.89 34.5 43.2

Nodes=1, Constant, fire and forget

Number of nodes 1
Number of txs 30
Avg. Confirmation Time (ms) 23.3
P99 23.8ms
P95 23.7ms
P50 23.4ms
Tx validation time p50 (ms) 17.3
End-to-end TPS 1250.03 tx/s
Backlog drain time (s) 0.0
Snapshots observed 2
Snapshots per second 83.34 /s
Avg txs per snapshot 15.0
Peak node RSS (MB) 143.6
Number of Invalid txs 0
Fanout outputs 2

Nodes=1, Constant, wait for tx valid

Number of nodes 1
Number of txs 30
Avg. Confirmation Time (ms) 4.7
P99 10.6ms
P95 6.2ms
P50 4.3ms
Tx validation time p50 (ms) 1.6
End-to-end TPS 210.34 tx/s
Sustained TPS 206.74 tx/s
Backlog drain time (s) 0.0
Snapshots observed 30
Snapshots per second 210.34 /s
Avg txs per snapshot 1.0
Peak node RSS (MB) 144.4
Number of Invalid txs 0
Fanout outputs 2

Nodes=1, Growing, fire and forget

Number of nodes 1
Number of txs 30
Avg. Confirmation Time (ms) 28.2
P99 28.7ms
P95 28.7ms
P50 28.4ms
Tx validation time p50 (ms) 11.6
End-to-end TPS 1036.73 tx/s
Backlog drain time (s) 0.0
Snapshots observed 2
Snapshots per second 69.12 /s
Avg txs per snapshot 15.0
Peak node RSS (MB) 144.0
Number of Invalid txs 0
Fanout outputs 31

Nodes=1, Growing, wait for tx valid

Number of nodes 1
Number of txs 30
Avg. Confirmation Time (ms) 6.5
P99 12.5ms
P95 9.9ms
P50 6.2ms
Tx validation time p50 (ms) 1.6
End-to-end TPS 151.38 tx/s
Sustained TPS 158.82 tx/s
Backlog drain time (s) 0.0
Snapshots observed 30
Snapshots per second 151.38 /s
Avg txs per snapshot 1.0
Peak node RSS (MB) 144.2
Number of Invalid txs 0
Fanout outputs 31

Nodes=1, Mixed, fire and forget

Each client first grows its UTxO set (1-in to 2-out) for half of its tx budget, then contracts it back (2-in to 1-out) for the remainder.

Number of nodes 1
Number of txs 30
Avg. Confirmation Time (ms) 35.8
P99 36.3ms
P95 36.3ms
P50 36.0ms
Tx validation time p50 (ms) 20.9
End-to-end TPS 820.13 tx/s
Backlog drain time (s) 0.0
Snapshots observed 2
Snapshots per second 54.68 /s
Avg txs per snapshot 15.0
Peak node RSS (MB) 143.4
Number of Invalid txs 0
Fanout outputs 2

Nodes=1, Mixed, wait for tx valid

Each client first grows its UTxO set (1-in to 2-out) for half of its tx budget, then contracts it back (2-in to 1-out) for the remainder.

Number of nodes 1
Number of txs 30
Avg. Confirmation Time (ms) 5.6
P99 11.1ms
P95 7.5ms
P50 5.2ms
Tx validation time p50 (ms) 1.6
End-to-end TPS 176.97 tx/s
Sustained TPS 179.39 tx/s
Backlog drain time (s) 0.0
Snapshots observed 30
Snapshots per second 176.97 /s
Avg txs per snapshot 1.0
Peak node RSS (MB) 143.9
Number of Invalid txs 0
Fanout outputs 2

Nodes=2, Constant, fire and forget

Number of nodes 2
Number of txs 60
Avg. Confirmation Time (ms) 61.4
P99 63.0ms
P95 62.5ms
P50 61.9ms
Tx validation time p50 (ms) 24.1
End-to-end TPS 941.88 tx/s
Backlog drain time (s) 0.1
Snapshots observed 2
Snapshots per second 31.40 /s
Avg txs per snapshot 30.0
Peak node RSS (MB) 144.9
Number of Invalid txs 0
Fanout outputs 3

Nodes=2, Constant, wait for tx valid

Number of nodes 2
Number of txs 60
Avg. Confirmation Time (ms) 14.2
P99 27.1ms
P95 20.7ms
P50 13.2ms
Tx validation time p50 (ms) 3.6
End-to-end TPS 139.29 tx/s
Sustained TPS 134.94 tx/s
Backlog drain time (s) 0.0
Snapshots observed 60
Snapshots per second 139.29 /s
Avg txs per snapshot 1.0
Peak node RSS (MB) 144.8
Number of Invalid txs 0
Fanout outputs 3

Nodes=2, Growing, fire and forget

Number of nodes 2
Number of txs 60
Avg. Confirmation Time (ms) 72.3
P99 73.7ms
P95 73.1ms
P50 72.8ms
Tx validation time p50 (ms) 23.7
End-to-end TPS 804.07 tx/s
Backlog drain time (s) 0.1
Snapshots observed 2
Snapshots per second 26.80 /s
Avg txs per snapshot 30.0
Peak node RSS (MB) 144.9
Number of Invalid txs 0
Fanout outputs 62

Nodes=2, Growing, wait for tx valid

Number of nodes 2
Number of txs 60
Avg. Confirmation Time (ms) 21.3
P99 32.8ms
P95 32.0ms
P50 20.6ms
Tx validation time p50 (ms) 6.3
End-to-end TPS 92.86 tx/s
Sustained TPS 92.98 tx/s
Backlog drain time (s) 0.0
Snapshots observed 60
Snapshots per second 92.86 /s
Avg txs per snapshot 1.0
Peak node RSS (MB) 146.1
Number of Invalid txs 0
Fanout outputs 62

Nodes=2, Mixed, fire and forget

Each client first grows its UTxO set (1-in to 2-out) for half of its tx budget, then contracts it back (2-in to 1-out) for the remainder.

Number of nodes 2
Number of txs 60
Avg. Confirmation Time (ms) 63.1
P99 64.7ms
P95 64.7ms
P50 63.0ms
Tx validation time p50 (ms) 22.5
End-to-end TPS 924.13 tx/s
Backlog drain time (s) 0.1
Snapshots observed 2
Snapshots per second 30.80 /s
Avg txs per snapshot 30.0
Peak node RSS (MB) 144.9
Number of Invalid txs 0
Fanout outputs 3

Nodes=2, Mixed, wait for tx valid

Each client first grows its UTxO set (1-in to 2-out) for half of its tx budget, then contracts it back (2-in to 1-out) for the remainder.

Number of nodes 2
Number of txs 60
Avg. Confirmation Time (ms) 19.7
P99 32.5ms
P95 29.3ms
P50 19.5ms
Tx validation time p50 (ms) 6.7
End-to-end TPS 100.21 tx/s
Sustained TPS 94.71 tx/s
Backlog drain time (s) 0.0
Snapshots observed 60
Snapshots per second 100.21 /s
Avg txs per snapshot 1.0
Peak node RSS (MB) 145.3
Number of Invalid txs 0
Fanout outputs 3

Nodes=3, Constant, fire and forget

Number of nodes 3
Number of txs 90
Avg. Confirmation Time (ms) 135.8
P99 138.2ms
P95 138.1ms
P50 136.3ms
Tx validation time p50 (ms) 66.1
End-to-end TPS 650.22 tx/s
Backlog drain time (s) 0.1
Snapshots observed 2
Snapshots per second 14.45 /s
Avg txs per snapshot 45.0
Peak node RSS (MB) 145.9
Number of Invalid txs 0
Fanout outputs 4

Nodes=3, Constant, wait for tx valid

Number of nodes 3
Number of txs 90
Avg. Confirmation Time (ms) 25.9
P99 40.8ms
P95 37.5ms
P50 24.5ms
Tx validation time p50 (ms) 6.7
End-to-end TPS 113.20 tx/s
Sustained TPS 111.56 tx/s
Backlog drain time (s) 0.0
Snapshots observed 61
Snapshots per second 76.72 /s
Avg txs per snapshot 1.5
Peak node RSS (MB) 145.0
Number of Invalid txs 0
Fanout outputs 4

Nodes=3, Growing, fire and forget

Number of nodes 3
Number of txs 90
Avg. Confirmation Time (ms) 156.4
P99 159.4ms
P95 159.3ms
P50 157.7ms
Tx validation time p50 (ms) 54.3
End-to-end TPS 563.87 tx/s
Backlog drain time (s) 0.2
Snapshots observed 2
Snapshots per second 12.53 /s
Avg txs per snapshot 45.0
Peak node RSS (MB) 146.1
Number of Invalid txs 0
Fanout outputs 0

Nodes=3, Growing, wait for tx valid

Number of nodes 3
Number of txs 90
Avg. Confirmation Time (ms) 40.8
P99 62.5ms
P95 54.8ms
P50 40.4ms
Tx validation time p50 (ms) 11.8
End-to-end TPS 72.15 tx/s
Sustained TPS 72.03 tx/s
Backlog drain time (s) 0.0
Snapshots observed 62
Snapshots per second 49.70 /s
Avg txs per snapshot 1.5
Peak node RSS (MB) 146.9
Number of Invalid txs 0
Fanout outputs 0

Nodes=3, Mixed, fire and forget

Each client first grows its UTxO set (1-in to 2-out) for half of its tx budget, then contracts it back (2-in to 1-out) for the remainder.

Number of nodes 3
Number of txs 90
Avg. Confirmation Time (ms) 170.9
P99 172.9ms
P95 172.8ms
P50 171.8ms
Tx validation time p50 (ms) 57.6
End-to-end TPS 516.36 tx/s
Backlog drain time (s) 0.2
Snapshots observed 2
Snapshots per second 11.47 /s
Avg txs per snapshot 45.0
Peak node RSS (MB) 145.6
Number of Invalid txs 0
Fanout outputs 4

Nodes=3, Mixed, wait for tx valid

Each client first grows its UTxO set (1-in to 2-out) for half of its tx budget, then contracts it back (2-in to 1-out) for the remainder.

Number of nodes 3
Number of txs 90
Avg. Confirmation Time (ms) 34.5
P99 46.0ms
P95 43.2ms
P50 35.8ms
Tx validation time p50 (ms) 9.4
End-to-end TPS 86.07 tx/s
Sustained TPS 82.89 tx/s
Backlog drain time (s) 0.0
Snapshots observed 61
Snapshots per second 58.34 /s
Avg txs per snapshot 1.5
Peak node RSS (MB) 146.0
Number of Invalid txs 0
Fanout outputs 4

Comment thread hydra-node/src/Hydra/Chain/Blockfrost/Client.hs
Comment thread hydra-node/src/Hydra/Chain/Blockfrost/Client.hs
Comment thread hydra-node/src/Hydra/Chain/Blockfrost/Client.hs
Comment thread hydra-node/src/Hydra/Chain/Backend.hs
Comment thread hydra-node/src/Hydra/Chain/Blockfrost.hs
Comment thread hydra-node/src/Hydra/Chain/Blockfrost.hs

@noonio noonio left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minor feedback about using a library

this is looking really nice! so satisfying to see things deleted. really nice change :)

@noonio noonio added this to the Performance milestone Aug 14, 2026
@noonio

noonio commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Filed a follow-up so I can just merge this now - #2824

@noonio
noonio enabled auto-merge (squash) August 14, 2026 08:10
@noonio
noonio merged commit 549dfa5 into master Aug 14, 2026
48 checks passed
@noonio
noonio deleted the blockfrost-speedup branch August 14, 2026 08:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Blockfrost: replace blind sleep with condition-based polling

2 participants