Make height-sync heartbeat and cadence safe against DoS, partial persistence, and nonce exhaustion #1770
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:
- Single floor read and per-heartbeat composition loop
- Pending transactions are included before heartbeat transactions
- Each diff is persisted and committed immediately
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,000is exhausted in approximately 2–4 hours.FeePerNonceis charged for each applied nonce.
Affected code:
- Quiet-session and timeout scheduling
- Heartbeat span and mandatory flush
- Default six-second interval
- Default
max_nonceandFeePerNonce
Acceptance criteria
- Cadence calculation terminates for every valid
uint64input. - 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,000and verifying exhaustion behavior without waiting several hours.
💬 Comments (2)
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.
I would drop Problem 1 as it is taking as input unrealistic
AnchorKIt is default as10, to hit the problem it should be2^64Problem 2 is real and will be solved.
Problem 3 is tuned with maximum nonces and heartbit period