diff --git a/internal/options/block_applicator_options.go b/internal/options/block_applicator_options.go index e26c72e..aedd9a2 100644 --- a/internal/options/block_applicator_options.go +++ b/internal/options/block_applicator_options.go @@ -2,16 +2,19 @@ package options const ( maxPendingBlocksDefault = 2500 + maxHeightDeltaDefault = 10 ) // BlockApplicatorOptions are options for BlockApplicator type BlockApplicatorOptions struct { MaxPendingBlocks uint64 + MaxHeightDelta uint64 } // NewBlockApplicatorOptions returns default initialized BlockApplicatorOptions func NewBlockApplicatorOptions() *BlockApplicatorOptions { return &BlockApplicatorOptions{ MaxPendingBlocks: maxPendingBlocksDefault, + MaxHeightDelta: maxHeightDeltaDefault, } } diff --git a/internal/options/error_handler_options.go b/internal/options/error_handler_options.go index 48abf8e..130aabc 100644 --- a/internal/options/error_handler_options.go +++ b/internal/options/error_handler_options.go @@ -9,20 +9,23 @@ const ( errorScoreDecayHalflifeDefault = time.Minute * 10 errorScoreThresholdDefault = 100000 - deserializationErrorScoreDefault = 5000 - serializationErrorScoreDefault = 0 - blockIrreversibilityErrorScoreDefault = 100 - blockApplicationErrorScoreDefault = 5000 - transactionApplicationErrorScoreDefault = 1000 - chainIDMismatchErrorScoreDefault = uint64(math.MaxUint32) - chainNotConnectedErrorScoreDefault = uint64(math.MaxUint32) - checkpointMismatchErrorScoreDefault = uint64(math.MaxUint32) - localRPCErrorScoreDefault = 0 - peerRPCErrorScoreDefault = 1000 - localRPCTimeoutErrorScoreDefault = 0 - peerRPCTimeoutErrorScoreDefault = 1000 - processRequestTimeoutErrorScoreDefault = 0 - unknownErrorScoreDefault = blockApplicationErrorScoreDefault + deserializationErrorScoreDefault = 5000 + serializationErrorScoreDefault = 0 + blockIrreversibilityErrorScoreDefault = 100 + blockApplicationErrorScoreDefault = 5000 + unknownPreviousBlockErrorScoreDefault = 5000 + blockApplicationTimeoutErrorScoreDefault = 5000 + maxPendingBlocksErrorScoreDefault = 1000 + transactionApplicationErrorScoreDefault = 1000 + chainIDMismatchErrorScoreDefault = uint64(math.MaxUint32) + chainNotConnectedErrorScoreDefault = uint64(math.MaxUint32) + checkpointMismatchErrorScoreDefault = uint64(math.MaxUint32) + localRPCErrorScoreDefault = 0 + peerRPCErrorScoreDefault = 1000 + localRPCTimeoutErrorScoreDefault = 0 + peerRPCTimeoutErrorScoreDefault = 1000 + processRequestTimeoutErrorScoreDefault = 0 + unknownErrorScoreDefault = blockApplicationErrorScoreDefault ) // PeerErrorHandlerOptions are options for PeerErrorHandler @@ -30,40 +33,46 @@ type PeerErrorHandlerOptions struct { ErrorScoreDecayHalflife time.Duration ErrorScoreThreshold uint64 - DeserializationErrorScore uint64 - SerializationErrorScore uint64 - BlockIrreversibilityErrorScore uint64 - BlockApplicationErrorScore uint64 - TransactionApplicationErrorScore uint64 - ChainIDMismatchErrorScore uint64 - ChainNotConnectedErrorScore uint64 - CheckpointMismatchErrorScore uint64 - LocalRPCErrorScore uint64 - PeerRPCErrorScore uint64 - LocalRPCTimeoutErrorScore uint64 - PeerRPCTimeoutErrorScore uint64 - ProcessRequestTimeoutErrorScore uint64 - UnknownErrorScore uint64 + DeserializationErrorScore uint64 + SerializationErrorScore uint64 + BlockIrreversibilityErrorScore uint64 + BlockApplicationErrorScore uint64 + UnknownPreviousBlockErrorScore uint64 + BlockApplicationTimeoutErrorScore uint64 + MaxPendingBlocksErrorScore uint64 + TransactionApplicationErrorScore uint64 + ChainIDMismatchErrorScore uint64 + ChainNotConnectedErrorScore uint64 + CheckpointMismatchErrorScore uint64 + LocalRPCErrorScore uint64 + PeerRPCErrorScore uint64 + LocalRPCTimeoutErrorScore uint64 + PeerRPCTimeoutErrorScore uint64 + ProcessRequestTimeoutErrorScore uint64 + UnknownErrorScore uint64 } // NewPeerErrorHandlerOptions returns default initialized PeerErrorHandlerOptions func NewPeerErrorHandlerOptions() *PeerErrorHandlerOptions { return &PeerErrorHandlerOptions{ - ErrorScoreDecayHalflife: errorScoreDecayHalflifeDefault, - ErrorScoreThreshold: errorScoreThresholdDefault, - DeserializationErrorScore: deserializationErrorScoreDefault, - SerializationErrorScore: serializationErrorScoreDefault, - BlockIrreversibilityErrorScore: blockIrreversibilityErrorScoreDefault, - BlockApplicationErrorScore: blockApplicationErrorScoreDefault, - TransactionApplicationErrorScore: transactionApplicationErrorScoreDefault, - ChainIDMismatchErrorScore: chainIDMismatchErrorScoreDefault, - ChainNotConnectedErrorScore: chainNotConnectedErrorScoreDefault, - CheckpointMismatchErrorScore: checkpointMismatchErrorScoreDefault, - LocalRPCErrorScore: localRPCErrorScoreDefault, - PeerRPCErrorScore: peerRPCErrorScoreDefault, - LocalRPCTimeoutErrorScore: localRPCTimeoutErrorScoreDefault, - PeerRPCTimeoutErrorScore: peerRPCTimeoutErrorScoreDefault, - ProcessRequestTimeoutErrorScore: processRequestTimeoutErrorScoreDefault, - UnknownErrorScore: unknownErrorScoreDefault, + ErrorScoreDecayHalflife: errorScoreDecayHalflifeDefault, + ErrorScoreThreshold: errorScoreThresholdDefault, + DeserializationErrorScore: deserializationErrorScoreDefault, + SerializationErrorScore: serializationErrorScoreDefault, + BlockIrreversibilityErrorScore: blockIrreversibilityErrorScoreDefault, + BlockApplicationErrorScore: blockApplicationErrorScoreDefault, + UnknownPreviousBlockErrorScore: unknownPreviousBlockErrorScoreDefault, + BlockApplicationTimeoutErrorScore: blockApplicationTimeoutErrorScoreDefault, + MaxPendingBlocksErrorScore: maxPendingBlocksErrorScoreDefault, + TransactionApplicationErrorScore: transactionApplicationErrorScoreDefault, + ChainIDMismatchErrorScore: chainIDMismatchErrorScoreDefault, + ChainNotConnectedErrorScore: chainNotConnectedErrorScoreDefault, + CheckpointMismatchErrorScore: checkpointMismatchErrorScoreDefault, + LocalRPCErrorScore: localRPCErrorScoreDefault, + PeerRPCErrorScore: peerRPCErrorScoreDefault, + LocalRPCTimeoutErrorScore: localRPCTimeoutErrorScoreDefault, + PeerRPCTimeoutErrorScore: peerRPCTimeoutErrorScoreDefault, + ProcessRequestTimeoutErrorScore: processRequestTimeoutErrorScoreDefault, + UnknownErrorScore: unknownErrorScoreDefault, } } diff --git a/internal/p2p/block_applicator.go b/internal/p2p/block_applicator.go index a3ed00f..e8b3625 100644 --- a/internal/p2p/block_applicator.go +++ b/internal/p2p/block_applicator.go @@ -146,7 +146,9 @@ func (b *BlockApplicator) applyBlock(ctx context.Context, id string) { func (b *BlockApplicator) handleNewBlock(ctx context.Context, entry *blockEntry) { var err error - if len(b.blocksById) >= int(b.opts.MaxPendingBlocks) { + if entry.block.Header.Height > b.head.Height+b.opts.MaxHeightDelta { + err = p2perrors.ErrBlockApplication + } else if len(b.blocksById) >= int(b.opts.MaxPendingBlocks) { err = p2perrors.ErrMaxPendingBlocks } else if entry.block.Header.Height > b.head.Height+1 { err = b.addEntry(entry) diff --git a/internal/p2p/block_applicator_test.go b/internal/p2p/block_applicator_test.go index 6c16020..41d301c 100644 --- a/internal/p2p/block_applicator_test.go +++ b/internal/p2p/block_applicator_test.go @@ -225,7 +225,7 @@ func TestBlockApplicatorLimits(t *testing.T) { head: []byte{0x00}, } - blockApplicator, err := NewBlockApplicator(ctx, &rpc, options.BlockApplicatorOptions{MaxPendingBlocks: 5}) + blockApplicator, err := NewBlockApplicator(ctx, &rpc, options.BlockApplicatorOptions{MaxPendingBlocks: 5, MaxHeightDelta: 5}) if err != nil { t.Error(err) } @@ -273,4 +273,17 @@ func TestBlockApplicatorLimits(t *testing.T) { }, }, ) + + futureBlock := &protocol.Block{ + Id: []byte{0x08}, + Header: &protocol.BlockHeader{ + Height: 8, + Previous: []byte{0}, + }, + } + + err = blockApplicator.ApplyBlock(ctx, futureBlock) + if err != p2perrors.ErrBlockApplication { + t.Errorf("block2b - ErrBlockApplication expected but not returned, was: %v", err) + } } diff --git a/internal/p2p/error_handler.go b/internal/p2p/error_handler.go index fedaad7..8a95ce3 100644 --- a/internal/p2p/error_handler.go +++ b/internal/p2p/error_handler.go @@ -99,6 +99,12 @@ func (p *PeerErrorHandler) getScoreForError(err error) uint64 { return p.opts.TransactionApplicationErrorScore case errors.Is(err, p2perrors.ErrBlockApplication): return p.opts.BlockApplicationErrorScore + case errors.Is(err, p2perrors.ErrUnknownPreviousBlock): + return p.opts.UnknownPreviousBlockErrorScore + case errors.Is(err, p2perrors.ErrBlockApplicationTimeout): + return p.opts.BlockApplicationTimeoutErrorScore + case errors.Is(err, p2perrors.ErrMaxPendingBlocks): + return p.opts.MaxPendingBlocksErrorScore case errors.Is(err, p2perrors.ErrDeserialization): return p.opts.DeserializationErrorScore case errors.Is(err, p2perrors.ErrBlockIrreversibility):