datahaven-xyz/datahaven · error · Error
SyncCommitteeParticipantsNotSupermajority
SyncCommitteeParticipantsNotSupermajority
Error message
SyncCommitteeParticipantsNotSupermajority
What it means
Thrown by `sync_committee_participation_is_supermajority` when the sync-aggregate bitfield has fewer than 2/3 of its bits set. Ethereum consensus requires a 2/3 supermajority of sync committee participants for an update signature to be valid; without it the attestation cannot be trusted.
Solutions
- Wait for and submit a later update with ≥2/3 participation; finalized updates typically have near-full participation.
- Verify the relayer does not truncate or corrupt the `sync_committee_bits` bitfield during serialization.
- Check beacon chain finality health; prolonged low participation indicates upstream liveness issues.
- Re-fetch the aggregate from a full node rather than a cached/derived copy.
Example fix
// before: submit any fetched update submit(update); // after: pre-check participation on the relayer let bits = count_bits(update.sync_aggregate.sync_committee_bits); require!(bits * 3 >= SYNC_COMMITTEE_SIZE * 2); submit(update);
Defensive patterns
Strategy: validation
Validate before calling
const sum = countBits(update.sync_aggregate.sync_committee_bits);
if (sum * 3 < SYNC_COMMITTEE_SIZE * 2) {
throw new Error('sync aggregate lacks 2/3 supermajority');
} Type guard
function hasSupermajority(bits, committeeSize) {
return bits.reduce((a, b) => a + b, 0) * 3 >= committeeSize * 2;
} Try / catch
try {
await submit(update);
} catch (e) {
if (String(e).includes('SyncCommitteeParticipantsNotSupermajority')) {
await waitForNextUpdateWithFullParticipation();
}
} Prevention
- Pre-check bitfield weight on the relayer before submission
- Prefer finalized updates, which normally carry near-full participation
- Monitor beacon chain liveness; alert when participation drops persistently
When it happens
Trigger: Submitting a light-client update whose `sync_aggregate.sync_committee_bits` produce `sync_committee_sum * 3 < bits.len() * 2` — i.e. a weakly signed update from the beacon chain.
Common situations: Replaying an update that was later superseded by one with higher participation, relayer picking malformed/edge-case aggregates, or an actual network liveness problem on the beacon chain.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
AI-assisted analysis of datahaven-xyz/datahaven@edcb13dbbc (2026-09-13).
Data as JSON: /api/errors/50ccf3bbc29a6698.
Report an issue: GitHub.
Appendix: source
Thrown at operator/pallets/ethereum-client/src/lib.rs:637
) -> Result<H256, DispatchError> {
let hash_root = ForkData {
current_version,
genesis_validators_root: genesis_validators_root.into(),
}
.hash_tree_root()
.map_err(|_| Error::<T>::ForkDataHashTreeRootFailed)?;
Ok(hash_root)
}
/// Checks that the sync committee bits (the votes of the sync committee members,
/// represented by bits 0 and 1) is more than a supermajority (2/3 of the votes are
/// positive).
pub(super) fn sync_committee_participation_is_supermajority(
sync_committee_bits: &[u8],
) -> DispatchResult {
let sync_committee_sum = sync_committee_sum(sync_committee_bits);
ensure!(
((sync_committee_sum * 3) as usize) >= sync_committee_bits.len() * 2,
Error::<T>::SyncCommitteeParticipantsNotSupermajority
);
Ok(())
}
/// Returns the fork version based on the current epoch. The hard fork versions
/// are defined in pallet config.
pub(super) fn compute_fork_version(epoch: u64) -> ForkVersion {
Self::select_fork_version(&T::ForkVersions::get(), epoch)
}
/// Returns the fork version based on the current epoch.
pub(super) fn select_fork_version(fork_versions: &ForkVersions, epoch: u64) -> ForkVersion {
if epoch >= fork_versions.fulu.epoch {
return fork_versions.fulu.version;
}View on GitHub (pinned to edcb13dbbc)