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

update slot viz struct to new design #59

Merged
merged 8 commits into from
Mar 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
116 changes: 84 additions & 32 deletions backend/pkg/api/data_access/data_access.go
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,8 @@ func (d DataAccessService) GetValidatorDashboardSlotViz(dashboardId t.VDBIdPrima
minEpoch := headEpoch - 2
maxEpoch := headEpoch + 1

maxValidatorsInResponse := 6

dutiesInfo, releaseLock, err := services.GetCurrentDutiesInfo()
defer releaseLock() // important to unlock once done, otherwise data updater cant update the data
if err != nil {
Expand Down Expand Up @@ -454,22 +456,15 @@ func (d DataAccessService) GetValidatorDashboardSlotViz(dashboardId t.VDBIdPrima
if proposerIndex, ok := dutiesInfo.PropAssignmentsForSlot[slot]; ok {
// Only add results for validators we care about
if _, ok := validatorsMap[uint32(proposerIndex)]; ok {
slotVizEpochs[epochIdx].Slots[slotIdx].Proposal = &t.VDBSlotVizActiveDuty{}
slotVizEpochs[epochIdx].Slots[slotIdx].Proposal = &t.VDBSlotVizTuple{}

slotVizEpochs[epochIdx].Slots[slotIdx].Proposal.Validator = dutiesInfo.PropAssignmentsForSlot[slot]

status := "scheduled"
dutyObject := slot
if _, ok := dutiesInfo.SlotStatus[slot]; ok {
switch dutiesInfo.SlotStatus[slot] {
case 0, 2:
status = "failed"
case 1, 3:
status = "success"
if dutiesInfo.SlotStatus[slot] == 1 || dutiesInfo.SlotStatus[slot] == 3 {
dutyObject = dutiesInfo.SlotBlock[slot]
}
}
slotVizEpochs[epochIdx].Slots[slotIdx].Proposal.Status = status
slotVizEpochs[epochIdx].Slots[slotIdx].Proposal.DutyObject = dutyObject
}
}
Expand All @@ -482,16 +477,32 @@ func (d DataAccessService) GetValidatorDashboardSlotViz(dashboardId t.VDBIdPrima
continue
}

if slotVizEpochs[epochIdx].Slots[slotIdx].Sync == nil {
slotVizEpochs[epochIdx].Slots[slotIdx].Sync = &t.VDBSlotVizPassiveDuty{}
if slotVizEpochs[epochIdx].Slots[slotIdx].Syncs == nil {
slotVizEpochs[epochIdx].Slots[slotIdx].Syncs = &t.VDBSlotVizStatus[t.VDBSlotVizDuty]{}
}
syncsRef := slotVizEpochs[epochIdx].Slots[slotIdx].Syncs

if slot > dutiesInfo.LatestSlot {
slotVizEpochs[epochIdx].Slots[slotIdx].Sync.PendingCount++
if syncsRef.Scheduled == nil {
syncsRef.Scheduled = &t.VDBSlotVizDuty{}
}
syncsRef.Scheduled.TotalCount++
if len(syncsRef.Scheduled.Validators) < maxValidatorsInResponse {
syncsRef.Scheduled.Validators = append(syncsRef.Scheduled.Validators, validator)
}
} else if _, ok := dutiesInfo.SlotSyncParticipated[slot][validator]; ok {
slotVizEpochs[epochIdx].Slots[slotIdx].Sync.SuccessCount++
if syncsRef.Success == nil {
syncsRef.Success = &t.VDBSlotVizDuty{}
}
syncsRef.Success.TotalCount++
} else {
slotVizEpochs[epochIdx].Slots[slotIdx].Sync.FailedCount++
if syncsRef.Failed == nil {
syncsRef.Failed = &t.VDBSlotVizDuty{}
}
syncsRef.Failed.TotalCount++
if len(syncsRef.Failed.Validators) < maxValidatorsInResponse {
syncsRef.Failed.Validators = append(syncsRef.Failed.Validators, validator)
}
}
}
}
Expand All @@ -505,12 +516,24 @@ func (d DataAccessService) GetValidatorDashboardSlotViz(dashboardId t.VDBIdPrima
if _, ok := validatorsMap[uint32(proposerIndex)]; ok {
// One of the dashboard validators slashed
for _, validator := range slashedValidators {
slotVizEpochs[epochIdx].Slots[slotIdx].Slashing = append(slotVizEpochs[epochIdx].Slots[slotIdx].Slashing,
t.VDBSlotVizActiveDuty{
Status: "success",
Validator: dutiesInfo.PropAssignmentsForSlot[slot], // Dashboard validator
DutyObject: validator, // Validator that got slashed
})
if slotVizEpochs[epochIdx].Slots[slotIdx].Slashings == nil {
slotVizEpochs[epochIdx].Slots[slotIdx].Slashings = &t.VDBSlotVizStatus[t.VDBSlotVizSlashing]{}
}
slashingsRef := slotVizEpochs[epochIdx].Slots[slotIdx].Slashings

if slashingsRef.Success == nil {
slashingsRef.Success = &t.VDBSlotVizSlashing{}
}

slashingsRef.Success.TotalCount++

if len(slashingsRef.Success.Slashings) < maxValidatorsInResponse {
slashing := t.VDBSlotVizTuple{
Validator: dutiesInfo.PropAssignmentsForSlot[slot], // Slashing validator
DutyObject: validator, // Slashed validator
}
slashingsRef.Success.Slashings = append(slashingsRef.Success.Slashings, slashing)
}
}
}
}
Expand All @@ -519,19 +542,31 @@ func (d DataAccessService) GetValidatorDashboardSlotViz(dashboardId t.VDBIdPrima
continue
}
// One of the dashboard validators got slashed
slotVizEpochs[epochIdx].Slots[slotIdx].Slashing = append(slotVizEpochs[epochIdx].Slots[slotIdx].Slashing,
t.VDBSlotVizActiveDuty{
Status: "failed",
Validator: validator, // Dashboard validator
DutyObject: validator, // Validator that got slashed
})
if slotVizEpochs[epochIdx].Slots[slotIdx].Slashings == nil {
slotVizEpochs[epochIdx].Slots[slotIdx].Slashings = &t.VDBSlotVizStatus[t.VDBSlotVizSlashing]{}
}
slashingsRef := slotVizEpochs[epochIdx].Slots[slotIdx].Slashings

if slashingsRef.Failed == nil {
slashingsRef.Failed = &t.VDBSlotVizSlashing{}
}

slashingsRef.Failed.TotalCount++

if len(slashingsRef.Failed.Slashings) < maxValidatorsInResponse {
slashing := t.VDBSlotVizTuple{
Validator: dutiesInfo.PropAssignmentsForSlot[slot], // Slashing validator
DutyObject: validator, // Slashed validator
}
slashingsRef.Failed.Slashings = append(slashingsRef.Failed.Slashings, slashing)
}
}
}
}

