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

Nobids/unify error handling in dashboard go #2580

Merged
merged 3 commits into from
Oct 2, 2023
Merged
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
93 changes: 58 additions & 35 deletions handlers/dashboard.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ func handleValidatorsQuery(w http.ResponseWriter, r *http.Request, checkValidato
q := r.URL.Query()
validatorLimit := getUserPremium(r).MaxValidators

fieldMap := map[string]interface{}{"route": r.URL.String()}
errFieldMap := map[string]interface{}{"route": r.URL.String()}

// Parse all the validator indices and pubkeys from the query string
queryValidatorIndices, queryValidatorPubkeys, err := parseValidatorsFromQueryString(q.Get("validators"), validatorLimit)
Expand All @@ -48,7 +48,7 @@ func handleValidatorsQuery(w http.ResponseWriter, r *http.Request, checkValidato
// Check whether pubkeys can be converted to indices and redirect if necessary
redirect, err := updateValidatorsQueryString(w, r, queryValidatorIndices, queryValidatorPubkeys)
if err != nil {
utils.LogError(err, fmt.Errorf("error finding validators in database for dashboard query update"), 0, fieldMap)
utils.LogError(err, fmt.Errorf("error finding validators in database for dashboard query update"), 0, errFieldMap)
http.Error(w, "Not found", http.StatusNotFound)
return nil, nil, false, err
}
Expand Down Expand Up @@ -243,15 +243,17 @@ func Heatmap(w http.ResponseWriter, r *http.Request) {
}
heatmapData.Epochs = epochs

errFieldMap := map[string]interface{}{"route": r.URL.String()}

start := time.Now()
if len(validators) == 0 {
logger.WithError(err).WithField("route", r.URL.String()).Error("error no validators provided")
utils.LogError(err, "error no validators provided", 0, errFieldMap)
http.Error(w, "Internal server error", http.StatusServiceUnavailable)
return
}
incomeData, err := db.BigtableClient.GetValidatorIncomeDetailsHistory(validators, endEpoch-100, endEpoch)
if err != nil {
logger.WithError(err).WithField("route", r.URL.String()).Error("error loading validator income history data")
utils.LogError(err, "error loading validator income history data", 0, errFieldMap)
http.Error(w, "Internal server error", http.StatusServiceUnavailable)
return
}
Expand Down Expand Up @@ -462,6 +464,7 @@ func DashboardDataBalanceCombined(w http.ResponseWriter, r *http.Request) {
}

currency := GetCurrency(r)
errFieldMap := map[string]interface{}{"route": r.URL.String()}

w.Header().Set("Content-Type", "application/json")

Expand All @@ -480,17 +483,23 @@ func DashboardDataBalanceCombined(w http.ResponseWriter, r *http.Request) {
var executionChartData []*types.ChartDataPoint
g.Go(func() error {
incomeHistoryChartData, err = db.GetValidatorIncomeHistoryChart(queryValidatorIndices, currency, services.LatestFinalizedEpoch(), lowerBoundDay)
return err
if err != nil {
return fmt.Errorf("error in GetValidatorIncomeHistoryChart: %w", err)
}
return nil
})

g.Go(func() error {
executionChartData, err = getExecutionChartData(queryValidatorIndices, currency, lowerBoundDay)
return err
if err != nil {
return fmt.Errorf("error in getExecutionChartData: %w", err)
}
return nil
})

err = g.Wait()
if err != nil {
logger.Errorf("combined balance chart %v", err)
utils.LogError(err, "error while combining balance chart", 0, errFieldMap)
sendErrorResponse(w, r.URL.String(), err.Error())
return
}
Expand All @@ -504,7 +513,7 @@ func DashboardDataBalanceCombined(w http.ResponseWriter, r *http.Request) {

err = json.NewEncoder(w).Encode(response)
if err != nil {
logger.WithError(err).WithField("route", r.URL.String()).Error("error enconding json response")
utils.LogError(err, "error enconding json response", 0, errFieldMap)
http.Error(w, "Internal server error", http.StatusServiceUnavailable)
return
}
Expand All @@ -513,14 +522,15 @@ func DashboardDataBalanceCombined(w http.ResponseWriter, r *http.Request) {
// DashboardDataBalance retrieves the income history of a set of validators
func DashboardDataBalance(w http.ResponseWriter, r *http.Request) {
currency := GetCurrency(r)
errFieldMap := map[string]interface{}{"route": r.URL.String()}

w.Header().Set("Content-Type", "application/json")

q := r.URL.Query()
validatorLimit := getUserPremium(r).MaxValidators
queryValidatorIndices, queryValidatorPubkeys, err := parseValidatorsFromQueryString(q.Get("validators"), validatorLimit)
if err != nil || len(queryValidatorPubkeys) > 0 {
utils.LogError(err, fmt.Errorf("error parsing validators from query string"), 0)
utils.LogError(err, "error parsing validators from query string", 0, errFieldMap)
http.Error(w, "Invalid query", http.StatusBadRequest)
return
}
Expand All @@ -531,14 +541,14 @@ func DashboardDataBalance(w http.ResponseWriter, r *http.Request) {

incomeHistoryChartData, err := db.GetValidatorIncomeHistoryChart(queryValidatorIndices, currency, services.LatestFinalizedEpoch(), 0)
if err != nil {
logger.Errorf("failed to genereate income history chart data for dashboard view: %v", err)
utils.LogError(err, "failed to genereate income history chart data for dashboard view", 0, errFieldMap)
http.Error(w, "Internal server error", http.StatusInternalServerError)
return
}

err = json.NewEncoder(w).Encode(incomeHistoryChartData)
if err != nil {
logger.WithError(err).WithField("route", r.URL.String()).Error("error enconding json response")
utils.LogError(err, "error enconding json response", 0, errFieldMap)
http.Error(w, "Internal server error", http.StatusServiceUnavailable)
return
}
Expand All @@ -559,13 +569,15 @@ func DashboardDataProposals(w http.ResponseWriter, r *http.Request) {
Status uint64
}{}

errFieldMap := map[string]interface{}{"route": r.URL.String()}

err = db.ReaderDb.Select(&proposals, `
SELECT slot, status
FROM blocks
WHERE proposer = ANY($1)
ORDER BY slot`, filter)
if err != nil {
logger.WithError(err).WithField("route", r.URL.String()).Error("error retrieving block-proposals")
utils.LogError(err, "error retrieving block-proposals", 0, errFieldMap)
http.Error(w, "Internal server error", http.StatusServiceUnavailable)
return
}
Expand All @@ -580,7 +592,7 @@ func DashboardDataProposals(w http.ResponseWriter, r *http.Request) {

err = json.NewEncoder(w).Encode(proposalsResult)
if err != nil {
logger.WithError(err).WithField("route", r.URL.String()).Error("error enconding json response")
utils.LogError(err, "error enconding json response", 0, errFieldMap)
http.Error(w, "Internal server error", http.StatusServiceUnavailable)
return
}
Expand Down Expand Up @@ -629,16 +641,18 @@ func DashboardDataWithdrawals(w http.ResponseWriter, r *http.Request) {

length := uint64(10)

errFieldMap := map[string]interface{}{"route": r.URL.String()}

withdrawalCount, err := db.GetTotalWithdrawalsCount(validatorIndices)
if err != nil {
utils.LogError(err, fmt.Errorf("error retrieving dashboard validator withdrawals count: %v", err), 0)
utils.LogError(err, "error retrieving dashboard validator withdrawals count", 0, errFieldMap)
http.Error(w, "Internal server error", http.StatusInternalServerError)
return
}

withdrawals, err := db.GetDashboardWithdrawals(validatorIndices, length, start, orderBy, orderDir)
if err != nil {
utils.LogError(err, fmt.Errorf("error retrieving validator withdrawals: %v", err), 0)
utils.LogError(err, "error retrieving validator withdrawals", 0, errFieldMap)
http.Error(w, "Internal server error", http.StatusInternalServerError)
return
}
Expand All @@ -648,7 +662,7 @@ func DashboardDataWithdrawals(w http.ResponseWriter, r *http.Request) {
// check if there is a NextWithdrawal and append
NextWithdrawalRow, err := getNextWithdrawalRow(validatorIndices)
if err != nil {
logger.WithError(err).WithField("route", r.URL.String()).Error("error calculating next withdrawal row")
utils.LogError(err, "error calculating next withdrawal row", 0, errFieldMap)
tableData = make([][]interface{}, 0, len(withdrawals))
} else {
if NextWithdrawalRow == nil {
Expand Down Expand Up @@ -680,7 +694,7 @@ func DashboardDataWithdrawals(w http.ResponseWriter, r *http.Request) {

err = json.NewEncoder(w).Encode(data)
if err != nil {
utils.LogError(err, fmt.Errorf("error enconding json response for %v route: %v", r.URL.String(), err), 0)
utils.LogError(err, "error enconding json response", 0, errFieldMap)
http.Error(w, "Internal server error", http.StatusInternalServerError)
return
}
Expand All @@ -696,6 +710,8 @@ func DashboardDataValidators(w http.ResponseWriter, r *http.Request) {
return
}

errFieldMap := map[string]interface{}{"route": r.URL.String()}

filter := pq.Array(validatorIndexArr)
validatorLimit := getUserPremium(r).MaxValidators

Expand All @@ -721,7 +737,7 @@ func DashboardDataValidators(w http.ResponseWriter, r *http.Request) {
LIMIT $2`, filter, validatorLimit)

if err != nil {
logger.WithError(err).WithField("route", r.URL.String()).Errorf("error retrieving validator data")
utils.LogError(err, "error retrieving validator data", 0, errFieldMap)
http.Error(w, "Internal server error", http.StatusServiceUnavailable)
return
}
Expand All @@ -743,7 +759,7 @@ func DashboardDataValidators(w http.ResponseWriter, r *http.Request) {
FROM eth1_deposits
WHERE publickey = ANY($1)`, pubkeyFilter)
if err != nil {
logger.WithError(err).WithField("route", r.URL.String()).Errorf("error retrieving validator deposists")
utils.LogError(err, "error retrieving validator deposists", 0, errFieldMap)
http.Error(w, "Internal server error", http.StatusServiceUnavailable)
return
}
Expand All @@ -765,7 +781,7 @@ func DashboardDataValidators(w http.ResponseWriter, r *http.Request) {
if len(validatorIndexArr) > 0 {
balances, err := db.BigtableClient.GetValidatorBalanceHistory(validatorIndexArr, latestEpoch, latestEpoch)
if err != nil {
logger.WithError(err).WithField("route", r.URL.String()).Errorf("error retrieving validator balance data")
utils.LogError(err, "error retrieving validator balance data", 0, errFieldMap)
http.Error(w, "Internal server error", http.StatusServiceUnavailable)
return
}
Expand All @@ -784,7 +800,7 @@ func DashboardDataValidators(w http.ResponseWriter, r *http.Request) {

lastAttestationSlots, err := db.BigtableClient.GetLastAttestationSlots(validatorIndexArr)
if err != nil {
logger.WithError(err).WithField("route", r.URL.String()).Errorf("error retrieving validator last attestation slot data")
utils.LogError(err, "error retrieving validator last attestation slot data", 0, errFieldMap)
http.Error(w, "Internal server error", http.StatusServiceUnavailable)
return
}
Expand Down Expand Up @@ -822,7 +838,7 @@ func DashboardDataValidators(w http.ResponseWriter, r *http.Request) {
if v.ActivationEpoch > 100_000_000 {
queueAhead, err = db.GetQueueAheadOfValidator(v.ValidatorIndex)
if err != nil {
logger.WithError(err).Errorf("failed to retrieve queue ahead of validator %v for dashboard", v.ValidatorIndex)
utils.LogError(err, fmt.Sprintf("failed to retrieve queue ahead of validator %v for dashboard", v.ValidatorIndex), 0, errFieldMap)
http.Error(w, "Internal server error", http.StatusServiceUnavailable)
return
}
Expand Down Expand Up @@ -916,7 +932,7 @@ func DashboardDataValidators(w http.ResponseWriter, r *http.Request) {

err = json.NewEncoder(w).Encode(data)
if err != nil {
logger.WithError(err).WithField("route", r.URL.String()).Errorf("error enconding json response")
utils.LogError(err, "error enconding json response", 0, errFieldMap)
http.Error(w, "Internal server error", http.StatusServiceUnavailable)
return
}
Expand All @@ -925,14 +941,16 @@ func DashboardDataValidators(w http.ResponseWriter, r *http.Request) {
func DashboardDataEarnings(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")

errFieldMap := map[string]interface{}{"route": r.URL.String()}

queryValidatorIndices, _, redirect, err := handleValidatorsQuery(w, r, true)
if err != nil || redirect {
return
}

earnings, _, err := GetValidatorEarnings(queryValidatorIndices, GetCurrency(r))
if err != nil {
logger.WithError(err).WithField("route", r.URL.String()).Errorf("error retrieving validator earnings")
utils.LogError(err, "error retrieving validator earnings", 0, errFieldMap)
http.Error(w, "Internal server error", http.StatusServiceUnavailable)
}

Expand All @@ -942,7 +960,7 @@ func DashboardDataEarnings(w http.ResponseWriter, r *http.Request) {

err = json.NewEncoder(w).Encode(earnings)
if err != nil {
logger.WithError(err).WithField("route", r.URL.String()).Errorf("error enconding json response")
utils.LogError(err, "error enconding json response", 0, errFieldMap)
http.Error(w, "Internal server error", http.StatusServiceUnavailable)
return
}
Expand All @@ -956,14 +974,16 @@ func DashboardDataEffectiveness(w http.ResponseWriter, r *http.Request) {
return
}

errFieldMap := map[string]interface{}{"route": r.URL.String()}

filter := pq.Array(filterArr)

var activeValidators []uint64
err = db.ReaderDb.Select(&activeValidators, `
SELECT validatorindex FROM validators where validatorindex = ANY($1) and activationepoch < $2 AND exitepoch > $2
`, filter, services.LatestEpoch())
if err != nil {
logger.Errorf("error retrieving active validators")
utils.LogError(err, "error retrieving active validators", 0, errFieldMap)
}

if len(activeValidators) == 0 {
Expand All @@ -979,18 +999,19 @@ func DashboardDataEffectiveness(w http.ResponseWriter, r *http.Request) {
}

effectiveness, err := db.BigtableClient.GetValidatorEffectiveness(activeValidators, epoch)
for _, e := range effectiveness {
avgIncDistance = append(avgIncDistance, e.AttestationEfficiency)
}
if err != nil {
logger.Errorf("error retrieving AverageAttestationInclusionDistance: %v", err)
utils.LogError(err, "error retrieving validator effectiveness", 0, errFieldMap)
http.Error(w, "Internal server error", http.StatusServiceUnavailable)
return
}

for _, e := range effectiveness {
avgIncDistance = append(avgIncDistance, e.AttestationEfficiency)
}

err = json.NewEncoder(w).Encode(avgIncDistance)
if err != nil {
logger.Errorf("error enconding json response for %v route: %v", r.URL.String(), err)
utils.LogError(err, "error enconding json response", 0, errFieldMap)
http.Error(w, "Internal server error", http.StatusServiceUnavailable)
return
}
Expand All @@ -1004,6 +1025,8 @@ func DashboardDataProposalsHistory(w http.ResponseWriter, r *http.Request) {
return
}

errFieldMap := map[string]interface{}{"route": r.URL.String()}

filter := pq.Array(filterArr)

proposals := []struct {
Expand All @@ -1021,14 +1044,14 @@ func DashboardDataProposalsHistory(w http.ResponseWriter, r *http.Request) {
WHERE validatorindex = ANY($1) AND (proposed_blocks IS NOT NULL OR missed_blocks IS NOT NULL OR orphaned_blocks IS NOT NULL)
ORDER BY day DESC`, filter)
if err != nil {
logger.WithError(err).WithField("route", r.URL.String()).Error("error retrieving validator_stats")
utils.LogError(err, "error retrieving validator_stats", 0, errFieldMap)
http.Error(w, "Internal server error", http.StatusServiceUnavailable)
return
}

lastDay, err := db.GetLastExportedStatisticDay()
if err != nil && err != db.ErrNoStats {
logger.WithError(err).WithField("route", r.URL.String()).Error("error retrieving last exported statistic day")
utils.LogError(err, "error retrieving last exported statistic day", 0, errFieldMap)
http.Error(w, "Internal server error", http.StatusServiceUnavailable)
return
}
Expand All @@ -1044,7 +1067,7 @@ func DashboardDataProposalsHistory(w http.ResponseWriter, r *http.Request) {
WHERE proposer = ANY($1) AND epoch > $2
group by proposer`, filter, lastExportedEpoch)
if err != nil {
logger.WithError(err).WithField("route", r.URL.String()).Error("error retrieving validator_stats")
utils.LogError(err, "error retrieving validator_stats", 0, errFieldMap)
http.Error(w, "Internal server error", http.StatusServiceUnavailable)
return
}
Expand Down Expand Up @@ -1078,7 +1101,7 @@ func DashboardDataProposalsHistory(w http.ResponseWriter, r *http.Request) {

err = json.NewEncoder(w).Encode(proposalsHistResult)
if err != nil {
logger.WithError(err).WithField("route", r.URL.String()).Error("error enconding json response")
utils.LogError(err, "error enconding json response", 0, errFieldMap)
http.Error(w, "Internal server error", http.StatusServiceUnavailable)
return
}
Expand Down
Loading