Skip to content

Commit

Permalink
Merge pull request #59 from gobitfly/NOBIDS/slot-viz-update
Browse files Browse the repository at this point in the history
update slot viz struct to new design
  • Loading branch information
Eisei24 authored Mar 5, 2024
2 parents 866d8ea + 456683f commit c68fca8
Show file tree
Hide file tree
Showing 5 changed files with 125 additions and 56 deletions.
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 @@ -315,6 +315,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 @@ -362,22 +364,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 @@ -390,16 +385,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 @@ -413,12 +424,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 @@ -427,19 +450,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)] {
for _, validator := range validatorsArray {
for slot, duty := range dutiesInfo.EpochAttestationDuties[validator] {
epoch := utils.EpochOfSlot(uint64(slot))
epochIdx, ok := epochToIndexMap[epoch]
if !ok {
Expand All @@ -451,14 +486,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 @@ -138,14 +138,11 @@ func (d DummyService) RemoveValidatorDashboardPublicId(dashboardId t.VDBIdPrimar
}

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]
7 changes: 7 additions & 0 deletions frontend/types/api/validator_dashboard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,13 @@ export type InternalGetValidatorDashboardValidatorsResponse = ApiPagingResponse<
* ------------------------------------------------------------
* 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 */;
Expand Down

0 comments on commit c68fca8

Please sign in to comment.