mirror of
https://gitlab.com/pulsechaincom/prysm-pulse.git
synced 2024-12-22 19:40:37 +00:00
Adapt Doppelganger to Altair (#9969)
Co-authored-by: rkapka <rkapka@wp.pl>
This commit is contained in:
parent
67c8776f3c
commit
defa602e50
@ -15,6 +15,7 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/monitoring/tracing"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/runtime/version"
|
||||
"github.com/prysmaticlabs/prysm/time/slots"
|
||||
"go.opencensus.io/trace"
|
||||
"google.golang.org/grpc/codes"
|
||||
@ -25,7 +26,7 @@ var errPubkeyDoesNotExist = errors.New("pubkey does not exist")
|
||||
var errOptimisticMode = errors.New("the node is currently optimistic and cannot serve validators")
|
||||
var nonExistentIndex = types.ValidatorIndex(^uint64(0))
|
||||
|
||||
const numStatesToCheck = 2
|
||||
var errParticipation = status.Errorf(codes.Internal, "Failed to obtain epoch participation")
|
||||
|
||||
// ValidatorStatus returns the validator status of the current epoch.
|
||||
// The status response can be one of the following:
|
||||
@ -110,44 +111,67 @@ func (vs *Server) CheckDoppelGanger(ctx context.Context, req *ethpb.DoppelGanger
|
||||
return nil, status.Error(codes.Internal, "Could not get head state")
|
||||
}
|
||||
|
||||
currEpoch := slots.ToEpoch(headState.Slot())
|
||||
isRecent, resp := checkValidatorsAreRecent(currEpoch, req)
|
||||
// Return early if we are in phase0.
|
||||
if headState.Version() == version.Phase0 {
|
||||
log.Info("Skipping goppelganger check for Phase 0")
|
||||
|
||||
resp := ðpb.DoppelGangerResponse{
|
||||
Responses: []*ethpb.DoppelGangerResponse_ValidatorResponse{},
|
||||
}
|
||||
for _, v := range req.ValidatorRequests {
|
||||
resp.Responses = append(resp.Responses,
|
||||
ðpb.DoppelGangerResponse_ValidatorResponse{
|
||||
PublicKey: v.PublicKey,
|
||||
DuplicateExists: false,
|
||||
})
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
headSlot := headState.Slot()
|
||||
currEpoch := slots.ToEpoch(headSlot)
|
||||
|
||||
// If all provided keys are recent we skip this check
|
||||
// as we are unable to effectively determine if a doppelganger
|
||||
// is active.
|
||||
isRecent, resp := checkValidatorsAreRecent(currEpoch, req)
|
||||
if isRecent {
|
||||
return resp, nil
|
||||
}
|
||||
// We walk back from the current head state to the state at the beginning of the previous 2 epochs.
|
||||
// Where S_i , i := 0,1,2. i = 0 would signify the current head state in this epoch.
|
||||
previousEpoch, err := currEpoch.SafeSub(1)
|
||||
if err != nil {
|
||||
previousEpoch = currEpoch
|
||||
}
|
||||
olderEpoch, err := previousEpoch.SafeSub(1)
|
||||
if err != nil {
|
||||
olderEpoch = previousEpoch
|
||||
}
|
||||
prevState, err := vs.retrieveAfterEpochTransition(ctx, previousEpoch)
|
||||
|
||||
// We request a state 32 slots ago. We are guaranteed to have
|
||||
// currentSlot > 32 since we assume that we are in Altair's fork.
|
||||
prevState, err := vs.ReplayerBuilder.ReplayerForSlot(headSlot - params.BeaconConfig().SlotsPerEpoch).ReplayBlocks(ctx)
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.Internal, "Could not get previous state")
|
||||
}
|
||||
olderState, err := vs.retrieveAfterEpochTransition(ctx, olderEpoch)
|
||||
|
||||
headCurrentParticipation, err := headState.CurrentEpochParticipation()
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.Internal, "Could not get older state")
|
||||
return nil, errParticipation
|
||||
}
|
||||
headPreviousParticipation, err := headState.PreviousEpochParticipation()
|
||||
if err != nil {
|
||||
return nil, errParticipation
|
||||
}
|
||||
prevCurrentParticipation, err := prevState.CurrentEpochParticipation()
|
||||
if err != nil {
|
||||
return nil, errParticipation
|
||||
}
|
||||
prevPreviousParticipation, err := prevState.PreviousEpochParticipation()
|
||||
if err != nil {
|
||||
return nil, errParticipation
|
||||
}
|
||||
|
||||
resp = ðpb.DoppelGangerResponse{
|
||||
Responses: []*ethpb.DoppelGangerResponse_ValidatorResponse{},
|
||||
}
|
||||
for _, v := range req.ValidatorRequests {
|
||||
// If the validator's last recorded epoch was
|
||||
// less than or equal to `numStatesToCheck` epochs ago, this method will not
|
||||
// be able to catch duplicates. This is due to how attestation
|
||||
// inclusion works, where an attestation for the current epoch
|
||||
// is able to included in the current or next epoch. Depending
|
||||
// on which epoch it is included the balance change will be
|
||||
// reflected in the following epoch.
|
||||
if v.Epoch+numStatesToCheck >= currEpoch {
|
||||
// If the validator's last recorded epoch was less than 1 epoch
|
||||
// ago, the current doppelganger check will not be able to
|
||||
// identify dopplelgangers since an attestation can take up to
|
||||
// 31 slots to be included.
|
||||
if v.Epoch+1 >= currEpoch {
|
||||
resp.Responses = append(resp.Responses,
|
||||
ðpb.DoppelGangerResponse_ValidatorResponse{
|
||||
PublicKey: v.PublicKey,
|
||||
@ -155,37 +179,15 @@ func (vs *Server) CheckDoppelGanger(ctx context.Context, req *ethpb.DoppelGanger
|
||||
})
|
||||
continue
|
||||
}
|
||||
valIndex, ok := olderState.ValidatorIndexByPubkey(bytesutil.ToBytes48(v.PublicKey))
|
||||
valIndex, ok := prevState.ValidatorIndexByPubkey(bytesutil.ToBytes48(v.PublicKey))
|
||||
if !ok {
|
||||
// Ignore if validator pubkey doesn't exist.
|
||||
continue
|
||||
}
|
||||
baseBal, err := olderState.BalanceAtIndex(valIndex)
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.Internal, "Could not get validator's balance")
|
||||
}
|
||||
nextBal, err := prevState.BalanceAtIndex(valIndex)
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.Internal, "Could not get validator's balance")
|
||||
}
|
||||
// If the next epoch's balance is higher, we mark it as an existing
|
||||
// duplicate.
|
||||
if nextBal > baseBal {
|
||||
log.Infof("current %d with last epoch %d and difference in bal %d gwei", currEpoch, v.Epoch, nextBal-baseBal)
|
||||
resp.Responses = append(resp.Responses,
|
||||
ðpb.DoppelGangerResponse_ValidatorResponse{
|
||||
PublicKey: v.PublicKey,
|
||||
DuplicateExists: true,
|
||||
})
|
||||
continue
|
||||
}
|
||||
currBal, err := headState.BalanceAtIndex(valIndex)
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.Internal, "Could not get validator's balance")
|
||||
}
|
||||
// If the current epoch's balance is higher, we mark it as an existing
|
||||
// duplicate.
|
||||
if currBal > nextBal {
|
||||
|
||||
if (headCurrentParticipation[valIndex] != 0) || (headPreviousParticipation[valIndex] != 0) ||
|
||||
(prevCurrentParticipation[valIndex] != 0) || (prevPreviousParticipation[valIndex] != 0) {
|
||||
log.WithField("ValidatorIndex", valIndex).Infof("Participation flag found")
|
||||
resp.Responses = append(resp.Responses,
|
||||
ðpb.DoppelGangerResponse_ValidatorResponse{
|
||||
PublicKey: v.PublicKey,
|
||||
@ -374,8 +376,8 @@ func checkValidatorsAreRecent(headEpoch types.Epoch, req *ethpb.DoppelGangerRequ
|
||||
// Due to how balances are reflected for individual
|
||||
// validators, we can only effectively determine if a
|
||||
// validator voted or not if we are able to look
|
||||
// back more than `numStatesToCheck` epochs into the past.
|
||||
if v.Epoch+numStatesToCheck < headEpoch {
|
||||
// back more than 1 epoch into the past.
|
||||
if v.Epoch+1 < headEpoch {
|
||||
validatorsAreRecent = false
|
||||
// Zero out response if we encounter non-recent validators to
|
||||
// guard against potential misuse.
|
||||
|
@ -8,7 +8,6 @@ import (
|
||||
|
||||
"github.com/d4l3k/messagediff"
|
||||
types "github.com/prysmaticlabs/eth2-types"
|
||||
"github.com/prysmaticlabs/go-bitfield"
|
||||
mockChain "github.com/prysmaticlabs/prysm/beacon-chain/blockchain/testing"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/cache/depositcache"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
@ -17,7 +16,6 @@ import (
|
||||
mockstategen "github.com/prysmaticlabs/prysm/beacon-chain/state/stategen/mock"
|
||||
v1 "github.com/prysmaticlabs/prysm/beacon-chain/state/v1"
|
||||
mockSync "github.com/prysmaticlabs/prysm/beacon-chain/sync/initial-sync/testing"
|
||||
fieldparams "github.com/prysmaticlabs/prysm/config/fieldparams"
|
||||
"github.com/prysmaticlabs/prysm/config/params"
|
||||
"github.com/prysmaticlabs/prysm/container/trie"
|
||||
"github.com/prysmaticlabs/prysm/crypto/bls"
|
||||
@ -961,27 +959,15 @@ func TestServer_CheckDoppelGanger(t *testing.T) {
|
||||
name: "normal doppelganger request",
|
||||
wantErr: false,
|
||||
svSetup: func(t *testing.T) (*Server, *ethpb.DoppelGangerRequest, *ethpb.DoppelGangerResponse) {
|
||||
hs, ps, os, keys, builder := createStateSetup(t, 4)
|
||||
// Previous Epoch State
|
||||
for i := 0; i < 3; i++ {
|
||||
bal, err := ps.BalanceAtIndex(types.ValidatorIndex(i))
|
||||
assert.NoError(t, err)
|
||||
// Add 100 gwei, to mock an inactivity leak
|
||||
assert.NoError(t, ps.UpdateBalancesAtIndex(types.ValidatorIndex(i), bal+1000000000))
|
||||
}
|
||||
// Older Epoch State
|
||||
for i := 0; i < 3; i++ {
|
||||
bal, err := os.BalanceAtIndex(types.ValidatorIndex(i))
|
||||
assert.NoError(t, err)
|
||||
// Add 200 gwei, to mock an inactivity leak
|
||||
assert.NoError(t, os.UpdateBalancesAtIndex(types.ValidatorIndex(i), bal+2000000000))
|
||||
}
|
||||
hs, ps, keys := createStateSetupAltair(t, 3)
|
||||
rb := mockstategen.NewMockReplayerBuilder()
|
||||
rb.SetMockStateForSlot(ps, 20)
|
||||
vs := &Server{
|
||||
HeadFetcher: &mockChain.ChainService{
|
||||
State: hs,
|
||||
},
|
||||
SyncChecker: &mockSync.Sync{IsSyncing: false},
|
||||
ReplayerBuilder: builder,
|
||||
ReplayerBuilder: rb,
|
||||
}
|
||||
request := ðpb.DoppelGangerRequest{
|
||||
ValidatorRequests: make([]*ethpb.DoppelGangerRequest_ValidatorRequest, 0),
|
||||
@ -1005,37 +991,19 @@ func TestServer_CheckDoppelGanger(t *testing.T) {
|
||||
name: "doppelganger exists current epoch",
|
||||
wantErr: false,
|
||||
svSetup: func(t *testing.T) (*Server, *ethpb.DoppelGangerRequest, *ethpb.DoppelGangerResponse) {
|
||||
hs, ps, os, keys, builder := createStateSetup(t, 4)
|
||||
// Previous Epoch State
|
||||
for i := 0; i < 2; i++ {
|
||||
bal, err := ps.BalanceAtIndex(types.ValidatorIndex(i))
|
||||
assert.NoError(t, err)
|
||||
// Add 100 gwei, to mock an inactivity leak
|
||||
assert.NoError(t, ps.UpdateBalancesAtIndex(types.ValidatorIndex(i), bal+1000000000))
|
||||
}
|
||||
bal, err := ps.BalanceAtIndex(types.ValidatorIndex(2))
|
||||
assert.NoError(t, err)
|
||||
// Sub 100 gwei, to mock an active validator.
|
||||
assert.NoError(t, ps.UpdateBalancesAtIndex(types.ValidatorIndex(2), bal-1000000000))
|
||||
|
||||
// Older Epoch State
|
||||
for i := 0; i < 2; i++ {
|
||||
bal, err := os.BalanceAtIndex(types.ValidatorIndex(i))
|
||||
assert.NoError(t, err)
|
||||
// Add 200 gwei, to mock an inactivity leak
|
||||
assert.NoError(t, os.UpdateBalancesAtIndex(types.ValidatorIndex(i), bal+2000000000))
|
||||
}
|
||||
bal, err = os.BalanceAtIndex(types.ValidatorIndex(2))
|
||||
assert.NoError(t, err)
|
||||
// Sub 100 gwei, to mock an active validator.
|
||||
assert.NoError(t, os.UpdateBalancesAtIndex(types.ValidatorIndex(2), bal-1000000000))
|
||||
hs, ps, keys := createStateSetupAltair(t, 3)
|
||||
rb := mockstategen.NewMockReplayerBuilder()
|
||||
rb.SetMockStateForSlot(ps, 20)
|
||||
currentIndices := make([]byte, 64)
|
||||
currentIndices[2] = 1
|
||||
require.NoError(t, hs.SetCurrentParticipationBits(currentIndices))
|
||||
|
||||
vs := &Server{
|
||||
HeadFetcher: &mockChain.ChainService{
|
||||
State: hs,
|
||||
},
|
||||
SyncChecker: &mockSync.Sync{IsSyncing: false},
|
||||
ReplayerBuilder: builder,
|
||||
ReplayerBuilder: rb,
|
||||
}
|
||||
request := ðpb.DoppelGangerRequest{
|
||||
ValidatorRequests: make([]*ethpb.DoppelGangerRequest_ValidatorRequest, 0),
|
||||
@ -1070,37 +1038,19 @@ func TestServer_CheckDoppelGanger(t *testing.T) {
|
||||
name: "doppelganger exists previous epoch",
|
||||
wantErr: false,
|
||||
svSetup: func(t *testing.T) (*Server, *ethpb.DoppelGangerRequest, *ethpb.DoppelGangerResponse) {
|
||||
hs, ps, os, keys, builder := createStateSetup(t, 4)
|
||||
// Previous Epoch State
|
||||
for i := 0; i < 2; i++ {
|
||||
bal, err := ps.BalanceAtIndex(types.ValidatorIndex(i))
|
||||
assert.NoError(t, err)
|
||||
// Add 100 gwei, to mock an inactivity leak
|
||||
assert.NoError(t, ps.UpdateBalancesAtIndex(types.ValidatorIndex(i), bal+1000000000))
|
||||
}
|
||||
bal, err := ps.BalanceAtIndex(types.ValidatorIndex(2))
|
||||
assert.NoError(t, err)
|
||||
// Sub 100 gwei, to mock an active validator.
|
||||
assert.NoError(t, ps.UpdateBalancesAtIndex(types.ValidatorIndex(2), bal-1000000000))
|
||||
|
||||
// Older Epoch State
|
||||
for i := 0; i < 2; i++ {
|
||||
bal, err := os.BalanceAtIndex(types.ValidatorIndex(i))
|
||||
assert.NoError(t, err)
|
||||
// Add 200 gwei, to mock an inactivity leak
|
||||
assert.NoError(t, os.UpdateBalancesAtIndex(types.ValidatorIndex(i), bal+2000000000))
|
||||
}
|
||||
bal, err = os.BalanceAtIndex(types.ValidatorIndex(2))
|
||||
assert.NoError(t, err)
|
||||
// Sub 200 gwei, to mock an active validator.
|
||||
assert.NoError(t, os.UpdateBalancesAtIndex(types.ValidatorIndex(2), bal-2000000000))
|
||||
hs, ps, keys := createStateSetupAltair(t, 3)
|
||||
prevIndices := make([]byte, 64)
|
||||
prevIndices[2] = 1
|
||||
require.NoError(t, ps.SetPreviousParticipationBits(prevIndices))
|
||||
rb := mockstategen.NewMockReplayerBuilder()
|
||||
rb.SetMockStateForSlot(ps, 20)
|
||||
|
||||
vs := &Server{
|
||||
HeadFetcher: &mockChain.ChainService{
|
||||
State: hs,
|
||||
},
|
||||
SyncChecker: &mockSync.Sync{IsSyncing: false},
|
||||
ReplayerBuilder: builder,
|
||||
ReplayerBuilder: rb,
|
||||
}
|
||||
request := ðpb.DoppelGangerRequest{
|
||||
ValidatorRequests: make([]*ethpb.DoppelGangerRequest_ValidatorRequest, 0),
|
||||
@ -1135,29 +1085,26 @@ func TestServer_CheckDoppelGanger(t *testing.T) {
|
||||
name: "multiple doppelganger exists",
|
||||
wantErr: false,
|
||||
svSetup: func(t *testing.T) (*Server, *ethpb.DoppelGangerRequest, *ethpb.DoppelGangerResponse) {
|
||||
hs, ps, os, keys, builder := createStateSetup(t, 4)
|
||||
// Previous Epoch State
|
||||
for i := 10; i < 15; i++ {
|
||||
bal, err := ps.BalanceAtIndex(types.ValidatorIndex(i))
|
||||
assert.NoError(t, err)
|
||||
// Add 100 gwei, to mock an inactivity leak
|
||||
assert.NoError(t, ps.UpdateBalancesAtIndex(types.ValidatorIndex(i), bal-1000000000))
|
||||
}
|
||||
hs, ps, keys := createStateSetupAltair(t, 3)
|
||||
currentIndices := make([]byte, 64)
|
||||
currentIndices[10] = 1
|
||||
currentIndices[11] = 2
|
||||
require.NoError(t, hs.SetPreviousParticipationBits(currentIndices))
|
||||
rb := mockstategen.NewMockReplayerBuilder()
|
||||
rb.SetMockStateForSlot(ps, 20)
|
||||
|
||||
// Older Epoch State
|
||||
for i := 10; i < 15; i++ {
|
||||
bal, err := os.BalanceAtIndex(types.ValidatorIndex(i))
|
||||
assert.NoError(t, err)
|
||||
// Add 200 gwei, to mock an inactivity leak
|
||||
assert.NoError(t, os.UpdateBalancesAtIndex(types.ValidatorIndex(i), bal-2000000000))
|
||||
prevIndices := make([]byte, 64)
|
||||
for i := 12; i < 20; i++ {
|
||||
prevIndices[i] = 1
|
||||
}
|
||||
require.NoError(t, ps.SetCurrentParticipationBits(prevIndices))
|
||||
|
||||
vs := &Server{
|
||||
HeadFetcher: &mockChain.ChainService{
|
||||
State: hs,
|
||||
},
|
||||
SyncChecker: &mockSync.Sync{IsSyncing: false},
|
||||
ReplayerBuilder: builder,
|
||||
ReplayerBuilder: rb,
|
||||
}
|
||||
request := ðpb.DoppelGangerRequest{
|
||||
ValidatorRequests: make([]*ethpb.DoppelGangerRequest_ValidatorRequest, 0),
|
||||
@ -1175,6 +1122,17 @@ func TestServer_CheckDoppelGanger(t *testing.T) {
|
||||
DuplicateExists: true,
|
||||
})
|
||||
}
|
||||
for i := 15; i < 20; i++ {
|
||||
request.ValidatorRequests = append(request.ValidatorRequests, ðpb.DoppelGangerRequest_ValidatorRequest{
|
||||
PublicKey: keys[i].PublicKey().Marshal(),
|
||||
Epoch: 3,
|
||||
SignedRoot: []byte{'A'},
|
||||
})
|
||||
response.Responses = append(response.Responses, ðpb.DoppelGangerResponse_ValidatorResponse{
|
||||
PublicKey: keys[i].PublicKey().Marshal(),
|
||||
DuplicateExists: false,
|
||||
})
|
||||
}
|
||||
|
||||
return vs, request, response
|
||||
},
|
||||
@ -1183,14 +1141,16 @@ func TestServer_CheckDoppelGanger(t *testing.T) {
|
||||
name: "attesters are too recent",
|
||||
wantErr: false,
|
||||
svSetup: func(t *testing.T) (*Server, *ethpb.DoppelGangerRequest, *ethpb.DoppelGangerResponse) {
|
||||
hs, _, _, keys, _ := createStateSetup(t, 4)
|
||||
hs, ps, keys := createStateSetupAltair(t, 3)
|
||||
rb := mockstategen.NewMockReplayerBuilder()
|
||||
rb.SetMockStateForSlot(ps, 20)
|
||||
|
||||
vs := &Server{
|
||||
HeadFetcher: &mockChain.ChainService{
|
||||
State: hs,
|
||||
},
|
||||
SyncChecker: &mockSync.Sync{IsSyncing: false},
|
||||
ReplayerBuilder: nil,
|
||||
ReplayerBuilder: rb,
|
||||
}
|
||||
request := ðpb.DoppelGangerRequest{
|
||||
ValidatorRequests: make([]*ethpb.DoppelGangerRequest_ValidatorRequest, 0),
|
||||
@ -1208,6 +1168,39 @@ func TestServer_CheckDoppelGanger(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
return vs, request, response
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "exit early for Phase 0",
|
||||
wantErr: false,
|
||||
svSetup: func(t *testing.T) (*Server, *ethpb.DoppelGangerRequest, *ethpb.DoppelGangerResponse) {
|
||||
hs, _, keys := createStateSetupPhase0(t, 3)
|
||||
|
||||
vs := &Server{
|
||||
HeadFetcher: &mockChain.ChainService{
|
||||
State: hs,
|
||||
},
|
||||
SyncChecker: &mockSync.Sync{IsSyncing: false},
|
||||
}
|
||||
request := ðpb.DoppelGangerRequest{
|
||||
ValidatorRequests: []*ethpb.DoppelGangerRequest_ValidatorRequest{
|
||||
{
|
||||
PublicKey: keys[0].PublicKey().Marshal(),
|
||||
Epoch: 1,
|
||||
SignedRoot: []byte{'A'},
|
||||
},
|
||||
},
|
||||
}
|
||||
response := ðpb.DoppelGangerResponse{
|
||||
Responses: []*ethpb.DoppelGangerResponse_ValidatorResponse{
|
||||
{
|
||||
PublicKey: keys[0].PublicKey().Marshal(),
|
||||
DuplicateExists: false,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
return vs, request, response
|
||||
},
|
||||
},
|
||||
@ -1228,104 +1221,36 @@ func TestServer_CheckDoppelGanger(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func createStateSetup(t *testing.T, head types.Epoch) (state.BeaconState,
|
||||
state.BeaconState, state.BeaconState, []bls.SecretKey, *mockstategen.MockReplayerBuilder) {
|
||||
rb := &mockstategen.MockReplayerBuilder{}
|
||||
func createStateSetupPhase0(t *testing.T, head types.Epoch) (state.BeaconState,
|
||||
state.BeaconState, []bls.SecretKey) {
|
||||
gs, keys := util.DeterministicGenesisState(t, 64)
|
||||
hs := gs.Copy()
|
||||
|
||||
// Head State
|
||||
headEpoch := head
|
||||
headSlot := types.Slot(headEpoch) * params.BeaconConfig().SlotsPerEpoch
|
||||
headSlot := types.Slot(head)*params.BeaconConfig().SlotsPerEpoch + params.BeaconConfig().SlotsPerEpoch/2
|
||||
assert.NoError(t, hs.SetSlot(headSlot))
|
||||
assingments, _, err := helpers.CommitteeAssignments(context.Background(), hs, headEpoch)
|
||||
assert.NoError(t, err)
|
||||
for _, ctr := range assingments {
|
||||
pendingAtt := ðpb.PendingAttestation{
|
||||
AggregationBits: bitfield.NewBitlist64(uint64(len(ctr.Committee))).ToBitlist().Not(),
|
||||
Data: ðpb.AttestationData{
|
||||
Slot: ctr.AttesterSlot,
|
||||
CommitteeIndex: ctr.CommitteeIndex,
|
||||
BeaconBlockRoot: make([]byte, fieldparams.RootLength),
|
||||
Source: ðpb.Checkpoint{
|
||||
Epoch: 0,
|
||||
Root: make([]byte, fieldparams.RootLength),
|
||||
},
|
||||
Target: ðpb.Checkpoint{
|
||||
Epoch: 1,
|
||||
Root: make([]byte, fieldparams.RootLength),
|
||||
},
|
||||
},
|
||||
InclusionDelay: 1,
|
||||
ProposerIndex: 10,
|
||||
}
|
||||
assert.NoError(t, hs.AppendCurrentEpochAttestations(pendingAtt))
|
||||
}
|
||||
rb.SetMockState(hs)
|
||||
|
||||
// Previous Epoch State
|
||||
prevEpoch := headEpoch - 1
|
||||
prevSlot := headSlot - params.BeaconConfig().SlotsPerEpoch
|
||||
ps := gs.Copy()
|
||||
prevSlot, err := slots.EpochEnd(prevEpoch)
|
||||
assert.NoError(t, err)
|
||||
assert.NoError(t, ps.SetSlot(prevSlot))
|
||||
assingments, _, err = helpers.CommitteeAssignments(context.Background(), ps, prevEpoch)
|
||||
assert.NoError(t, err)
|
||||
for _, ctr := range assingments {
|
||||
pendingAtt := ðpb.PendingAttestation{
|
||||
AggregationBits: bitfield.NewBitlist64(uint64(len(ctr.Committee))).ToBitlist().Not(),
|
||||
Data: ðpb.AttestationData{
|
||||
Slot: ctr.AttesterSlot,
|
||||
CommitteeIndex: ctr.CommitteeIndex,
|
||||
BeaconBlockRoot: make([]byte, fieldparams.RootLength),
|
||||
Source: ðpb.Checkpoint{
|
||||
Epoch: 0,
|
||||
Root: make([]byte, fieldparams.RootLength),
|
||||
},
|
||||
Target: ðpb.Checkpoint{
|
||||
Epoch: 1,
|
||||
Root: make([]byte, fieldparams.RootLength),
|
||||
},
|
||||
},
|
||||
InclusionDelay: 1,
|
||||
ProposerIndex: 10,
|
||||
}
|
||||
assert.NoError(t, ps.AppendCurrentEpochAttestations(pendingAtt))
|
||||
}
|
||||
rb.SetMockState(ps)
|
||||
|
||||
// Older Epoch State
|
||||
olderEpoch := prevEpoch - 1
|
||||
os := gs.Copy()
|
||||
olderSlot, err := slots.EpochEnd(olderEpoch)
|
||||
assert.NoError(t, err)
|
||||
assert.NoError(t, os.SetSlot(olderSlot))
|
||||
assingments, _, err = helpers.CommitteeAssignments(context.Background(), os, olderEpoch)
|
||||
assert.NoError(t, err)
|
||||
for _, ctr := range assingments {
|
||||
attSlot := ctr.AttesterSlot
|
||||
if attSlot == olderSlot {
|
||||
continue
|
||||
}
|
||||
pendingAtt := ðpb.PendingAttestation{
|
||||
AggregationBits: bitfield.NewBitlist64(uint64(len(ctr.Committee))).ToBitlist().Not(),
|
||||
Data: ðpb.AttestationData{
|
||||
Slot: attSlot,
|
||||
CommitteeIndex: ctr.CommitteeIndex,
|
||||
BeaconBlockRoot: make([]byte, fieldparams.RootLength),
|
||||
Source: ðpb.Checkpoint{
|
||||
Epoch: 0,
|
||||
Root: make([]byte, fieldparams.RootLength),
|
||||
},
|
||||
Target: ðpb.Checkpoint{
|
||||
Epoch: 1,
|
||||
Root: make([]byte, fieldparams.RootLength),
|
||||
},
|
||||
},
|
||||
InclusionDelay: 1,
|
||||
ProposerIndex: 10,
|
||||
}
|
||||
assert.NoError(t, os.AppendCurrentEpochAttestations(pendingAtt))
|
||||
}
|
||||
rb.SetMockState(os)
|
||||
return hs, ps, os, keys, rb
|
||||
return hs, ps, keys
|
||||
}
|
||||
|
||||
func createStateSetupAltair(t *testing.T, head types.Epoch) (state.BeaconState,
|
||||
state.BeaconState, []bls.SecretKey) {
|
||||
gs, keys := util.DeterministicGenesisStateAltair(t, 64)
|
||||
hs := gs.Copy()
|
||||
|
||||
// Head State
|
||||
headSlot := types.Slot(head)*params.BeaconConfig().SlotsPerEpoch + params.BeaconConfig().SlotsPerEpoch/2
|
||||
assert.NoError(t, hs.SetSlot(headSlot))
|
||||
|
||||
// Previous Epoch State
|
||||
prevSlot := headSlot - params.BeaconConfig().SlotsPerEpoch
|
||||
ps := gs.Copy()
|
||||
assert.NoError(t, ps.SetSlot(prevSlot))
|
||||
|
||||
return hs, ps, keys
|
||||
}
|
||||
|
@ -41,6 +41,13 @@ func (b *MockReplayerBuilder) SetMockState(s state.BeaconState) {
|
||||
b.forSlot[s.Slot()] = &MockReplayer{State: s}
|
||||
}
|
||||
|
||||
func (b *MockReplayerBuilder) SetMockStateForSlot(s state.BeaconState, slot types.Slot) {
|
||||
if b.forSlot == nil {
|
||||
b.forSlot = make(map[types.Slot]*MockReplayer)
|
||||
}
|
||||
b.forSlot[slot] = &MockReplayer{State: s}
|
||||
}
|
||||
|
||||
func (b *MockReplayerBuilder) SetMockSlotError(s types.Slot, e error) {
|
||||
if b.forSlot == nil {
|
||||
b.forSlot = make(map[types.Slot]*MockReplayer)
|
||||
|
@ -83,14 +83,7 @@ func run(ctx context.Context, v iface.Validator) {
|
||||
if err != nil {
|
||||
log.Fatalf("Could not wait for validator activation: %v", err)
|
||||
}
|
||||
err = v.CheckDoppelGanger(ctx)
|
||||
if isConnectionError(err) {
|
||||
log.Warnf("Could not wait for checking doppelganger: %v", err)
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
log.Fatalf("Could not succeed with doppelganger check: %v", err)
|
||||
}
|
||||
|
||||
headSlot, err = v.CanonicalHeadSlot(ctx)
|
||||
if isConnectionError(err) {
|
||||
log.Warnf("Could not get current canonical head slot: %v", err)
|
||||
@ -99,6 +92,14 @@ func run(ctx context.Context, v iface.Validator) {
|
||||
if err != nil {
|
||||
log.Fatalf("Could not get current canonical head slot: %v", err)
|
||||
}
|
||||
err = v.CheckDoppelGanger(ctx)
|
||||
if isConnectionError(err) {
|
||||
log.Warnf("Could not wait for checking doppelganger: %v", err)
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
log.Fatalf("Could not succeed with doppelganger check: %v", err)
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user