Skip to content

Commit

Permalink
add exit reason to validator details page
Browse files Browse the repository at this point in the history
  • Loading branch information
pk910 committed Dec 3, 2024
1 parent 6ae1da9 commit ab75463
Show file tree
Hide file tree
Showing 4 changed files with 153 additions and 28 deletions.
83 changes: 82 additions & 1 deletion handlers/validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ func buildValidatorPageData(validatorIndex uint64, tabView string) (*models.Vali
pageData.ExitEpoch = uint64(validator.Validator.ExitEpoch)
pageData.ExitTs = chainState.EpochToTime(validator.Validator.ExitEpoch)
}
if validator.Validator.WithdrawalCredentials[0] == 0x01 {
if validator.Validator.WithdrawalCredentials[0] == 0x01 || validator.Validator.WithdrawalCredentials[0] == 0x02 {
pageData.ShowWithdrawAddress = true
pageData.WithdrawAddress = validator.Validator.WithdrawalCredentials[12:]
}
Expand Down Expand Up @@ -583,5 +583,86 @@ func buildValidatorPageData(validatorIndex uint64, tabView string) (*models.Vali
pageData.ConsolidationRequestCount = uint64(len(pageData.ConsolidationRequests))
}

// Check for exit reason if validator is exiting or has exited
if pageData.ShowExit {
zeroAmount := uint64(0)
exitSlot := uint64(chainState.EpochToSlot(validator.Validator.ExitEpoch))

// Check for slashing
if slashings, totalSlashings := services.GlobalBeaconService.GetSlashingsByFilter(&dbtypes.SlashingFilter{
MinIndex: validatorIndex,
MaxIndex: validatorIndex,
}, 0, 1); totalSlashings > 0 && len(slashings) > 0 {
pageData.ExitReason = "Validator was slashed"
pageData.ExitReasonSlashing = true
pageData.ExitReasonSlot = slashings[0].SlotNumber
pageData.ExitReasonSlashingReason = uint64(slashings[0].Reason)

// Check for voluntary exit
} else if exits, totalExits := services.GlobalBeaconService.GetVoluntaryExitsByFilter(&dbtypes.VoluntaryExitFilter{
MinIndex: validatorIndex,
MaxIndex: validatorIndex,
}, 0, 1); totalExits > 0 && len(exits) > 0 {
pageData.ExitReason = "Validator submitted a voluntary exit request"
pageData.ExitReasonVoluntaryExit = true
pageData.ExitReasonSlot = exits[0].SlotNumber

// Check for full withdrawal request
} else if withdrawals, totalWithdrawals := services.GlobalBeaconService.GetWithdrawalRequestsByFilter(&services.CombinedWithdrawalRequestFilter{
Filter: &dbtypes.WithdrawalRequestFilter{
PublicKey: validator.Validator.PublicKey[:],
SourceAddress: pageData.WithdrawAddress,
MaxAmount: &zeroAmount,
MaxSlot: exitSlot,
},
}, 0, 1); totalWithdrawals > 0 && len(withdrawals) > 0 && pageData.ShowWithdrawAddress {
withdrawal := withdrawals[0]
pageData.ExitReason = "Validator submitted a full withdrawal request"
pageData.ExitReasonWithdrawal = true
pageData.ExitReasonSlot = withdrawal.Request.SlotNumber

if withdrawal.Transaction != nil {
pageData.ExitReasonTxHash = withdrawal.Transaction.TxHash
pageData.ExitReasonTxDetails = &models.ValidatorPageDataWithdrawalTxDetails{
BlockNumber: withdrawal.Transaction.BlockNumber,
BlockHash: fmt.Sprintf("%#x", withdrawal.Transaction.BlockRoot),
BlockTime: withdrawal.Transaction.BlockTime,
TxOrigin: common.Address(withdrawal.Transaction.TxSender).Hex(),
TxTarget: common.Address(withdrawal.Transaction.TxTarget).Hex(),
TxHash: fmt.Sprintf("%#x", withdrawal.Transaction.TxHash),
}
}
// Check for consolidation request
} else if consolidations, totalConsolidations := services.GlobalBeaconService.GetConsolidationRequestsByFilter(&services.CombinedConsolidationRequestFilter{
Filter: &dbtypes.ConsolidationRequestFilter{
PublicKey: validator.Validator.PublicKey[:],
SourceAddress: pageData.WithdrawAddress,
MaxSlot: exitSlot,
},
}, 0, 1); totalConsolidations > 0 && len(consolidations) > 0 && pageData.ShowWithdrawAddress {
consolidation := consolidations[0]
pageData.ExitReason = "Validator was consolidated"
pageData.ExitReasonConsolidation = true
pageData.ExitReasonSlot = consolidation.Request.SlotNumber

if targetIndex := consolidation.TargetIndex(); targetIndex != nil {
pageData.ExitReasonTargetIndex = *targetIndex
pageData.ExitReasonTargetName = services.GlobalBeaconService.GetValidatorName(*targetIndex)
}

if consolidation.Transaction != nil {
pageData.ExitReasonTxHash = consolidation.Transaction.TxHash
pageData.ExitReasonTxDetails = &models.ValidatorPageDataWithdrawalTxDetails{
BlockNumber: consolidation.Transaction.BlockNumber,
BlockHash: fmt.Sprintf("%#x", consolidation.Transaction.BlockRoot),
BlockTime: consolidation.Transaction.BlockTime,
TxOrigin: common.Address(consolidation.Transaction.TxSender).Hex(),
TxTarget: common.Address(consolidation.Transaction.TxTarget).Hex(),
TxHash: fmt.Sprintf("%#x", consolidation.Transaction.TxHash),
}
}
}
}

return pageData, 10 * time.Minute
}
6 changes: 3 additions & 3 deletions templates/validator/recentDeposits.html
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,10 @@
<div>
<i class="fa fa-copy text-muted ml-2 p-1" role="button" data-bs-toggle="tooltip" title="Copy to clipboard" data-clipboard-text="0x{{ printf "%x" $deposit.TxHash }}"></i>
</div>
<div>
<i class="fa fa-info-circle text-muted ml-2 p-1 nojs-hide tx-details-btn" role="button" data-txdetails="{{ includeJSON $deposit.TxDetails true }}"></i>
</div>
<div>
<i class="fa fa-info-circle text-muted ml-2 p-1 nojs-hide tx-details-btn" role="button" data-txdetails="{{ includeJSON $deposit.TxDetails true }}"></i>
</div>
</div>
{{- else }}
<span data-bs-toggle="tooltip" data-bs-placement="top" data-bs-title="Corresponding consolidation transaction has not been indexed yet.">?</span>
{{- end }}
Expand Down
33 changes: 33 additions & 0 deletions templates/validator/validator.html
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,39 @@ <h1 class="h4 mb-1 mb-md-0"><i class="fas fa-table mx-2"></i> Validator {{ forma
</div>
</div>
{{ end }}
{{ if .ExitReason }}
<div class="row border-bottom p-2 mx-0">
<div class="col-md-2"><span data-bs-toggle="tooltip" data-bs-placement="top" title="Reason why this validator is exiting or has exited">Exit Reason:</span></div>
<div class="col-md-10">
{{ if .ExitReasonSlashing }}
Validator was slashed in <a href="/slot/{{ .ExitReasonSlot }}">slot {{ .ExitReasonSlot }}</a>
({{ if eq .ExitReasonSlashingReason 1 }}Proposer Slashing{{ else if eq .ExitReasonSlashingReason 2 }}Attester Slashing{{ else }}Unknown Slashing{{ end }})
{{ else if .ExitReasonVoluntaryExit }}
Validator submitted a voluntary exit request in <a href="/slot/{{ .ExitReasonSlot }}">slot {{ .ExitReasonSlot }}</a>
{{ else if .ExitReasonWithdrawal }}
Validator submitted a full withdrawal request in <a href="/slot/{{ .ExitReasonSlot }}">slot {{ .ExitReasonSlot }}</a>
{{ if .ExitReasonTxDetails }}
<br/>
<small class="text-muted">
Transaction: {{ ethTransactionLink .ExitReasonTxHash 0 }}
<i class="fa fa-info-circle text-muted ml-2 p-1 nojs-hide tx-details-btn" role="button" data-txdetails="{{ includeJSON .ExitReasonTxDetails true }}"></i>
</small>
{{ end }}
{{ else if .ExitReasonConsolidation }}
Validator was consolidated into validator {{ formatValidatorWithIndex .ExitReasonTargetIndex .ExitReasonTargetName }} (Requested in <a href="/slot/{{ .ExitReasonSlot }}">slot {{ .ExitReasonSlot }}</a>)
{{ if .ExitReasonTxDetails }}
<br/>
<small class="text-muted">
Transaction: {{ ethTransactionLink .ExitReasonTxHash 0 }}
<i class="fa fa-info-circle text-muted ml-2 p-1 nojs-hide tx-details-btn" role="button" data-txdetails="{{ includeJSON .ExitReasonTxDetails true }}"></i>
</small>
{{ end }}
{{ else }}
{{ .ExitReason }}
{{ end }}
</div>
</div>
{{ end }}

</div>
</div>
Expand Down
59 changes: 35 additions & 24 deletions types/models/validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,30 +6,41 @@ import (

// ValidatorPageData is a struct to hold info for the validator page
type ValidatorPageData struct {
CurrentEpoch uint64 `json:"current_epoch"`
Index uint64 `json:"index"`
Name string `json:"name"`
PublicKey []byte `json:"pubkey"`
Balance uint64 `json:"balance"`
EffectiveBalance uint64 `json:"eff_balance"`
State string `json:"state"`
BeaconState string `json:"beacon_state"`
ShowEligible bool `json:"show_eligible"`
EligibleTs time.Time `json:"eligible_ts"`
EligibleEpoch uint64 `json:"eligible_epoch"`
ShowActivation bool `json:"show_activation"`
ActivationTs time.Time `json:"activation_ts"`
ActivationEpoch uint64 `json:"activation_epoch"`
IsActive bool `json:"is_active"`
WasActive bool `json:"was_active"`
UpcheckActivity uint8 `json:"upcheck_act"`
UpcheckMaximum uint8 `json:"upcheck_max"`
ShowExit bool `json:"show_exit"`
ExitTs time.Time `json:"exit_ts"`
ExitEpoch uint64 `json:"exit_epoch"`
WithdrawCredentials []byte `json:"withdraw_credentials"`
ShowWithdrawAddress bool `json:"show_withdraw_address"`
WithdrawAddress []byte `json:"withdraw_address"`
CurrentEpoch uint64 `json:"current_epoch"`
Index uint64 `json:"index"`
Name string `json:"name"`
PublicKey []byte `json:"pubkey"`
Balance uint64 `json:"balance"`
EffectiveBalance uint64 `json:"eff_balance"`
State string `json:"state"`
BeaconState string `json:"beacon_state"`
ShowEligible bool `json:"show_eligible"`
EligibleTs time.Time `json:"eligible_ts"`
EligibleEpoch uint64 `json:"eligible_epoch"`
ShowActivation bool `json:"show_activation"`
ActivationTs time.Time `json:"activation_ts"`
ActivationEpoch uint64 `json:"activation_epoch"`
IsActive bool `json:"is_active"`
WasActive bool `json:"was_active"`
UpcheckActivity uint8 `json:"upcheck_act"`
UpcheckMaximum uint8 `json:"upcheck_max"`
ShowExit bool `json:"show_exit"`
ExitTs time.Time `json:"exit_ts"`
ExitEpoch uint64 `json:"exit_epoch"`
WithdrawCredentials []byte `json:"withdraw_credentials"`
ShowWithdrawAddress bool `json:"show_withdraw_address"`
WithdrawAddress []byte `json:"withdraw_address"`
ExitReason string `json:"exit_reason"`
ExitReasonSlot uint64 `json:"exit_reason_slot"`
ExitReasonSlashing bool `json:"exit_reason_slashing"`
ExitReasonSlashingReason uint64 `json:"exit_reason_slashing_reason"`
ExitReasonVoluntaryExit bool `json:"exit_reason_voluntary_exit"`
ExitReasonWithdrawal bool `json:"exit_reason_withdrawal"`
ExitReasonConsolidation bool `json:"exit_reason_consolidation"`
ExitReasonTargetIndex uint64 `json:"exit_reason_target_index"`
ExitReasonTargetName string `json:"exit_reason_target_name"`
ExitReasonTxHash []byte `json:"exit_reason_tx_hash"`
ExitReasonTxDetails *ValidatorPageDataWithdrawalTxDetails `json:"exit_reason_tx_details"`

TabView string `json:"tab_view"`
ElectraIsActive bool `json:"electra_is_active"`
Expand Down

0 comments on commit ab75463

Please sign in to comment.