// Hydrate the attestation data
for validator := range validatorsArray {
for slot, duty := range dutiesInfo.EpochAttestationDuties[uint32(validator)] {
Comment on lines -533 to -534
Copy link
Contributor

Choose a reason for hiding this comment

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

I assume this here was a bug before my changes.

Copy link
Contributor

Choose a reason for hiding this comment

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

good catch!

for _, validator := range validatorsArray {
for slot, duty := range dutiesInfo.EpochAttestationDuties[validator] {
epoch := utils.EpochOfSlot(uint64(slot))
epochIdx, ok := epochToIndexMap[epoch]
if !ok {
Expand All @@ -543,14 +578,31 @@ func (d DataAccessService) GetValidatorDashboardSlotViz(dashboardId t.VDBIdPrima
}

if slotVizEpochs[epochIdx].Slots[slotIdx].Attestations == nil {
slotVizEpochs[epochIdx].Slots[slotIdx].Attestations = &t.VDBSlotVizPassiveDuty{}
slotVizEpochs[epochIdx].Slots[slotIdx].Attestations = &t.VDBSlotVizStatus[t.VDBSlotVizDuty]{}
}
attestationsRef := slotVizEpochs[epochIdx].Slots[slotIdx].Attestations

if uint64(slot) >= dutiesInfo.LatestSlot {
slotVizEpochs[epochIdx].Slots[slotIdx].Attestations.PendingCount++
if attestationsRef.Scheduled == nil {
attestationsRef.Scheduled = &t.VDBSlotVizDuty{}
}
attestationsRef.Scheduled.TotalCount++
if len(attestationsRef.Scheduled.Validators) < maxValidatorsInResponse {
attestationsRef.Scheduled.Validators = append(attestationsRef.Scheduled.Validators, uint64(validator))
}
} else if duty {
slotVizEpochs[epochIdx].Slots[slotIdx].Attestations.SuccessCount++
if attestationsRef.Success == nil {
attestationsRef.Success = &t.VDBSlotVizDuty{}
}
attestationsRef.Success.TotalCount++
} else {
slotVizEpochs[epochIdx].Slots[slotIdx].Attestations.FailedCount++
if attestationsRef.Failed == nil {
attestationsRef.Failed = &t.VDBSlotVizDuty{}
}
attestationsRef.Failed.TotalCount++
if len(attestationsRef.Failed.Validators) < maxValidatorsInResponse {
attestationsRef.Failed.Validators = append(attestationsRef.Failed.Validators, uint64(validator))
}
}
}
}
Expand Down
13 changes: 5 additions & 8 deletions backend/pkg/api/data_access/dummy.go
Original file line number Diff line number Diff line change
Expand Up @@ -158,14 +158,11 @@ func (d DummyService) RemoveValidatorDashboardPublicIdByPublicId(dashboardId t.V
}

func (d DummyService) GetValidatorDashboardSlotViz(dashboardId t.VDBIdPrimary) ([]t.SlotVizEpoch, error) {
r := []t.SlotVizEpoch{}
var err error
for i := 0; i < 4; i++ {
epoch := t.SlotVizEpoch{}
err = commonFakeData(&epoch)
r = append(r, epoch)
}
return r, err
r := struct {
Epochs []t.SlotVizEpoch `faker:"slice_len=4"`
}{}
err := commonFakeData(&r)
return r.Epochs, err
}

func (d DummyService) GetValidatorDashboardSlotVizByPublicId(dashboardId t.VDBIdPublic) ([]t.SlotVizEpoch, error) {
Expand Down
6 changes: 5 additions & 1 deletion backend/pkg/api/services/service_slot_viz.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,11 @@ func updateSlotVizData() error {

encodedRedisCachedEpochAssignments, err := db.PersistentRedisDbClient.Get(ctx, key).Result()
if err != nil {
return errors.Wrap(err, "error getting epoch assignments data")
if epoch == headEpoch+1 {
log.Infof("headEpoch + 1 assignments not yet available, epoch %d", epoch)
return nil
}
return errors.Wrap(err, fmt.Sprintf("error getting epoch assignments data for epoch %d", epoch))
}

var serializedAssignmentsData bytes.Buffer
Expand Down
39 changes: 24 additions & 15 deletions backend/pkg/api/types/slot_viz.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,12 @@ package types

// ------------------------------------------------------------
// Slot Viz
type VDBSlotVizPassiveDuty struct {
PendingCount uint64 `json:"pending_count"`
SuccessCount uint64 `json:"success_count"`
FailedCount uint64 `json:"failed_count"`
type VDBSlotVizDuty struct {
TotalCount uint64 `json:"total_count"`
Validators []uint64 `json:"validators" faker:"slice_len=6"` // up to 6 validators that performed the duty, only for scheduled and failed
}

type VDBSlotVizActiveDuty struct {
Status string `json:"status" tstype:"'success' | 'failed' | 'scheduled'" faker:"oneof: success, failed, scheduled"`
type VDBSlotVizTuple struct {
Validator uint64 `json:"validator"`
// If the duty is a proposal & it's successful, the duty_object is the proposed block
// If the duty is a proposal & it failed/scheduled, the duty_object is the slot
Expand All @@ -18,19 +16,30 @@ type VDBSlotVizActiveDuty struct {
DutyObject uint64 `json:"duty_object"`
}

type VDBSlotVizSlashing struct {
TotalCount uint64 `json:"total_count"`
Slashings []VDBSlotVizTuple `json:"slashings" faker:"slice_len=6"` // up to 6 slashings, validator is always the slashing validator
}

type VDBSlotVizStatus[T any] struct {
Success *T `json:"success,omitempty"`
Failed *T `json:"failed,omitempty"`
Scheduled *T `json:"scheduled,omitempty"`
}

type VDBSlotVizSlot struct {
Slot uint64 `json:"slot"`
Status string `json:"status" tstype:"'proposed' | 'missed' | 'scheduled' | 'orphaned'" faker:"oneof: proposed, missed, scheduled, orphaned"`
Attestations *VDBSlotVizPassiveDuty `json:"attestations,omitempty"`
Sync *VDBSlotVizPassiveDuty `json:"sync,omitempty"`
Proposal *VDBSlotVizActiveDuty `json:"proposal,omitempty"`
Slashing []VDBSlotVizActiveDuty `json:"slashing,omitempty"`
Slot uint64 `json:"slot"`
Status string `json:"status" tstype:"'proposed' | 'missed' | 'scheduled' | 'orphaned'" faker:"oneof: proposed, missed, scheduled, orphaned"`
Proposal *VDBSlotVizTuple `json:"proposal,omitempty"`
Attestations *VDBSlotVizStatus[VDBSlotVizDuty] `json:"attestations,omitempty"`
Syncs *VDBSlotVizStatus[VDBSlotVizDuty] `json:"sync,omitempty"`
Slashings *VDBSlotVizStatus[VDBSlotVizSlashing] `json:"slashing,omitempty"`
}
type SlotVizEpoch struct {
Epoch uint64 `json:"epoch"`
State string `json:"state,omitempty" tstype:"'scheduled' | 'head' | 'justifying' | 'justified' | 'finalized'" faker:"oneof: scheduled, head, justifying, justified, finalized"`
Progress float64 `json:"progress,omitempty"` // only on landing page
Slots []VDBSlotVizSlot `json:"slots,omitempty" faker:"slice_len=32"` // only on dashboard page
State string `json:"state,omitempty" tstype:"'scheduled' | 'head' | 'justifying' | 'justified' | 'finalized'" faker:"oneof: scheduled, head, justifying, justified, finalized"` // only on landing page
Progress float64 `json:"progress,omitempty"` // only on landing page
Slots []VDBSlotVizSlot `json:"slots,omitempty" faker:"slice_len=32"` // only on dashboard page
}

type InternalGetValidatorDashboardSlotVizResponse ApiDataResponse[[]SlotVizEpoch]
2 changes: 1 addition & 1 deletion frontend/types/api/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export interface StatusCount {
success: number /* uint64 */;
failed: number /* uint64 */;
}
export type ClElUnion =
export type ClElUnion =
number /* float64 */ | string /* decimal.Decimal */;
export interface ClElValue<T extends ClElUnion> {
el: T;
Expand Down
35 changes: 18 additions & 17 deletions frontend/types/api/slot_viz.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,33 +9,34 @@ import type { ApiDataResponse } from './common'
* ------------------------------------------------------------
* Slot Viz
*/
export interface VDBSlotVizPassiveDuty {
pending_count: number /* uint64 */;
success_count: number /* uint64 */;
failed_count: number /* uint64 */;
export interface VDBSlotVizDuty {
total_count: number /* uint64 */;
validators: number /* uint64 */[]; // up to 6 validators that performed the duty, only for scheduled and failed
}
export interface VDBSlotVizActiveDuty {
status: 'success' | 'failed' | 'scheduled';
export interface VDBSlotVizTuple {
validator: number /* uint64 */;
/**
* If the duty is a proposal & it's successful, the duty_object is the proposed block
* If the duty is a proposal & it failed/scheduled, the duty_object is the slot
* If the duty is a slashing & it's successful, the duty_object is the validator you slashed
* If the duty is a slashing & it failed, the duty_object is your validator that was slashed
*/
duty_object: number /* uint64 */;
}
export interface VDBSlotVizSlashing {
total_count: number /* uint64 */;
slashings: VDBSlotVizTuple[]; // up to 6 slashings, validator is always the slashing validator
}
export interface VDBSlotVizStatus<T extends any> {
success?: T;
failed?: T;
scheduled?: T;
}
export interface VDBSlotVizSlot {
slot: number /* uint64 */;
status: 'proposed' | 'missed' | 'scheduled' | 'orphaned';
attestations?: VDBSlotVizPassiveDuty;
sync?: VDBSlotVizPassiveDuty;
proposal?: VDBSlotVizActiveDuty;
slashing?: VDBSlotVizActiveDuty[];
proposal?: VDBSlotVizTuple;
attestations?: VDBSlotVizStatus<VDBSlotVizDuty>;
sync?: VDBSlotVizStatus<VDBSlotVizDuty>;
slashing?: VDBSlotVizStatus<VDBSlotVizSlashing>;
}
export interface SlotVizEpoch {
epoch: number /* uint64 */;
state?: 'scheduled' | 'head' | 'justifying' | 'justified' | 'finalized' ; // only on landing page
state?: 'scheduled' | 'head' | 'justifying' | 'justified' | 'finalized'; // only on landing page
progress?: number /* float64 */; // only on landing page
slots?: VDBSlotVizSlot[]; // only on dashboard page
}
Expand Down
20 changes: 19 additions & 1 deletion frontend/types/api/validator_dashboard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -223,12 +223,30 @@ export interface VDBManageValidatorsTableRow {
export type InternalGetValidatorDashboardValidatorsResponse = ApiPagingResponse<VDBManageValidatorsTableRow>;
/**
* ------------------------------------------------------------
* Misc. Responses
* Misc.
*/
export type VDBIdPrimary = number /* int */;
export type VDBIdPublic = string;
export type VDBIdValidatorSet = VDBValidator[];
export interface VDBValidator {
index: number /* uint64 */;
version: number /* uint64 */;
}
export interface VDBPostReturnData {
id: number /* uint64 */;
user_id: number /* uint64 */;
name: string;
network: number /* uint64 */;
created_at: string /* time.Time */;
}
export interface VDBPostValidatorsData {
public_key: string;
group_id: number /* uint64 */;
}
export interface VDBPostPublicIdData {
public_id: string;
name: string;
share_settings: {
group_names: boolean;
};
}
Loading