Committees and sortition
For every task of a mining project, a committee of miners executes the same call and votes on the receipt hash. Anyone can recompute who was on a committee from public data.
Epochs and slots
Section titled “Epochs and slots”A project has fixed-length epochs (epoch_secs = 3600 × m with m ∈ 24, aligned to
UTC; immutable for a project). Epoch E starts at E × epoch_secs. Every task takes the next slot
(project_id, E, seq), with seq counting from 0 in arrival order. The committee of a slot is fixed before
the task content exists.
The beacon
Section titled “The beacon”T(E) = start(E) − beacon_offset_secs (960 s on the testnet)B(E) = the last Sepolia block with timestamp < T(E)beacon(E) = keccak256("necter-beacon-v1" ‖ blockhash(B(E)))The miner-set snapshot
Section titled “The miner-set snapshot”Before each epoch (at least snapshot_lead_secs = 300 s ahead), the Hub builds a snapshot of the project’s
eligible subscriptions as of block B(E): bonded, not unbonding, not jailed, collateral ≥ the project’s
min_collateral, bound to the same owner as the subscription, not paused. Each entry has the node key,
owner, payout address, collateral, reputation and binding hash.
Every validator checks the snapshot independently against its own Sepolia RPC (replaying Staking
events and verifying bindings) and signs it. A snapshot is valid only with signatures from
floor(2n/3)+1 validators. Without a valid snapshot the epoch’s tasks use validator fallback.
curl -s https://testnet-rpc.necter.network/v1/committees/<project_id>/<epoch> # attested snapshotcurl -s https://testnet-rpc.necter.network/v1/committees/<project_id>/<epoch>/<seq> # one slot's drawWeights
Section titled “Weights”cap_i = min(collateral_i, weight_cap) weight_cap = min_collateral × weight_cap_multiplew_i = floor(cap_i / 10^15) × reputation_i (reputation in basis points, 1000..10000)More collateral and a better reputation raise a miner’s chance of selection, up to the cap, which limits how much one large bond can dominate.
The draw
Section titled “The draw”seed(slot) = keccak256("necter-sortition-v1" ‖ beacon(E) ‖ project_id ‖ u64be(E) ‖ u64be(seq) ‖ set_hash)k_eff = min(size, N); b_eff = min(backups, N − k_eff)for j in 0 .. k_eff + b_eff − 1: x = uint256(keccak256(seed ‖ u32be(j))) mod W # weighted draw without replacement pick the entry whose cumulative weight first exceeds x; remove itThe first k_eff picks are the primary members; the rest are ordered backups. If fewer than
min_size miners are eligible, the slot has no committee and runs as a validator round.
Offers, leases and backups
Section titled “Offers, leases and backups”sequenceDiagram
participant H as Hub relay
participant P as Primary member
participant B as Backup
H->>P: offer (position, accept_by = now + 10 s)
alt accepts in time
P->>H: accept (node-signed)
H->>P: lease (input, deadline)
P->>H: result + vote
else declines, times out, offline, or misses the lease deadline
H->>B: offer for the same position
end
H-->>P: outcome (finalized / escalated / failed, your_vote, units)
Declining an offer is never penalized. Accepting and then missing the lease costs reputation (collateral
slashing for missed leases is coming soon). The committee quorum is floor(2·k_eff/3)+1 over primaries
and activated backups. A round is clean when that many votes agree and none disagrees; otherwise it is
contested, and validators always audit contested rounds. Validators then finalize the round through SecureWeave. Finality
Reputation
Section titled “Reputation”Each subscription starts at 5,000 bp and changes when an epoch closes:
rep(E+1) = clamp(rep(E) + 25·min(a,40) − 150·m − 25·min(o,40) − 2500·i, 1000, 10000)a = accepted leases whose vote made it into a finalized round, m = accepted leases with no valid vote
in time, o = offers left unanswered, i = votes proven invalid. The snapshot for epoch E uses the value
computed when epoch E−2 closed.