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

WaitForActivation optimizations #5396

Merged
merged 25 commits into from
Apr 20, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
ee276b1
WaitForActrivation improvements
0xKiwi Apr 12, 2020
39c6f78
Merge branch 'master' of https://github.com/prysmaticlabs/prysm into …
0xKiwi Apr 12, 2020
573101d
Changes to handle new statuses
0xKiwi Apr 12, 2020
78e89e9
Merge branch 'master' into waitforactivation
rauljordan Apr 12, 2020
6913c78
Fix tests
0xKiwi Apr 12, 2020
6c98c49
Merge branch 'master' of https://github.com/prysmaticlabs/prysm into …
0xKiwi Apr 12, 2020
eecec4e
Merge branch 'waitforactivation' of https://github.com/0xKiwi/Prysm i…
0xKiwi Apr 12, 2020
a41e367
Remove unkown status being set
0xKiwi Apr 12, 2020
85cd97f
Fix test
0xKiwi Apr 14, 2020
c95af82
Merge branch 'master' of https://github.com/prysmaticlabs/prysm into …
0xKiwi Apr 14, 2020
1c3b240
Merge branch 'master' into waitforactivation
rauljordan Apr 14, 2020
2904250
Modify logging slightly
0xKiwi Apr 14, 2020
7ae558d
Merge branch 'waitforactivation' of https://github.com/0xKiwi/Prysm i…
0xKiwi Apr 14, 2020
07931b4
Improve deposit ux
0xKiwi Apr 14, 2020
88f04e0
Merge branch 'master' of https://github.com/prysmaticlabs/prysm into …
0xKiwi Apr 14, 2020
f51df73
Add test for logs
0xKiwi Apr 14, 2020
351049a
Rename
0xKiwi Apr 15, 2020
658ac7f
Merge branch 'master' of https://github.com/prysmaticlabs/prysm into …
0xKiwi Apr 15, 2020
4414752
Merge branch 'master' into waitforactivation
0xKiwi Apr 19, 2020
23f0657
Merge branch 'master' into waitforactivation
0xKiwi Apr 19, 2020
d4f3604
Merge branch 'master' into waitforactivation
rauljordan Apr 20, 2020
bb6409f
Merge branch 'master' into waitforactivation
rauljordan Apr 20, 2020
0fb530e
Merge branch 'master' into waitforactivation
rauljordan Apr 20, 2020
6b674f6
Merge branch 'master' into waitforactivation
rauljordan Apr 20, 2020
4440c3b
Merge branch 'master' into waitforactivation
0xKiwi Apr 20, 2020
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
25 changes: 10 additions & 15 deletions beacon-chain/cache/depositcache/deposits_cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,20 +35,19 @@ type DepositFetcher interface {
// stores all the deposit related data that is required by the beacon-node.
type DepositCache struct {
// Beacon chain deposits in memory.
pendingDeposits []*dbpb.DepositContainer
deposits []*dbpb.DepositContainer
depositsLock sync.RWMutex
chainStartDeposits []*ethpb.Deposit
chainstartPubkeys map[string]bool
chainstartPubkeysLock sync.RWMutex
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Removing because the only calling function already has a lock.

pendingDeposits []*dbpb.DepositContainer
deposits []*dbpb.DepositContainer
depositsLock sync.RWMutex
chainStartDeposits []*ethpb.Deposit
chainStartPubkeys map[string]bool
}

// NewDepositCache instantiates a new deposit cache
func NewDepositCache() *DepositCache {
return &DepositCache{
pendingDeposits: []*dbpb.DepositContainer{},
deposits: []*dbpb.DepositContainer{},
chainstartPubkeys: make(map[string]bool),
chainStartPubkeys: make(map[string]bool),
chainStartDeposits: make([]*ethpb.Deposit, 0),
}
}
Expand Down Expand Up @@ -102,21 +101,17 @@ func (dc *DepositCache) AllDepositContainers(ctx context.Context) []*dbpb.Deposi
func (dc *DepositCache) MarkPubkeyForChainstart(ctx context.Context, pubkey string) {
ctx, span := trace.StartSpan(ctx, "DepositsCache.MarkPubkeyForChainstart")
defer span.End()
dc.chainstartPubkeysLock.Lock()
defer dc.chainstartPubkeysLock.Unlock()
dc.chainstartPubkeys[pubkey] = true
dc.chainStartPubkeys[pubkey] = true
}

// PubkeyInChainstart returns bool for whether the pubkey passed in has deposited.
func (dc *DepositCache) PubkeyInChainstart(ctx context.Context, pubkey string) bool {
ctx, span := trace.StartSpan(ctx, "DepositsCache.PubkeyInChainstart")
defer span.End()
dc.chainstartPubkeysLock.Lock()
defer dc.chainstartPubkeysLock.Unlock()
if dc.chainstartPubkeys != nil {
return dc.chainstartPubkeys[pubkey]
if dc.chainStartPubkeys != nil {
return dc.chainStartPubkeys[pubkey]
}
dc.chainstartPubkeys = make(map[string]bool)
dc.chainStartPubkeys = make(map[string]bool)
return false
}

Expand Down
4 changes: 1 addition & 3 deletions beacon-chain/rpc/validator/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -199,9 +199,7 @@ func TestWaitForActivation_ValidatorOriginallyExists(t *testing.T) {
Statuses: []*ethpb.ValidatorActivationResponse_Status{
{PublicKey: pubKey1,
Status: &ethpb.ValidatorStatusResponse{
Status: ethpb.ValidatorStatus_ACTIVE,
Eth1DepositBlockNumber: 10,
DepositInclusionSlot: 2218,
Status: ethpb.ValidatorStatus_ACTIVE,
},
},
{PublicKey: pubKey2,
Expand Down
72 changes: 33 additions & 39 deletions beacon-chain/rpc/validator/status.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,52 +94,46 @@ func (vs *Server) validatorStatus(ctx context.Context, pubKey []byte, headState
resp.ActivationEpoch = int64(val.ActivationEpoch)
}

// If no connection to ETH1, the deposit block number or position in queue cannot be determined.
if !vs.Eth1InfoFetcher.IsConnectedToETH1() {
log.Warn("Not connected to ETH1. Cannot determine validator ETH1 deposit block number")
return resp
}

_, eth1BlockNumBigInt := vs.DepositFetcher.DepositByPubkey(ctx, pubKey)
if eth1BlockNumBigInt == nil { // No deposit found in ETH1.
return resp
}

if resp.Status == ethpb.ValidatorStatus_UNKNOWN_STATUS {
resp.Status = ethpb.ValidatorStatus_DEPOSITED
}

resp.Eth1DepositBlockNumber = eth1BlockNumBigInt.Uint64()
switch resp.Status {
// Unknown status means the validator has not been put into the state yet.
case ethpb.ValidatorStatus_UNKNOWN_STATUS:
// If no connection to ETH1, the deposit block number or position in queue cannot be determined.
if !vs.Eth1InfoFetcher.IsConnectedToETH1() {
log.Warn("Not connected to ETH1. Cannot determine validator ETH1 deposit block number")
return resp
}

depositBlockSlot, err := vs.depositBlockSlot(ctx, eth1BlockNumBigInt, headState)
if err != nil {
return resp
}
resp.DepositInclusionSlot = int64(depositBlockSlot)
_, eth1BlockNumBigInt := vs.DepositFetcher.DepositByPubkey(ctx, pubKey)
if eth1BlockNumBigInt == nil { // No deposit found in ETH1.
return resp
}

// If validator has been activated at any point, they are not in the queue so we can return
// the request early. Also if the validator has exited,slashed or initiated its exit
// we return the request early too. We only proceed if its status is pending active
// Additionally, if idx is zero (default return value) then we know this
// validator cannot be in the queue either.
if resp.Status != ethpb.ValidatorStatus_PENDING || idx == 0 {
return resp
}
resp.Eth1DepositBlockNumber = eth1BlockNumBigInt.Uint64()

var lastActivatedValidatorIdx uint64
for j := headState.NumValidators() - 1; j >= 0; j-- {
val, err := headState.ValidatorAtIndex(uint64(j))
depositBlockSlot, err := vs.depositBlockSlot(ctx, eth1BlockNumBigInt, headState)
if err != nil {
return resp
}
if helpers.IsActiveValidator(val, helpers.CurrentEpoch(headState)) {
lastActivatedValidatorIdx = uint64(j)
break
resp.DepositInclusionSlot = int64(depositBlockSlot)
// Deposited and Pending mean the validator has been put into the state.
case ethpb.ValidatorStatus_DEPOSITED, ethpb.ValidatorStatus_PENDING:
var lastActivatedValidatorIdx uint64
for j := headState.NumValidators() - 1; j >= 0; j-- {
val, err := headState.ValidatorAtIndex(uint64(j))
if err != nil {
return resp
}
if helpers.IsActiveValidator(val, helpers.CurrentEpoch(headState)) {
lastActivatedValidatorIdx = uint64(j)
break
}
}
}
// Our position in the activation queue is the above index - our validator index.
if lastActivatedValidatorIdx < idx {
resp.PositionInActivationQueue = int64(idx - lastActivatedValidatorIdx)
// Our position in the activation queue is the above index - our validator index.
if lastActivatedValidatorIdx < idx {
resp.PositionInActivationQueue = int64(idx - lastActivatedValidatorIdx)
}
default:
return resp
}

return resp
Expand Down
85 changes: 78 additions & 7 deletions beacon-chain/rpc/validator/status_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import (
"github.com/prysmaticlabs/prysm/shared/trieutil"
)

func TestValidatorStatus_Deposited(t *testing.T) {
func TestValidatorStatus_Unknown(t *testing.T) {
db := dbutil.SetupDB(t)
defer dbutil.TeardownDB(t, db)
ctx := context.Background()
Expand Down Expand Up @@ -68,6 +68,68 @@ func TestValidatorStatus_Deposited(t *testing.T) {
if err != nil {
t.Fatalf("Could not get validator status %v", err)
}
if resp.Status != ethpb.ValidatorStatus_UNKNOWN_STATUS {
t.Errorf("Wanted %v, got %v", ethpb.ValidatorStatus_UNKNOWN_STATUS, resp.Status)
}
if resp.DepositInclusionSlot == 0 {
t.Errorf("Wanted 0, got %d", resp.DepositInclusionSlot)
}
}

func TestValidatorStatus_Deposited(t *testing.T) {
db := dbutil.SetupDB(t)
defer dbutil.TeardownDB(t, db)
ctx := context.Background()

pubKey1 := pubKey(1)
pubKey2 := pubKey(2)
depData := &ethpb.Deposit_Data{
PublicKey: pubKey1,
Signature: []byte("hi"),
WithdrawalCredentials: []byte("hey"),
}
deposit := &ethpb.Deposit{
Data: depData,
}
depositTrie, err := trieutil.NewTrie(int(params.BeaconConfig().DepositContractTreeDepth))
if err != nil {
t.Fatalf("Could not setup deposit trie: %v", err)
}
depositCache := depositcache.NewDepositCache()
depositCache.InsertDeposit(ctx, deposit, 0 /*blockNum*/, 0, depositTrie.Root())
height := time.Unix(int64(params.BeaconConfig().Eth1FollowDistance), 0).Unix()
p := &mockPOW.POWChain{
TimesByHeight: map[int]uint64{
0: uint64(height),
},
}
stateObj, err := stateTrie.InitializeFromProtoUnsafe(&pbp2p.BeaconState{
Validators: []*ethpb.Validator{
{
PublicKey: pubKey2,
ActivationEligibilityEpoch: 1,
},
},
})
if err != nil {
t.Fatal(err)
}
vs := &Server{
BeaconDB: db,
DepositFetcher: depositCache,
BlockFetcher: p,
HeadFetcher: &mockChain.ChainService{
State: stateObj,
},
Eth1InfoFetcher: p,
}
req := &ethpb.ValidatorStatusRequest{
PublicKey: pubKey2,
}
resp, err := vs.ValidatorStatus(context.Background(), req)
if err != nil {
t.Fatalf("Could not get validator status %v", err)
}
if resp.Status != ethpb.ValidatorStatus_DEPOSITED {
t.Errorf("Wanted %v, got %v", ethpb.ValidatorStatus_DEPOSITED, resp.Status)
}
Expand Down Expand Up @@ -226,9 +288,8 @@ func TestValidatorStatus_Active(t *testing.T) {
}

expected := &ethpb.ValidatorStatusResponse{
Status: ethpb.ValidatorStatus_ACTIVE,
ActivationEpoch: 5,
DepositInclusionSlot: 2218,
Status: ethpb.ValidatorStatus_ACTIVE,
ActivationEpoch: 5,
}
if !proto.Equal(resp, expected) {
t.Errorf("Wanted %v, got %v", expected, resp)
Expand Down Expand Up @@ -495,7 +556,7 @@ func TestMultipleValidatorStatus_OK(t *testing.T) {
defer dbutil.TeardownDB(t, db)
ctx := context.Background()

pubKeys := [][]byte{pubKey(1), pubKey(2), pubKey(3)}
pubKeys := [][]byte{pubKey(1), pubKey(2), pubKey(3), pubKey(4)}
stateObj, err := stateTrie.InitializeFromProtoUnsafe(&pbp2p.BeaconState{
Slot: 4000,
Validators: []*ethpb.Validator{
Expand All @@ -509,6 +570,11 @@ func TestMultipleValidatorStatus_OK(t *testing.T) {
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
PublicKey: pubKeys[1],
},
{
ActivationEligibilityEpoch: 700,
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
PublicKey: pubKeys[3],
},
},
})
block := blk.NewGenesisBlock([]byte{})
Expand Down Expand Up @@ -572,10 +638,15 @@ func TestMultipleValidatorStatus_OK(t *testing.T) {
response[1].PublicKey)
}

if response[2].Status.Status != ethpb.ValidatorStatus_DEPOSITED {
t.Errorf("Validator with pubkey %#x is not activated and instead has this status: %s",
if response[2].Status.Status != ethpb.ValidatorStatus_UNKNOWN_STATUS {
t.Errorf("Validator with pubkey %#x is not unknown and instead has this status: %s",
response[2].PublicKey, response[2].Status.Status.String())
}

if response[3].Status.Status != ethpb.ValidatorStatus_DEPOSITED {
t.Errorf("Validator with pubkey %#x was not deposited and has this status: %s",
response[3].PublicKey, response[3].Status.Status.String())
}
}

func TestValidatorStatus_CorrectActivationQueue(t *testing.T) {
Expand Down
29 changes: 15 additions & 14 deletions validator/client/validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -238,23 +238,24 @@ func (v *validator) checkAndLogValidatorStatus(validatorStatuses []*ethpb.Valida
validatorStatusesGaugeVec.WithLabelValues(fmtKey).Set(float64(status.Status.Status))
}
switch status.Status.Status {
case ethpb.ValidatorStatus_UNKNOWN_STATUS, ethpb.ValidatorStatus_DEPOSITED:
if status.Status.DepositInclusionSlot == 0 {
log.Info("Waiting for deposit to be seen")
} else {
log.WithField("expectedInclusionSlot", status.Status.DepositInclusionSlot).Info(
"Deposit for validator received but not processed into state")
}
case ethpb.ValidatorStatus_PENDING:
if uint64(status.Status.ActivationEpoch) == params.BeaconConfig().FarFutureEpoch {
case ethpb.ValidatorStatus_UNKNOWN_STATUS:
if status.Status.DepositInclusionSlot != 0 {
log.WithFields(logrus.Fields{
"positionInActivationQueue": status.Status.PositionInActivationQueue,
}).Info("Waiting to be activated")
"expectedInclusionSlot": status.Status.DepositInclusionSlot,
"eth1DepositBlockNumber": status.Status.Eth1DepositBlockNumber,
}).Info("Waiting for deposit to be processed by the beacon chain")
} else {
log.WithFields(logrus.Fields{
"activationEpoch": status.Status.ActivationEpoch,
}).Info("Waiting to be activated")
log.Info("Waiting for a deposit to be put into an eth1 block")
}
case ethpb.ValidatorStatus_DEPOSITED:
log.WithField(
"positionInActivationQueue", status.Status.PositionInActivationQueue,
).Info("Deposit processed, entering activation queue after finalization")
case ethpb.ValidatorStatus_PENDING:
log.WithFields(logrus.Fields{
"positionInActivationQueue": status.Status.PositionInActivationQueue,
"activationEpoch": status.Status.ActivationEpoch,
}).Info("Waiting to be activated")
case ethpb.ValidatorStatus_ACTIVE:
activatedKeys = append(activatedKeys, status.PublicKey)
case ethpb.ValidatorStatus_EXITED:
Expand Down
Loading