Skip to content

Commit

Permalink
Merge pull request #50 from gobitfly/BIDS-3000/Dashboard_SlotViz_Backend
Browse files Browse the repository at this point in the history
Bids 3000/dashboard slot viz backend
  • Loading branch information
Eisei24 authored Feb 29, 2024
2 parents 3fbce17 + 62c1f64 commit c1adac8
Show file tree
Hide file tree
Showing 3 changed files with 105 additions and 32 deletions.
2 changes: 1 addition & 1 deletion backend/cmd/api/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import (
// TODO load these from config
const (
host = "0.0.0.0"
port = "8081"
port = "8080"
dummyApi = false
)

Expand Down
133 changes: 103 additions & 30 deletions backend/pkg/api/data_access/data_access.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"github.com/gobitfly/beaconchain/pkg/commons/types"
"github.com/gobitfly/beaconchain/pkg/commons/utils"
"github.com/jmoiron/sqlx"
"github.com/lib/pq"
"golang.org/x/sync/errgroup"
)

Expand Down Expand Up @@ -224,13 +225,19 @@ func (d DataAccessService) RemoveValidatorDashboardPublicId(dashboardId uint64,
return d.dummy.RemoveValidatorDashboardPublicId(dashboardId, publicDashboardId)
}

var getValidatorDashboardSlotVizMux = &sync.Mutex{}

