mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-05-02 03:02:54 -04:00
219 lines
7.5 KiB
Go
219 lines
7.5 KiB
Go
package initialsync
|
|
|
|
import (
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/OffchainLabs/prysm/v7/beacon-chain/blockchain"
|
|
mock "github.com/OffchainLabs/prysm/v7/beacon-chain/blockchain/testing"
|
|
"github.com/OffchainLabs/prysm/v7/beacon-chain/p2p/peers/peerdata"
|
|
p2pt "github.com/OffchainLabs/prysm/v7/beacon-chain/p2p/testing"
|
|
"github.com/OffchainLabs/prysm/v7/beacon-chain/startup"
|
|
"github.com/OffchainLabs/prysm/v7/beacon-chain/sync"
|
|
"github.com/OffchainLabs/prysm/v7/beacon-chain/verification"
|
|
"github.com/OffchainLabs/prysm/v7/consensus-types/primitives"
|
|
"github.com/OffchainLabs/prysm/v7/testing/assert"
|
|
"github.com/OffchainLabs/prysm/v7/testing/require"
|
|
"github.com/libp2p/go-libp2p/core/peer"
|
|
"github.com/pkg/errors"
|
|
)
|
|
|
|
type testDownscorePeer int
|
|
|
|
const (
|
|
testDownscoreNeither testDownscorePeer = iota
|
|
testDownscoreBlock
|
|
testDownscoreBlob
|
|
)
|
|
|
|
func peerIDForTestDownscore(w testDownscorePeer, name string) peer.ID {
|
|
switch w {
|
|
case testDownscoreBlock:
|
|
return peer.ID("block" + name)
|
|
case testDownscoreBlob:
|
|
return peer.ID("blob" + name)
|
|
default:
|
|
return ""
|
|
}
|
|
}
|
|
|
|
func TestUpdatePeerScorerStats(t *testing.T) {
|
|
cases := []struct {
|
|
name string
|
|
err error
|
|
processed uint64
|
|
downPeer testDownscorePeer
|
|
}{
|
|
{
|
|
name: "invalid block",
|
|
err: blockchain.ErrInvalidPayload,
|
|
downPeer: testDownscoreBlock,
|
|
processed: 10,
|
|
},
|
|
{
|
|
name: "invalid blob",
|
|
err: verification.ErrBlobIndexInvalid,
|
|
downPeer: testDownscoreBlob,
|
|
processed: 3,
|
|
},
|
|
{
|
|
name: "not validity error",
|
|
err: errors.New("test"),
|
|
processed: 32,
|
|
},
|
|
{
|
|
name: "no error",
|
|
processed: 32,
|
|
},
|
|
}
|
|
s := &Service{
|
|
cfg: &Config{
|
|
P2P: p2pt.NewTestP2P(t),
|
|
},
|
|
}
|
|
for _, c := range cases {
|
|
t.Run(c.name, func(t *testing.T) {
|
|
data := &blocksQueueFetchedData{
|
|
blocksFrom: peerIDForTestDownscore(testDownscoreBlock, c.name),
|
|
blobsFrom: peerIDForTestDownscore(testDownscoreBlob, c.name),
|
|
}
|
|
s.updatePeerScorerStats(data, c.processed, c.err)
|
|
if c.err != nil && c.downPeer != testDownscoreNeither {
|
|
switch c.downPeer {
|
|
case testDownscoreBlock:
|
|
// block should be downscored
|
|
blocksCount, err := s.cfg.P2P.Peers().Scorers().BadResponsesScorer().Count(data.blocksFrom)
|
|
require.NoError(t, err)
|
|
require.Equal(t, 1, blocksCount)
|
|
// blob should not be downscored - also we expect a not found error since peer scoring did not interact with blobs
|
|
blobCount, err := s.cfg.P2P.Peers().Scorers().BadResponsesScorer().Count(data.blobsFrom)
|
|
require.ErrorIs(t, err, peerdata.ErrPeerUnknown)
|
|
require.Equal(t, -1, blobCount)
|
|
case testDownscoreBlob:
|
|
// block should not be downscored - also we expect a not found error since peer scoring did not interact with blocks
|
|
blocksCount, err := s.cfg.P2P.Peers().Scorers().BadResponsesScorer().Count(data.blocksFrom)
|
|
require.ErrorIs(t, err, peerdata.ErrPeerUnknown)
|
|
require.Equal(t, -1, blocksCount)
|
|
// blob should be downscored
|
|
blobCount, err := s.cfg.P2P.Peers().Scorers().BadResponsesScorer().Count(data.blobsFrom)
|
|
require.NoError(t, err)
|
|
require.Equal(t, 1, blobCount)
|
|
}
|
|
assert.Equal(t, uint64(0), s.cfg.P2P.Peers().Scorers().BlockProviderScorer().ProcessedBlocks(data.blocksFrom))
|
|
return
|
|
}
|
|
// block should not be downscored - also we expect a not found error since peer scoring did not interact with blocks
|
|
blocksCount, err := s.cfg.P2P.Peers().Scorers().BadResponsesScorer().Count(data.blocksFrom)
|
|
// The scorer will know about the the block peer because it will have a processed blocks count
|
|
require.NoError(t, err)
|
|
require.Equal(t, 0, blocksCount)
|
|
// no downscore, so scorer doesn't know the peer
|
|
blobCount, err := s.cfg.P2P.Peers().Scorers().BadResponsesScorer().Count(data.blobsFrom)
|
|
require.ErrorIs(t, err, peerdata.ErrPeerUnknown)
|
|
require.Equal(t, -1, blobCount)
|
|
|
|
assert.Equal(t, c.processed, s.cfg.P2P.Peers().Scorers().BlockProviderScorer().ProcessedBlocks(data.blocksFrom))
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestOnDataReceivedDownscore(t *testing.T) {
|
|
cases := []struct {
|
|
name string
|
|
err error
|
|
downPeer testDownscorePeer
|
|
}{
|
|
{
|
|
name: "invalid block",
|
|
err: sync.ErrInvalidFetchedData,
|
|
downPeer: testDownscoreBlock,
|
|
},
|
|
{
|
|
name: "invalid blob",
|
|
err: errors.Wrap(verification.ErrBlobInvalid, "test"),
|
|
downPeer: testDownscoreBlob,
|
|
},
|
|
{
|
|
name: "not validity error",
|
|
err: errors.New("test"),
|
|
},
|
|
{
|
|
name: "no error",
|
|
},
|
|
}
|
|
for _, c := range cases {
|
|
t.Run(c.name, func(t *testing.T) {
|
|
data := &fetchRequestResponse{
|
|
blocksFrom: peerIDForTestDownscore(testDownscoreBlock, c.name),
|
|
blobsFrom: peerIDForTestDownscore(testDownscoreBlob, c.name),
|
|
err: c.err,
|
|
}
|
|
if c.downPeer == testDownscoreBlob {
|
|
require.Equal(t, true, verification.IsBlobValidationFailure(c.err))
|
|
}
|
|
ctx := t.Context()
|
|
p2p := p2pt.NewTestP2P(t)
|
|
mc := &mock.ChainService{Genesis: time.Now(), ValidatorsRoot: [32]byte{}}
|
|
fetcher := newBlocksFetcher(ctx, &blocksFetcherConfig{
|
|
chain: mc,
|
|
p2p: p2p,
|
|
clock: startup.NewClock(mc.Genesis, mc.ValidatorsRoot),
|
|
})
|
|
q := newBlocksQueue(ctx, &blocksQueueConfig{
|
|
p2p: p2p,
|
|
blocksFetcher: fetcher,
|
|
highestExpectedSlot: primitives.Slot(32),
|
|
chain: mc})
|
|
sm := q.smm.addStateMachine(0)
|
|
sm.state = stateScheduled
|
|
handle := q.onDataReceivedEvent(t.Context())
|
|
endState, err := handle(sm, data)
|
|
if c.err != nil {
|
|
require.ErrorIs(t, err, c.err)
|
|
} else {
|
|
require.NoError(t, err)
|
|
}
|
|
// state machine should stay in "scheduled" if there's an error
|
|
// and transition to "data parsed" if there's no error
|
|
if c.err != nil {
|
|
require.Equal(t, stateScheduled, endState)
|
|
} else {
|
|
require.Equal(t, stateDataParsed, endState)
|
|
}
|
|
if c.err != nil && c.downPeer != testDownscoreNeither {
|
|
switch c.downPeer {
|
|
case testDownscoreBlock:
|
|
// block should be downscored
|
|
blocksCount, err := p2p.Peers().Scorers().BadResponsesScorer().Count(data.blocksFrom)
|
|
require.NoError(t, err)
|
|
require.Equal(t, 1, blocksCount)
|
|
// blob should not be downscored - also we expect a not found error since peer scoring did not interact with blobs
|
|
blobCount, err := p2p.Peers().Scorers().BadResponsesScorer().Count(data.blobsFrom)
|
|
require.ErrorIs(t, err, peerdata.ErrPeerUnknown)
|
|
require.Equal(t, -1, blobCount)
|
|
case testDownscoreBlob:
|
|
// block should not be downscored - also we expect a not found error since peer scoring did not interact with blocks
|
|
blocksCount, err := p2p.Peers().Scorers().BadResponsesScorer().Count(data.blocksFrom)
|
|
require.ErrorIs(t, err, peerdata.ErrPeerUnknown)
|
|
require.Equal(t, -1, blocksCount)
|
|
// blob should be downscored
|
|
blobCount, err := p2p.Peers().Scorers().BadResponsesScorer().Count(data.blobsFrom)
|
|
require.NoError(t, err)
|
|
require.Equal(t, 1, blobCount)
|
|
}
|
|
assert.Equal(t, uint64(0), p2p.Peers().Scorers().BlockProviderScorer().ProcessedBlocks(data.blocksFrom))
|
|
return
|
|
}
|
|
// block should not be downscored - also we expect a not found error since peer scoring did not interact with blocks
|
|
blocksCount, err := p2p.Peers().Scorers().BadResponsesScorer().Count(data.blocksFrom)
|
|
// no downscore, so scorer doesn't know the peer
|
|
require.ErrorIs(t, err, peerdata.ErrPeerUnknown)
|
|
require.Equal(t, -1, blocksCount)
|
|
blobCount, err := p2p.Peers().Scorers().BadResponsesScorer().Count(data.blobsFrom)
|
|
// no downscore, so scorer doesn't know the peer
|
|
require.ErrorIs(t, err, peerdata.ErrPeerUnknown)
|
|
require.Equal(t, -1, blobCount)
|
|
})
|
|
}
|
|
}
|