Skip to content

Make height-sync heartbeat and cadence safe against DoS, partial persistence, and nonce exhaustion #1770

Closed @anatoly-kuz-mntn opened 2026-09-15 01:58 UTC 2 comments Updated 2026-09-16 05:53 UTC

Description

The heartbeat/cadence implementation contains three related availability and resource-consumption problems.

Problem 1: cadence arithmetic can loop forever

ComputeCadenceSwallow iterates through periodic windows using unsigned multiplication. With a sufficiently large AnchorK, i * anchorK wraps and the termination condition may never be reached.

Affected code:

The relevant window should be calculated directly using division and checked arithmetic.

Problem 2: heartbeat spans can be partially persisted

A span reads the floor once and gives every heartbeat the same height. However, the first span diff may also drain pending host-signed transactions and raise the floor.

A later heartbeat can then fail L0 after the earlier diff has already been persisted and committed. composeHeartbeatSpan returns an error and does not dispatch the persisted prefix.

Affected code:

Problem 3: quiet escrows rapidly consume the nonce budget

For a group of 16 hosts, one quiet height-sync turn consumes approximately 17 nonces: 16 heartbeat diffs and at least one flush diff.

With the default configuration:

  • Healthy acknowledgements: approximately 17 nonces every 6 seconds.
  • Missing acknowledgements: approximately 17 nonces every 12 seconds.
  • max_nonce = 20,000 is exhausted in approximately 2–4 hours.
  • FeePerNonce is charged for each applied nonce.

Affected code:

Acceptance criteria

  • Cadence calculation terminates for every valid uint64 input.
  • Arithmetic overflow is explicitly prevented.
  • Heartbeat composition cannot leave persisted but undispatched prefixes.
  • Pending host raises cannot invalidate later heartbeats in the same span.
  • Define an acceptable minimum lifetime for an idle escrow.
  • Add a fake-clock test measuring nonce and fee consumption.
  • Add a snapshot-based test starting near nonce 20,000 and verifying exhaustion behavior without waiting several hours.

💬 Comments (2)

@a-kuprin commented 2026-09-15 21:13 UTC

I would drop Problem 1 as it is taking as input unrealistic AnchorK It is default as 10, to hit the problem it should be 2^64

Problem 2 is real and will be solved.

Problem 3 is tuned with maximum nonces and heartbit period

@a-kuprin commented 2026-09-16 05:53 UTC

I'm closing it.

Problem 1 can never appear Problem 2: https://github.com/gonka-ai/gonka/pull/1783 Problem 3 is solved by raising maxNonce to 1 mln and making heartbit less often


🔄 Auto-synced from Issue #1770 every hour.