Summary
Running a mainnet shard-1 validator (v2026.1.0-gdb22d51, "Bloom") on a config
verified byte-identical to harmony config dump -n mainnet from this exact
binary (only difference: inert ShardData.ShardCount). Over the past ~24
hours we've captured hard evidence of two distinct mechanisms causing real
signing-percentage loss, both reproducible with log traces, neither explained
by local config, hardware, or network issues (all independently ruled out —
detail below). Filing since together they may point at a real gap: default
mainnet config (Sync.Client = false, i.e. not using the experimental
streamsync client) has no fast reactive-recovery path when a single consensus
message is missed, and a substantial fraction of signing loss appears to
come from the FBFT tight-deadline design working exactly as intended but with
no operator-facing signal.
Mechanism 1: missed commit-confirmation message → no fast recovery on default config
Traced second-by-second from zerolog-harmony.log, 2026-07-31 23:00:00–23:06:51 UTC:
23:00:04.438 — validator sends its own FBFT Commit vote for block
94505738, on schedule.
- The network's aggregated Committed confirmation for that specific
block never arrives at this node.
23:00:06+ — Announce/Prepared messages for the next blocks (739, 740,
741, ...) arrive while still parked waiting on 738's commit confirmation.
Each rejected: [VerifyNewBlock] Cannot Verify New Block!!!, blockHeight 94505739, myHeight 94505737 / error: unknown ancestor.
consensus.OnCommitted correctly detects this
([OnCommitted] low consensus block number. Spin up state sync) and calls
consensus.spinUpStateSync() immediately (not on a timer).
- However,
spinUpStateSync() only does consensus.dHelper.DownloadAsync(),
and consensus.dHelper is only initialized via SetDownloader(), which
cmd/harmony/main.go gates behind if hc.Sync.Client && .... Since
Sync.Client = false is the binary's own default (confirmed via fresh
harmony config dump -n mainnet diff), this fast path appears to be a
no-op on any node running default config.
- Actual recovery instead comes from a separate, independent, much slower
periodic legacysync check (getMaxPeerHeight / EPOCHSYNC cycle,
observed running on a ~20-40s cadence). Full recovery took until
23:06:51 — ~6.5 minutes, during which the node correctly detects
OUT OF SYNC repeatedly but cannot sign.
- Network-wide block cadence stayed completely normal throughout (204
blocks in 407s, ~2.0s/block, cross-checked against public RPC) — only
this node fell behind. Confirmed identical signature (unknown ancestor
cascade + ~5-7 min self-heal) present in this node's logs going back to
at least 2026-07-28, so not a new regression, and reproduced 7 times in
19 hours of monitoring before this report.
Is this a known limitation of running with default (non-streamsync) config?
Is there a non-experimental way to shorten this recovery window, or is a
faster reactive path planned for the legacysync/default path specifically
(not just the experimental streamsync client)?
Mechanism 2: silent late-signature exclusion, zero local trace
Observed live during this report, 2026-08-01 02:00:02–02:05:02 UTC:
- Two consecutive 5-minute sampling ticks: 28/127 missed (22.0%), then
30/129 missed (23.3%).
- No
unknown ancestor errors, no stall — local block height advanced
normally throughout, gap vs. public reference stayed at 0 (briefly -9,
i.e. momentarily ahead of a lagging public RPC, not behind).
- Only routine
timeout reason was overwritten phase-timer log lines
present — nothing that would let an operator distinguish this from
healthy operation without external signing-percent monitoring.
This matches Harmony's own "1-Second Finality" design notes: FBFT proceeds
once 2/3 of signatures arrive per phase and explicitly excludes late
signatures past a tight per-block deadline, with no error generated on the
excluded validator's side. Understood this is by design, not a bug — but
raising because it means a well-connected, fully-synced, default-config
validator can lose 20%+ of an epoch's signing with zero actionable local
signal, which seems worth documenting/exposing (e.g. a debug-level metric
or log line specifically for "signature arrived but too late to include")
so operators aren't left inferring this purely from external explorers.
Environment
v2026.1.0-gdb22d51 (built 2026-07-08, current mainnet release)
- Config:
harmony config dump -n mainnet from this binary, zero
modifications besides inert ShardData.ShardCount
- Wired gigabit, no Wi-Fi hop, TCP 9000 forwarded and externally verified
p2p-connectivity.connected: 368-621 throughout every incident (healthy)
- NIC hardware/driver error counters (rx_errors, rx_crc_errors,
rx_missed_errors, etc.): all 0
- No NVMe/ATA/MCE/EDAC kernel warnings in dmesg for the full incident window
- chrony synced, ~32µs offset from NTP at time of worst incident
What we're not asking
Not asking for the streamsync client itself to be un-experimental — we
understand that's a deliberate, ongoing effort. Asking specifically about
the default (legacysync) path's recovery behavior and whether Mechanism 2's
silence is expected/by-design or something worth better operator-facing
visibility for.
Happy to provide full raw logs for either window if useful.
Summary
Running a mainnet shard-1 validator (
v2026.1.0-gdb22d51, "Bloom") on a configverified byte-identical to
harmony config dump -n mainnetfrom this exactbinary (only difference: inert
ShardData.ShardCount). Over the past ~24hours we've captured hard evidence of two distinct mechanisms causing real
signing-percentage loss, both reproducible with log traces, neither explained
by local config, hardware, or network issues (all independently ruled out —
detail below). Filing since together they may point at a real gap: default
mainnet config (
Sync.Client = false, i.e. not using the experimentalstreamsync client) has no fast reactive-recovery path when a single consensus
message is missed, and a substantial fraction of signing loss appears to
come from the FBFT tight-deadline design working exactly as intended but with
no operator-facing signal.
Mechanism 1: missed commit-confirmation message → no fast recovery on default config
Traced second-by-second from
zerolog-harmony.log, 2026-07-31 23:00:00–23:06:51 UTC:23:00:04.438— validator sends its own FBFT Commit vote for block94505738, on schedule.block never arrives at this node.
23:00:06+— Announce/Prepared messages for the next blocks (739, 740,741, ...) arrive while still parked waiting on 738's commit confirmation.
Each rejected:
[VerifyNewBlock] Cannot Verify New Block!!!, blockHeight 94505739, myHeight 94505737/error: unknown ancestor.consensus.OnCommittedcorrectly detects this(
[OnCommitted] low consensus block number. Spin up state sync) and callsconsensus.spinUpStateSync()immediately (not on a timer).spinUpStateSync()only doesconsensus.dHelper.DownloadAsync(),and
consensus.dHelperis only initialized viaSetDownloader(), whichcmd/harmony/main.gogates behindif hc.Sync.Client && .... SinceSync.Client = falseis the binary's own default (confirmed via freshharmony config dump -n mainnetdiff), this fast path appears to be ano-op on any node running default config.
periodic legacysync check (
getMaxPeerHeight/EPOCHSYNCcycle,observed running on a ~20-40s cadence). Full recovery took until
23:06:51— ~6.5 minutes, during which the node correctly detectsOUT OF SYNCrepeatedly but cannot sign.blocks in 407s, ~2.0s/block, cross-checked against public RPC) — only
this node fell behind. Confirmed identical signature (
unknown ancestorcascade + ~5-7 min self-heal) present in this node's logs going back to
at least 2026-07-28, so not a new regression, and reproduced 7 times in
19 hours of monitoring before this report.
Is this a known limitation of running with default (non-streamsync) config?
Is there a non-experimental way to shorten this recovery window, or is a
faster reactive path planned for the legacysync/default path specifically
(not just the experimental streamsync client)?
Mechanism 2: silent late-signature exclusion, zero local trace
Observed live during this report, 2026-08-01 02:00:02–02:05:02 UTC:
30/129 missed (23.3%).
unknown ancestorerrors, no stall — local block height advancednormally throughout, gap vs. public reference stayed at 0 (briefly -9,
i.e. momentarily ahead of a lagging public RPC, not behind).
timeout reason was overwrittenphase-timer log linespresent — nothing that would let an operator distinguish this from
healthy operation without external signing-percent monitoring.
This matches Harmony's own "1-Second Finality" design notes: FBFT proceeds
once 2/3 of signatures arrive per phase and explicitly excludes late
signatures past a tight per-block deadline, with no error generated on the
excluded validator's side. Understood this is by design, not a bug — but
raising because it means a well-connected, fully-synced, default-config
validator can lose 20%+ of an epoch's signing with zero actionable local
signal, which seems worth documenting/exposing (e.g. a debug-level metric
or log line specifically for "signature arrived but too late to include")
so operators aren't left inferring this purely from external explorers.
Environment
v2026.1.0-gdb22d51(built 2026-07-08, current mainnet release)harmony config dump -n mainnetfrom this binary, zeromodifications besides inert
ShardData.ShardCountp2p-connectivity.connected: 368-621 throughout every incident (healthy)rx_missed_errors, etc.): all 0
What we're not asking
Not asking for the streamsync client itself to be un-experimental — we
understand that's a deliberate, ongoing effort. Asking specifically about
the default (legacysync) path's recovery behavior and whether Mechanism 2's
silence is expected/by-design or something worth better operator-facing
visibility for.
Happy to provide full raw logs for either window if useful.