Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement Doppelganger Check #9120

Merged
merged 28 commits into from
Jul 2, 2021
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
fa6d7ea
checkpoint changes
nisdas Jun 29, 2021
3c3c39e
Merge branch 'develop' into implementDoppleganger
nisdas Jun 29, 2021
461faa7
Update beacon-chain/rpc/validator/status.go
nisdas Jun 30, 2021
240127d
Update beacon-chain/rpc/validator/status.go
nisdas Jun 30, 2021
baba3ee
add in client side tests
nisdas Jun 30, 2021
a74b646
add ordering
nisdas Jun 30, 2021
e0c84be
add all new test cases
nisdas Jun 30, 2021
5102d5a
gate feature
nisdas Jun 30, 2021
c53ca33
Merge branch 'develop' into implementDoppleganger
nisdas Jun 30, 2021
382c221
handle edge case
nisdas Jun 30, 2021
43101ed
Merge branch 'implementDoppleganger' of https://github.com/prysmaticl…
nisdas Jun 30, 2021
2f23842
add one more test case
nisdas Jun 30, 2021
db90b7a
fatal error
nisdas Jun 30, 2021
69d4c6a
zahoor's review
nisdas Jun 30, 2021
dfaaf4a
Merge branch 'develop' of https://github.com/prysmaticlabs/geth-shard…
nisdas Jul 1, 2021
20d95bc
Update validator/client/validator.go
nisdas Jul 1, 2021
3611f5d
Update validator/client/validator.go
nisdas Jul 1, 2021
d624bbd
doppelganger not doppleganger
nisdas Jul 1, 2021
09f260e
Merge branch 'implementDoppleganger' of https://github.com/prysmaticl…
nisdas Jul 1, 2021
0a3941a
preston's review
nisdas Jul 1, 2021
959bcbc
add in comment
nisdas Jul 1, 2021
3845258
change comment
nisdas Jul 1, 2021
684038c
Fix e2e to only run new flags on the current version
prestonvanloon Jul 1, 2021
2e5ad7f
Fix bug where zero byte public keys were always sent in the request w…
prestonvanloon Jul 1, 2021
dac200f
go mod tidy, gazelle
prestonvanloon Jul 1, 2021
c6b6b21
Merge branch 'develop' into implementDoppleganger
nisdas Jul 1, 2021
5f3677e
Increase test size
prestonvanloon Jul 1, 2021
4b74efa
fix timeout, change size back to small
prestonvanloon Jul 1, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion beacon-chain/rpc/validator/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ type Server struct {
Eth1BlockFetcher powchain.POWBlockFetcher
PendingDepositsFetcher depositcache.PendingDepositsFetcher
OperationNotifier opfeed.Notifier
StateGen *stategen.State
StateGen stategen.StateManager
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For my benefit. why this change?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Simply changes it from a struct to an interface, this allows us to mock it correctly for tests. *stategen.State fulfills the state manager interface.

}

// WaitForActivation checks if a validator public key exists in the active validator registry of the current
Expand Down
95 changes: 95 additions & 0 deletions beacon-chain/rpc/validator/status.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,101 @@ func (vs *Server) MultipleValidatorStatus(
}, nil
}

// CheckDoppelGanger checks if the provided keys are currently active in the network.
func (vs *Server) CheckDoppelGanger(ctx context.Context, req *ethpb.DoppelGangerRequest) (*ethpb.DoppelGangerResponse, error) {
if vs.SyncChecker.Syncing() {
return nil, status.Errorf(codes.Unavailable, "Syncing to latest head, not ready to respond")
}
if req == nil || req.ValidatorRequests == nil || len(req.ValidatorRequests) == 0 {
return &ethpb.DoppelGangerResponse{
Responses: []*ethpb.DoppelGangerResponse_ValidatorResponse{},
}, nil
}
headState, err := vs.HeadFetcher.HeadState(ctx)
if err != nil {
return nil, status.Error(codes.Internal, "Could not get head state")
}
// 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.
currEpoch := helpers.SlotToEpoch(headState.Slot())
previousEpoch, err := currEpoch.SafeSub(1)
if err != nil {
previousEpoch = currEpoch
}
prestonvanloon marked this conversation as resolved.
Show resolved Hide resolved
olderEpoch, err := previousEpoch.SafeSub(1)
if err != nil {
olderEpoch = previousEpoch
}
prestonvanloon marked this conversation as resolved.
Show resolved Hide resolved
prevState, err := vs.StateGen.StateBySlot(ctx, params.BeaconConfig().SlotsPerEpoch.Mul(uint64(previousEpoch)))
if err != nil {
return nil, status.Error(codes.Internal, "Could not get previous state")
}
olderState, err := vs.StateGen.StateBySlot(ctx, params.BeaconConfig().SlotsPerEpoch.Mul(uint64(olderEpoch)))
if err != nil {
return nil, status.Error(codes.Internal, "Could not get previous state")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Could not get older state" would be appropriate.

}
resp := &ethpb.DoppelGangerResponse{
Responses: []*ethpb.DoppelGangerResponse_ValidatorResponse{},
}
for _, v := range req.ValidatorRequests {
// If the validator's last recorded epoch was
// less than 2 epoch ago, this method will not
// be able to catch duplicates.
if v.Epoch+2 >= currEpoch {
resp.Responses = append(resp.Responses,
&ethpb.DoppelGangerResponse_ValidatorResponse{
PublicKey: v.PublicKey,
DuplicateExists: false,
})
continue
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this the case? It isn't clear to the reader why a request within the last 2 epochs will be marked as false or safe to proceed without actually checking.

valIndex, ok := olderState.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 {
prestonvanloon marked this conversation as resolved.
Show resolved Hide resolved
resp.Responses = append(resp.Responses,
&ethpb.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 {
resp.Responses = append(resp.Responses,
&ethpb.DoppelGangerResponse_ValidatorResponse{
PublicKey: v.PublicKey,
DuplicateExists: true,
})
continue
}
// Mark the public key as valid.
resp.Responses = append(resp.Responses,
&ethpb.DoppelGangerResponse_ValidatorResponse{
PublicKey: v.PublicKey,
DuplicateExists: false,
})
}
return resp, nil
}

// activationStatus returns the validator status response for the set of validators
// requested by their pub keys.
func (vs *Server) activationStatus(
Expand Down
Loading