You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The post-quicknet (unchained) branch unconditionally returns a single entry:
// We only ever need one entry after drand quicknet upgrade (FIP-0063)if curr_beacon.network().is_unchained(){let entry = curr_beacon.entry(max_round).await?;Ok(vec![entry])}
The comment holds only when the parent is exactly one epoch back. A block covers every epoch since its parent, contributing one beacon entry per covered epoch. When one or more null rounds sit between parent and current epoch, the block must carry one entry per covered epoch.
Correct behavior
Lotus BeaconEntriesForBlock (chain/beacon/beacon.go#L115) loops currEpoch from epoch down to parentEpoch+1, emitting MaxBeaconRoundForEpoch(currEpoch) for each — epoch − parentEpoch entries. The loop runs for chained and unchained alike; Forest special-cased unchained to one entry and lost the null-round case.
On-chain confirmation
Mainnet epoch 6216199 is null; the block at 6216200 (parent 6216198) carries two entries — rounds 30662992 (for null epoch 6216199) and 30663002 (for 6216200). Forest's beacon_entries_for_block(epoch=6216200, parent=6216198) returns only [30663002].
Impact
An external miner (lotus-miner / Venus / curio) using Forest as its full node builds a block missing a beacon entry whenever the previous epoch was null. The rest of the network rejects it (Lotus ValidateBlockValues requires the per-epoch entries), so the miner orphans its own block and loses the reward. Intermittent (null rounds are low-single-digit % of epochs) but not rare. Not a chain-safety issue — Forest serves wrong mining base info, it does not produce the block.
Fix
Replace the single-entry shortcut with the same per-covered-epoch loop the chained branch (#L119-L130) already uses — iterate parent_epoch+1..=epoch, one entry(max_beacon_round_for_epoch(e)) per epoch.
Test
MinerGetBaseInfo at an epoch whose parent tipset is 2+ epochs back must return epoch − parent_epoch entries at the per-epoch rounds; the 6216200 case above is a ready fixture.
Note
This was AI found and seems correct, but do your own checks. Regardless of that, a test will be useful.
Location:
src/beacon/drand.rs#L115-L118, inbeacon_entries_for_block(#L76-L131). Reached only viaminer_get_base_info(src/state_manager/mining.rs#L83-L90) → theFilecoin.MinerGetBaseInfoRPC.Current behavior
The post-quicknet (unchained) branch unconditionally returns a single entry:
The comment holds only when the parent is exactly one epoch back. A block covers every epoch since its parent, contributing one beacon entry per covered epoch. When one or more null rounds sit between parent and current epoch, the block must carry one entry per covered epoch.
Correct behavior
Lotus
BeaconEntriesForBlock(chain/beacon/beacon.go#L115) loopscurrEpochfromepochdown toparentEpoch+1, emittingMaxBeaconRoundForEpoch(currEpoch)for each —epoch − parentEpochentries. The loop runs for chained and unchained alike; Forest special-cased unchained to one entry and lost the null-round case.On-chain confirmation
Mainnet epoch 6216199 is null; the block at 6216200 (parent 6216198) carries two entries — rounds
30662992(for null epoch 6216199) and30663002(for 6216200). Forest'sbeacon_entries_for_block(epoch=6216200, parent=6216198)returns only[30663002].Impact
An external miner (lotus-miner / Venus / curio) using Forest as its full node builds a block missing a beacon entry whenever the previous epoch was null. The rest of the network rejects it (Lotus
ValidateBlockValuesrequires the per-epoch entries), so the miner orphans its own block and loses the reward. Intermittent (null rounds are low-single-digit % of epochs) but not rare. Not a chain-safety issue — Forest serves wrong mining base info, it does not produce the block.Fix
Replace the single-entry shortcut with the same per-covered-epoch loop the chained branch (
#L119-L130) already uses — iterateparent_epoch+1..=epoch, oneentry(max_beacon_round_for_epoch(e))per epoch.Test
MinerGetBaseInfoat an epoch whose parent tipset is 2+ epochs back must returnepoch − parent_epochentries at the per-epoch rounds; the 6216200 case above is a ready fixture.