func (d DataAccessService) GetValidatorDashboardSlotViz(dashboardId uint64) ([]t.SlotVizEpoch, error) {
log.Infof("retrieving data for dashboard with id %d", dashboardId)
// make sure that the function is only executed once during development not to go oom
getValidatorDashboardSlotVizMux.Lock()
defer getValidatorDashboardSlotVizMux.Unlock()
// TODO: Get the validators from the dashboardId

dummyValidators := []uint64{900000, 900001, 900002, 900003, 900004, 900005, 900006, 900007, 900008, 1053541}
ValidatorsMap := make(map[uint64]bool)
dummyValidators := []uint64{900005, 900006, 900007, 900008, 900009}
validatorsMap := make(map[uint64]bool)
for _, v := range dummyValidators {
ValidatorsMap[v] = true
validatorsMap[v] = true
}

// Get min/max slot/epoch
Expand All @@ -240,16 +247,14 @@ func (d DataAccessService) GetValidatorDashboardSlotViz(dashboardId uint64) ([]t
minEpoch := headEpoch - 2
maxEpoch := headEpoch + 1

minSlot := minEpoch * slotsPerEpoch

// create waiting group for concurrency
gOuter := &errgroup.Group{}

// Get the fulfilled duties
var validatorDuties []types.ValidatorDutyInfo
var validatorDutiesInfo []types.ValidatorDutyInfo
gOuter.Go(func() error {
var err error
validatorDuties, err = db.GetValidatorDuties(d.readerDb, minSlot)
validatorDutiesInfo, err = db.GetValidatorDutiesInfo(d.readerDb, minEpoch*slotsPerEpoch)
return err
})

Expand Down Expand Up @@ -292,7 +297,7 @@ func (d DataAccessService) GetValidatorDashboardSlotViz(dashboardId uint64) ([]t
// Proposals
for slot, propValidator := range decodedRedisCachedEpochAssignments.Assignments.ProposerAssignments {
// Only add results for validators we care about
if _, isValid := ValidatorsMap[propValidator]; isValid {
if _, isValid := validatorsMap[propValidator]; isValid {
muxPropAssignmentsForSlot.Lock()
propAssignmentsForSlot[slot] = propValidator
muxPropAssignmentsForSlot.Unlock()
Expand All @@ -312,7 +317,7 @@ func (d DataAccessService) GetValidatorDashboardSlotViz(dashboardId uint64) ([]t
attAssignmentsForSlot[slot] = make(map[uint64]bool, 0)
}
// Only add results for validators we care about
if _, isValid := ValidatorsMap[attValidator]; isValid {
if _, isValid := validatorsMap[attValidator]; isValid {
attAssignmentsForSlot[slot][attValidator] = true
}
muxAttAssignmentsForSlot.Unlock()
Expand All @@ -328,7 +333,7 @@ func (d DataAccessService) GetValidatorDashboardSlotViz(dashboardId uint64) ([]t
}
for _, validator := range decodedRedisCachedEpochAssignments.Assignments.SyncAssignments {
// Only add results for validators we care about
if _, isValid := ValidatorsMap[validator]; isValid {
if _, isValid := validatorsMap[validator]; isValid {
syncAssignmentsForEpoch[epoch][validator] = true
}
}
Expand All @@ -344,13 +349,15 @@ func (d DataAccessService) GetValidatorDashboardSlotViz(dashboardId uint64) ([]t
return nil, err
}

// Restructure proposal status, attestations and sync duties
// Restructure proposal status, attestations, sync duties and slashings
latestSlot := uint64(0)
slotStatus := make(map[uint64]uint64)
slotBlock := make(map[uint64]uint64)
slotAttested := make(map[uint64]map[uint64]bool)
slotSyncParticipated := make(map[uint64]map[uint64]bool)
for _, duty := range validatorDuties {
slotValiPropSlashed := make(map[uint64]bool)
slotValiAttSlashed := make(map[uint64]bool)
for _, duty := range validatorDutiesInfo {
if duty.Slot > latestSlot {
latestSlot = duty.Slot
}
Expand All @@ -376,6 +383,13 @@ func (d DataAccessService) GetValidatorDashboardSlotViz(dashboardId uint64) ([]t
slotSyncParticipated[duty.Slot][validator] = true
}
}
// Slashings
if duty.ProposerSlashingsCount > 0 {
slotValiPropSlashed[duty.Slot] = true
}
if duty.AttesterSlashingsCount > 0 {
slotValiAttSlashed[duty.Slot] = true
}
}
}

Expand Down Expand Up @@ -429,32 +443,91 @@ func (d DataAccessService) GetValidatorDashboardSlotViz(dashboardId uint64) ([]t
}

// Get the attestation summary for the slot
slotVizEpochs[epochIdx].Slots[slotIdx].Attestations = &t.VDBSlotVizPassiveDuty{}
for validator := range attAssignmentsForSlot[slot] {
if slot >= latestSlot {
// If the latest slot is the one that must be attested we still show it as pending
// as the attestation cannot yet have been included in a block
slotVizEpochs[epochIdx].Slots[slotIdx].Attestations.PendingCount++
} else if _, ok := slotAttested[slot][validator]; ok {
slotVizEpochs[epochIdx].Slots[slotIdx].Attestations.SuccessCount++
} else {
slotVizEpochs[epochIdx].Slots[slotIdx].Attestations.FailedCount++
if len(attAssignmentsForSlot[slot]) > 0 {
slotVizEpochs[epochIdx].Slots[slotIdx].Attestations = &t.VDBSlotVizPassiveDuty{}
for validator := range attAssignmentsForSlot[slot] {
if slot >= latestSlot {
// If the latest slot is the one that must be attested we still show it as pending
// as the attestation cannot yet have been included in a block
slotVizEpochs[epochIdx].Slots[slotIdx].Attestations.PendingCount++
} else if _, ok := slotAttested[slot][validator]; ok {
slotVizEpochs[epochIdx].Slots[slotIdx].Attestations.SuccessCount++
} else {
slotVizEpochs[epochIdx].Slots[slotIdx].Attestations.FailedCount++
}
}
}

// Get the sync summary for the slot
for validator := range syncAssignmentsForEpoch[epoch] {
if len(syncAssignmentsForEpoch[epoch]) > 0 {
slotVizEpochs[epochIdx].Slots[slotIdx].Sync = &t.VDBSlotVizPassiveDuty{}
if slot > latestSlot {
slotVizEpochs[epochIdx].Slots[slotIdx].Sync.PendingCount++
} else if _, ok := slotSyncParticipated[slot][validator]; ok {
slotVizEpochs[epochIdx].Slots[slotIdx].Sync.SuccessCount++
} else {
slotVizEpochs[epochIdx].Slots[slotIdx].Sync.FailedCount++
for validator := range syncAssignmentsForEpoch[epoch] {
if slot > latestSlot {
slotVizEpochs[epochIdx].Slots[slotIdx].Sync.PendingCount++
} else if _, ok := slotSyncParticipated[slot][validator]; ok {
slotVizEpochs[epochIdx].Slots[slotIdx].Sync.SuccessCount++
} else {
slotVizEpochs[epochIdx].Slots[slotIdx].Sync.FailedCount++
}
}
}

// TODO: Get the slashings for the slot
// Get the slashings for the slot
slashedValidators := []uint64{}
if _, ok := slotValiPropSlashed[slot]; ok {
slashedPropValidators := []uint64{}
err := d.readerDb.Select(&slashedPropValidators, `
SELECT
proposerindex
FROM blocks_proposerslashings
WHERE block_slot = $1`, slot)
if err != nil {
return nil, err
}

slashedValidators = append(slashedValidators, slashedPropValidators...)
}
if _, ok := slotValiAttSlashed[slot]; ok {
slashedAttValidators := []pq.Int64Array{}

err := d.readerDb.Select(&slashedAttValidators, `
SELECT
attestation2_indices
FROM blocks_attesterslashings
WHERE block_slot = $1`, slot)
if err != nil {
return nil, err
}

for _, slashedAttValidator := range slashedAttValidators {
for _, validator := range slashedAttValidator {
slashedValidators = append(slashedValidators, uint64(validator))
}
}
}
if _, ok := propAssignmentsForSlot[slot]; 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: propAssignmentsForSlot[slot], // Dashboard validator
DutyObject: validator, // Validator that got slashed
})
}
}
for _, validator := range slashedValidators {
if _, ok := validatorsMap[validator]; !ok {
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
})
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion backend/pkg/commons/db/db.go
Original file line number Diff line number Diff line change
Expand Up @@ -2132,7 +2132,7 @@ func GetValidatorProposals(validators []uint64, proposals *[]types.ValidatorProp
`, validatorsPQArray)
}

func GetValidatorDuties(readerDb *sqlx.DB, startSlot uint64) ([]types.ValidatorDutyInfo, error) {
func GetValidatorDutiesInfo(readerDb *sqlx.DB, startSlot uint64) ([]types.ValidatorDutyInfo, error) {
validatorDutyInfo := []types.ValidatorDutyInfo{}

err := readerDb.Select(&validatorDutyInfo, `
Expand Down

0 comments on commit c1adac8

Please sign in to comment.