feat: sync: validate (early) that blocks fall within range (#10691)
This will reject blocks in pubsub validation if they're either: 1. Too far into the future (5 blocks beyond the expected head). 2. Too far into the past (before finality with respect to our current head). Specifically: 1. We were previously rejecting future blocks in the sync logic, but not in pubsub itself. 2. We never used to check if a block was too _old_. Motivation: Blocks that are too new/too old can cause us to perform quite a bit of unnecessary work.
This commit is contained in:
parent
875c09840b
commit
784214ae05
@ -382,13 +382,21 @@ func (filec *FilecoinEC) VerifyWinningPoStProof(ctx context.Context, nv network.
|
||||
return nil
|
||||
}
|
||||
|
||||
func (filec *FilecoinEC) IsEpochBeyondCurrMax(epoch abi.ChainEpoch) bool {
|
||||
func (filec *FilecoinEC) IsEpochInConsensusRange(epoch abi.ChainEpoch) bool {
|
||||
if filec.genesis == nil {
|
||||
return true
|
||||
}
|
||||
|
||||
// Don't try to sync anything before finality. Don't propagate such blocks either.
|
||||
//
|
||||
// We use _our_ current head, not the expected head, because the network's head can lag on
|
||||
// catch-up (after a network outage).
|
||||
if epoch < filec.store.GetHeaviestTipSet().Height()-build.Finality {
|
||||
return false
|
||||
}
|
||||
|
||||
now := uint64(build.Clock.Now().Unix())
|
||||
return epoch > (abi.ChainEpoch((now-filec.genesis.MinTimestamp())/build.BlockDelaySecs) + MaxHeightDrift)
|
||||
return epoch <= (abi.ChainEpoch((now-filec.genesis.MinTimestamp())/build.BlockDelaySecs) + MaxHeightDrift)
|
||||
}
|
||||
|
||||
func (filec *FilecoinEC) minerIsValid(ctx context.Context, maddr address.Address, baseTs *types.TipSet) error {
|
||||
|
@ -32,9 +32,10 @@ type Consensus interface {
|
||||
// the block (signature verifications, VRF checks, message validity, etc.)
|
||||
ValidateBlock(ctx context.Context, b *types.FullBlock) (err error)
|
||||
|
||||
// IsEpochBeyondCurrMax is used to configure the fork rules for longest-chain
|
||||
// consensus protocols.
|
||||
IsEpochBeyondCurrMax(epoch abi.ChainEpoch) bool
|
||||
// IsEpochInConsensusRange returns true if the epoch is "in range" for consensus. That is:
|
||||
// - It's not before finality.
|
||||
// - It's not too far in the future.
|
||||
IsEpochInConsensusRange(epoch abi.ChainEpoch) bool
|
||||
|
||||
// CreateBlock implements all the logic required to propose and assemble a new Filecoin block.
|
||||
//
|
||||
@ -71,6 +72,14 @@ func ValidateBlockPubsub(ctx context.Context, cns Consensus, self bool, msg *pub
|
||||
return pubsub.ValidationReject, what
|
||||
}
|
||||
|
||||
if !cns.IsEpochInConsensusRange(blk.Header.Height) {
|
||||
// We ignore these blocks instead of rejecting to avoid breaking the network if
|
||||
// we're recovering from an outage (e.g., where nobody agrees on where "head" is
|
||||
// currently).
|
||||
log.Warnf("received block outside of consensus range (%d)", blk.Header.Height)
|
||||
return pubsub.ValidationIgnore, "invalid_block_height"
|
||||
}
|
||||
|
||||
// validate the block meta: the Message CID in the header must match the included messages
|
||||
err = validateMsgMeta(ctx, blk)
|
||||
if err != nil {
|
||||
|
@ -208,7 +208,7 @@ func (syncer *Syncer) InformNewHead(from peer.ID, fts *store.FullTipSet) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
if syncer.consensus.IsEpochBeyondCurrMax(fts.TipSet().Height()) {
|
||||
if !syncer.consensus.IsEpochInConsensusRange(fts.TipSet().Height()) {
|
||||
log.Errorf("Received block with impossibly large height %d", fts.TipSet().Height())
|
||||
return false
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user