More Efficient Validation of Proposer Index (#8107)

* metric

* make it better

* make it better

* gaz

Co-authored-by: Raul Jordan <raul@prysmaticlabs.com>
This commit is contained in:
Nishant Das
2020-12-16 00:27:05 +08:00
committed by GitHub
parent a0c475671c
commit 508c5fcf2f
3 changed files with 86 additions and 5 deletions

View File

@@ -47,6 +47,7 @@ var (
Help: "Count the number of times a node resyncs.",
},
)
arrivalBlockPropagationHistogram = promauto.NewHistogram(
prometheus.HistogramOpts{
Name: "block_arrival_latency_milliseconds",

View File

@@ -136,7 +136,8 @@ func (s *Service) validateBeaconBlockPubSub(ctx context.Context, pid peer.ID, ms
log.WithError(err).WithField("blockSlot", blk.Block.Slot).Warn("Rejected block")
return pubsub.ValidationReject
}
// Record attribute of valid block.
span.AddAttributes(trace.Int64Attribute("slotInEpoch", int64(blk.Block.Slot%params.BeaconConfig().SlotsPerEpoch)))
msg.ValidatorData = blk // Used in downstream subscriber
return pubsub.ValidationAccept
}
@@ -167,10 +168,26 @@ func (s *Service) validateBeaconBlock(ctx context.Context, blk *ethpb.SignedBeac
s.setBadBlock(ctx, blockRoot)
return err
}
parentState, err = state.ProcessSlots(ctx, parentState, blk.Block.Slot)
if err != nil {
return err
// There is an epoch lookahead for validator proposals
// for the next epoch from the start of our current epoch. We
// use the randao mix at the end of the previous epoch as the seed
// to determine proposals.
// Seed for Next Epoch => Derived From Randao Mix at the end of the Previous Epoch.
// Which is why we simply set the slot over here.
nextEpoch := helpers.NextEpoch(parentState)
expectedEpoch := helpers.SlotToEpoch(blk.Block.Slot)
if expectedEpoch <= nextEpoch {
err = parentState.SetSlot(blk.Block.Slot)
if err != nil {
return err
}
} else {
// In the event the block is more than an epoch ahead from its
// parent state, we have to advance the state forward.
parentState, err = state.ProcessSlots(ctx, parentState, blk.Block.Slot)
if err != nil {
return err
}
}
idx, err := helpers.BeaconProposerIndex(parentState)
if err != nil {

View File

@@ -244,6 +244,69 @@ func TestValidateBeaconBlockPubSub_ValidProposerSignature(t *testing.T) {
assert.NotNil(t, m.ValidatorData, "Decoded message was not set on the message validator data")
}
func TestValidateBeaconBlockPubSub_WithLookahead(t *testing.T) {
db, stateSummaryCache := dbtest.SetupDB(t)
p := p2ptest.NewTestP2P(t)
ctx := context.Background()
beaconState, privKeys := testutil.DeterministicGenesisState(t, 100)
parentBlock := testutil.NewBeaconBlock()
require.NoError(t, db.SaveBlock(ctx, parentBlock))
bRoot, err := parentBlock.Block.HashTreeRoot()
require.NoError(t, err)
require.NoError(t, db.SaveState(ctx, beaconState, bRoot))
require.NoError(t, db.SaveStateSummary(ctx, &pb.StateSummary{Root: bRoot[:]}))
copied := beaconState.Copy()
// The next block is only 1 epoch ahead so as to not induce a new seed.
blkSlot := params.BeaconConfig().SlotsPerEpoch * helpers.NextEpoch(copied)
copied, err = state.ProcessSlots(context.Background(), copied, blkSlot)
require.NoError(t, err)
proposerIdx, err := helpers.BeaconProposerIndex(copied)
require.NoError(t, err)
msg := testutil.NewBeaconBlock()
msg.Block.ProposerIndex = proposerIdx
msg.Block.Slot = blkSlot
msg.Block.ParentRoot = bRoot[:]
msg.Signature, err = helpers.ComputeDomainAndSign(beaconState, 0, msg.Block, params.BeaconConfig().DomainBeaconProposer, privKeys[proposerIdx])
require.NoError(t, err)
c, err := lru.New(10)
require.NoError(t, err)
c2, err := lru.New(10)
require.NoError(t, err)
stateGen := stategen.New(db, stateSummaryCache)
chainService := &mock.ChainService{Genesis: time.Unix(time.Now().Unix()-int64(blkSlot*params.BeaconConfig().SecondsPerSlot), 0),
State: beaconState,
FinalizedCheckPoint: &ethpb.Checkpoint{
Epoch: 0,
}}
r := &Service{
db: db,
p2p: p,
initialSync: &mockSync.Sync{IsSyncing: false},
chain: chainService,
blockNotifier: chainService.BlockNotifier(),
seenBlockCache: c,
badBlockCache: c2,
slotToPendingBlocks: gcache.New(time.Second, 2*time.Second),
seenPendingBlocks: make(map[[32]byte]bool),
stateSummaryCache: stateSummaryCache,
stateGen: stateGen,
}
buf := new(bytes.Buffer)
_, err = p.Encoding().EncodeGossip(buf, msg)
require.NoError(t, err)
topic := p2p.GossipTypeMapping[reflect.TypeOf(msg)]
m := &pubsub.Message{
Message: &pubsubpb.Message{
Data: buf.Bytes(),
Topic: &topic,
},
}
result := r.validateBeaconBlockPubSub(ctx, "", m) == pubsub.ValidationAccept
assert.Equal(t, true, result)
assert.NotNil(t, m.ValidatorData, "Decoded message was not set on the message validator data")
}
func TestValidateBeaconBlockPubSub_AdvanceEpochsForState(t *testing.T) {
db, stateSummaryCache := dbtest.SetupDB(t)
p := p2ptest.NewTestP2P(t)