From 5968845cd8d997bf5d6072447f8da582e81c3224 Mon Sep 17 00:00:00 2001
From: peter <1674920+peterbitfly@users.noreply.github.com>
Date: Fri, 5 Jul 2024 08:09:58 +0200
Subject: [PATCH 01/39] use map for pubkey filter
---
backend/pkg/notification/db.go | 9 +++----
backend/pkg/notification/notifications.go | 32 ++++++++++++++++-------
2 files changed, 26 insertions(+), 15 deletions(-)
diff --git a/backend/pkg/notification/db.go b/backend/pkg/notification/db.go
index eed83b0f1..cf2a217e0 100644
--- a/backend/pkg/notification/db.go
+++ b/backend/pkg/notification/db.go
@@ -1,15 +1,13 @@
package notification
import (
- "encoding/hex"
-
"github.com/gobitfly/beaconchain/pkg/commons/db"
"github.com/gobitfly/beaconchain/pkg/commons/types"
"github.com/gobitfly/beaconchain/pkg/commons/utils"
"github.com/lib/pq"
)
-func GetSubsForEventFilter(eventName types.EventName) ([][]byte, map[string][]types.Subscription, error) {
+func GetSubsForEventFilter(eventName types.EventName) (map[string]bool, map[string][]types.Subscription, error) {
var subs []types.Subscription
subQuery := `
SELECT id, user_id, event_filter, last_sent_epoch, created_epoch, event_threshold, ENCODE(unsubscribe_hash, 'hex') as unsubscribe_hash, internal_state from users_subscriptions where event_name = $1
@@ -21,7 +19,7 @@ func GetSubsForEventFilter(eventName types.EventName) ([][]byte, map[string][]ty
return nil, nil, err
}
- filtersEncode := make([][]byte, 0, len(subs))
+ filtersEncode := make(map[string]bool, len(subs))
for _, sub := range subs {
if _, ok := subMap[sub.EventFilter]; !ok {
subMap[sub.EventFilter] = make([]types.Subscription, 0)
@@ -36,8 +34,7 @@ func GetSubsForEventFilter(eventName types.EventName) ([][]byte, map[string][]ty
State: sub.State,
})
- b, _ := hex.DecodeString(sub.EventFilter)
- filtersEncode = append(filtersEncode, b)
+ filtersEncode[sub.EventFilter] = true
}
return filtersEncode, subMap, nil
}
diff --git a/backend/pkg/notification/notifications.go b/backend/pkg/notification/notifications.go
index e40a83b44..ec0e841a9 100644
--- a/backend/pkg/notification/notifications.go
+++ b/backend/pkg/notification/notifications.go
@@ -2959,20 +2959,34 @@ func collectRocketpoolRPLCollateralNotifications(notificationsByUserID map[uint6
RPLStakeMax BigFloat `db:"max_rpl_stake"`
}
+ // filter nodes with no minipools (anymore) because they have min/max stake of 0
+ // TODO properly remove notification entry from db
stakeInfoPerNode := make([]dbResult, 0)
batchSize := 5000
- dataLen := len(pubkeys)
- for i := 0; i < dataLen; i += batchSize {
- var keys [][]byte
- start := i
- end := i + batchSize
-
- if dataLen < end {
- end = dataLen
+ keys := make([][]byte, 0, batchSize)
+ for pubkey := range pubkeys {
+ b, err := hex.DecodeString(pubkey)
+ if err != nil {
+ log.Error(err, fmt.Sprintf("error decoding pubkey %s", pubkey), 0)
+ continue
}
+ keys = append(keys, b)
- keys = pubkeys[start:end]
+ if len(keys) > batchSize {
+ var partial []dbResult
+ err = db.WriterDb.Select(&partial, `
+ SELECT address, rpl_stake, min_rpl_stake, max_rpl_stake
+ FROM rocketpool_nodes
+ WHERE address = ANY($1) AND min_rpl_stake != 0 AND max_rpl_stake != 0`, pq.ByteaArray(keys))
+ if err != nil {
+ return err
+ }
+ stakeInfoPerNode = append(stakeInfoPerNode, partial...)
+ keys = make([][]byte, 0, batchSize)
+ }
+ }
+ if len(keys) > 0 {
var partial []dbResult
// filter nodes with no minipools (anymore) because they have min/max stake of 0
From 94b87dc9682c6dae3948018c16a2354ec0294d69 Mon Sep 17 00:00:00 2001
From: peter <1674920+peterbitfly@users.noreply.github.com>
Date: Fri, 5 Jul 2024 08:25:01 +0200
Subject: [PATCH 02/39] simplify handling of pubkeys in notifications
---
backend/pkg/commons/types/frontend.go | 16 ++++++++++++++++
backend/pkg/notification/db.go | 13 +++++++------
backend/pkg/notification/notifications.go | 12 ++++++------
3 files changed, 29 insertions(+), 12 deletions(-)
diff --git a/backend/pkg/commons/types/frontend.go b/backend/pkg/commons/types/frontend.go
index ee589fcbb..f468b5c43 100644
--- a/backend/pkg/commons/types/frontend.go
+++ b/backend/pkg/commons/types/frontend.go
@@ -266,6 +266,22 @@ type Subscription struct {
EventThreshold float64 `db:"event_threshold"`
UnsubscribeHash sql.NullString `db:"unsubscribe_hash" swaggertype:"string"`
State sql.NullString `db:"internal_state" swaggertype:"string"`
+ GroupId *uint32
+ DashboardId *uint32
+}
+
+type ValidatorDashboardConfig struct {
+ DashboardsByUserId map[uint64]map[uint32]*ValidatorDashboard
+}
+
+type ValidatorDashboard struct {
+ Name string `db:"name"`
+ Groups map[uint32]*ValidatorDashboardGroup
+}
+
+type ValidatorDashboardGroup struct {
+ Name string `db:"name"`
+ Validators [][]byte
}
type TaggedValidators struct {
diff --git a/backend/pkg/notification/db.go b/backend/pkg/notification/db.go
index cf2a217e0..26838c9bb 100644
--- a/backend/pkg/notification/db.go
+++ b/backend/pkg/notification/db.go
@@ -7,7 +7,11 @@ import (
"github.com/lib/pq"
)
-func GetSubsForEventFilter(eventName types.EventName) (map[string]bool, map[string][]types.Subscription, error) {
+// Retrieves all subscription for a given event filter
+// Map key corresponds to the event filter which can be
+// a validator pubkey or an eth1 address (for RPL notifications)
+// or a list of validators for the tax report notifications
+func GetSubsForEventFilter(eventName types.EventName) (map[string][]types.Subscription, error) {
var subs []types.Subscription
subQuery := `
SELECT id, user_id, event_filter, last_sent_epoch, created_epoch, event_threshold, ENCODE(unsubscribe_hash, 'hex') as unsubscribe_hash, internal_state from users_subscriptions where event_name = $1
@@ -16,10 +20,9 @@ func GetSubsForEventFilter(eventName types.EventName) (map[string]bool, map[stri
subMap := make(map[string][]types.Subscription, 0)
err := db.FrontendWriterDB.Select(&subs, subQuery, utils.GetNetwork()+":"+string(eventName))
if err != nil {
- return nil, nil, err
+ return nil, err
}
- filtersEncode := make(map[string]bool, len(subs))
for _, sub := range subs {
if _, ok := subMap[sub.EventFilter]; !ok {
subMap[sub.EventFilter] = make([]types.Subscription, 0)
@@ -33,10 +36,8 @@ func GetSubsForEventFilter(eventName types.EventName) (map[string]bool, map[stri
EventThreshold: sub.EventThreshold,
State: sub.State,
})
-
- filtersEncode[sub.EventFilter] = true
}
- return filtersEncode, subMap, nil
+ return subMap, nil
}
func GetUserPushTokenByIds(ids []uint64) (map[uint64][]string, error) {
diff --git a/backend/pkg/notification/notifications.go b/backend/pkg/notification/notifications.go
index ec0e841a9..4a58768dc 100644
--- a/backend/pkg/notification/notifications.go
+++ b/backend/pkg/notification/notifications.go
@@ -1207,7 +1207,7 @@ func collectBlockProposalNotifications(notificationsByUserID map[uint64]map[type
ExecRewardETH float64
}
- _, subMap, err := GetSubsForEventFilter(eventName)
+ subMap, err := GetSubsForEventFilter(eventName)
if err != nil {
return fmt.Errorf("error getting subscriptions for (missed) block proposals %w", err)
}
@@ -1394,7 +1394,7 @@ func (n *validatorProposalNotification) GetInfoMarkdown() string {
}
func collectAttestationAndOfflineValidatorNotifications(notificationsByUserID map[uint64]map[types.EventName][]types.Notification, epoch uint64) error {
- _, subMap, err := GetSubsForEventFilter(types.ValidatorMissedAttestationEventName)
+ subMap, err := GetSubsForEventFilter(types.ValidatorMissedAttestationEventName)
if err != nil {
return fmt.Errorf("error getting subscriptions for missted attestations %w", err)
}
@@ -1573,7 +1573,7 @@ func collectAttestationAndOfflineValidatorNotifications(notificationsByUserID ma
return fmt.Errorf("retrieved more than %v online validators notifications: %v, exiting", onlineValidatorsLimit, len(onlineValidators))
}
- _, subMap, err = GetSubsForEventFilter(types.ValidatorIsOfflineEventName)
+ subMap, err = GetSubsForEventFilter(types.ValidatorIsOfflineEventName)
if err != nil {
return fmt.Errorf("failed to get subs for %v: %v", types.ValidatorIsOfflineEventName, err)
}
@@ -2022,7 +2022,7 @@ func (n *validatorWithdrawalNotification) GetInfoMarkdown() string {
// collectWithdrawalNotifications collects all notifications validator withdrawals
func collectWithdrawalNotifications(notificationsByUserID map[uint64]map[types.EventName][]types.Notification, epoch uint64) error {
// get all users that are subscribed to this event (scale: a few thousand rows depending on how many users we have)
- _, subMap, err := GetSubsForEventFilter(types.ValidatorReceivedWithdrawalEventName)
+ subMap, err := GetSubsForEventFilter(types.ValidatorReceivedWithdrawalEventName)
if err != nil {
return fmt.Errorf("error getting subscriptions for missed attestations %w", err)
}
@@ -2947,7 +2947,7 @@ func collectRocketpoolRewardClaimRoundNotifications(notificationsByUserID map[ui
}
func collectRocketpoolRPLCollateralNotifications(notificationsByUserID map[uint64]map[types.EventName][]types.Notification, eventName types.EventName, epoch uint64) error {
- pubkeys, subMap, err := GetSubsForEventFilter(eventName)
+ subMap, err := GetSubsForEventFilter(eventName)
if err != nil {
return fmt.Errorf("error getting subscriptions for RocketpoolRPLCollateral %w", err)
}
@@ -2964,7 +2964,7 @@ func collectRocketpoolRPLCollateralNotifications(notificationsByUserID map[uint6
stakeInfoPerNode := make([]dbResult, 0)
batchSize := 5000
keys := make([][]byte, 0, batchSize)
- for pubkey := range pubkeys {
+ for pubkey := range subMap {
b, err := hex.DecodeString(pubkey)
if err != nil {
log.Error(err, fmt.Sprintf("error decoding pubkey %s", pubkey), 0)
From 67b8529f8b4b8580b7472c190eb251dad5cef1a8 Mon Sep 17 00:00:00 2001
From: peter <1674920+peterbitfly@users.noreply.github.com>
Date: Fri, 5 Jul 2024 08:54:13 +0200
Subject: [PATCH 03/39] improve typing of userid
---
backend/pkg/commons/db/bigtable.go | 30 ++---
backend/pkg/commons/types/frontend.go | 18 +--
backend/pkg/notification/db.go | 16 +--
backend/pkg/notification/notifications.go | 130 +++++++++++++++-------
4 files changed, 125 insertions(+), 69 deletions(-)
diff --git a/backend/pkg/commons/db/bigtable.go b/backend/pkg/commons/db/bigtable.go
index edd9b3c17..7b7cd147e 100644
--- a/backend/pkg/commons/db/bigtable.go
+++ b/backend/pkg/commons/db/bigtable.go
@@ -194,7 +194,7 @@ func (bigtable *Bigtable) GetClient() *gcp_bigtable.Client {
return bigtable.client
}
-func (bigtable *Bigtable) SaveMachineMetric(process string, userID uint64, machine string, data []byte) error {
+func (bigtable *Bigtable) SaveMachineMetric(process string, userID types.UserId, machine string, data []byte) error {
ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
defer cancel()
@@ -234,7 +234,7 @@ func (bigtable *Bigtable) SaveMachineMetric(process string, userID uint64, machi
return nil
}
-func (bigtable Bigtable) getMachineMetricNamesMap(userID uint64, searchDepth int) (map[string]bool, error) {
+func (bigtable Bigtable) getMachineMetricNamesMap(userID types.UserId, searchDepth int) (map[string]bool, error) {
ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(time.Second*30))
defer cancel()
@@ -265,7 +265,7 @@ func (bigtable Bigtable) getMachineMetricNamesMap(userID uint64, searchDepth int
return machineNames, nil
}
-func (bigtable Bigtable) GetMachineMetricsMachineNames(userID uint64) ([]string, error) {
+func (bigtable Bigtable) GetMachineMetricsMachineNames(userID types.UserId) ([]string, error) {
tmr := time.AfterFunc(REPORT_TIMEOUT, func() {
log.WarnWithFields(log.Fields{
"userId": userID,
@@ -288,7 +288,7 @@ func (bigtable Bigtable) GetMachineMetricsMachineNames(userID uint64) ([]string,
return result, nil
}
-func (bigtable Bigtable) GetMachineMetricsMachineCount(userID uint64) (uint64, error) {
+func (bigtable Bigtable) GetMachineMetricsMachineCount(userID types.UserId) (uint64, error) {
tmr := time.AfterFunc(REPORT_TIMEOUT, func() {
log.WarnWithFields(log.Fields{
"userId": userID,
@@ -310,7 +310,7 @@ func (bigtable Bigtable) GetMachineMetricsMachineCount(userID uint64) (uint64, e
return uint64(card), nil
}
-func (bigtable Bigtable) GetMachineMetricsNode(userID uint64, limit, offset int) ([]*types.MachineMetricNode, error) {
+func (bigtable Bigtable) GetMachineMetricsNode(userID types.UserId, limit, offset int) ([]*types.MachineMetricNode, error) {
tmr := time.AfterFunc(REPORT_TIMEOUT, func() {
log.WarnWithFields(log.Fields{
"userId": userID,
@@ -335,7 +335,7 @@ func (bigtable Bigtable) GetMachineMetricsNode(userID uint64, limit, offset int)
)
}
-func (bigtable Bigtable) GetMachineMetricsValidator(userID uint64, limit, offset int) ([]*types.MachineMetricValidator, error) {
+func (bigtable Bigtable) GetMachineMetricsValidator(userID types.UserId, limit, offset int) ([]*types.MachineMetricValidator, error) {
tmr := time.AfterFunc(REPORT_TIMEOUT, func() {
log.WarnWithFields(log.Fields{
"userId": userID,
@@ -360,7 +360,7 @@ func (bigtable Bigtable) GetMachineMetricsValidator(userID uint64, limit, offset
)
}
-func (bigtable Bigtable) GetMachineMetricsSystem(userID uint64, limit, offset int) ([]*types.MachineMetricSystem, error) {
+func (bigtable Bigtable) GetMachineMetricsSystem(userID types.UserId, limit, offset int) ([]*types.MachineMetricSystem, error) {
tmr := time.AfterFunc(REPORT_TIMEOUT, func() {
log.WarnWithFields(log.Fields{
"userId": userID,
@@ -385,7 +385,7 @@ func (bigtable Bigtable) GetMachineMetricsSystem(userID uint64, limit, offset in
)
}
-func getMachineMetrics[T types.MachineMetricSystem | types.MachineMetricNode | types.MachineMetricValidator](bigtable Bigtable, process string, userID uint64, limit, offset int, marshler func(data []byte, machine string) *T) ([]*T, error) {
+func getMachineMetrics[T types.MachineMetricSystem | types.MachineMetricNode | types.MachineMetricValidator](bigtable Bigtable, process string, userID types.UserId, limit, offset int, marshler func(data []byte, machine string) *T) ([]*T, error) {
ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(time.Second*30))
defer cancel()
@@ -429,7 +429,7 @@ func getMachineMetrics[T types.MachineMetricSystem | types.MachineMetricNode | t
return res, nil
}
-func (bigtable Bigtable) GetMachineRowKey(userID uint64, process string, machine string) string {
+func (bigtable Bigtable) GetMachineRowKey(userID types.UserId, process string, machine string) string {
return fmt.Sprintf("u:%s:p:%s:m:%s", bigtable.reversePaddedUserID(userID), process, machine)
}
@@ -437,7 +437,7 @@ func (bigtable Bigtable) GetMachineRowKey(userID uint64, process string, machine
// machineData contains the latest machine data in CurrentData
// and 5 minute old data in fiveMinuteOldData (defined in limit)
// as well as the insert timestamps of both
-func (bigtable Bigtable) GetMachineMetricsForNotifications(rowKeys gcp_bigtable.RowList) (map[uint64]map[string]*types.MachineMetricSystemUser, error) {
+func (bigtable Bigtable) GetMachineMetricsForNotifications(rowKeys gcp_bigtable.RowList) (map[types.UserId]map[string]*types.MachineMetricSystemUser, error) {
tmr := time.AfterFunc(REPORT_TIMEOUT, func() {
log.WarnWithFields(log.Fields{
"rowKeys": rowKeys,
@@ -449,7 +449,7 @@ func (bigtable Bigtable) GetMachineMetricsForNotifications(rowKeys gcp_bigtable.
ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(time.Second*200))
defer cancel()
- res := make(map[uint64]map[string]*types.MachineMetricSystemUser) // userID -> machine -> data
+ res := make(map[types.UserId]map[string]*types.MachineMetricSystemUser) // userID -> machine -> data
limit := 5
@@ -509,7 +509,7 @@ func (bigtable Bigtable) GetMachineMetricsForNotifications(rowKeys gcp_bigtable.
}
//nolint:unparam
-func machineMetricRowParts(r string) (bool, uint64, string, string) {
+func machineMetricRowParts(r string) (bool, types.UserId, string, string) {
keySplit := strings.Split(r, ":")
userID, err := strconv.ParseUint(keySplit[1], 10, 64)
@@ -526,7 +526,7 @@ func machineMetricRowParts(r string) (bool, uint64, string, string) {
process := keySplit[3]
- return true, userID, machine, process
+ return true, types.UserId(userID), machine, process
}
func (bigtable *Bigtable) SaveValidatorBalances(epoch uint64, validators []*types.Validator) error {
@@ -2678,8 +2678,8 @@ func GetCurrentDayClIncome(validator_indices []uint64) (map[uint64]int64, error)
return dayIncome, nil
}
-func (bigtable *Bigtable) reversePaddedUserID(userID uint64) string {
- return fmt.Sprintf("%09d", ^uint64(0)-userID)
+func (bigtable *Bigtable) reversePaddedUserID(userID types.UserId) string {
+ return fmt.Sprintf("%09d", ^uint64(0)-uint64(userID))
}
func (bigtable *Bigtable) reversedPaddedEpoch(epoch uint64) string {
diff --git a/backend/pkg/commons/types/frontend.go b/backend/pkg/commons/types/frontend.go
index f468b5c43..d91d60747 100644
--- a/backend/pkg/commons/types/frontend.go
+++ b/backend/pkg/commons/types/frontend.go
@@ -12,6 +12,7 @@ import (
"firebase.google.com/go/messaging"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
+ "github.com/gobitfly/beaconchain/pkg/consapi/types"
"github.com/lib/pq"
"github.com/pkg/errors"
"golang.org/x/text/cases"
@@ -164,7 +165,7 @@ type EventNameDesc struct {
}
type MachineMetricSystemUser struct {
- UserID uint64
+ UserID UserId
Machine string
CurrentData *MachineMetricSystem
CurrentDataInsertTs int64
@@ -255,7 +256,7 @@ type Notification interface {
type Subscription struct {
ID *uint64 `db:"id,omitempty"`
- UserID *uint64 `db:"user_id,omitempty"`
+ UserID *UserId `db:"user_id,omitempty"`
EventName string `db:"event_name"`
EventFilter string `db:"event_filter"`
LastSent *time.Time `db:"last_sent_ts"`
@@ -266,22 +267,25 @@ type Subscription struct {
EventThreshold float64 `db:"event_threshold"`
UnsubscribeHash sql.NullString `db:"unsubscribe_hash" swaggertype:"string"`
State sql.NullString `db:"internal_state" swaggertype:"string"`
- GroupId *uint32
- DashboardId *uint32
+ GroupId *int64
+ DashboardId *int64
}
+type UserId uint64
+type DashboardId uint64
+type DashboardGroupId uint64
type ValidatorDashboardConfig struct {
- DashboardsByUserId map[uint64]map[uint32]*ValidatorDashboard
+ DashboardsByUserId map[UserId]map[DashboardId]*ValidatorDashboard
}
type ValidatorDashboard struct {
Name string `db:"name"`
- Groups map[uint32]*ValidatorDashboardGroup
+ Groups map[DashboardGroupId]*ValidatorDashboardGroup
}
type ValidatorDashboardGroup struct {
Name string `db:"name"`
- Validators [][]byte
+ Validators []types.ValidatorIndex
}
type TaggedValidators struct {
diff --git a/backend/pkg/notification/db.go b/backend/pkg/notification/db.go
index 26838c9bb..23f890ba6 100644
--- a/backend/pkg/notification/db.go
+++ b/backend/pkg/notification/db.go
@@ -40,14 +40,14 @@ func GetSubsForEventFilter(eventName types.EventName) (map[string][]types.Subscr
return subMap, nil
}
-func GetUserPushTokenByIds(ids []uint64) (map[uint64][]string, error) {
- pushByID := map[uint64][]string{}
+func GetUserPushTokenByIds(ids []types.UserId) (map[types.UserId][]string, error) {
+ pushByID := map[types.UserId][]string{}
if len(ids) == 0 {
return pushByID, nil
}
var rows []struct {
- ID uint64 `db:"user_id"`
- Token string `db:"notification_token"`
+ ID types.UserId `db:"user_id"`
+ Token string `db:"notification_token"`
}
err := db.FrontendWriterDB.Select(&rows, "SELECT DISTINCT ON (user_id, notification_token) user_id, notification_token FROM users_devices WHERE (user_id = ANY($1) AND user_id NOT IN (SELECT user_id from users_notification_channels WHERE active = false and channel = $2)) AND notify_enabled = true AND active = true AND notification_token IS NOT NULL AND LENGTH(notification_token) > 20 ORDER BY user_id, notification_token, id DESC", pq.Array(ids), types.PushNotificationChannel)
@@ -67,14 +67,14 @@ func GetUserPushTokenByIds(ids []uint64) (map[uint64][]string, error) {
}
// GetUserEmailsByIds returns the emails of users.
-func GetUserEmailsByIds(ids []uint64) (map[uint64]string, error) {
- mailsByID := map[uint64]string{}
+func GetUserEmailsByIds(ids []types.UserId) (map[types.UserId]string, error) {
+ mailsByID := map[types.UserId]string{}
if len(ids) == 0 {
return mailsByID, nil
}
var rows []struct {
- ID uint64 `db:"id"`
- Email string `db:"email"`
+ ID types.UserId `db:"id"`
+ Email string `db:"email"`
}
//
err := db.FrontendWriterDB.Select(&rows, "SELECT id, email FROM users WHERE id = ANY($1) AND id NOT IN (SELECT user_id from users_notification_channels WHERE active = false and channel = $2)", pq.Array(ids), types.EmailNotificationChannel)
diff --git a/backend/pkg/notification/notifications.go b/backend/pkg/notification/notifications.go
index 4a58768dc..c408c1cdf 100644
--- a/backend/pkg/notification/notifications.go
+++ b/backend/pkg/notification/notifications.go
@@ -225,8 +225,8 @@ func notificationSender() {
}
}
-func collectNotifications(epoch uint64) (map[uint64]map[types.EventName][]types.Notification, error) {
- notificationsByUserID := map[uint64]map[types.EventName][]types.Notification{}
+func collectNotifications(epoch uint64) (map[types.UserId]map[types.EventName][]types.Notification, error) {
+ notificationsByUserID := map[types.UserId]map[types.EventName][]types.Notification{}
start := time.Now()
var err error
var dbIsCoherent bool
@@ -253,6 +253,58 @@ func collectNotifications(epoch uint64) (map[uint64]map[types.EventName][]types.
log.Infof("started collecting notifications")
+ type dashboardDefinitionRow struct {
+ DashboardId types.DashboardId `db:"dashboard_id"`
+ DashboardName string `db:"dashboard_name"`
+ UserId types.UserId `db:"user_id"`
+ GroupId types.DashboardGroupId `db:"group_id"`
+ GroupName string `db:"group_name"`
+ ValidatorIndex types.ValidatorIndex `db:"validator_index"`
+ }
+
+ log.Infof("retrieving dashboard definitions")
+ // TODO: add a filter to retrieve only groups that have notifications enabled
+ // Needs a new field in the db
+ var dashboardDefinitions []dashboardDefinitionRow
+ err = db.AlloyWriter.Select(&dashboardDefinitions, `
+ select
+ users_val_dashboards.id as dashboard_id,
+ users_val_dashboards.name as dashboard_name,
+ users_val_dashboards.user_id,
+ users_val_dashboards_groups.id as group_id,
+ users_val_dashboards_groups.name as group_name,
+ users_val_dashboards_validators.validator_index
+ from users_val_dashboards
+ left join users_val_dashboards_groups on users_val_dashboards_groups.dashboard_id = users_val_dashboards.id
+ left join users_val_dashboards_validators on users_val_dashboards_validators.dashboard_id = users_val_dashboards_groups.dashboard_id AND users_val_dashboards_validators.group_id = users_val_dashboards_groups.id;
+ `)
+ if err != nil {
+ return nil, fmt.Errorf("error getting dashboard definitions: %v", err)
+ }
+
+ // Now initialize the validator dashboard configuration map
+ validatorDashboardConfig := &types.ValidatorDashboardConfig{
+ DashboardsByUserId: make(map[types.UserId]map[types.DashboardId]*types.ValidatorDashboard),
+ }
+ for _, row := range dashboardDefinitions {
+ if validatorDashboardConfig.DashboardsByUserId[row.UserId] == nil {
+ validatorDashboardConfig.DashboardsByUserId[row.UserId] = make(map[types.DashboardId]*types.ValidatorDashboard)
+ }
+ if validatorDashboardConfig.DashboardsByUserId[row.UserId][row.DashboardId] == nil {
+ validatorDashboardConfig.DashboardsByUserId[row.UserId][row.DashboardId] = &types.ValidatorDashboard{
+ Name: row.DashboardName,
+ Groups: make(map[types.DashboardGroupId]*types.ValidatorDashboardGroup),
+ }
+ }
+ if validatorDashboardConfig.DashboardsByUserId[row.UserId][row.DashboardId].Groups[row.GroupId] == nil {
+ validatorDashboardConfig.DashboardsByUserId[row.UserId][row.DashboardId].Groups[row.GroupId] = &types.ValidatorDashboardGroup{
+ Name: row.GroupName,
+ Validators: []uint64{},
+ }
+ }
+ validatorDashboardConfig.DashboardsByUserId[row.UserId][row.DashboardId].Groups[row.GroupId].Validators = append(validatorDashboardConfig.DashboardsByUserId[row.UserId][row.DashboardId].Groups[row.GroupId].Validators, uint64(row.ValidatorIndex))
+ }
+
err = collectAttestationAndOfflineValidatorNotifications(notificationsByUserID, epoch)
if err != nil {
metrics.Errors.WithLabelValues("notifications_collect_missed_attestation").Inc()
@@ -356,8 +408,8 @@ func collectNotifications(epoch uint64) (map[uint64]map[types.EventName][]types.
return notificationsByUserID, nil
}
-func collectUserDbNotifications(epoch uint64) (map[uint64]map[types.EventName][]types.Notification, error) {
- notificationsByUserID := map[uint64]map[types.EventName][]types.Notification{}
+func collectUserDbNotifications(epoch uint64) (map[types.UserId]map[types.EventName][]types.Notification, error) {
+ notificationsByUserID := map[types.UserId]map[types.EventName][]types.Notification{}
var err error
// Monitoring (premium): machine offline
@@ -405,7 +457,7 @@ func collectUserDbNotifications(epoch uint64) (map[uint64]map[types.EventName][]
return notificationsByUserID, nil
}
-func queueNotifications(notificationsByUserID map[uint64]map[types.EventName][]types.Notification, useDB *sqlx.DB) {
+func queueNotifications(notificationsByUserID map[types.UserId]map[types.EventName][]types.Notification, useDB *sqlx.DB) {
subByEpoch := map[uint64][]uint64{}
// prevent multiple events being sent with the same subscription id
@@ -541,8 +593,8 @@ func getNetwork() string {
return ""
}
-func queuePushNotification(notificationsByUserID map[uint64]map[types.EventName][]types.Notification, useDB *sqlx.DB) error {
- userIDs := []uint64{}
+func queuePushNotification(notificationsByUserID map[types.UserId]map[types.EventName][]types.Notification, useDB *sqlx.DB) error {
+ userIDs := []types.UserId{}
for userID := range notificationsByUserID {
userIDs = append(userIDs, userID)
}
@@ -646,8 +698,8 @@ func sendPushNotifications(useDB *sqlx.DB) error {
return nil
}
-func queueEmailNotifications(notificationsByUserID map[uint64]map[types.EventName][]types.Notification, useDB *sqlx.DB) error {
- userIDs := []uint64{}
+func queueEmailNotifications(notificationsByUserID map[types.UserId]map[types.EventName][]types.Notification, useDB *sqlx.DB) error {
+ userIDs := []types.UserId{}
for userID := range notificationsByUserID {
userIDs = append(userIDs, userID)
}
@@ -841,7 +893,7 @@ func sendEmailNotifications(useDb *sqlx.DB) error {
return nil
}
-func queueWebhookNotifications(notificationsByUserID map[uint64]map[types.EventName][]types.Notification, useDB *sqlx.DB) error {
+func queueWebhookNotifications(notificationsByUserID map[types.UserId]map[types.EventName][]types.Notification, useDB *sqlx.DB) error {
for userID, userNotifications := range notificationsByUserID {
var webhooks []types.UserWebhook
err := useDB.Select(&webhooks, `
@@ -1198,7 +1250,7 @@ func getUrlPart(validatorIndex uint64) string {
return fmt.Sprintf(` For more information visit: https://%s/validator/%v.`, utils.Config.Frontend.SiteDomain, validatorIndex, utils.Config.Frontend.SiteDomain, validatorIndex)
}
-func collectBlockProposalNotifications(notificationsByUserID map[uint64]map[types.EventName][]types.Notification, status uint64, eventName types.EventName, epoch uint64) error {
+func collectBlockProposalNotifications(notificationsByUserID map[types.UserId]map[types.EventName][]types.Notification, status uint64, eventName types.EventName, epoch uint64) error {
type dbResult struct {
Proposer uint64 `db:"proposer"`
Status uint64 `db:"status"`
@@ -1393,7 +1445,7 @@ func (n *validatorProposalNotification) GetInfoMarkdown() string {
return generalPart
}
-func collectAttestationAndOfflineValidatorNotifications(notificationsByUserID map[uint64]map[types.EventName][]types.Notification, epoch uint64) error {
+func collectAttestationAndOfflineValidatorNotifications(notificationsByUserID map[types.UserId]map[types.EventName][]types.Notification, epoch uint64) error {
subMap, err := GetSubsForEventFilter(types.ValidatorMissedAttestationEventName)
if err != nil {
return fmt.Errorf("error getting subscriptions for missted attestations %w", err)
@@ -1898,7 +1950,7 @@ func (n *validatorGotSlashedNotification) GetInfoMarkdown() string {
return generalPart
}
-func collectValidatorGotSlashedNotifications(notificationsByUserID map[uint64]map[types.EventName][]types.Notification, epoch uint64) error {
+func collectValidatorGotSlashedNotifications(notificationsByUserID map[types.UserId]map[types.EventName][]types.Notification, epoch uint64) error {
dbResult, err := db.GetValidatorsGotSlashed(epoch)
if err != nil {
return fmt.Errorf("error getting slashed validators from database, err: %w", err)
@@ -1919,7 +1971,7 @@ func collectValidatorGotSlashedNotifications(notificationsByUserID map[uint64]ma
var subscribers []struct {
Ref uint64 `db:"ref"`
Id uint64 `db:"id"`
- UserId uint64 `db:"user_id"`
+ UserId types.UserId `db:"user_id"`
UnsubscribeHash sql.NullString `db:"unsubscribe_hash"`
}
@@ -2020,7 +2072,7 @@ func (n *validatorWithdrawalNotification) GetInfoMarkdown() string {
}
// collectWithdrawalNotifications collects all notifications validator withdrawals
-func collectWithdrawalNotifications(notificationsByUserID map[uint64]map[types.EventName][]types.Notification, epoch uint64) error {
+func collectWithdrawalNotifications(notificationsByUserID map[types.UserId]map[types.EventName][]types.Notification, epoch uint64) error {
// get all users that are subscribed to this event (scale: a few thousand rows depending on how many users we have)
subMap, err := GetSubsForEventFilter(types.ValidatorReceivedWithdrawalEventName)
if err != nil {
@@ -2075,7 +2127,7 @@ func collectWithdrawalNotifications(notificationsByUserID map[uint64]map[types.E
type ethClientNotification struct {
SubscriptionID uint64
- UserID uint64
+ UserID types.UserId
Epoch uint64
EthClient string
EventFilter string
@@ -2183,12 +2235,12 @@ func (n *ethClientNotification) GetInfoMarkdown() string {
return generalPart
}
-func collectEthClientNotifications(notificationsByUserID map[uint64]map[types.EventName][]types.Notification, eventName types.EventName) error {
+func collectEthClientNotifications(notificationsByUserID map[types.UserId]map[types.EventName][]types.Notification, eventName types.EventName) error {
updatedClients := ethclients.GetUpdatedClients() //only check if there are new updates
for _, client := range updatedClients {
var dbResult []struct {
SubscriptionID uint64 `db:"id"`
- UserID uint64 `db:"user_id"`
+ UserID types.UserId `db:"user_id"`
Epoch uint64 `db:"created_epoch"`
EventFilter string `db:"event_filter"`
UnsubscribeHash sql.NullString `db:"unsubscribe_hash"`
@@ -2234,13 +2286,13 @@ func collectEthClientNotifications(notificationsByUserID map[uint64]map[types.Ev
type MachineEvents struct {
SubscriptionID uint64 `db:"id"`
- UserID uint64 `db:"user_id"`
+ UserID types.UserId `db:"user_id"`
MachineName string `db:"machine"`
UnsubscribeHash sql.NullString `db:"unsubscribe_hash"`
EventThreshold float64 `db:"event_threshold"`
}
-func collectMonitoringMachineOffline(notificationsByUserID map[uint64]map[types.EventName][]types.Notification, epoch uint64) error {
+func collectMonitoringMachineOffline(notificationsByUserID map[types.UserId]map[types.EventName][]types.Notification, epoch uint64) error {
nowTs := time.Now().Unix()
return collectMonitoringMachine(notificationsByUserID, types.MonitoringMachineOfflineEventName, 120,
// notify condition
@@ -2259,7 +2311,7 @@ func isMachineDataRecent(machineData *types.MachineMetricSystemUser) bool {
return machineData.CurrentDataInsertTs >= nowTs-60*60
}
-func collectMonitoringMachineDiskAlmostFull(notificationsByUserID map[uint64]map[types.EventName][]types.Notification, epoch uint64) error {
+func collectMonitoringMachineDiskAlmostFull(notificationsByUserID map[types.UserId]map[types.EventName][]types.Notification, epoch uint64) error {
return collectMonitoringMachine(notificationsByUserID, types.MonitoringMachineDiskAlmostFullEventName, 750,
// notify condition
func(subscribeData *MachineEvents, machineData *types.MachineMetricSystemUser) bool {
@@ -2274,7 +2326,7 @@ func collectMonitoringMachineDiskAlmostFull(notificationsByUserID map[uint64]map
)
}
-func collectMonitoringMachineCPULoad(notificationsByUserID map[uint64]map[types.EventName][]types.Notification, epoch uint64) error {
+func collectMonitoringMachineCPULoad(notificationsByUserID map[types.UserId]map[types.EventName][]types.Notification, epoch uint64) error {
return collectMonitoringMachine(notificationsByUserID, types.MonitoringMachineCpuLoadEventName, 10,
// notify condition
func(subscribeData *MachineEvents, machineData *types.MachineMetricSystemUser) bool {
@@ -2296,7 +2348,7 @@ func collectMonitoringMachineCPULoad(notificationsByUserID map[uint64]map[types.
)
}
-func collectMonitoringMachineMemoryUsage(notificationsByUserID map[uint64]map[types.EventName][]types.Notification, epoch uint64) error {
+func collectMonitoringMachineMemoryUsage(notificationsByUserID map[types.UserId]map[types.EventName][]types.Notification, epoch uint64) error {
return collectMonitoringMachine(notificationsByUserID, types.MonitoringMachineMemoryUsageEventName, 10,
// notify condition
func(subscribeData *MachineEvents, machineData *types.MachineMetricSystemUser) bool {
@@ -2317,7 +2369,7 @@ func collectMonitoringMachineMemoryUsage(notificationsByUserID map[uint64]map[ty
var isFirstNotificationCheck = true
func collectMonitoringMachine(
- notificationsByUserID map[uint64]map[types.EventName][]types.Notification,
+ notificationsByUserID map[types.UserId]map[types.EventName][]types.Notification,
eventName types.EventName,
epochWaitInBetween int,
notifyConditionFulfilled func(subscribeData *MachineEvents, machineData *types.MachineMetricSystemUser) bool,
@@ -2439,7 +2491,7 @@ func collectMonitoringMachine(
type monitorMachineNotification struct {
SubscriptionID uint64
MachineName string
- UserID uint64
+ UserID types.UserId
Epoch uint64
EventName types.EventName
UnsubscribeHash sql.NullString
@@ -2518,7 +2570,7 @@ func (n *monitorMachineNotification) GetInfoMarkdown() string {
type taxReportNotification struct {
SubscriptionID uint64
- UserID uint64
+ UserID types.UserId
Epoch uint64
EventFilter string
UnsubscribeHash sql.NullString
@@ -2598,7 +2650,7 @@ func (n *taxReportNotification) GetInfoMarkdown() string {
return n.GetInfo(false)
}
-func collectTaxReportNotificationNotifications(notificationsByUserID map[uint64]map[types.EventName][]types.Notification, eventName types.EventName) error {
+func collectTaxReportNotificationNotifications(notificationsByUserID map[types.UserId]map[types.EventName][]types.Notification, eventName types.EventName) error {
lastStatsDay, err := cache.LatestExportedStatisticDay.GetOrDefault(db.GetLastExportedStatisticDay)
if err != nil {
@@ -2613,7 +2665,7 @@ func collectTaxReportNotificationNotifications(notificationsByUserID map[uint64]
var dbResult []struct {
SubscriptionID uint64 `db:"id"`
- UserID uint64 `db:"user_id"`
+ UserID types.UserId `db:"user_id"`
Epoch uint64 `db:"created_epoch"`
EventFilter string `db:"event_filter"`
UnsubscribeHash sql.NullString `db:"unsubscribe_hash"`
@@ -2658,7 +2710,7 @@ func collectTaxReportNotificationNotifications(notificationsByUserID map[uint64]
type networkNotification struct {
SubscriptionID uint64
- UserID uint64
+ UserID types.UserId
Epoch uint64
EventFilter string
UnsubscribeHash sql.NullString
@@ -2709,7 +2761,7 @@ func (n *networkNotification) GetInfoMarkdown() string {
return generalPart
}
-func collectNetworkNotifications(notificationsByUserID map[uint64]map[types.EventName][]types.Notification, eventName types.EventName) error {
+func collectNetworkNotifications(notificationsByUserID map[types.UserId]map[types.EventName][]types.Notification, eventName types.EventName) error {
count := 0
err := db.WriterDb.Get(&count, `
SELECT count(ts) FROM network_liveness WHERE (headepoch-finalizedepoch) > 3 AND ts > now() - interval '60 minutes';
@@ -2722,7 +2774,7 @@ func collectNetworkNotifications(notificationsByUserID map[uint64]map[types.Even
if count > 0 {
var dbResult []struct {
SubscriptionID uint64 `db:"id"`
- UserID uint64 `db:"user_id"`
+ UserID types.UserId `db:"user_id"`
Epoch uint64 `db:"created_epoch"`
EventFilter string `db:"event_filter"`
UnsubscribeHash sql.NullString `db:"unsubscribe_hash"`
@@ -2763,7 +2815,7 @@ func collectNetworkNotifications(notificationsByUserID map[uint64]map[types.Even
type rocketpoolNotification struct {
SubscriptionID uint64
- UserID uint64
+ UserID types.UserId
Epoch uint64
EventFilter string
EventName types.EventName
@@ -2839,7 +2891,7 @@ func (n *rocketpoolNotification) GetInfoMarkdown() string {
return n.GetInfo(false)
}
-func collectRocketpoolComissionNotifications(notificationsByUserID map[uint64]map[types.EventName][]types.Notification, eventName types.EventName) error {
+func collectRocketpoolComissionNotifications(notificationsByUserID map[types.UserId]map[types.EventName][]types.Notification, eventName types.EventName) error {
fee := 0.0
err := db.WriterDb.Get(&fee, `
select current_node_fee from rocketpool_network_stats order by id desc LIMIT 1;
@@ -2852,7 +2904,7 @@ func collectRocketpoolComissionNotifications(notificationsByUserID map[uint64]ma
if fee > 0 {
var dbResult []struct {
SubscriptionID uint64 `db:"id"`
- UserID uint64 `db:"user_id"`
+ UserID types.UserId `db:"user_id"`
Epoch uint64 `db:"created_epoch"`
EventFilter string `db:"event_filter"`
UnsubscribeHash sql.NullString `db:"unsubscribe_hash"`
@@ -2893,7 +2945,7 @@ func collectRocketpoolComissionNotifications(notificationsByUserID map[uint64]ma
return nil
}
-func collectRocketpoolRewardClaimRoundNotifications(notificationsByUserID map[uint64]map[types.EventName][]types.Notification, eventName types.EventName) error {
+func collectRocketpoolRewardClaimRoundNotifications(notificationsByUserID map[types.UserId]map[types.EventName][]types.Notification, eventName types.EventName) error {
var ts int64
err := db.WriterDb.Get(&ts, `
select date_part('epoch', claim_interval_time_start)::int from rocketpool_network_stats order by id desc LIMIT 1;
@@ -2906,7 +2958,7 @@ func collectRocketpoolRewardClaimRoundNotifications(notificationsByUserID map[ui
if ts+3*60*60 > time.Now().Unix() {
var dbResult []struct {
SubscriptionID uint64 `db:"id"`
- UserID uint64 `db:"user_id"`
+ UserID types.UserId `db:"user_id"`
Epoch uint64 `db:"created_epoch"`
EventFilter string `db:"event_filter"`
UnsubscribeHash sql.NullString `db:"unsubscribe_hash"`
@@ -2946,7 +2998,7 @@ func collectRocketpoolRewardClaimRoundNotifications(notificationsByUserID map[ui
return nil
}
-func collectRocketpoolRPLCollateralNotifications(notificationsByUserID map[uint64]map[types.EventName][]types.Notification, eventName types.EventName, epoch uint64) error {
+func collectRocketpoolRPLCollateralNotifications(notificationsByUserID map[types.UserId]map[types.EventName][]types.Notification, eventName types.EventName, epoch uint64) error {
subMap, err := GetSubsForEventFilter(eventName)
if err != nil {
return fmt.Errorf("error getting subscriptions for RocketpoolRPLCollateral %w", err)
@@ -3124,7 +3176,7 @@ func bigFloat(x float64) *big.Float {
return new(big.Float).SetFloat64(x)
}
-func collectSyncCommittee(notificationsByUserID map[uint64]map[types.EventName][]types.Notification, eventName types.EventName, epoch uint64) error {
+func collectSyncCommittee(notificationsByUserID map[types.UserId]map[types.EventName][]types.Notification, eventName types.EventName, epoch uint64) error {
slotsPerSyncCommittee := utils.SlotsPerSyncCommittee()
currentPeriod := epoch * utils.Config.Chain.ClConfig.SlotsPerEpoch / slotsPerSyncCommittee
nextPeriod := currentPeriod + 1
@@ -3152,7 +3204,7 @@ func collectSyncCommittee(notificationsByUserID map[uint64]map[types.EventName][
var dbResult []struct {
SubscriptionID uint64 `db:"id"`
- UserID uint64 `db:"user_id"`
+ UserID types.UserId `db:"user_id"`
EventFilter string `db:"event_filter"`
UnsubscribeHash sql.NullString `db:"unsubscribe_hash"`
}
From 3aa7d8e8b56800b56551b52fd361169c34b3b39c Mon Sep 17 00:00:00 2001
From: peter <1674920+peterbitfly@users.noreply.github.com>
Date: Fri, 5 Jul 2024 09:37:07 +0200
Subject: [PATCH 04/39] ensure that there is never more than one notification
per user / type / filter combination
---
backend/pkg/commons/types/frontend.go | 2 +
backend/pkg/notification/notifications.go | 208 +++++++++-------------
2 files changed, 84 insertions(+), 126 deletions(-)
diff --git a/backend/pkg/commons/types/frontend.go b/backend/pkg/commons/types/frontend.go
index d91d60747..5367951a1 100644
--- a/backend/pkg/commons/types/frontend.go
+++ b/backend/pkg/commons/types/frontend.go
@@ -20,6 +20,8 @@ import (
)
type EventName string
+type EventFilter string
+type NotificationsPerUserId map[UserId]map[EventName]map[EventFilter]Notification
const (
ValidatorBalanceDecreasedEventName EventName = "validator_balance_decreased"
diff --git a/backend/pkg/notification/notifications.go b/backend/pkg/notification/notifications.go
index c408c1cdf..e2db123f1 100644
--- a/backend/pkg/notification/notifications.go
+++ b/backend/pkg/notification/notifications.go
@@ -225,8 +225,8 @@ func notificationSender() {
}
}
-func collectNotifications(epoch uint64) (map[types.UserId]map[types.EventName][]types.Notification, error) {
- notificationsByUserID := map[types.UserId]map[types.EventName][]types.Notification{}
+func collectNotifications(epoch uint64) (types.NotificationsPerUserId, error) {
+ notificationsByUserID := types.NotificationsPerUserId{}
start := time.Now()
var err error
var dbIsCoherent bool
@@ -408,8 +408,8 @@ func collectNotifications(epoch uint64) (map[types.UserId]map[types.EventName][]
return notificationsByUserID, nil
}
-func collectUserDbNotifications(epoch uint64) (map[types.UserId]map[types.EventName][]types.Notification, error) {
- notificationsByUserID := map[types.UserId]map[types.EventName][]types.Notification{}
+func collectUserDbNotifications(epoch uint64) (types.NotificationsPerUserId, error) {
+ notificationsByUserID := types.NotificationsPerUserId{}
var err error
// Monitoring (premium): machine offline
@@ -457,29 +457,9 @@ func collectUserDbNotifications(epoch uint64) (map[types.UserId]map[types.EventN
return notificationsByUserID, nil
}
-func queueNotifications(notificationsByUserID map[types.UserId]map[types.EventName][]types.Notification, useDB *sqlx.DB) {
+func queueNotifications(notificationsByUserID types.NotificationsPerUserId, useDB *sqlx.DB) {
subByEpoch := map[uint64][]uint64{}
- // prevent multiple events being sent with the same subscription id
- for user, notifications := range notificationsByUserID {
- for eventType, events := range notifications {
- filteredEvents := make([]types.Notification, 0)
-
- for _, ev := range events {
- isDuplicate := false
- for _, fe := range filteredEvents {
- if fe.GetSubscriptionID() == ev.GetSubscriptionID() {
- isDuplicate = true
- }
- }
- if !isDuplicate {
- filteredEvents = append(filteredEvents, ev)
- }
- }
- notificationsByUserID[user][eventType] = filteredEvents
- }
- }
-
err := queueEmailNotifications(notificationsByUserID, useDB)
if err != nil {
log.Error(err, "error queuing email notifications", 0)
@@ -593,7 +573,7 @@ func getNetwork() string {
return ""
}
-func queuePushNotification(notificationsByUserID map[types.UserId]map[types.EventName][]types.Notification, useDB *sqlx.DB) error {
+func queuePushNotification(notificationsByUserID types.NotificationsPerUserId, useDB *sqlx.DB) error {
userIDs := []types.UserId{}
for userID := range notificationsByUserID {
userIDs = append(userIDs, userID)
@@ -611,7 +591,7 @@ func queuePushNotification(notificationsByUserID map[types.UserId]map[types.Even
continue
}
- go func(userTokens []string, userNotifications map[types.EventName][]types.Notification) {
+ go func(userTokens []string, userNotifications map[types.EventName]map[types.EventFilter]types.Notification) {
var batch []*messaging.Message
for event, ns := range userNotifications {
for _, n := range ns {
@@ -698,7 +678,7 @@ func sendPushNotifications(useDB *sqlx.DB) error {
return nil
}
-func queueEmailNotifications(notificationsByUserID map[types.UserId]map[types.EventName][]types.Notification, useDB *sqlx.DB) error {
+func queueEmailNotifications(notificationsByUserID types.NotificationsPerUserId, useDB *sqlx.DB) error {
userIDs := []types.UserId{}
for userID := range notificationsByUserID {
userIDs = append(userIDs, userID)
@@ -717,7 +697,7 @@ func queueEmailNotifications(notificationsByUserID map[types.UserId]map[types.Ev
// metrics.Errors.WithLabelValues("notifications_mail_not_found").Inc()
continue
}
- go func(userEmail string, userNotifications map[types.EventName][]types.Notification) {
+ go func(userEmail string, userNotifications map[types.EventName]map[types.EventFilter]types.Notification) {
attachments := []types.EmailAttachment{}
var msg types.Email
@@ -741,7 +721,8 @@ func queueEmailNotifications(notificationsByUserID map[types.UserId]map[types.Ev
//nolint:gosec // this is a static string
msg.Body += template.HTML(fmt.Sprintf("%s
====
", types.EventLabel[event_title]))
unsubURL := "https://" + utils.Config.Frontend.SiteDomain + "/notifications/unsubscribe"
- for i, n := range ns {
+ i := 0
+ for _, n := range ns {
// Find all unique notification titles for the subject
title := n.GetTitle()
if _, ok := notificationTitlesMap[title]; !ok {
@@ -822,6 +803,7 @@ func queueEmailNotifications(notificationsByUserID map[types.UserId]map[types.Ev
}
metrics.NotificationsQueued.WithLabelValues("email", string(event)).Inc()
+ i++
}
eventInfo := getEventInfo(event, ns)
@@ -893,7 +875,7 @@ func sendEmailNotifications(useDb *sqlx.DB) error {
return nil
}
-func queueWebhookNotifications(notificationsByUserID map[types.UserId]map[types.EventName][]types.Notification, useDB *sqlx.DB) error {
+func queueWebhookNotifications(notificationsByUserID types.NotificationsPerUserId, useDB *sqlx.DB) error {
for userID, userNotifications := range notificationsByUserID {
var webhooks []types.UserWebhook
err := useDB.Select(&webhooks, `
@@ -1250,7 +1232,7 @@ func getUrlPart(validatorIndex uint64) string {
return fmt.Sprintf(` For more information visit: https://%s/validator/%v.`, utils.Config.Frontend.SiteDomain, validatorIndex, utils.Config.Frontend.SiteDomain, validatorIndex)
}
-func collectBlockProposalNotifications(notificationsByUserID map[types.UserId]map[types.EventName][]types.Notification, status uint64, eventName types.EventName, epoch uint64) error {
+func collectBlockProposalNotifications(notificationsByUserID types.NotificationsPerUserId, status uint64, eventName types.EventName, epoch uint64) error {
type dbResult struct {
Proposer uint64 `db:"proposer"`
Status uint64 `db:"status"`
@@ -1342,12 +1324,12 @@ func collectBlockProposalNotifications(notificationsByUserID map[types.UserId]ma
Slot: event.Slot,
}
if _, exists := notificationsByUserID[*sub.UserID]; !exists {
- notificationsByUserID[*sub.UserID] = map[types.EventName][]types.Notification{}
+ notificationsByUserID[*sub.UserID] = map[types.EventName]map[types.EventFilter]types.Notification{}
}
if _, exists := notificationsByUserID[*sub.UserID][n.GetEventName()]; !exists {
- notificationsByUserID[*sub.UserID][n.GetEventName()] = []types.Notification{}
+ notificationsByUserID[*sub.UserID][n.GetEventName()] = map[types.EventFilter]types.Notification{}
}
- notificationsByUserID[*sub.UserID][n.GetEventName()] = append(notificationsByUserID[*sub.UserID][n.GetEventName()], n)
+ notificationsByUserID[*sub.UserID][n.GetEventName()][types.EventFilter(n.EventFilter)] = n
metrics.NotificationsCollected.WithLabelValues(string(n.GetEventName())).Inc()
}
}
@@ -1445,7 +1427,7 @@ func (n *validatorProposalNotification) GetInfoMarkdown() string {
return generalPart
}
-func collectAttestationAndOfflineValidatorNotifications(notificationsByUserID map[types.UserId]map[types.EventName][]types.Notification, epoch uint64) error {
+func collectAttestationAndOfflineValidatorNotifications(notificationsByUserID types.NotificationsPerUserId, epoch uint64) error {
subMap, err := GetSubsForEventFilter(types.ValidatorMissedAttestationEventName)
if err != nil {
return fmt.Errorf("error getting subscriptions for missted attestations %w", err)
@@ -1530,21 +1512,12 @@ func collectAttestationAndOfflineValidatorNotifications(notificationsByUserID ma
EventFilter: hex.EncodeToString(event.EventFilter),
}
if _, exists := notificationsByUserID[*sub.UserID]; !exists {
- notificationsByUserID[*sub.UserID] = map[types.EventName][]types.Notification{}
+ notificationsByUserID[*sub.UserID] = map[types.EventName]map[types.EventFilter]types.Notification{}
}
if _, exists := notificationsByUserID[*sub.UserID][n.GetEventName()]; !exists {
- notificationsByUserID[*sub.UserID][n.GetEventName()] = []types.Notification{}
- }
- isDuplicate := false
- for _, userEvent := range notificationsByUserID[*sub.UserID][n.GetEventName()] {
- if userEvent.GetSubscriptionID() == n.SubscriptionID {
- isDuplicate = true
- }
+ notificationsByUserID[*sub.UserID][n.GetEventName()] = map[types.EventFilter]types.Notification{}
}
- if isDuplicate {
- continue
- }
- notificationsByUserID[*sub.UserID][n.GetEventName()] = append(notificationsByUserID[*sub.UserID][n.GetEventName()], n)
+ notificationsByUserID[*sub.UserID][n.GetEventName()][types.EventFilter(n.EventFilter)] = n
metrics.NotificationsCollected.WithLabelValues(string(n.GetEventName())).Inc()
}
}
@@ -1639,7 +1612,7 @@ func collectAttestationAndOfflineValidatorNotifications(notificationsByUserID ma
}
log.Infof("new event: validator %v detected as offline since epoch %v", validator.Index, epoch)
- n := validatorIsOfflineNotification{
+ n := &validatorIsOfflineNotification{
SubscriptionID: *sub.ID,
ValidatorIndex: validator.Index,
IsOffline: true,
@@ -1650,23 +1623,13 @@ func collectAttestationAndOfflineValidatorNotifications(notificationsByUserID ma
}
if _, exists := notificationsByUserID[*sub.UserID]; !exists {
- notificationsByUserID[*sub.UserID] = map[types.EventName][]types.Notification{}
+ notificationsByUserID[*sub.UserID] = map[types.EventName]map[types.EventFilter]types.Notification{}
}
if _, exists := notificationsByUserID[*sub.UserID][n.GetEventName()]; !exists {
- notificationsByUserID[*sub.UserID][n.GetEventName()] = []types.Notification{}
- }
- isDuplicate := false
- for _, userEvent := range notificationsByUserID[*sub.UserID][n.GetEventName()] {
- if userEvent.GetSubscriptionID() == n.SubscriptionID {
- isDuplicate = true
- break
- }
- }
- if isDuplicate {
- log.Infof("duplicate offline notification detected")
- continue
+ notificationsByUserID[*sub.UserID][n.GetEventName()] = map[types.EventFilter]types.Notification{}
}
- notificationsByUserID[*sub.UserID][n.GetEventName()] = append(notificationsByUserID[*sub.UserID][n.GetEventName()], &n)
+
+ notificationsByUserID[*sub.UserID][n.GetEventName()][types.EventFilter(n.EventFilter)] = n
metrics.NotificationsCollected.WithLabelValues(string(n.GetEventName())).Inc()
}
}
@@ -1697,7 +1660,7 @@ func collectAttestationAndOfflineValidatorNotifications(notificationsByUserID ma
log.Infof("new event: validator %v detected as online again at epoch %v", validator.Index, epoch)
- n := validatorIsOfflineNotification{
+ n := &validatorIsOfflineNotification{
SubscriptionID: *sub.ID,
ValidatorIndex: validator.Index,
IsOffline: false,
@@ -1709,23 +1672,12 @@ func collectAttestationAndOfflineValidatorNotifications(notificationsByUserID ma
}
if _, exists := notificationsByUserID[*sub.UserID]; !exists {
- notificationsByUserID[*sub.UserID] = map[types.EventName][]types.Notification{}
+ notificationsByUserID[*sub.UserID] = map[types.EventName]map[types.EventFilter]types.Notification{}
}
if _, exists := notificationsByUserID[*sub.UserID][n.GetEventName()]; !exists {
- notificationsByUserID[*sub.UserID][n.GetEventName()] = []types.Notification{}
- }
- isDuplicate := false
- for _, userEvent := range notificationsByUserID[*sub.UserID][n.GetEventName()] {
- if userEvent.GetSubscriptionID() == n.SubscriptionID {
- isDuplicate = true
- break
- }
- }
- if isDuplicate {
- log.Infof("duplicate online notification detected")
- continue
+ notificationsByUserID[*sub.UserID][n.GetEventName()] = map[types.EventFilter]types.Notification{}
}
- notificationsByUserID[*sub.UserID][n.GetEventName()] = append(notificationsByUserID[*sub.UserID][n.GetEventName()], &n)
+ notificationsByUserID[*sub.UserID][n.GetEventName()][types.EventFilter(n.EventFilter)] = n
metrics.NotificationsCollected.WithLabelValues(string(n.GetEventName())).Inc()
}
}
@@ -1950,7 +1902,7 @@ func (n *validatorGotSlashedNotification) GetInfoMarkdown() string {
return generalPart
}
-func collectValidatorGotSlashedNotifications(notificationsByUserID map[types.UserId]map[types.EventName][]types.Notification, epoch uint64) error {
+func collectValidatorGotSlashedNotifications(notificationsByUserID types.NotificationsPerUserId, epoch uint64) error {
dbResult, err := db.GetValidatorsGotSlashed(epoch)
if err != nil {
return fmt.Errorf("error getting slashed validators from database, err: %w", err)
@@ -2000,12 +1952,12 @@ func collectValidatorGotSlashedNotifications(notificationsByUserID map[types.Use
}
if _, exists := notificationsByUserID[sub.UserId]; !exists {
- notificationsByUserID[sub.UserId] = map[types.EventName][]types.Notification{}
+ notificationsByUserID[sub.UserId] = map[types.EventName]map[types.EventFilter]types.Notification{}
}
if _, exists := notificationsByUserID[sub.UserId][n.GetEventName()]; !exists {
- notificationsByUserID[sub.UserId][n.GetEventName()] = []types.Notification{}
+ notificationsByUserID[sub.UserId][n.GetEventName()] = map[types.EventFilter]types.Notification{}
}
- notificationsByUserID[sub.UserId][n.GetEventName()] = append(notificationsByUserID[sub.UserId][n.GetEventName()], n)
+ notificationsByUserID[sub.UserId][n.GetEventName()][types.EventFilter(n.EventFilter)] = n
metrics.NotificationsCollected.WithLabelValues(string(n.GetEventName())).Inc()
}
@@ -2072,7 +2024,7 @@ func (n *validatorWithdrawalNotification) GetInfoMarkdown() string {
}
// collectWithdrawalNotifications collects all notifications validator withdrawals
-func collectWithdrawalNotifications(notificationsByUserID map[types.UserId]map[types.EventName][]types.Notification, epoch uint64) error {
+func collectWithdrawalNotifications(notificationsByUserID types.NotificationsPerUserId, epoch uint64) error {
// get all users that are subscribed to this event (scale: a few thousand rows depending on how many users we have)
subMap, err := GetSubsForEventFilter(types.ValidatorReceivedWithdrawalEventName)
if err != nil {
@@ -2111,12 +2063,12 @@ func collectWithdrawalNotifications(notificationsByUserID map[types.UserId]map[t
UnsubscribeHash: sub.UnsubscribeHash,
}
if _, exists := notificationsByUserID[*sub.UserID]; !exists {
- notificationsByUserID[*sub.UserID] = map[types.EventName][]types.Notification{}
+ notificationsByUserID[*sub.UserID] = map[types.EventName]map[types.EventFilter]types.Notification{}
}
if _, exists := notificationsByUserID[*sub.UserID][n.GetEventName()]; !exists {
- notificationsByUserID[*sub.UserID][n.GetEventName()] = []types.Notification{}
+ notificationsByUserID[*sub.UserID][n.GetEventName()] = map[types.EventFilter]types.Notification{}
}
- notificationsByUserID[*sub.UserID][n.GetEventName()] = append(notificationsByUserID[*sub.UserID][n.GetEventName()], n)
+ notificationsByUserID[*sub.UserID][n.GetEventName()][types.EventFilter(n.EventFilter)] = n
metrics.NotificationsCollected.WithLabelValues(string(n.GetEventName())).Inc()
}
}
@@ -2235,7 +2187,7 @@ func (n *ethClientNotification) GetInfoMarkdown() string {
return generalPart
}
-func collectEthClientNotifications(notificationsByUserID map[types.UserId]map[types.EventName][]types.Notification, eventName types.EventName) error {
+func collectEthClientNotifications(notificationsByUserID types.NotificationsPerUserId, eventName types.EventName) error {
updatedClients := ethclients.GetUpdatedClients() //only check if there are new updates
for _, client := range updatedClients {
var dbResult []struct {
@@ -2272,12 +2224,12 @@ func collectEthClientNotifications(notificationsByUserID map[types.UserId]map[ty
UnsubscribeHash: r.UnsubscribeHash,
}
if _, exists := notificationsByUserID[r.UserID]; !exists {
- notificationsByUserID[r.UserID] = map[types.EventName][]types.Notification{}
+ notificationsByUserID[r.UserID] = map[types.EventName]map[types.EventFilter]types.Notification{}
}
if _, exists := notificationsByUserID[r.UserID][n.GetEventName()]; !exists {
- notificationsByUserID[r.UserID][n.GetEventName()] = []types.Notification{}
+ notificationsByUserID[r.UserID][n.GetEventName()] = map[types.EventFilter]types.Notification{}
}
- notificationsByUserID[r.UserID][n.GetEventName()] = append(notificationsByUserID[r.UserID][n.GetEventName()], n)
+ notificationsByUserID[r.UserID][n.GetEventName()][types.EventFilter(n.EventFilter)] = n
metrics.NotificationsCollected.WithLabelValues(string(n.GetEventName())).Inc()
}
}
@@ -2292,7 +2244,7 @@ type MachineEvents struct {
EventThreshold float64 `db:"event_threshold"`
}
-func collectMonitoringMachineOffline(notificationsByUserID map[types.UserId]map[types.EventName][]types.Notification, epoch uint64) error {
+func collectMonitoringMachineOffline(notificationsByUserID types.NotificationsPerUserId, epoch uint64) error {
nowTs := time.Now().Unix()
return collectMonitoringMachine(notificationsByUserID, types.MonitoringMachineOfflineEventName, 120,
// notify condition
@@ -2311,7 +2263,7 @@ func isMachineDataRecent(machineData *types.MachineMetricSystemUser) bool {
return machineData.CurrentDataInsertTs >= nowTs-60*60
}
-func collectMonitoringMachineDiskAlmostFull(notificationsByUserID map[types.UserId]map[types.EventName][]types.Notification, epoch uint64) error {
+func collectMonitoringMachineDiskAlmostFull(notificationsByUserID types.NotificationsPerUserId, epoch uint64) error {
return collectMonitoringMachine(notificationsByUserID, types.MonitoringMachineDiskAlmostFullEventName, 750,
// notify condition
func(subscribeData *MachineEvents, machineData *types.MachineMetricSystemUser) bool {
@@ -2326,7 +2278,7 @@ func collectMonitoringMachineDiskAlmostFull(notificationsByUserID map[types.User
)
}
-func collectMonitoringMachineCPULoad(notificationsByUserID map[types.UserId]map[types.EventName][]types.Notification, epoch uint64) error {
+func collectMonitoringMachineCPULoad(notificationsByUserID types.NotificationsPerUserId, epoch uint64) error {
return collectMonitoringMachine(notificationsByUserID, types.MonitoringMachineCpuLoadEventName, 10,
// notify condition
func(subscribeData *MachineEvents, machineData *types.MachineMetricSystemUser) bool {
@@ -2348,7 +2300,7 @@ func collectMonitoringMachineCPULoad(notificationsByUserID map[types.UserId]map[
)
}
-func collectMonitoringMachineMemoryUsage(notificationsByUserID map[types.UserId]map[types.EventName][]types.Notification, epoch uint64) error {
+func collectMonitoringMachineMemoryUsage(notificationsByUserID types.NotificationsPerUserId, epoch uint64) error {
return collectMonitoringMachine(notificationsByUserID, types.MonitoringMachineMemoryUsageEventName, 10,
// notify condition
func(subscribeData *MachineEvents, machineData *types.MachineMetricSystemUser) bool {
@@ -2369,7 +2321,7 @@ func collectMonitoringMachineMemoryUsage(notificationsByUserID map[types.UserId]
var isFirstNotificationCheck = true
func collectMonitoringMachine(
- notificationsByUserID map[types.UserId]map[types.EventName][]types.Notification,
+ notificationsByUserID types.NotificationsPerUserId,
eventName types.EventName,
epochWaitInBetween int,
notifyConditionFulfilled func(subscribeData *MachineEvents, machineData *types.MachineMetricSystemUser) bool,
@@ -2471,12 +2423,12 @@ func collectMonitoringMachine(
}
//logrus.Infof("notify %v %v", eventName, n)
if _, exists := notificationsByUserID[r.UserID]; !exists {
- notificationsByUserID[r.UserID] = map[types.EventName][]types.Notification{}
+ notificationsByUserID[r.UserID] = map[types.EventName]map[types.EventFilter]types.Notification{}
}
if _, exists := notificationsByUserID[r.UserID][n.GetEventName()]; !exists {
- notificationsByUserID[r.UserID][n.GetEventName()] = []types.Notification{}
+ notificationsByUserID[r.UserID][n.GetEventName()] = map[types.EventFilter]types.Notification{}
}
- notificationsByUserID[r.UserID][n.GetEventName()] = append(notificationsByUserID[r.UserID][n.GetEventName()], n)
+ notificationsByUserID[r.UserID][n.GetEventName()][types.EventFilter(n.GetEventFilter())] = n
metrics.NotificationsCollected.WithLabelValues(string(n.GetEventName())).Inc()
}
@@ -2650,7 +2602,7 @@ func (n *taxReportNotification) GetInfoMarkdown() string {
return n.GetInfo(false)
}
-func collectTaxReportNotificationNotifications(notificationsByUserID map[types.UserId]map[types.EventName][]types.Notification, eventName types.EventName) error {
+func collectTaxReportNotificationNotifications(notificationsByUserID types.NotificationsPerUserId, eventName types.EventName) error {
lastStatsDay, err := cache.LatestExportedStatisticDay.GetOrDefault(db.GetLastExportedStatisticDay)
if err != nil {
@@ -2696,12 +2648,12 @@ func collectTaxReportNotificationNotifications(notificationsByUserID map[types.U
UnsubscribeHash: r.UnsubscribeHash,
}
if _, exists := notificationsByUserID[r.UserID]; !exists {
- notificationsByUserID[r.UserID] = map[types.EventName][]types.Notification{}
+ notificationsByUserID[r.UserID] = map[types.EventName]map[types.EventFilter]types.Notification{}
}
if _, exists := notificationsByUserID[r.UserID][n.GetEventName()]; !exists {
- notificationsByUserID[r.UserID][n.GetEventName()] = []types.Notification{}
+ notificationsByUserID[r.UserID][n.GetEventName()] = map[types.EventFilter]types.Notification{}
}
- notificationsByUserID[r.UserID][n.GetEventName()] = append(notificationsByUserID[r.UserID][n.GetEventName()], n)
+ notificationsByUserID[r.UserID][n.GetEventName()][types.EventFilter(n.GetEventFilter())] = n
metrics.NotificationsCollected.WithLabelValues(string(n.GetEventName())).Inc()
}
@@ -2761,7 +2713,7 @@ func (n *networkNotification) GetInfoMarkdown() string {
return generalPart
}
-func collectNetworkNotifications(notificationsByUserID map[types.UserId]map[types.EventName][]types.Notification, eventName types.EventName) error {
+func collectNetworkNotifications(notificationsByUserID types.NotificationsPerUserId, eventName types.EventName) error {
count := 0
err := db.WriterDb.Get(&count, `
SELECT count(ts) FROM network_liveness WHERE (headepoch-finalizedepoch) > 3 AND ts > now() - interval '60 minutes';
@@ -2800,12 +2752,12 @@ func collectNetworkNotifications(notificationsByUserID map[types.UserId]map[type
UnsubscribeHash: r.UnsubscribeHash,
}
if _, exists := notificationsByUserID[r.UserID]; !exists {
- notificationsByUserID[r.UserID] = map[types.EventName][]types.Notification{}
+ notificationsByUserID[r.UserID] = map[types.EventName]map[types.EventFilter]types.Notification{}
}
if _, exists := notificationsByUserID[r.UserID][n.GetEventName()]; !exists {
- notificationsByUserID[r.UserID][n.GetEventName()] = []types.Notification{}
+ notificationsByUserID[r.UserID][n.GetEventName()] = map[types.EventFilter]types.Notification{}
}
- notificationsByUserID[r.UserID][n.GetEventName()] = append(notificationsByUserID[r.UserID][n.GetEventName()], n)
+ notificationsByUserID[r.UserID][n.GetEventName()][types.EventFilter(n.EventFilter)] = n
metrics.NotificationsCollected.WithLabelValues(string(n.GetEventName())).Inc()
}
}
@@ -2861,7 +2813,9 @@ func (n *rocketpoolNotification) GetInfo(includeUrl bool) string {
case types.RocketpoolCollateralMinReached:
return fmt.Sprintf(`Your RPL collateral has reached your configured threshold at %v%%.`, n.ExtraData)
case types.SyncCommitteeSoon:
- return getSyncCommitteeSoonInfo([]types.Notification{n})
+ return getSyncCommitteeSoonInfo(map[types.EventFilter]types.Notification{
+ types.EventFilter(n.EventFilter): n,
+ })
}
return ""
@@ -2891,7 +2845,7 @@ func (n *rocketpoolNotification) GetInfoMarkdown() string {
return n.GetInfo(false)
}
-func collectRocketpoolComissionNotifications(notificationsByUserID map[types.UserId]map[types.EventName][]types.Notification, eventName types.EventName) error {
+func collectRocketpoolComissionNotifications(notificationsByUserID types.NotificationsPerUserId, eventName types.EventName) error {
fee := 0.0
err := db.WriterDb.Get(&fee, `
select current_node_fee from rocketpool_network_stats order by id desc LIMIT 1;
@@ -2932,12 +2886,12 @@ func collectRocketpoolComissionNotifications(notificationsByUserID map[types.Use
UnsubscribeHash: r.UnsubscribeHash,
}
if _, exists := notificationsByUserID[r.UserID]; !exists {
- notificationsByUserID[r.UserID] = map[types.EventName][]types.Notification{}
+ notificationsByUserID[r.UserID] = map[types.EventName]map[types.EventFilter]types.Notification{}
}
if _, exists := notificationsByUserID[r.UserID][n.GetEventName()]; !exists {
- notificationsByUserID[r.UserID][n.GetEventName()] = []types.Notification{}
+ notificationsByUserID[r.UserID][n.GetEventName()] = map[types.EventFilter]types.Notification{}
}
- notificationsByUserID[r.UserID][n.GetEventName()] = append(notificationsByUserID[r.UserID][n.GetEventName()], n)
+ notificationsByUserID[r.UserID][n.GetEventName()][types.EventFilter(n.EventFilter)] = n
metrics.NotificationsCollected.WithLabelValues(string(n.GetEventName())).Inc()
}
}
@@ -2945,7 +2899,7 @@ func collectRocketpoolComissionNotifications(notificationsByUserID map[types.Use
return nil
}
-func collectRocketpoolRewardClaimRoundNotifications(notificationsByUserID map[types.UserId]map[types.EventName][]types.Notification, eventName types.EventName) error {
+func collectRocketpoolRewardClaimRoundNotifications(notificationsByUserID types.NotificationsPerUserId, eventName types.EventName) error {
var ts int64
err := db.WriterDb.Get(&ts, `
select date_part('epoch', claim_interval_time_start)::int from rocketpool_network_stats order by id desc LIMIT 1;
@@ -2985,12 +2939,12 @@ func collectRocketpoolRewardClaimRoundNotifications(notificationsByUserID map[ty
UnsubscribeHash: r.UnsubscribeHash,
}
if _, exists := notificationsByUserID[r.UserID]; !exists {
- notificationsByUserID[r.UserID] = map[types.EventName][]types.Notification{}
+ notificationsByUserID[r.UserID] = map[types.EventName]map[types.EventFilter]types.Notification{}
}
if _, exists := notificationsByUserID[r.UserID][n.GetEventName()]; !exists {
- notificationsByUserID[r.UserID][n.GetEventName()] = []types.Notification{}
+ notificationsByUserID[r.UserID][n.GetEventName()] = map[types.EventFilter]types.Notification{}
}
- notificationsByUserID[r.UserID][n.GetEventName()] = append(notificationsByUserID[r.UserID][n.GetEventName()], n)
+ notificationsByUserID[r.UserID][n.GetEventName()][types.EventFilter(n.EventFilter)] = n
metrics.NotificationsCollected.WithLabelValues(string(n.GetEventName())).Inc()
}
}
@@ -2998,7 +2952,7 @@ func collectRocketpoolRewardClaimRoundNotifications(notificationsByUserID map[ty
return nil
}
-func collectRocketpoolRPLCollateralNotifications(notificationsByUserID map[types.UserId]map[types.EventName][]types.Notification, eventName types.EventName, epoch uint64) error {
+func collectRocketpoolRPLCollateralNotifications(notificationsByUserID types.NotificationsPerUserId, eventName types.EventName, epoch uint64) error {
subMap, err := GetSubsForEventFilter(eventName)
if err != nil {
return fmt.Errorf("error getting subscriptions for RocketpoolRPLCollateral %w", err)
@@ -3123,12 +3077,12 @@ func collectRocketpoolRPLCollateralNotifications(notificationsByUserID map[types
UnsubscribeHash: sub.UnsubscribeHash,
}
if _, exists := notificationsByUserID[*sub.UserID]; !exists {
- notificationsByUserID[*sub.UserID] = map[types.EventName][]types.Notification{}
+ notificationsByUserID[*sub.UserID] = map[types.EventName]map[types.EventFilter]types.Notification{}
}
if _, exists := notificationsByUserID[*sub.UserID][n.GetEventName()]; !exists {
- notificationsByUserID[*sub.UserID][n.GetEventName()] = []types.Notification{}
+ notificationsByUserID[*sub.UserID][n.GetEventName()] = map[types.EventFilter]types.Notification{}
}
- notificationsByUserID[*sub.UserID][n.GetEventName()] = append(notificationsByUserID[*sub.UserID][n.GetEventName()], n)
+ notificationsByUserID[*sub.UserID][n.GetEventName()][types.EventFilter(n.EventFilter)] = n
metrics.NotificationsCollected.WithLabelValues(string(n.GetEventName())).Inc()
}
@@ -3176,7 +3130,7 @@ func bigFloat(x float64) *big.Float {
return new(big.Float).SetFloat64(x)
}
-func collectSyncCommittee(notificationsByUserID map[types.UserId]map[types.EventName][]types.Notification, eventName types.EventName, epoch uint64) error {
+func collectSyncCommittee(notificationsByUserID types.NotificationsPerUserId, eventName types.EventName, epoch uint64) error {
slotsPerSyncCommittee := utils.SlotsPerSyncCommittee()
currentPeriod := epoch * utils.Config.Chain.ClConfig.SlotsPerEpoch / slotsPerSyncCommittee
nextPeriod := currentPeriod + 1
@@ -3232,12 +3186,12 @@ func collectSyncCommittee(notificationsByUserID map[types.UserId]map[types.Event
UnsubscribeHash: r.UnsubscribeHash,
}
if _, exists := notificationsByUserID[r.UserID]; !exists {
- notificationsByUserID[r.UserID] = map[types.EventName][]types.Notification{}
+ notificationsByUserID[r.UserID] = map[types.EventName]map[types.EventFilter]types.Notification{}
}
if _, exists := notificationsByUserID[r.UserID][n.GetEventName()]; !exists {
- notificationsByUserID[r.UserID][n.GetEventName()] = []types.Notification{}
+ notificationsByUserID[r.UserID][n.GetEventName()] = map[types.EventFilter]types.Notification{}
}
- notificationsByUserID[r.UserID][n.GetEventName()] = append(notificationsByUserID[r.UserID][n.GetEventName()], n)
+ notificationsByUserID[r.UserID][n.GetEventName()][types.EventFilter(n.EventFilter)] = n
metrics.NotificationsCollected.WithLabelValues(string(n.GetEventName())).Inc()
}
@@ -3254,7 +3208,7 @@ type WebhookQueue struct {
LastTry time.Time `db:"last_try"`
}
-func getEventInfo(event types.EventName, ns []types.Notification) string {
+func getEventInfo(event types.EventName, ns map[types.EventFilter]types.Notification) string {
switch event {
case types.SyncCommitteeSoon:
return getSyncCommitteeSoonInfo(ns)
@@ -3265,12 +3219,13 @@ func getEventInfo(event types.EventName, ns []types.Notification) string {
return ""
}
-func getSyncCommitteeSoonInfo(ns []types.Notification) string {
+func getSyncCommitteeSoonInfo(ns map[types.EventFilter]types.Notification) string {
validators := []string{}
var startEpoch, endEpoch string
var inTime time.Duration
- for i, n := range ns {
+ i := 0
+ for _, n := range ns {
n, ok := n.(*rocketpoolNotification)
if !ok {
log.Error(nil, "Sync committee notification not of type rocketpoolNotification", 0)
@@ -3296,6 +3251,7 @@ func getSyncCommitteeSoonInfo(ns []types.Notification) string {
}
inTime = inTime.Round(time.Second)
}
+ i++
}
if len(validators) > 0 {
From 9661fee2a15be88d2834bb0e15d61d80dde0a5b0 Mon Sep 17 00:00:00 2001
From: peter <1674920+peterbitfly@users.noreply.github.com>
Date: Fri, 5 Jul 2024 09:54:42 +0200
Subject: [PATCH 05/39] simplify collecting notifications
---
backend/pkg/commons/types/frontend.go | 25 ++++
backend/pkg/notification/notifications.go | 168 +++++++++-------------
2 files changed, 93 insertions(+), 100 deletions(-)
diff --git a/backend/pkg/commons/types/frontend.go b/backend/pkg/commons/types/frontend.go
index 5367951a1..467f6f5c7 100644
--- a/backend/pkg/commons/types/frontend.go
+++ b/backend/pkg/commons/types/frontend.go
@@ -4,6 +4,7 @@ import (
"database/sql"
"database/sql/driver"
"encoding/json"
+ "fmt"
"html/template"
"math/big"
"strings"
@@ -12,6 +13,7 @@ import (
"firebase.google.com/go/messaging"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
+ "github.com/gobitfly/beaconchain/pkg/commons/log"
"github.com/gobitfly/beaconchain/pkg/consapi/types"
"github.com/lib/pq"
"github.com/pkg/errors"
@@ -21,8 +23,30 @@ import (
type EventName string
type EventFilter string
+
type NotificationsPerUserId map[UserId]map[EventName]map[EventFilter]Notification
+func (npui NotificationsPerUserId) AddNotification(n Notification) {
+
+ if n.GetUserId() == 0 {
+ log.Fatal(fmt.Errorf("Notification user id is 0"), fmt.Sprintf("Notification: %v", n), 0)
+ }
+ if n.GetEventName() == "" {
+ log.Fatal(fmt.Errorf("Notification event name is empty"), fmt.Sprintf("Notification: %v", n), 0)
+ }
+ if n.GetEventFilter() == "" {
+ log.Fatal(fmt.Errorf("Notification event filter is empty"), fmt.Sprintf("Notification: %v", n), 0)
+ }
+
+ if _, ok := npui[n.GetUserId()]; !ok {
+ npui[n.GetUserId()] = make(map[EventName]map[EventFilter]Notification)
+ }
+ if _, ok := npui[n.GetUserId()][n.GetEventName()]; !ok {
+ npui[n.GetUserId()][EventName(n.GetEventFilter())] = make(map[EventFilter]Notification)
+ }
+ npui[n.GetUserId()][n.GetEventName()][EventFilter(n.GetEventFilter())] = n
+}
+
const (
ValidatorBalanceDecreasedEventName EventName = "validator_balance_decreased"
ValidatorMissedProposalEventName EventName = "validator_proposal_missed"
@@ -252,6 +276,7 @@ type Notification interface {
GetEmailAttachment() *EmailAttachment
GetUnsubscribeHash() string
GetInfoMarkdown() string
+ GetUserId() UserId
}
// func UnMarschal
diff --git a/backend/pkg/notification/notifications.go b/backend/pkg/notification/notifications.go
index e2db123f1..f39309de9 100644
--- a/backend/pkg/notification/notifications.go
+++ b/backend/pkg/notification/notifications.go
@@ -1315,6 +1315,7 @@ func collectBlockProposalNotifications(notificationsByUserID types.Notifications
log.Infof("creating %v notification for validator %v in epoch %v", eventName, event.Proposer, epoch)
n := &validatorProposalNotification{
SubscriptionID: *sub.ID,
+ UserID: *sub.UserID,
ValidatorIndex: event.Proposer,
Epoch: epoch,
Status: event.Status,
@@ -1323,13 +1324,7 @@ func collectBlockProposalNotifications(notificationsByUserID types.Notifications
EventFilter: hex.EncodeToString(pubkey),
Slot: event.Slot,
}
- if _, exists := notificationsByUserID[*sub.UserID]; !exists {
- notificationsByUserID[*sub.UserID] = map[types.EventName]map[types.EventFilter]types.Notification{}
- }
- if _, exists := notificationsByUserID[*sub.UserID][n.GetEventName()]; !exists {
- notificationsByUserID[*sub.UserID][n.GetEventName()] = map[types.EventFilter]types.Notification{}
- }
- notificationsByUserID[*sub.UserID][n.GetEventName()][types.EventFilter(n.EventFilter)] = n
+ notificationsByUserID.AddNotification(n)
metrics.NotificationsCollected.WithLabelValues(string(n.GetEventName())).Inc()
}
}
@@ -1339,6 +1334,7 @@ func collectBlockProposalNotifications(notificationsByUserID types.Notifications
type validatorProposalNotification struct {
SubscriptionID uint64
+ UserID types.UserId
ValidatorIndex uint64
ValidatorPublicKey string
Epoch uint64
@@ -1350,6 +1346,10 @@ type validatorProposalNotification struct {
UnsubscribeHash sql.NullString
}
+func (n *validatorProposalNotification) GetUserId() types.UserId {
+ return n.UserID
+}
+
func (n *validatorProposalNotification) GetLatestState() string {
return ""
}
@@ -1505,19 +1505,14 @@ func collectAttestationAndOfflineValidatorNotifications(notificationsByUserID ty
log.Infof("creating %v notification for validator %v in epoch %v", types.ValidatorMissedAttestationEventName, event.ValidatorIndex, event.Epoch)
n := &validatorAttestationNotification{
SubscriptionID: *sub.ID,
+ UserID: *sub.UserID,
ValidatorIndex: event.ValidatorIndex,
Epoch: event.Epoch,
Status: event.Status,
EventName: types.ValidatorMissedAttestationEventName,
EventFilter: hex.EncodeToString(event.EventFilter),
}
- if _, exists := notificationsByUserID[*sub.UserID]; !exists {
- notificationsByUserID[*sub.UserID] = map[types.EventName]map[types.EventFilter]types.Notification{}
- }
- if _, exists := notificationsByUserID[*sub.UserID][n.GetEventName()]; !exists {
- notificationsByUserID[*sub.UserID][n.GetEventName()] = map[types.EventFilter]types.Notification{}
- }
- notificationsByUserID[*sub.UserID][n.GetEventName()][types.EventFilter(n.EventFilter)] = n
+ notificationsByUserID.AddNotification(n)
metrics.NotificationsCollected.WithLabelValues(string(n.GetEventName())).Inc()
}
}
@@ -1622,14 +1617,7 @@ func collectAttestationAndOfflineValidatorNotifications(notificationsByUserID ty
EventFilter: hex.EncodeToString(validator.Pubkey),
}
- if _, exists := notificationsByUserID[*sub.UserID]; !exists {
- notificationsByUserID[*sub.UserID] = map[types.EventName]map[types.EventFilter]types.Notification{}
- }
- if _, exists := notificationsByUserID[*sub.UserID][n.GetEventName()]; !exists {
- notificationsByUserID[*sub.UserID][n.GetEventName()] = map[types.EventFilter]types.Notification{}
- }
-
- notificationsByUserID[*sub.UserID][n.GetEventName()][types.EventFilter(n.EventFilter)] = n
+ notificationsByUserID.AddNotification(n)
metrics.NotificationsCollected.WithLabelValues(string(n.GetEventName())).Inc()
}
}
@@ -1662,6 +1650,7 @@ func collectAttestationAndOfflineValidatorNotifications(notificationsByUserID ty
n := &validatorIsOfflineNotification{
SubscriptionID: *sub.ID,
+ UserID: *sub.UserID,
ValidatorIndex: validator.Index,
IsOffline: false,
EventEpoch: epoch,
@@ -1671,13 +1660,7 @@ func collectAttestationAndOfflineValidatorNotifications(notificationsByUserID ty
EpochsOffline: epochsSinceOffline,
}
- if _, exists := notificationsByUserID[*sub.UserID]; !exists {
- notificationsByUserID[*sub.UserID] = map[types.EventName]map[types.EventFilter]types.Notification{}
- }
- if _, exists := notificationsByUserID[*sub.UserID][n.GetEventName()]; !exists {
- notificationsByUserID[*sub.UserID][n.GetEventName()] = map[types.EventFilter]types.Notification{}
- }
- notificationsByUserID[*sub.UserID][n.GetEventName()][types.EventFilter(n.EventFilter)] = n
+ notificationsByUserID.AddNotification(n)
metrics.NotificationsCollected.WithLabelValues(string(n.GetEventName())).Inc()
}
}
@@ -1687,6 +1670,7 @@ func collectAttestationAndOfflineValidatorNotifications(notificationsByUserID ty
type validatorIsOfflineNotification struct {
SubscriptionID uint64
+ UserID types.UserId
ValidatorIndex uint64
EventEpoch uint64
EpochsOffline uint64
@@ -1697,6 +1681,10 @@ type validatorIsOfflineNotification struct {
InternalState string
}
+func (n *validatorIsOfflineNotification) GetUserId() types.UserId {
+ return n.UserID
+}
+
func (n *validatorIsOfflineNotification) GetLatestState() string {
return n.InternalState
}
@@ -1762,6 +1750,7 @@ func (n *validatorIsOfflineNotification) GetInfoMarkdown() string {
type validatorAttestationNotification struct {
SubscriptionID uint64
+ UserID types.UserId
ValidatorIndex uint64
ValidatorPublicKey string
Epoch uint64
@@ -1771,6 +1760,10 @@ type validatorAttestationNotification struct {
UnsubscribeHash sql.NullString
}
+func (n *validatorAttestationNotification) GetUserId() types.UserId {
+ return n.UserID
+}
+
func (n *validatorAttestationNotification) GetLatestState() string {
return ""
}
@@ -1846,6 +1839,7 @@ func (n *validatorAttestationNotification) GetInfoMarkdown() string {
type validatorGotSlashedNotification struct {
SubscriptionID uint64
+ UserID types.UserId
ValidatorIndex uint64
Epoch uint64
Slasher uint64
@@ -1854,6 +1848,10 @@ type validatorGotSlashedNotification struct {
UnsubscribeHash sql.NullString
}
+func (n *validatorGotSlashedNotification) GetUserId() types.UserId {
+ return n.UserID
+}
+
func (n *validatorGotSlashedNotification) GetLatestState() string {
return ""
}
@@ -1943,6 +1941,7 @@ func collectValidatorGotSlashedNotifications(notificationsByUserID types.Notific
n := &validatorGotSlashedNotification{
SubscriptionID: sub.Id,
+ UserID: sub.UserId,
Slasher: event.SlasherIndex,
Epoch: event.Epoch,
Reason: event.Reason,
@@ -1950,14 +1949,7 @@ func collectValidatorGotSlashedNotifications(notificationsByUserID types.Notific
EventFilter: hex.EncodeToString(event.SlashedValidatorPubkey),
UnsubscribeHash: sub.UnsubscribeHash,
}
-
- if _, exists := notificationsByUserID[sub.UserId]; !exists {
- notificationsByUserID[sub.UserId] = map[types.EventName]map[types.EventFilter]types.Notification{}
- }
- if _, exists := notificationsByUserID[sub.UserId][n.GetEventName()]; !exists {
- notificationsByUserID[sub.UserId][n.GetEventName()] = map[types.EventFilter]types.Notification{}
- }
- notificationsByUserID[sub.UserId][n.GetEventName()][types.EventFilter(n.EventFilter)] = n
+ notificationsByUserID.AddNotification(n)
metrics.NotificationsCollected.WithLabelValues(string(n.GetEventName())).Inc()
}
@@ -1965,6 +1957,7 @@ func collectValidatorGotSlashedNotifications(notificationsByUserID types.Notific
}
type validatorWithdrawalNotification struct {
+ UserID types.UserId
SubscriptionID uint64
ValidatorIndex uint64
Epoch uint64
@@ -1975,6 +1968,10 @@ type validatorWithdrawalNotification struct {
UnsubscribeHash sql.NullString
}
+func (n *validatorWithdrawalNotification) GetUserId() types.UserId {
+ return n.UserID
+}
+
func (n *validatorWithdrawalNotification) GetLatestState() string {
return ""
}
@@ -2054,6 +2051,7 @@ func collectWithdrawalNotifications(notificationsByUserID types.NotificationsPer
// log.Infof("creating %v notification for validator %v in epoch %v", types.ValidatorReceivedWithdrawalEventName, event.ValidatorIndex, epoch)
n := &validatorWithdrawalNotification{
SubscriptionID: *sub.ID,
+ UserID: *sub.UserID,
ValidatorIndex: event.ValidatorIndex,
Epoch: epoch,
Slot: event.Slot,
@@ -2062,13 +2060,7 @@ func collectWithdrawalNotifications(notificationsByUserID types.NotificationsPer
EventFilter: hex.EncodeToString(event.Pubkey),
UnsubscribeHash: sub.UnsubscribeHash,
}
- if _, exists := notificationsByUserID[*sub.UserID]; !exists {
- notificationsByUserID[*sub.UserID] = map[types.EventName]map[types.EventFilter]types.Notification{}
- }
- if _, exists := notificationsByUserID[*sub.UserID][n.GetEventName()]; !exists {
- notificationsByUserID[*sub.UserID][n.GetEventName()] = map[types.EventFilter]types.Notification{}
- }
- notificationsByUserID[*sub.UserID][n.GetEventName()][types.EventFilter(n.EventFilter)] = n
+ notificationsByUserID.AddNotification(n)
metrics.NotificationsCollected.WithLabelValues(string(n.GetEventName())).Inc()
}
}
@@ -2086,6 +2078,10 @@ type ethClientNotification struct {
UnsubscribeHash sql.NullString
}
+func (n *ethClientNotification) GetUserId() types.UserId {
+ return n.UserID
+}
+
func (n *ethClientNotification) GetLatestState() string {
return ""
}
@@ -2223,13 +2219,7 @@ func collectEthClientNotifications(notificationsByUserID types.NotificationsPerU
EthClient: client.Name,
UnsubscribeHash: r.UnsubscribeHash,
}
- if _, exists := notificationsByUserID[r.UserID]; !exists {
- notificationsByUserID[r.UserID] = map[types.EventName]map[types.EventFilter]types.Notification{}
- }
- if _, exists := notificationsByUserID[r.UserID][n.GetEventName()]; !exists {
- notificationsByUserID[r.UserID][n.GetEventName()] = map[types.EventFilter]types.Notification{}
- }
- notificationsByUserID[r.UserID][n.GetEventName()][types.EventFilter(n.EventFilter)] = n
+ notificationsByUserID.AddNotification(n)
metrics.NotificationsCollected.WithLabelValues(string(n.GetEventName())).Inc()
}
}
@@ -2422,13 +2412,7 @@ func collectMonitoringMachine(
UnsubscribeHash: r.UnsubscribeHash,
}
//logrus.Infof("notify %v %v", eventName, n)
- if _, exists := notificationsByUserID[r.UserID]; !exists {
- notificationsByUserID[r.UserID] = map[types.EventName]map[types.EventFilter]types.Notification{}
- }
- if _, exists := notificationsByUserID[r.UserID][n.GetEventName()]; !exists {
- notificationsByUserID[r.UserID][n.GetEventName()] = map[types.EventFilter]types.Notification{}
- }
- notificationsByUserID[r.UserID][n.GetEventName()][types.EventFilter(n.GetEventFilter())] = n
+ notificationsByUserID.AddNotification(n)
metrics.NotificationsCollected.WithLabelValues(string(n.GetEventName())).Inc()
}
@@ -2449,6 +2433,10 @@ type monitorMachineNotification struct {
UnsubscribeHash sql.NullString
}
+func (n *monitorMachineNotification) GetUserId() types.UserId {
+ return n.UserID
+}
+
func (n *monitorMachineNotification) GetLatestState() string {
return ""
}
@@ -2528,6 +2516,10 @@ type taxReportNotification struct {
UnsubscribeHash sql.NullString
}
+func (n *taxReportNotification) GetUserId() types.UserId {
+ return n.UserID
+}
+
func (n *taxReportNotification) GetLatestState() string {
return ""
}
@@ -2647,13 +2639,7 @@ func collectTaxReportNotificationNotifications(notificationsByUserID types.Notif
EventFilter: r.EventFilter,
UnsubscribeHash: r.UnsubscribeHash,
}
- if _, exists := notificationsByUserID[r.UserID]; !exists {
- notificationsByUserID[r.UserID] = map[types.EventName]map[types.EventFilter]types.Notification{}
- }
- if _, exists := notificationsByUserID[r.UserID][n.GetEventName()]; !exists {
- notificationsByUserID[r.UserID][n.GetEventName()] = map[types.EventFilter]types.Notification{}
- }
- notificationsByUserID[r.UserID][n.GetEventName()][types.EventFilter(n.GetEventFilter())] = n
+ notificationsByUserID.AddNotification(n)
metrics.NotificationsCollected.WithLabelValues(string(n.GetEventName())).Inc()
}
@@ -2668,6 +2654,10 @@ type networkNotification struct {
UnsubscribeHash sql.NullString
}
+func (n *networkNotification) GetUserId() types.UserId {
+ return n.UserID
+}
+
func (n *networkNotification) GetLatestState() string {
return ""
}
@@ -2751,13 +2741,8 @@ func collectNetworkNotifications(notificationsByUserID types.NotificationsPerUse
EventFilter: r.EventFilter,
UnsubscribeHash: r.UnsubscribeHash,
}
- if _, exists := notificationsByUserID[r.UserID]; !exists {
- notificationsByUserID[r.UserID] = map[types.EventName]map[types.EventFilter]types.Notification{}
- }
- if _, exists := notificationsByUserID[r.UserID][n.GetEventName()]; !exists {
- notificationsByUserID[r.UserID][n.GetEventName()] = map[types.EventFilter]types.Notification{}
- }
- notificationsByUserID[r.UserID][n.GetEventName()][types.EventFilter(n.EventFilter)] = n
+
+ notificationsByUserID.AddNotification(n)
metrics.NotificationsCollected.WithLabelValues(string(n.GetEventName())).Inc()
}
}
@@ -2775,6 +2760,10 @@ type rocketpoolNotification struct {
UnsubscribeHash sql.NullString
}
+func (n *rocketpoolNotification) GetUserId() types.UserId {
+ return n.UserID
+}
+
func (n *rocketpoolNotification) GetLatestState() string {
return ""
}
@@ -2885,13 +2874,8 @@ func collectRocketpoolComissionNotifications(notificationsByUserID types.Notific
ExtraData: strconv.FormatInt(int64(fee*100), 10) + "%",
UnsubscribeHash: r.UnsubscribeHash,
}
- if _, exists := notificationsByUserID[r.UserID]; !exists {
- notificationsByUserID[r.UserID] = map[types.EventName]map[types.EventFilter]types.Notification{}
- }
- if _, exists := notificationsByUserID[r.UserID][n.GetEventName()]; !exists {
- notificationsByUserID[r.UserID][n.GetEventName()] = map[types.EventFilter]types.Notification{}
- }
- notificationsByUserID[r.UserID][n.GetEventName()][types.EventFilter(n.EventFilter)] = n
+
+ notificationsByUserID.AddNotification(n)
metrics.NotificationsCollected.WithLabelValues(string(n.GetEventName())).Inc()
}
}
@@ -2938,13 +2922,8 @@ func collectRocketpoolRewardClaimRoundNotifications(notificationsByUserID types.
EventName: eventName,
UnsubscribeHash: r.UnsubscribeHash,
}
- if _, exists := notificationsByUserID[r.UserID]; !exists {
- notificationsByUserID[r.UserID] = map[types.EventName]map[types.EventFilter]types.Notification{}
- }
- if _, exists := notificationsByUserID[r.UserID][n.GetEventName()]; !exists {
- notificationsByUserID[r.UserID][n.GetEventName()] = map[types.EventFilter]types.Notification{}
- }
- notificationsByUserID[r.UserID][n.GetEventName()][types.EventFilter(n.EventFilter)] = n
+
+ notificationsByUserID.AddNotification(n)
metrics.NotificationsCollected.WithLabelValues(string(n.GetEventName())).Inc()
}
}
@@ -3076,13 +3055,8 @@ func collectRocketpoolRPLCollateralNotifications(notificationsByUserID types.Not
ExtraData: strings.TrimRight(strings.TrimRight(fmt.Sprintf("%.2f", threshold*100), "0"), "."),
UnsubscribeHash: sub.UnsubscribeHash,
}
- if _, exists := notificationsByUserID[*sub.UserID]; !exists {
- notificationsByUserID[*sub.UserID] = map[types.EventName]map[types.EventFilter]types.Notification{}
- }
- if _, exists := notificationsByUserID[*sub.UserID][n.GetEventName()]; !exists {
- notificationsByUserID[*sub.UserID][n.GetEventName()] = map[types.EventFilter]types.Notification{}
- }
- notificationsByUserID[*sub.UserID][n.GetEventName()][types.EventFilter(n.EventFilter)] = n
+
+ notificationsByUserID.AddNotification(n)
metrics.NotificationsCollected.WithLabelValues(string(n.GetEventName())).Inc()
}
@@ -3185,13 +3159,7 @@ func collectSyncCommittee(notificationsByUserID types.NotificationsPerUserId, ev
ExtraData: fmt.Sprintf("%v|%v|%v", mapping[r.EventFilter], nextPeriod*utils.Config.Chain.ClConfig.EpochsPerSyncCommitteePeriod, (nextPeriod+1)*utils.Config.Chain.ClConfig.EpochsPerSyncCommitteePeriod),
UnsubscribeHash: r.UnsubscribeHash,
}
- if _, exists := notificationsByUserID[r.UserID]; !exists {
- notificationsByUserID[r.UserID] = map[types.EventName]map[types.EventFilter]types.Notification{}
- }
- if _, exists := notificationsByUserID[r.UserID][n.GetEventName()]; !exists {
- notificationsByUserID[r.UserID][n.GetEventName()] = map[types.EventFilter]types.Notification{}
- }
- notificationsByUserID[r.UserID][n.GetEventName()][types.EventFilter(n.EventFilter)] = n
+ notificationsByUserID.AddNotification(n)
metrics.NotificationsCollected.WithLabelValues(string(n.GetEventName())).Inc()
}
From ec0f3c9bedfa00fe196405a087d607f92094f222 Mon Sep 17 00:00:00 2001
From: peter <1674920+peterbitfly@users.noreply.github.com>
Date: Sat, 6 Jul 2024 10:23:29 +0200
Subject: [PATCH 06/39] refractor notification structs
---
backend/pkg/commons/types/frontend.go | 61 ++++
backend/pkg/notification/notifications.go | 383 ++++++----------------
2 files changed, 157 insertions(+), 287 deletions(-)
diff --git a/backend/pkg/commons/types/frontend.go b/backend/pkg/commons/types/frontend.go
index 467f6f5c7..a51e5e4c2 100644
--- a/backend/pkg/commons/types/frontend.go
+++ b/backend/pkg/commons/types/frontend.go
@@ -279,6 +279,67 @@ type Notification interface {
GetUserId() UserId
}
+type NotificationBaseImpl struct {
+ LatestState string
+ SubscriptionID uint64
+ EventName EventName
+ Epoch uint64
+ Info string
+ Title string
+ EventFilter string
+ EmailAttachment *EmailAttachment
+ UnsubscribeHash sql.NullString
+ InfoMarkdown string
+ UserID UserId
+}
+
+func (n NotificationBaseImpl) GetLatestState() string {
+ return n.LatestState
+}
+
+func (n NotificationBaseImpl) GetSubscriptionID() uint64 {
+ return n.SubscriptionID
+}
+
+func (n NotificationBaseImpl) GetEventName() EventName {
+ return n.EventName
+}
+
+func (n NotificationBaseImpl) GetEpoch() uint64 {
+ return n.Epoch
+}
+
+func (n NotificationBaseImpl) GetInfo(includeUrl bool) string {
+ return n.Info
+}
+
+func (n NotificationBaseImpl) GetTitle() string {
+ return n.Title
+}
+
+func (n NotificationBaseImpl) GetEventFilter() string {
+ return n.EventFilter
+}
+
+func (n NotificationBaseImpl) GetEmailAttachment() *EmailAttachment {
+ return n.EmailAttachment
+}
+
+func (n NotificationBaseImpl) GetUnsubscribeHash() string {
+ if n.UnsubscribeHash.Valid {
+ return n.UnsubscribeHash.String
+ }
+ return ""
+}
+
+func (n NotificationBaseImpl) GetInfoMarkdown() string {
+ return n.InfoMarkdown
+}
+
+func (n NotificationBaseImpl) GetUserId() UserId {
+ return n.UserID
+}
+
// func UnMarschal
type Subscription struct {
diff --git a/backend/pkg/notification/notifications.go b/backend/pkg/notification/notifications.go
index f39309de9..b177a8d74 100644
--- a/backend/pkg/notification/notifications.go
+++ b/backend/pkg/notification/notifications.go
@@ -1504,13 +1504,15 @@ func collectAttestationAndOfflineValidatorNotifications(notificationsByUserID ty
log.Infof("creating %v notification for validator %v in epoch %v", types.ValidatorMissedAttestationEventName, event.ValidatorIndex, event.Epoch)
n := &validatorAttestationNotification{
- SubscriptionID: *sub.ID,
- UserID: *sub.UserID,
+ NotificationBaseImpl: types.NotificationBaseImpl{
+ SubscriptionID: *sub.ID,
+ UserID: *sub.UserID,
+ Epoch: event.Epoch,
+ EventName: types.ValidatorMissedAttestationEventName,
+ EventFilter: hex.EncodeToString(event.EventFilter),
+ },
ValidatorIndex: event.ValidatorIndex,
- Epoch: event.Epoch,
Status: event.Status,
- EventName: types.ValidatorMissedAttestationEventName,
- EventFilter: hex.EncodeToString(event.EventFilter),
}
notificationsByUserID.AddNotification(n)
metrics.NotificationsCollected.WithLabelValues(string(n.GetEventName())).Inc()
@@ -1608,13 +1610,15 @@ func collectAttestationAndOfflineValidatorNotifications(notificationsByUserID ty
log.Infof("new event: validator %v detected as offline since epoch %v", validator.Index, epoch)
n := &validatorIsOfflineNotification{
- SubscriptionID: *sub.ID,
+ NotificationBaseImpl: types.NotificationBaseImpl{
+ SubscriptionID: *sub.ID,
+ Epoch: epoch,
+ EventName: types.ValidatorIsOfflineEventName,
+ LatestState: fmt.Sprint(epoch - 2), // first epoch the validator stopped attesting
+ EventFilter: hex.EncodeToString(validator.Pubkey),
+ },
ValidatorIndex: validator.Index,
IsOffline: true,
- EventEpoch: epoch,
- EventName: types.ValidatorIsOfflineEventName,
- InternalState: fmt.Sprint(epoch - 2), // first epoch the validator stopped attesting
- EventFilter: hex.EncodeToString(validator.Pubkey),
}
notificationsByUserID.AddNotification(n)
@@ -1632,7 +1636,7 @@ func collectAttestationAndOfflineValidatorNotifications(notificationsByUserID ty
originalLastSeenEpoch, err := strconv.ParseUint(sub.State.String, 10, 64)
if err != nil {
- // i have no idea what just happened.
+ // I have no idea what just happened.
return fmt.Errorf("this should never happen. couldn't parse state as uint64: %v", err)
}
@@ -1649,14 +1653,16 @@ func collectAttestationAndOfflineValidatorNotifications(notificationsByUserID ty
log.Infof("new event: validator %v detected as online again at epoch %v", validator.Index, epoch)
n := &validatorIsOfflineNotification{
- SubscriptionID: *sub.ID,
- UserID: *sub.UserID,
+ NotificationBaseImpl: types.NotificationBaseImpl{
+ SubscriptionID: *sub.ID,
+ UserID: *sub.UserID,
+ Epoch: epoch,
+ EventName: types.ValidatorIsOfflineEventName,
+ EventFilter: hex.EncodeToString(validator.Pubkey),
+ LatestState: "-",
+ },
ValidatorIndex: validator.Index,
IsOffline: false,
- EventEpoch: epoch,
- EventName: types.ValidatorIsOfflineEventName,
- InternalState: "-",
- EventFilter: hex.EncodeToString(validator.Pubkey),
EpochsOffline: epochsSinceOffline,
}
@@ -1669,50 +1675,26 @@ func collectAttestationAndOfflineValidatorNotifications(notificationsByUserID ty
}
type validatorIsOfflineNotification struct {
- SubscriptionID uint64
- UserID types.UserId
- ValidatorIndex uint64
- EventEpoch uint64
- EpochsOffline uint64
- IsOffline bool
- EventName types.EventName
- EventFilter string
- UnsubscribeHash sql.NullString
- InternalState string
-}
-
-func (n *validatorIsOfflineNotification) GetUserId() types.UserId {
- return n.UserID
-}
-
-func (n *validatorIsOfflineNotification) GetLatestState() string {
- return n.InternalState
-}
+ types.NotificationBaseImpl
-func (n *validatorIsOfflineNotification) GetSubscriptionID() uint64 {
- return n.SubscriptionID
-}
-
-func (n *validatorIsOfflineNotification) GetEventName() types.EventName {
- return n.EventName
-}
-
-func (n *validatorIsOfflineNotification) GetEpoch() uint64 {
- return n.EventEpoch
+ ValidatorIndex uint64
+ EpochsOffline uint64
+ IsOffline bool
}
+// Overwrite specific methods
func (n *validatorIsOfflineNotification) GetInfo(includeUrl bool) string {
if n.IsOffline {
if includeUrl {
- return fmt.Sprintf(`Validator %[1]v is offline since epoch %[2]s).`, n.ValidatorIndex, n.InternalState, utils.Config.Frontend.SiteDomain)
+ return fmt.Sprintf(`Validator %[1]v is offline since epoch %[2]s).`, n.ValidatorIndex, n.LatestState, utils.Config.Frontend.SiteDomain)
} else {
- return fmt.Sprintf(`Validator %v is offline since epoch %s.`, n.ValidatorIndex, n.InternalState)
+ return fmt.Sprintf(`Validator %v is offline since epoch %s.`, n.ValidatorIndex, n.LatestState)
}
} else {
if includeUrl {
- return fmt.Sprintf(`Validator %[1]v is back online since epoch %[2]v (was offline for %[4]v epoch(s)).`, n.ValidatorIndex, n.EventEpoch, utils.Config.Frontend.SiteDomain, n.EpochsOffline)
+ return fmt.Sprintf(`Validator %[1]v is back online since epoch %[2]v (was offline for %[4]v epoch(s)).`, n.ValidatorIndex, n.Epoch, utils.Config.Frontend.SiteDomain, n.EpochsOffline)
} else {
- return fmt.Sprintf(`Validator %v is back online since epoch %v (was offline for %v epoch(s)).`, n.ValidatorIndex, n.EventEpoch, n.EpochsOffline)
+ return fmt.Sprintf(`Validator %v is back online since epoch %v (was offline for %v epoch(s)).`, n.ValidatorIndex, n.Epoch, n.EpochsOffline)
}
}
}
@@ -1725,59 +1707,24 @@ func (n *validatorIsOfflineNotification) GetTitle() string {
}
}
-func (n *validatorIsOfflineNotification) GetEventFilter() string {
- return n.EventFilter
-}
-
-func (n *validatorIsOfflineNotification) GetEmailAttachment() *types.EmailAttachment {
- return nil
-}
-
-func (n *validatorIsOfflineNotification) GetUnsubscribeHash() string {
- if n.UnsubscribeHash.Valid {
- return n.UnsubscribeHash.String
- }
- return ""
-}
-
func (n *validatorIsOfflineNotification) GetInfoMarkdown() string {
if n.IsOffline {
- return fmt.Sprintf(`Validator [%[1]v](https://%[3]v/validator/%[1]v) is offline since epoch [%[2]v](https://%[3]v/epoch/%[2]v).`, n.ValidatorIndex, n.EventEpoch, utils.Config.Frontend.SiteDomain)
+ return fmt.Sprintf(`Validator [%[1]v](https://%[3]v/validator/%[1]v) is offline since epoch [%[2]v](https://%[3]v/epoch/%[2]v).`, n.ValidatorIndex, n.Epoch, utils.Config.Frontend.SiteDomain)
} else {
- return fmt.Sprintf(`Validator [%[1]v](https://%[3]v/validator/%[1]v) is back online since epoch [%[2]v](https://%[3]v/epoch/%[2]v) (was offline for %[4]v epoch(s)).`, n.ValidatorIndex, n.EventEpoch, utils.Config.Frontend.SiteDomain, n.EpochsOffline)
+ return fmt.Sprintf(`Validator [%[1]v](https://%[3]v/validator/%[1]v) is back online since epoch [%[2]v](https://%[3]v/epoch/%[2]v) (was offline for %[4]v epoch(s)).`, n.ValidatorIndex, n.Epoch, utils.Config.Frontend.SiteDomain, n.EpochsOffline)
}
}
+func (n *validatorIsOfflineNotification) GetEventName() types.EventName {
+ return types.ValidatorIsOfflineEventName
+}
+
type validatorAttestationNotification struct {
- SubscriptionID uint64
- UserID types.UserId
+ types.NotificationBaseImpl
+
ValidatorIndex uint64
ValidatorPublicKey string
- Epoch uint64
Status uint64 // * Can be 0 = scheduled | missed, 1 executed
- EventName types.EventName
- EventFilter string
- UnsubscribeHash sql.NullString
-}
-
-func (n *validatorAttestationNotification) GetUserId() types.UserId {
- return n.UserID
-}
-
-func (n *validatorAttestationNotification) GetLatestState() string {
- return ""
-}
-
-func (n *validatorAttestationNotification) GetSubscriptionID() uint64 {
- return n.SubscriptionID
-}
-
-func (n *validatorAttestationNotification) GetEventName() types.EventName {
- return n.EventName
-}
-
-func (n *validatorAttestationNotification) GetEpoch() uint64 {
- return n.Epoch
}
func (n *validatorAttestationNotification) GetInfo(includeUrl bool) string {
@@ -1811,21 +1758,6 @@ func (n *validatorAttestationNotification) GetTitle() string {
return "-"
}
-func (n *validatorAttestationNotification) GetEventFilter() string {
- return n.EventFilter
-}
-
-func (n *validatorAttestationNotification) GetEmailAttachment() *types.EmailAttachment {
- return nil
-}
-
-func (n *validatorAttestationNotification) GetUnsubscribeHash() string {
- if n.UnsubscribeHash.Valid {
- return n.UnsubscribeHash.String
- }
- return ""
-}
-
func (n *validatorAttestationNotification) GetInfoMarkdown() string {
var generalPart = ""
switch n.Status {
@@ -1837,46 +1769,16 @@ func (n *validatorAttestationNotification) GetInfoMarkdown() string {
return generalPart
}
-type validatorGotSlashedNotification struct {
- SubscriptionID uint64
- UserID types.UserId
- ValidatorIndex uint64
- Epoch uint64
- Slasher uint64
- Reason string
- EventFilter string
- UnsubscribeHash sql.NullString
-}
-
-func (n *validatorGotSlashedNotification) GetUserId() types.UserId {
- return n.UserID
-}
-
-func (n *validatorGotSlashedNotification) GetLatestState() string {
- return ""
-}
-
-func (n *validatorGotSlashedNotification) GetUnsubscribeHash() string {
- if n.UnsubscribeHash.Valid {
- return n.UnsubscribeHash.String
- }
- return ""
-}
-
-func (n *validatorGotSlashedNotification) GetEmailAttachment() *types.EmailAttachment {
- return nil
-}
-
-func (n *validatorGotSlashedNotification) GetSubscriptionID() uint64 {
- return n.SubscriptionID
+func (n *validatorAttestationNotification) GetEventName() types.EventName {
+ return types.ValidatorMissedAttestationEventName
}
-func (n *validatorGotSlashedNotification) GetEpoch() uint64 {
- return n.Epoch
-}
+type validatorGotSlashedNotification struct {
+ types.NotificationBaseImpl
-func (n *validatorGotSlashedNotification) GetEventName() types.EventName {
- return types.ValidatorGotSlashedEventName
+ ValidatorIndex uint64
+ Slasher uint64
+ Reason string
}
func (n *validatorGotSlashedNotification) GetInfo(includeUrl bool) string {
@@ -1891,8 +1793,8 @@ func (n *validatorGotSlashedNotification) GetTitle() string {
return "Validator got Slashed"
}
-func (n *validatorGotSlashedNotification) GetEventFilter() string {
- return n.EventFilter
+func (n *validatorGotSlashedNotification) GetEventName() types.EventName {
+ return types.ValidatorGotSlashedEventName
}
func (n *validatorGotSlashedNotification) GetInfoMarkdown() string {
@@ -1940,14 +1842,16 @@ func collectValidatorGotSlashedNotifications(notificationsByUserID types.Notific
log.Infof("creating %v notification for validator %v in epoch %v", event.SlashedValidatorPubkey, event.Reason, epoch)
n := &validatorGotSlashedNotification{
- SubscriptionID: sub.Id,
- UserID: sub.UserId,
- Slasher: event.SlasherIndex,
- Epoch: event.Epoch,
- Reason: event.Reason,
- ValidatorIndex: event.SlashedValidatorIndex,
- EventFilter: hex.EncodeToString(event.SlashedValidatorPubkey),
- UnsubscribeHash: sub.UnsubscribeHash,
+ NotificationBaseImpl: types.NotificationBaseImpl{
+ SubscriptionID: sub.Id,
+ UserID: sub.UserId,
+ Epoch: event.Epoch,
+ EventFilter: hex.EncodeToString(event.SlashedValidatorPubkey),
+ UnsubscribeHash: sub.UnsubscribeHash,
+ },
+ Slasher: event.SlasherIndex,
+ Reason: event.Reason,
+ ValidatorIndex: event.SlashedValidatorIndex,
}
notificationsByUserID.AddNotification(n)
metrics.NotificationsCollected.WithLabelValues(string(n.GetEventName())).Inc()
@@ -1957,42 +1861,13 @@ func collectValidatorGotSlashedNotifications(notificationsByUserID types.Notific
}
type validatorWithdrawalNotification struct {
- UserID types.UserId
- SubscriptionID uint64
- ValidatorIndex uint64
- Epoch uint64
- Slot uint64
- Amount uint64
- Address []byte
- EventFilter string
- UnsubscribeHash sql.NullString
-}
-
-func (n *validatorWithdrawalNotification) GetUserId() types.UserId {
- return n.UserID
-}
+ types.NotificationBaseImpl
-func (n *validatorWithdrawalNotification) GetLatestState() string {
- return ""
-}
-
-func (n *validatorWithdrawalNotification) GetUnsubscribeHash() string {
- if n.UnsubscribeHash.Valid {
- return n.UnsubscribeHash.String
- }
- return ""
-}
-
-func (n *validatorWithdrawalNotification) GetEmailAttachment() *types.EmailAttachment {
- return nil
-}
-
-func (n *validatorWithdrawalNotification) GetSubscriptionID() uint64 {
- return n.SubscriptionID
-}
-
-func (n *validatorWithdrawalNotification) GetEpoch() uint64 {
- return n.Epoch
+ ValidatorIndex uint64
+ Epoch uint64
+ Slot uint64
+ Amount uint64
+ Address []byte
}
func (n *validatorWithdrawalNotification) GetEventName() types.EventName {
@@ -2011,10 +1886,6 @@ func (n *validatorWithdrawalNotification) GetTitle() string {
return "Withdrawal Processed"
}
-func (n *validatorWithdrawalNotification) GetEventFilter() string {
- return n.EventFilter
-}
-
func (n *validatorWithdrawalNotification) GetInfoMarkdown() string {
generalPart := fmt.Sprintf(`An automatic withdrawal of %[2]v has been processed for validator [%[1]v](https://%[6]v/validator/%[1]v) during slot [%[3]v](https://%[6]v/slot/%[3]v). The funds have been sent to: [%[4]v](https://%[6]v/address/0x%[5]x).`, n.ValidatorIndex, utils.FormatClCurrencyString(n.Amount, utils.Config.Frontend.MainCurrency, 6, true, false, false), n.Slot, utils.FormatHashRaw(n.Address), n.Address, utils.Config.Frontend.SiteDomain)
return generalPart
@@ -2050,15 +1921,17 @@ func collectWithdrawalNotifications(notificationsByUserID types.NotificationsPer
}
// log.Infof("creating %v notification for validator %v in epoch %v", types.ValidatorReceivedWithdrawalEventName, event.ValidatorIndex, epoch)
n := &validatorWithdrawalNotification{
- SubscriptionID: *sub.ID,
- UserID: *sub.UserID,
- ValidatorIndex: event.ValidatorIndex,
- Epoch: epoch,
- Slot: event.Slot,
- Amount: event.Amount,
- Address: event.Address,
- EventFilter: hex.EncodeToString(event.Pubkey),
- UnsubscribeHash: sub.UnsubscribeHash,
+ NotificationBaseImpl: types.NotificationBaseImpl{
+ SubscriptionID: *sub.ID,
+ UserID: *sub.UserID,
+ EventFilter: hex.EncodeToString(event.Pubkey),
+ UnsubscribeHash: sub.UnsubscribeHash,
+ },
+ ValidatorIndex: event.ValidatorIndex,
+ Epoch: epoch,
+ Slot: event.Slot,
+ Amount: event.Amount,
+ Address: event.Address,
}
notificationsByUserID.AddNotification(n)
metrics.NotificationsCollected.WithLabelValues(string(n.GetEventName())).Inc()
@@ -2070,39 +1943,9 @@ func collectWithdrawalNotifications(notificationsByUserID types.NotificationsPer
}
type ethClientNotification struct {
- SubscriptionID uint64
- UserID types.UserId
- Epoch uint64
- EthClient string
- EventFilter string
- UnsubscribeHash sql.NullString
-}
-
-func (n *ethClientNotification) GetUserId() types.UserId {
- return n.UserID
-}
-
-func (n *ethClientNotification) GetLatestState() string {
- return ""
-}
-
-func (n *ethClientNotification) GetUnsubscribeHash() string {
- if n.UnsubscribeHash.Valid {
- return n.UnsubscribeHash.String
- }
- return ""
-}
-
-func (n *ethClientNotification) GetEmailAttachment() *types.EmailAttachment {
- return nil
-}
+ types.NotificationBaseImpl
-func (n *ethClientNotification) GetSubscriptionID() uint64 {
- return n.SubscriptionID
-}
-
-func (n *ethClientNotification) GetEpoch() uint64 {
- return n.Epoch
+ EthClient string
}
func (n *ethClientNotification) GetEventName() types.EventName {
@@ -2147,10 +1990,6 @@ func (n *ethClientNotification) GetTitle() string {
return fmt.Sprintf("New %s update", n.EthClient)
}
-func (n *ethClientNotification) GetEventFilter() string {
- return n.EventFilter
-}
-
func (n *ethClientNotification) GetInfoMarkdown() string {
url := ""
switch n.EthClient {
@@ -2212,12 +2051,14 @@ func collectEthClientNotifications(notificationsByUserID types.NotificationsPerU
for _, r := range dbResult {
n := ðClientNotification{
- SubscriptionID: r.SubscriptionID,
- UserID: r.UserID,
- Epoch: r.Epoch,
- EventFilter: r.EventFilter,
- EthClient: client.Name,
- UnsubscribeHash: r.UnsubscribeHash,
+ NotificationBaseImpl: types.NotificationBaseImpl{
+ SubscriptionID: r.SubscriptionID,
+ UserID: r.UserID,
+ Epoch: r.Epoch,
+ EventFilter: r.EventFilter,
+ UnsubscribeHash: r.UnsubscribeHash,
+ },
+ EthClient: client.Name,
}
notificationsByUserID.AddNotification(n)
metrics.NotificationsCollected.WithLabelValues(string(n.GetEventName())).Inc()
@@ -2404,12 +2245,14 @@ func collectMonitoringMachine(
for _, r := range result {
n := &monitorMachineNotification{
- SubscriptionID: r.SubscriptionID,
- MachineName: r.MachineName,
- UserID: r.UserID,
- EventName: eventName,
- Epoch: epoch,
- UnsubscribeHash: r.UnsubscribeHash,
+ NotificationBaseImpl: types.NotificationBaseImpl{
+ SubscriptionID: r.SubscriptionID,
+ UserID: r.UserID,
+ EventName: eventName,
+ Epoch: epoch,
+ UnsubscribeHash: r.UnsubscribeHash,
+ },
+ MachineName: r.MachineName,
}
//logrus.Infof("notify %v %v", eventName, n)
notificationsByUserID.AddNotification(n)
@@ -2425,43 +2268,9 @@ func collectMonitoringMachine(
}
type monitorMachineNotification struct {
- SubscriptionID uint64
- MachineName string
- UserID types.UserId
- Epoch uint64
- EventName types.EventName
- UnsubscribeHash sql.NullString
-}
+ types.NotificationBaseImpl
-func (n *monitorMachineNotification) GetUserId() types.UserId {
- return n.UserID
-}
-
-func (n *monitorMachineNotification) GetLatestState() string {
- return ""
-}
-
-func (n *monitorMachineNotification) GetUnsubscribeHash() string {
- if n.UnsubscribeHash.Valid {
- return n.UnsubscribeHash.String
- }
- return ""
-}
-
-func (n *monitorMachineNotification) GetEmailAttachment() *types.EmailAttachment {
- return nil
-}
-
-func (n *monitorMachineNotification) GetSubscriptionID() uint64 {
- return n.SubscriptionID
-}
-
-func (n *monitorMachineNotification) GetEpoch() uint64 {
- return n.Epoch
-}
-
-func (n *monitorMachineNotification) GetEventName() types.EventName {
- return n.EventName
+ MachineName string
}
func (n *monitorMachineNotification) GetInfo(includeUrl bool) string {
From 7e235b241195533dd37db02a5ff93b00e6c067bf Mon Sep 17 00:00:00 2001
From: peter <1674920+peterbitfly@users.noreply.github.com>
Date: Sat, 6 Jul 2024 10:30:15 +0200
Subject: [PATCH 07/39] add missing structs
---
backend/pkg/notification/notifications.go | 258 ++++++----------------
1 file changed, 65 insertions(+), 193 deletions(-)
diff --git a/backend/pkg/notification/notifications.go b/backend/pkg/notification/notifications.go
index b177a8d74..3a2dc4ce8 100644
--- a/backend/pkg/notification/notifications.go
+++ b/backend/pkg/notification/notifications.go
@@ -1314,14 +1314,16 @@ func collectBlockProposalNotifications(notificationsByUserID types.Notifications
}
log.Infof("creating %v notification for validator %v in epoch %v", eventName, event.Proposer, epoch)
n := &validatorProposalNotification{
- SubscriptionID: *sub.ID,
- UserID: *sub.UserID,
+ NotificationBaseImpl: types.NotificationBaseImpl{
+ SubscriptionID: *sub.ID,
+ UserID: *sub.UserID,
+ Epoch: epoch,
+ EventName: eventName,
+ EventFilter: hex.EncodeToString(pubkey),
+ },
ValidatorIndex: event.Proposer,
- Epoch: epoch,
Status: event.Status,
- EventName: eventName,
Reward: event.ExecRewardETH,
- EventFilter: hex.EncodeToString(pubkey),
Slot: event.Slot,
}
notificationsByUserID.AddNotification(n)
@@ -1333,48 +1335,12 @@ func collectBlockProposalNotifications(notificationsByUserID types.Notifications
}
type validatorProposalNotification struct {
- SubscriptionID uint64
- UserID types.UserId
- ValidatorIndex uint64
- ValidatorPublicKey string
- Epoch uint64
- Slot uint64
- Status uint64 // * Can be 0 = scheduled, 1 executed, 2 missed */
- EventName types.EventName
- EventFilter string
- Reward float64
- UnsubscribeHash sql.NullString
-}
-
-func (n *validatorProposalNotification) GetUserId() types.UserId {
- return n.UserID
-}
-
-func (n *validatorProposalNotification) GetLatestState() string {
- return ""
-}
-
-func (n *validatorProposalNotification) GetUnsubscribeHash() string {
- if n.UnsubscribeHash.Valid {
- return n.UnsubscribeHash.String
- }
- return ""
-}
-
-func (n *validatorProposalNotification) GetEmailAttachment() *types.EmailAttachment {
- return nil
-}
-
-func (n *validatorProposalNotification) GetSubscriptionID() uint64 {
- return n.SubscriptionID
-}
-
-func (n *validatorProposalNotification) GetEpoch() uint64 {
- return n.Epoch
-}
+ types.NotificationBaseImpl
-func (n *validatorProposalNotification) GetEventName() types.EventName {
- return n.EventName
+ ValidatorIndex uint64
+ Slot uint64
+ Status uint64 // * Can be 0 = scheduled, 1 executed, 2 missed */
+ Reward float64
}
func (n *validatorProposalNotification) GetInfo(includeUrl bool) string {
@@ -1409,10 +1375,6 @@ func (n *validatorProposalNotification) GetTitle() string {
return "-"
}
-func (n *validatorProposalNotification) GetEventFilter() string {
- return n.EventFilter
-}
-
func (n *validatorProposalNotification) GetInfoMarkdown() string {
var generalPart = ""
switch n.Status {
@@ -2318,26 +2280,7 @@ func (n *monitorMachineNotification) GetInfoMarkdown() string {
}
type taxReportNotification struct {
- SubscriptionID uint64
- UserID types.UserId
- Epoch uint64
- EventFilter string
- UnsubscribeHash sql.NullString
-}
-
-func (n *taxReportNotification) GetUserId() types.UserId {
- return n.UserID
-}
-
-func (n *taxReportNotification) GetLatestState() string {
- return ""
-}
-
-func (n *taxReportNotification) GetUnsubscribeHash() string {
- if n.UnsubscribeHash.Valid {
- return n.UnsubscribeHash.String
- }
- return ""
+ types.NotificationBaseImpl
}
func (n *taxReportNotification) GetEmailAttachment() *types.EmailAttachment {
@@ -2374,14 +2317,6 @@ func (n *taxReportNotification) GetEmailAttachment() *types.EmailAttachment {
return &types.EmailAttachment{Attachment: pdf, Name: fmt.Sprintf("income_history_%v_%v.pdf", firstDay.Format("20060102"), lastDay.Format("20060102"))}
}
-func (n *taxReportNotification) GetSubscriptionID() uint64 {
- return n.SubscriptionID
-}
-
-func (n *taxReportNotification) GetEpoch() uint64 {
- return n.Epoch
-}
-
func (n *taxReportNotification) GetEventName() types.EventName {
return types.TaxReportEventName
}
@@ -2442,11 +2377,13 @@ func collectTaxReportNotificationNotifications(notificationsByUserID types.Notif
for _, r := range dbResult {
n := &taxReportNotification{
- SubscriptionID: r.SubscriptionID,
- UserID: r.UserID,
- Epoch: r.Epoch,
- EventFilter: r.EventFilter,
- UnsubscribeHash: r.UnsubscribeHash,
+ NotificationBaseImpl: types.NotificationBaseImpl{
+ SubscriptionID: r.SubscriptionID,
+ UserID: r.UserID,
+ Epoch: r.Epoch,
+ EventFilter: r.EventFilter,
+ UnsubscribeHash: r.UnsubscribeHash,
+ },
}
notificationsByUserID.AddNotification(n)
metrics.NotificationsCollected.WithLabelValues(string(n.GetEventName())).Inc()
@@ -2456,38 +2393,7 @@ func collectTaxReportNotificationNotifications(notificationsByUserID types.Notif
}
type networkNotification struct {
- SubscriptionID uint64
- UserID types.UserId
- Epoch uint64
- EventFilter string
- UnsubscribeHash sql.NullString
-}
-
-func (n *networkNotification) GetUserId() types.UserId {
- return n.UserID
-}
-
-func (n *networkNotification) GetLatestState() string {
- return ""
-}
-
-func (n *networkNotification) GetUnsubscribeHash() string {
- if n.UnsubscribeHash.Valid {
- return n.UnsubscribeHash.String
- }
- return ""
-}
-
-func (n *networkNotification) GetEmailAttachment() *types.EmailAttachment {
- return nil
-}
-
-func (n *networkNotification) GetSubscriptionID() uint64 {
- return n.SubscriptionID
-}
-
-func (n *networkNotification) GetEpoch() uint64 {
- return n.Epoch
+ types.NotificationBaseImpl
}
func (n *networkNotification) GetEventName() types.EventName {
@@ -2503,10 +2409,6 @@ func (n *networkNotification) GetTitle() string {
return "Beaconchain Network Issues"
}
-func (n *networkNotification) GetEventFilter() string {
- return n.EventFilter
-}
-
func (n *networkNotification) GetInfoMarkdown() string {
generalPart := fmt.Sprintf(`Network experienced finality issues ([view chart](https://%v/charts/network_liveness)).`, utils.Config.Frontend.SiteDomain)
return generalPart
@@ -2544,11 +2446,13 @@ func collectNetworkNotifications(notificationsByUserID types.NotificationsPerUse
for _, r := range dbResult {
n := &networkNotification{
- SubscriptionID: r.SubscriptionID,
- UserID: r.UserID,
- Epoch: r.Epoch,
- EventFilter: r.EventFilter,
- UnsubscribeHash: r.UnsubscribeHash,
+ NotificationBaseImpl: types.NotificationBaseImpl{
+ SubscriptionID: r.SubscriptionID,
+ UserID: r.UserID,
+ Epoch: r.Epoch,
+ EventFilter: r.EventFilter,
+ UnsubscribeHash: r.UnsubscribeHash,
+ },
}
notificationsByUserID.AddNotification(n)
@@ -2560,44 +2464,8 @@ func collectNetworkNotifications(notificationsByUserID types.NotificationsPerUse
}
type rocketpoolNotification struct {
- SubscriptionID uint64
- UserID types.UserId
- Epoch uint64
- EventFilter string
- EventName types.EventName
- ExtraData string
- UnsubscribeHash sql.NullString
-}
-
-func (n *rocketpoolNotification) GetUserId() types.UserId {
- return n.UserID
-}
-
-func (n *rocketpoolNotification) GetLatestState() string {
- return ""
-}
-
-func (n *rocketpoolNotification) GetUnsubscribeHash() string {
- if n.UnsubscribeHash.Valid {
- return n.UnsubscribeHash.String
- }
- return ""
-}
-
-func (n *rocketpoolNotification) GetEmailAttachment() *types.EmailAttachment {
- return nil
-}
-
-func (n *rocketpoolNotification) GetSubscriptionID() uint64 {
- return n.SubscriptionID
-}
-
-func (n *rocketpoolNotification) GetEpoch() uint64 {
- return n.Epoch
-}
-
-func (n *rocketpoolNotification) GetEventName() types.EventName {
- return n.EventName
+ types.NotificationBaseImpl
+ ExtraData string
}
func (n *rocketpoolNotification) GetInfo(includeUrl bool) string {
@@ -2635,10 +2503,6 @@ func (n *rocketpoolNotification) GetTitle() string {
return ""
}
-func (n *rocketpoolNotification) GetEventFilter() string {
- return n.EventFilter
-}
-
func (n *rocketpoolNotification) GetInfoMarkdown() string {
return n.GetInfo(false)
}
@@ -2675,13 +2539,15 @@ func collectRocketpoolComissionNotifications(notificationsByUserID types.Notific
for _, r := range dbResult {
n := &rocketpoolNotification{
- SubscriptionID: r.SubscriptionID,
- UserID: r.UserID,
- Epoch: r.Epoch,
- EventFilter: r.EventFilter,
- EventName: eventName,
- ExtraData: strconv.FormatInt(int64(fee*100), 10) + "%",
- UnsubscribeHash: r.UnsubscribeHash,
+ NotificationBaseImpl: types.NotificationBaseImpl{
+ SubscriptionID: r.SubscriptionID,
+ UserID: r.UserID,
+ Epoch: r.Epoch,
+ EventFilter: r.EventFilter,
+ EventName: eventName,
+ UnsubscribeHash: r.UnsubscribeHash,
+ },
+ ExtraData: strconv.FormatInt(int64(fee*100), 10) + "%",
}
notificationsByUserID.AddNotification(n)
@@ -2724,12 +2590,14 @@ func collectRocketpoolRewardClaimRoundNotifications(notificationsByUserID types.
for _, r := range dbResult {
n := &rocketpoolNotification{
- SubscriptionID: r.SubscriptionID,
- UserID: r.UserID,
- Epoch: r.Epoch,
- EventFilter: r.EventFilter,
- EventName: eventName,
- UnsubscribeHash: r.UnsubscribeHash,
+ NotificationBaseImpl: types.NotificationBaseImpl{
+ SubscriptionID: r.SubscriptionID,
+ UserID: r.UserID,
+ Epoch: r.Epoch,
+ EventFilter: r.EventFilter,
+ EventName: eventName,
+ UnsubscribeHash: r.UnsubscribeHash,
+ },
}
notificationsByUserID.AddNotification(n)
@@ -2856,13 +2724,15 @@ func collectRocketpoolRPLCollateralNotifications(notificationsByUserID types.Not
}
n := &rocketpoolNotification{
- SubscriptionID: *sub.ID,
- UserID: *sub.UserID,
- Epoch: epoch,
- EventFilter: sub.EventFilter,
- EventName: eventName,
- ExtraData: strings.TrimRight(strings.TrimRight(fmt.Sprintf("%.2f", threshold*100), "0"), "."),
- UnsubscribeHash: sub.UnsubscribeHash,
+ NotificationBaseImpl: types.NotificationBaseImpl{
+ SubscriptionID: *sub.ID,
+ UserID: *sub.UserID,
+ Epoch: epoch,
+ EventFilter: sub.EventFilter,
+ EventName: eventName,
+ UnsubscribeHash: sub.UnsubscribeHash,
+ },
+ ExtraData: strings.TrimRight(strings.TrimRight(fmt.Sprintf("%.2f", threshold*100), "0"), "."),
}
notificationsByUserID.AddNotification(n)
@@ -2960,13 +2830,15 @@ func collectSyncCommittee(notificationsByUserID types.NotificationsPerUserId, ev
for _, r := range dbResult {
n := &rocketpoolNotification{
- SubscriptionID: r.SubscriptionID,
- UserID: r.UserID,
- Epoch: epoch,
- EventFilter: r.EventFilter,
- EventName: eventName,
- ExtraData: fmt.Sprintf("%v|%v|%v", mapping[r.EventFilter], nextPeriod*utils.Config.Chain.ClConfig.EpochsPerSyncCommitteePeriod, (nextPeriod+1)*utils.Config.Chain.ClConfig.EpochsPerSyncCommitteePeriod),
- UnsubscribeHash: r.UnsubscribeHash,
+ NotificationBaseImpl: types.NotificationBaseImpl{
+ SubscriptionID: r.SubscriptionID,
+ UserID: r.UserID,
+ Epoch: epoch,
+ EventFilter: r.EventFilter,
+ EventName: eventName,
+ UnsubscribeHash: r.UnsubscribeHash,
+ },
+ ExtraData: fmt.Sprintf("%v|%v|%v", mapping[r.EventFilter], nextPeriod*utils.Config.Chain.ClConfig.EpochsPerSyncCommitteePeriod, (nextPeriod+1)*utils.Config.Chain.ClConfig.EpochsPerSyncCommitteePeriod),
}
notificationsByUserID.AddNotification(n)
metrics.NotificationsCollected.WithLabelValues(string(n.GetEventName())).Inc()
From bf095cc9ed932e12c53de3e68636723b60e4878f Mon Sep 17 00:00:00 2001
From: peter <1674920+peterbitfly@users.noreply.github.com>
Date: Mon, 8 Jul 2024 10:21:21 +0200
Subject: [PATCH 08/39] refractor GetSubsForEventFilter
---
backend/pkg/notification/db.go | 51 ++-
backend/pkg/notification/notifications.go | 382 +++++++++++-----------
2 files changed, 235 insertions(+), 198 deletions(-)
diff --git a/backend/pkg/notification/db.go b/backend/pkg/notification/db.go
index 23f890ba6..36810d6b3 100644
--- a/backend/pkg/notification/db.go
+++ b/backend/pkg/notification/db.go
@@ -1,6 +1,7 @@
package notification
import (
+ "github.com/doug-martin/goqu/v9"
"github.com/gobitfly/beaconchain/pkg/commons/db"
"github.com/gobitfly/beaconchain/pkg/commons/types"
"github.com/gobitfly/beaconchain/pkg/commons/utils"
@@ -11,14 +12,54 @@ import (
// Map key corresponds to the event filter which can be
// a validator pubkey or an eth1 address (for RPL notifications)
// or a list of validators for the tax report notifications
-func GetSubsForEventFilter(eventName types.EventName) (map[string][]types.Subscription, error) {
+// optionally it is possible to set a filter on the last sent ts and the event filter
+// fields
+func GetSubsForEventFilter(eventName types.EventName, lastSentFilter string, lastSentFilterArgs []interface{}, eventFilters []string) (map[string][]types.Subscription, error) {
var subs []types.Subscription
- subQuery := `
- SELECT id, user_id, event_filter, last_sent_epoch, created_epoch, event_threshold, ENCODE(unsubscribe_hash, 'hex') as unsubscribe_hash, internal_state from users_subscriptions where event_name = $1
- `
+
+ // subQuery := `
+ // SELECT
+ // id,
+ // user_id,
+ // event_filter,
+ // last_sent_epoch,
+ // created_epoch,
+ // event_threshold,
+ // ENCODE(unsubscribe_hash, 'hex') as unsubscribe_hash,
+ // internal_state
+ // from users_subscriptions
+ // where event_name = $1
+ // `
+
+ ds := goqu.Dialect("postgres").From("users_subscriptions").Select(
+ goqu.C("id"),
+ goqu.C("user_id"),
+ goqu.C("event_filter"),
+ goqu.C("last_sent_epoch"),
+ goqu.C("created_epoch"),
+ goqu.C("event_threshold"),
+ goqu.L("ENCODE(unsubscribe_hash, 'hex') as unsubscribe_hash"),
+ goqu.C("internal_state"),
+ ).Where(goqu.C("event_name").Eq(utils.GetNetwork() + ":" + string(eventName)))
+
+ if lastSentFilter != "" {
+ if len(lastSentFilterArgs) > 0 {
+ ds = ds.Where(goqu.L(lastSentFilter, lastSentFilterArgs...))
+ } else {
+ ds = ds.Where(goqu.L(lastSentFilter))
+ }
+ }
+ if len(eventFilters) > 0 {
+ ds = ds.Where(goqu.L("event_filter = ANY(?)", pq.StringArray(eventFilters)))
+ }
+
+ query, args, err := ds.Prepared(true).ToSQL()
+ if err != nil {
+ return nil, err
+ }
subMap := make(map[string][]types.Subscription, 0)
- err := db.FrontendWriterDB.Select(&subs, subQuery, utils.GetNetwork()+":"+string(eventName))
+ err = db.FrontendWriterDB.Select(&subs, query, args)
if err != nil {
return nil, err
}
diff --git a/backend/pkg/notification/notifications.go b/backend/pkg/notification/notifications.go
index 3a2dc4ce8..0f1a71b3e 100644
--- a/backend/pkg/notification/notifications.go
+++ b/backend/pkg/notification/notifications.go
@@ -1241,7 +1241,7 @@ func collectBlockProposalNotifications(notificationsByUserID types.Notifications
ExecRewardETH float64
}
- subMap, err := GetSubsForEventFilter(eventName)
+ subMap, err := GetSubsForEventFilter(eventName, "", nil, nil)
if err != nil {
return fmt.Errorf("error getting subscriptions for (missed) block proposals %w", err)
}
@@ -1390,7 +1390,7 @@ func (n *validatorProposalNotification) GetInfoMarkdown() string {
}
func collectAttestationAndOfflineValidatorNotifications(notificationsByUserID types.NotificationsPerUserId, epoch uint64) error {
- subMap, err := GetSubsForEventFilter(types.ValidatorMissedAttestationEventName)
+ subMap, err := GetSubsForEventFilter(types.ValidatorMissedAttestationEventName, "", nil, nil)
if err != nil {
return fmt.Errorf("error getting subscriptions for missted attestations %w", err)
}
@@ -1557,7 +1557,7 @@ func collectAttestationAndOfflineValidatorNotifications(notificationsByUserID ty
return fmt.Errorf("retrieved more than %v online validators notifications: %v, exiting", onlineValidatorsLimit, len(onlineValidators))
}
- subMap, err = GetSubsForEventFilter(types.ValidatorIsOfflineEventName)
+ subMap, err = GetSubsForEventFilter(types.ValidatorIsOfflineEventName, "", nil, nil)
if err != nil {
return fmt.Errorf("failed to get subs for %v: %v", types.ValidatorIsOfflineEventName, err)
}
@@ -1772,6 +1772,7 @@ func collectValidatorGotSlashedNotifications(notificationsByUserID types.Notific
query := ""
resultsLen := len(dbResult)
for i, event := range dbResult {
+ // TODO: clarify why we need the id here?!
query += fmt.Sprintf(`SELECT %d AS ref, id, user_id, ENCODE(unsubscribe_hash, 'hex') AS unsubscribe_hash from users_subscriptions where event_name = $1 AND event_filter = '%x'`, i, event.SlashedValidatorPubkey)
if i < resultsLen-1 {
query += " UNION "
@@ -1856,7 +1857,7 @@ func (n *validatorWithdrawalNotification) GetInfoMarkdown() string {
// collectWithdrawalNotifications collects all notifications validator withdrawals
func collectWithdrawalNotifications(notificationsByUserID types.NotificationsPerUserId, epoch uint64) error {
// get all users that are subscribed to this event (scale: a few thousand rows depending on how many users we have)
- subMap, err := GetSubsForEventFilter(types.ValidatorReceivedWithdrawalEventName)
+ subMap, err := GetSubsForEventFilter(types.ValidatorReceivedWithdrawalEventName, "", nil, nil)
if err != nil {
return fmt.Errorf("error getting subscriptions for missed attestations %w", err)
}
@@ -1987,43 +1988,43 @@ func (n *ethClientNotification) GetInfoMarkdown() string {
func collectEthClientNotifications(notificationsByUserID types.NotificationsPerUserId, eventName types.EventName) error {
updatedClients := ethclients.GetUpdatedClients() //only check if there are new updates
for _, client := range updatedClients {
- var dbResult []struct {
- SubscriptionID uint64 `db:"id"`
- UserID types.UserId `db:"user_id"`
- Epoch uint64 `db:"created_epoch"`
- EventFilter string `db:"event_filter"`
- UnsubscribeHash sql.NullString `db:"unsubscribe_hash"`
- }
-
- err := db.FrontendWriterDB.Select(&dbResult, `
- SELECT us.id, us.user_id, us.created_epoch, us.event_filter, ENCODE(us.unsubscribe_hash, 'hex') AS unsubscribe_hash
- FROM users_subscriptions AS us
- WHERE
- us.event_name=$1
- AND
- us.event_filter=$2
- AND
- ((us.last_sent_ts <= NOW() - INTERVAL '2 DAY' AND TO_TIMESTAMP($3) > us.last_sent_ts) OR us.last_sent_ts IS NULL)
- `,
- eventName, strings.ToLower(client.Name), client.Date.Unix()) // was last notification sent 2 days ago for this client
+ // err := db.FrontendWriterDB.Select(&dbResult, `
+ // SELECT us.id, us.user_id, us.created_epoch, us.event_filter, ENCODE(us.unsubscribe_hash, 'hex') AS unsubscribe_hash
+ // FROM users_subscriptions AS us
+ // WHERE
+ // us.event_name=$1
+ // AND
+ // us.event_filter=$2
+ // AND
+ // ((us.last_sent_ts <= NOW() - INTERVAL '2 DAY' AND TO_TIMESTAMP($3) > us.last_sent_ts) OR us.last_sent_ts IS NULL)
+ // `,
+ // eventName, strings.ToLower(client.Name), client.Date.Unix()) // was last notification sent 2 days ago for this client
+
+ dbResult, err := GetSubsForEventFilter(
+ eventName,
+ "(us.last_sent_ts <= NOW() - INTERVAL '2 DAY' AND TO_TIMESTAMP(?) > us.last_sent_ts) OR us.last_sent_ts IS NULL",
+ []interface{}{client.Date.Unix()},
+ []string{strings.ToLower(client.Name)})
if err != nil {
return err
}
- for _, r := range dbResult {
- n := ðClientNotification{
- NotificationBaseImpl: types.NotificationBaseImpl{
- SubscriptionID: r.SubscriptionID,
- UserID: r.UserID,
- Epoch: r.Epoch,
- EventFilter: r.EventFilter,
- UnsubscribeHash: r.UnsubscribeHash,
- },
- EthClient: client.Name,
+ for _, subs := range dbResult {
+ for _, sub := range subs {
+ n := ðClientNotification{
+ NotificationBaseImpl: types.NotificationBaseImpl{
+ SubscriptionID: *sub.ID,
+ UserID: *sub.UserID,
+ Epoch: sub.CreatedEpoch,
+ EventFilter: sub.EventFilter,
+ UnsubscribeHash: sub.UnsubscribeHash,
+ },
+ EthClient: client.Name,
+ }
+ notificationsByUserID.AddNotification(n)
+ metrics.NotificationsCollected.WithLabelValues(string(n.GetEventName())).Inc()
}
- notificationsByUserID.AddNotification(n)
- metrics.NotificationsCollected.WithLabelValues(string(n.GetEventName())).Inc()
}
}
return nil
@@ -2041,7 +2042,7 @@ func collectMonitoringMachineOffline(notificationsByUserID types.NotificationsPe
nowTs := time.Now().Unix()
return collectMonitoringMachine(notificationsByUserID, types.MonitoringMachineOfflineEventName, 120,
// notify condition
- func(_ *MachineEvents, machineData *types.MachineMetricSystemUser) bool {
+ func(subscribeData *types.Subscription, machineData *types.MachineMetricSystemUser) bool {
if machineData.CurrentDataInsertTs < nowTs-10*60 && machineData.CurrentDataInsertTs > nowTs-90*60 {
return true
}
@@ -2059,7 +2060,7 @@ func isMachineDataRecent(machineData *types.MachineMetricSystemUser) bool {
func collectMonitoringMachineDiskAlmostFull(notificationsByUserID types.NotificationsPerUserId, epoch uint64) error {
return collectMonitoringMachine(notificationsByUserID, types.MonitoringMachineDiskAlmostFullEventName, 750,
// notify condition
- func(subscribeData *MachineEvents, machineData *types.MachineMetricSystemUser) bool {
+ func(subscribeData *types.Subscription, machineData *types.MachineMetricSystemUser) bool {
if !isMachineDataRecent(machineData) {
return false
}
@@ -2074,7 +2075,7 @@ func collectMonitoringMachineDiskAlmostFull(notificationsByUserID types.Notifica
func collectMonitoringMachineCPULoad(notificationsByUserID types.NotificationsPerUserId, epoch uint64) error {
return collectMonitoringMachine(notificationsByUserID, types.MonitoringMachineCpuLoadEventName, 10,
// notify condition
- func(subscribeData *MachineEvents, machineData *types.MachineMetricSystemUser) bool {
+ func(subscribeData *types.Subscription, machineData *types.MachineMetricSystemUser) bool {
if !isMachineDataRecent(machineData) {
return false
}
@@ -2096,7 +2097,7 @@ func collectMonitoringMachineCPULoad(notificationsByUserID types.NotificationsPe
func collectMonitoringMachineMemoryUsage(notificationsByUserID types.NotificationsPerUserId, epoch uint64) error {
return collectMonitoringMachine(notificationsByUserID, types.MonitoringMachineMemoryUsageEventName, 10,
// notify condition
- func(subscribeData *MachineEvents, machineData *types.MachineMetricSystemUser) bool {
+ func(subscribeData *types.Subscription, machineData *types.MachineMetricSystemUser) bool {
if !isMachineDataRecent(machineData) {
return false
}
@@ -2117,21 +2118,23 @@ func collectMonitoringMachine(
notificationsByUserID types.NotificationsPerUserId,
eventName types.EventName,
epochWaitInBetween int,
- notifyConditionFulfilled func(subscribeData *MachineEvents, machineData *types.MachineMetricSystemUser) bool,
+ notifyConditionFulfilled func(subscribeData *types.Subscription, machineData *types.MachineMetricSystemUser) bool,
epoch uint64,
) error {
- var allSubscribed []MachineEvents
+ var allSubscribed []*types.Subscription
+ // event_filter == machine name
+ // TODO: clarify why we need grouping here?!
err := db.FrontendWriterDB.Select(&allSubscribed,
`SELECT
us.user_id,
max(us.id) AS id,
ENCODE((array_agg(us.unsubscribe_hash))[1], 'hex') AS unsubscribe_hash,
- event_filter AS machine,
+ event_filter,
COALESCE(event_threshold, 0) AS event_threshold
FROM users_subscriptions us
WHERE us.event_name = $1 AND us.created_epoch <= $2
AND (us.last_sent_epoch < ($2 - $3) OR us.last_sent_epoch IS NULL)
- group by us.user_id, machine, event_threshold`,
+ group by us.user_id, event_filter, event_threshold`,
eventName, epoch, epochWaitInBetween)
if err != nil {
return err
@@ -2139,7 +2142,7 @@ func collectMonitoringMachine(
rowKeys := gcp_bigtable.RowList{}
for _, data := range allSubscribed {
- rowKeys = append(rowKeys, db.BigtableClient.GetMachineRowKey(data.UserID, "system", data.MachineName))
+ rowKeys = append(rowKeys, db.BigtableClient.GetMachineRowKey(*data.UserID, "system", data.EventFilter))
}
machineDataOfSubscribed, err := db.BigtableClient.GetMachineMetricsForNotifications(rowKeys)
@@ -2147,20 +2150,20 @@ func collectMonitoringMachine(
return err
}
- var result []MachineEvents
+ var result []*types.Subscription
for _, data := range allSubscribed {
localData := data // Create a local copy of the data variable
- machineMap, found := machineDataOfSubscribed[localData.UserID]
+ machineMap, found := machineDataOfSubscribed[*localData.UserID]
if !found {
continue
}
- currentMachineData, found := machineMap[localData.MachineName]
+ currentMachineData, found := machineMap[localData.EventFilter]
if !found {
continue
}
//logrus.Infof("currentMachineData %v | %v | %v | %v", currentMachine.CurrentDataInsertTs, currentMachine.CompareDataInsertTs, currentMachine.UserID, currentMachine.Machine)
- if notifyConditionFulfilled(&localData, currentMachineData) {
+ if notifyConditionFulfilled(localData, currentMachineData) {
result = append(result, localData)
}
}
@@ -2208,13 +2211,13 @@ func collectMonitoringMachine(
for _, r := range result {
n := &monitorMachineNotification{
NotificationBaseImpl: types.NotificationBaseImpl{
- SubscriptionID: r.SubscriptionID,
- UserID: r.UserID,
+ SubscriptionID: *r.ID,
+ UserID: *r.UserID,
EventName: eventName,
Epoch: epoch,
UnsubscribeHash: r.UnsubscribeHash,
},
- MachineName: r.MachineName,
+ MachineName: r.EventFilter,
}
//logrus.Infof("notify %v %v", eventName, n)
notificationsByUserID.AddNotification(n)
@@ -2351,42 +2354,37 @@ func collectTaxReportNotificationNotifications(notificationsByUserID types.Notif
return nil
}
- var dbResult []struct {
- SubscriptionID uint64 `db:"id"`
- UserID types.UserId `db:"user_id"`
- Epoch uint64 `db:"created_epoch"`
- EventFilter string `db:"event_filter"`
- UnsubscribeHash sql.NullString `db:"unsubscribe_hash"`
- }
-
- name := string(eventName)
- if utils.Config.Chain.ClConfig.ConfigName != "" {
- name = utils.Config.Chain.ClConfig.ConfigName + ":" + name
- }
-
- err = db.FrontendWriterDB.Select(&dbResult, `
- SELECT us.id, us.user_id, us.created_epoch, us.event_filter, ENCODE(us.unsubscribe_hash, 'hex') AS unsubscribe_hash
- FROM users_subscriptions AS us
- WHERE us.event_name=$1 AND (us.last_sent_ts < $2 OR (us.last_sent_ts IS NULL AND us.created_ts < $2));
- `,
- name, firstDayOfMonth)
+ // err = db.FrontendWriterDB.Select(&dbResult, `
+ // SELECT us.id, us.user_id, us.created_epoch, us.event_filter, ENCODE(us.unsubscribe_hash, 'hex') AS unsubscribe_hash
+ // FROM users_subscriptions AS us
+ // WHERE us.event_name=$1 AND (us.last_sent_ts < $2 OR (us.last_sent_ts IS NULL AND us.created_ts < $2));
+ // `,
+ // name, firstDayOfMonth)
+ dbResults, err := GetSubsForEventFilter(
+ types.TaxReportEventName,
+ "us.last_sent_ts < ? OR (us.last_sent_ts IS NULL AND us.created_ts < ?)",
+ []interface{}{firstDayOfMonth, firstDayOfMonth},
+ nil,
+ )
if err != nil {
return err
}
- for _, r := range dbResult {
- n := &taxReportNotification{
- NotificationBaseImpl: types.NotificationBaseImpl{
- SubscriptionID: r.SubscriptionID,
- UserID: r.UserID,
- Epoch: r.Epoch,
- EventFilter: r.EventFilter,
- UnsubscribeHash: r.UnsubscribeHash,
- },
+ for _, subs := range dbResults {
+ for _, sub := range subs {
+ n := &taxReportNotification{
+ NotificationBaseImpl: types.NotificationBaseImpl{
+ SubscriptionID: *sub.ID,
+ UserID: *sub.UserID,
+ Epoch: sub.CreatedEpoch,
+ EventFilter: sub.EventFilter,
+ UnsubscribeHash: sub.UnsubscribeHash,
+ },
+ }
+ notificationsByUserID.AddNotification(n)
+ metrics.NotificationsCollected.WithLabelValues(string(n.GetEventName())).Inc()
}
- notificationsByUserID.AddNotification(n)
- metrics.NotificationsCollected.WithLabelValues(string(n.GetEventName())).Inc()
}
return nil
@@ -2425,38 +2423,38 @@ func collectNetworkNotifications(notificationsByUserID types.NotificationsPerUse
}
if count > 0 {
- var dbResult []struct {
- SubscriptionID uint64 `db:"id"`
- UserID types.UserId `db:"user_id"`
- Epoch uint64 `db:"created_epoch"`
- EventFilter string `db:"event_filter"`
- UnsubscribeHash sql.NullString `db:"unsubscribe_hash"`
- }
-
- err := db.FrontendWriterDB.Select(&dbResult, `
- SELECT us.id, us.user_id, us.created_epoch, us.event_filter, ENCODE(us.unsubscribe_hash, 'hex') AS unsubscribe_hash
- FROM users_subscriptions AS us
- WHERE us.event_name=$1 AND (us.last_sent_ts <= NOW() - INTERVAL '1 hour' OR us.last_sent_ts IS NULL);
- `,
- utils.GetNetwork()+":"+string(eventName))
-
+ // err := db.FrontendWriterDB.Select(&dbResult, `
+ // SELECT us.id, us.user_id, us.created_epoch, us.event_filter, ENCODE(us.unsubscribe_hash, 'hex') AS unsubscribe_hash
+ // FROM users_subscriptions AS us
+ // WHERE us.event_name=$1 AND (us.last_sent_ts <= NOW() - INTERVAL '1 hour' OR us.last_sent_ts IS NULL);
+ // `,
+ // utils.GetNetwork()+":"+string(eventName))
+
+ dbResult, err := GetSubsForEventFilter(
+ eventName,
+ "us.last_sent_ts <= NOW() - INTERVAL '1 hour' OR us.last_sent_ts IS NULL",
+ nil,
+ nil,
+ )
if err != nil {
return err
}
- for _, r := range dbResult {
- n := &networkNotification{
- NotificationBaseImpl: types.NotificationBaseImpl{
- SubscriptionID: r.SubscriptionID,
- UserID: r.UserID,
- Epoch: r.Epoch,
- EventFilter: r.EventFilter,
- UnsubscribeHash: r.UnsubscribeHash,
- },
- }
+ for _, subs := range dbResult {
+ for _, sub := range subs {
+ n := &networkNotification{
+ NotificationBaseImpl: types.NotificationBaseImpl{
+ SubscriptionID: *sub.ID,
+ UserID: *sub.UserID,
+ Epoch: sub.CreatedEpoch,
+ EventFilter: sub.EventFilter,
+ UnsubscribeHash: sub.UnsubscribeHash,
+ },
+ }
- notificationsByUserID.AddNotification(n)
- metrics.NotificationsCollected.WithLabelValues(string(n.GetEventName())).Inc()
+ notificationsByUserID.AddNotification(n)
+ metrics.NotificationsCollected.WithLabelValues(string(n.GetEventName())).Inc()
+ }
}
}
@@ -2518,40 +2516,40 @@ func collectRocketpoolComissionNotifications(notificationsByUserID types.Notific
}
if fee > 0 {
- var dbResult []struct {
- SubscriptionID uint64 `db:"id"`
- UserID types.UserId `db:"user_id"`
- Epoch uint64 `db:"created_epoch"`
- EventFilter string `db:"event_filter"`
- UnsubscribeHash sql.NullString `db:"unsubscribe_hash"`
- }
-
- err := db.FrontendWriterDB.Select(&dbResult, `
- SELECT us.id, us.user_id, us.created_epoch, us.event_filter, ENCODE(us.unsubscribe_hash, 'hex') AS unsubscribe_hash
- FROM users_subscriptions AS us
- WHERE us.event_name=$1 AND (us.last_sent_ts <= NOW() - INTERVAL '8 hours' OR us.last_sent_ts IS NULL) AND (us.event_threshold <= $2 OR (us.event_threshold < 0 AND us.event_threshold * -1 >= $2));
- `,
- utils.GetNetwork()+":"+string(eventName), fee)
-
+ // err := db.FrontendWriterDB.Select(&dbResult, `
+ // SELECT us.id, us.user_id, us.created_epoch, us.event_filter, ENCODE(us.unsubscribe_hash, 'hex') AS unsubscribe_hash
+ // FROM users_subscriptions AS us
+ // WHERE us.event_name=$1 AND (us.last_sent_ts <= NOW() - INTERVAL '8 hours' OR us.last_sent_ts IS NULL) AND (us.event_threshold <= $2 OR (us.event_threshold < 0 AND us.event_threshold * -1 >= $2));
+ // `,
+ // utils.GetNetwork()+":"+string(eventName), fee)
+
+ dbResult, err := GetSubsForEventFilter(
+ eventName,
+ "(us.last_sent_ts <= NOW() - INTERVAL '8 hours' OR us.last_sent_ts IS NULL) AND (us.event_threshold <= ? OR (us.event_threshold < 0 AND us.event_threshold * -1 >= ?)",
+ []interface{}{fee, fee},
+ nil,
+ )
if err != nil {
return err
}
- for _, r := range dbResult {
- n := &rocketpoolNotification{
- NotificationBaseImpl: types.NotificationBaseImpl{
- SubscriptionID: r.SubscriptionID,
- UserID: r.UserID,
- Epoch: r.Epoch,
- EventFilter: r.EventFilter,
- EventName: eventName,
- UnsubscribeHash: r.UnsubscribeHash,
- },
- ExtraData: strconv.FormatInt(int64(fee*100), 10) + "%",
- }
+ for _, subs := range dbResult {
+ for _, sub := range subs {
+ n := &rocketpoolNotification{
+ NotificationBaseImpl: types.NotificationBaseImpl{
+ SubscriptionID: *sub.ID,
+ UserID: *sub.UserID,
+ Epoch: sub.CreatedEpoch,
+ EventFilter: sub.EventFilter,
+ EventName: eventName,
+ UnsubscribeHash: sub.UnsubscribeHash,
+ },
+ ExtraData: strconv.FormatInt(int64(fee*100), 10) + "%",
+ }
- notificationsByUserID.AddNotification(n)
- metrics.NotificationsCollected.WithLabelValues(string(n.GetEventName())).Inc()
+ notificationsByUserID.AddNotification(n)
+ metrics.NotificationsCollected.WithLabelValues(string(n.GetEventName())).Inc()
+ }
}
}
@@ -2569,39 +2567,41 @@ func collectRocketpoolRewardClaimRoundNotifications(notificationsByUserID types.
}
if ts+3*60*60 > time.Now().Unix() {
- var dbResult []struct {
- SubscriptionID uint64 `db:"id"`
- UserID types.UserId `db:"user_id"`
- Epoch uint64 `db:"created_epoch"`
- EventFilter string `db:"event_filter"`
- UnsubscribeHash sql.NullString `db:"unsubscribe_hash"`
- }
-
- err := db.FrontendWriterDB.Select(&dbResult, `
- SELECT us.id, us.user_id, us.created_epoch, us.event_filter, ENCODE(us.unsubscribe_hash, 'hex') AS unsubscribe_hash
- FROM users_subscriptions AS us
- WHERE us.event_name=$1 AND (us.last_sent_ts <= NOW() - INTERVAL '5 hours' OR us.last_sent_ts IS NULL);
- `,
- utils.GetNetwork()+":"+string(eventName))
-
+ // var dbResult []*types.Subscription
+
+ // err := db.FrontendWriterDB.Select(&dbResult, `
+ // SELECT us.id, us.user_id, us.created_epoch, us.event_filter, ENCODE(us.unsubscribe_hash, 'hex') AS unsubscribe_hash
+ // FROM users_subscriptions AS us
+ // WHERE us.event_name=$1 AND (us.last_sent_ts <= NOW() - INTERVAL '5 hours' OR us.last_sent_ts IS NULL);
+ // `,
+ // utils.GetNetwork()+":"+string(eventName))
+
+ dbResult, err := GetSubsForEventFilter(
+ eventName,
+ "us.last_sent_ts <= NOW() - INTERVAL '5 hours' OR us.last_sent_ts IS NULL",
+ nil,
+ nil,
+ )
if err != nil {
return err
}
- for _, r := range dbResult {
- n := &rocketpoolNotification{
- NotificationBaseImpl: types.NotificationBaseImpl{
- SubscriptionID: r.SubscriptionID,
- UserID: r.UserID,
- Epoch: r.Epoch,
- EventFilter: r.EventFilter,
- EventName: eventName,
- UnsubscribeHash: r.UnsubscribeHash,
- },
- }
+ for _, subs := range dbResult {
+ for _, sub := range subs {
+ n := &rocketpoolNotification{
+ NotificationBaseImpl: types.NotificationBaseImpl{
+ SubscriptionID: *sub.ID,
+ UserID: *sub.UserID,
+ Epoch: sub.CreatedEpoch,
+ EventFilter: sub.EventFilter,
+ EventName: eventName,
+ UnsubscribeHash: sub.UnsubscribeHash,
+ },
+ }
- notificationsByUserID.AddNotification(n)
- metrics.NotificationsCollected.WithLabelValues(string(n.GetEventName())).Inc()
+ notificationsByUserID.AddNotification(n)
+ metrics.NotificationsCollected.WithLabelValues(string(n.GetEventName())).Inc()
+ }
}
}
@@ -2609,7 +2609,7 @@ func collectRocketpoolRewardClaimRoundNotifications(notificationsByUserID types.
}
func collectRocketpoolRPLCollateralNotifications(notificationsByUserID types.NotificationsPerUserId, eventName types.EventName, epoch uint64) error {
- subMap, err := GetSubsForEventFilter(eventName)
+ subMap, err := GetSubsForEventFilter(eventName, "", nil, nil)
if err != nil {
return fmt.Errorf("error getting subscriptions for RocketpoolRPLCollateral %w", err)
}
@@ -2809,39 +2809,35 @@ func collectSyncCommittee(notificationsByUserID types.NotificationsPerUserId, ev
pubKeys = append(pubKeys, val.PubKey)
}
- var dbResult []struct {
- SubscriptionID uint64 `db:"id"`
- UserID types.UserId `db:"user_id"`
- EventFilter string `db:"event_filter"`
- UnsubscribeHash sql.NullString `db:"unsubscribe_hash"`
- }
-
- err = db.FrontendWriterDB.Select(&dbResult, `
- SELECT us.id, us.user_id, us.event_filter, ENCODE(us.unsubscribe_hash, 'hex') as unsubscribe_hash
- FROM users_subscriptions AS us
- WHERE us.event_name=$1 AND (us.last_sent_ts <= NOW() - INTERVAL '26 hours' OR us.last_sent_ts IS NULL) AND event_filter = ANY($2);
- `,
- utils.GetNetwork()+":"+string(eventName), pq.StringArray(pubKeys),
- )
+ dbResult, err := GetSubsForEventFilter(eventName, "us.last_sent_ts <= NOW() - INTERVAL '26 hours' OR us.last_sent_ts IS NULL", nil, pubKeys)
+ // err = db.FrontendWriterDB.Select(&dbResult, `
+ // SELECT us.id, us.user_id, us.event_filter, ENCODE(us.unsubscribe_hash, 'hex') as unsubscribe_hash
+ // FROM users_subscriptions AS us
+ // WHERE us.event_name=$1 AND (us.last_sent_ts <= NOW() - INTERVAL '26 hours' OR us.last_sent_ts IS NULL) AND event_filter = ANY($2);
+ // `,
+ // utils.GetNetwork()+":"+string(eventName), pq.StringArray(pubKeys),
+ // )
if err != nil {
return err
}
- for _, r := range dbResult {
- n := &rocketpoolNotification{
- NotificationBaseImpl: types.NotificationBaseImpl{
- SubscriptionID: r.SubscriptionID,
- UserID: r.UserID,
- Epoch: epoch,
- EventFilter: r.EventFilter,
- EventName: eventName,
- UnsubscribeHash: r.UnsubscribeHash,
- },
- ExtraData: fmt.Sprintf("%v|%v|%v", mapping[r.EventFilter], nextPeriod*utils.Config.Chain.ClConfig.EpochsPerSyncCommitteePeriod, (nextPeriod+1)*utils.Config.Chain.ClConfig.EpochsPerSyncCommitteePeriod),
+ for _, subs := range dbResult {
+ for _, sub := range subs {
+ n := &rocketpoolNotification{
+ NotificationBaseImpl: types.NotificationBaseImpl{
+ SubscriptionID: *sub.ID,
+ UserID: *sub.UserID,
+ Epoch: epoch,
+ EventFilter: sub.EventFilter,
+ EventName: eventName,
+ UnsubscribeHash: sub.UnsubscribeHash,
+ },
+ ExtraData: fmt.Sprintf("%v|%v|%v", mapping[sub.EventFilter], nextPeriod*utils.Config.Chain.ClConfig.EpochsPerSyncCommitteePeriod, (nextPeriod+1)*utils.Config.Chain.ClConfig.EpochsPerSyncCommitteePeriod),
+ }
+ notificationsByUserID.AddNotification(n)
+ metrics.NotificationsCollected.WithLabelValues(string(n.GetEventName())).Inc()
}
- notificationsByUserID.AddNotification(n)
- metrics.NotificationsCollected.WithLabelValues(string(n.GetEventName())).Inc()
}
return nil
From f89ce9738c86f21d5b4067c878358308324ef59b Mon Sep 17 00:00:00 2001
From: peter <1674920+peterbitfly@users.noreply.github.com>
Date: Mon, 8 Jul 2024 10:29:47 +0200
Subject: [PATCH 09/39] fix linter
---
backend/pkg/commons/types/frontend.go | 1 -
backend/pkg/notification/notifications.go | 13 ++++++++++---
2 files changed, 10 insertions(+), 4 deletions(-)
diff --git a/backend/pkg/commons/types/frontend.go b/backend/pkg/commons/types/frontend.go
index a51e5e4c2..f9669b9ec 100644
--- a/backend/pkg/commons/types/frontend.go
+++ b/backend/pkg/commons/types/frontend.go
@@ -27,7 +27,6 @@ type EventFilter string
type NotificationsPerUserId map[UserId]map[EventName]map[EventFilter]Notification
func (npui NotificationsPerUserId) AddNotification(n Notification) {
-
if n.GetUserId() == 0 {
log.Fatal(fmt.Errorf("Notification user id is 0"), fmt.Sprintf("Notification: %v", n), 0)
}
diff --git a/backend/pkg/notification/notifications.go b/backend/pkg/notification/notifications.go
index 0f1a71b3e..c81d29e6a 100644
--- a/backend/pkg/notification/notifications.go
+++ b/backend/pkg/notification/notifications.go
@@ -231,6 +231,7 @@ func collectNotifications(epoch uint64) (types.NotificationsPerUserId, error) {
var err error
var dbIsCoherent bool
+ // do a consistency check to make sure that we have all the data we need in the db
err = db.WriterDb.Get(&dbIsCoherent, `
SELECT
NOT (array[false] && array_agg(is_coherent)) AS is_coherent
@@ -263,6 +264,8 @@ func collectNotifications(epoch uint64) (types.NotificationsPerUserId, error) {
}
log.Infof("retrieving dashboard definitions")
+ // Retrieve all dashboard definitions to be able to retrieve validators included in
+ // the group notification subscriptions
// TODO: add a filter to retrieve only groups that have notifications enabled
// Needs a new field in the db
var dashboardDefinitions []dashboardDefinitionRow
@@ -305,6 +308,8 @@ func collectNotifications(epoch uint64) (types.NotificationsPerUserId, error) {
validatorDashboardConfig.DashboardsByUserId[row.UserId][row.DashboardId].Groups[row.GroupId].Validators = append(validatorDashboardConfig.DashboardsByUserId[row.UserId][row.DashboardId].Groups[row.GroupId].Validators, uint64(row.ValidatorIndex))
}
+ // TODO: pass the validatorDashboardConfig to the notification collection functions
+
err = collectAttestationAndOfflineValidatorNotifications(notificationsByUserID, epoch)
if err != nil {
metrics.Errors.WithLabelValues("notifications_collect_missed_attestation").Inc()
@@ -1389,7 +1394,9 @@ func (n *validatorProposalNotification) GetInfoMarkdown() string {
return generalPart
}
+// collectAttestationAndOfflineValidatorNotifications collects notifications for missed attestations and offline validators
func collectAttestationAndOfflineValidatorNotifications(notificationsByUserID types.NotificationsPerUserId, epoch uint64) error {
+ // Retrieve subscriptions for missed attestations
subMap, err := GetSubsForEventFilter(types.ValidatorMissedAttestationEventName, "", nil, nil)
if err != nil {
return fmt.Errorf("error getting subscriptions for missted attestations %w", err)
@@ -1403,12 +1410,13 @@ func collectAttestationAndOfflineValidatorNotifications(notificationsByUserID ty
}
// get attestations for all validators for the last 4 epochs
-
+ // we need 4 epochs so that can detect the online / offline status of validators
validators, err := db.GetValidatorIndices()
if err != nil {
return err
}
+ // this reads the submitted attestations for the last 4 epochs
participationPerEpoch, err := db.GetValidatorAttestationHistoryForNotifications(epoch-3, epoch)
if err != nil {
return fmt.Errorf("error getting validator attestations from db %w", err)
@@ -1988,7 +1996,6 @@ func (n *ethClientNotification) GetInfoMarkdown() string {
func collectEthClientNotifications(notificationsByUserID types.NotificationsPerUserId, eventName types.EventName) error {
updatedClients := ethclients.GetUpdatedClients() //only check if there are new updates
for _, client := range updatedClients {
-
// err := db.FrontendWriterDB.Select(&dbResult, `
// SELECT us.id, us.user_id, us.created_epoch, us.event_filter, ENCODE(us.unsubscribe_hash, 'hex') AS unsubscribe_hash
// FROM users_subscriptions AS us
@@ -2362,7 +2369,7 @@ func collectTaxReportNotificationNotifications(notificationsByUserID types.Notif
// name, firstDayOfMonth)
dbResults, err := GetSubsForEventFilter(
- types.TaxReportEventName,
+ eventName,
"us.last_sent_ts < ? OR (us.last_sent_ts IS NULL AND us.created_ts < ?)",
[]interface{}{firstDayOfMonth, firstDayOfMonth},
nil,
From 370bff2970a29c62f63903478c89e4dc7e188185 Mon Sep 17 00:00:00 2001
From: peter <1674920+peterbitfly@users.noreply.github.com>
Date: Mon, 8 Jul 2024 12:18:58 +0200
Subject: [PATCH 10/39] fix bug in AddNotification function
---
backend/pkg/commons/types/frontend.go | 4 +-
backend/pkg/notification/notifications.go | 96 ++++++++++++-----------
2 files changed, 53 insertions(+), 47 deletions(-)
diff --git a/backend/pkg/commons/types/frontend.go b/backend/pkg/commons/types/frontend.go
index f9669b9ec..2a4f0d8ca 100644
--- a/backend/pkg/commons/types/frontend.go
+++ b/backend/pkg/commons/types/frontend.go
@@ -41,7 +41,7 @@ func (npui NotificationsPerUserId) AddNotification(n Notification) {
npui[n.GetUserId()] = make(map[EventName]map[EventFilter]Notification)
}
if _, ok := npui[n.GetUserId()][n.GetEventName()]; !ok {
- npui[n.GetUserId()][EventName(n.GetEventFilter())] = make(map[EventFilter]Notification)
+ npui[n.GetUserId()][n.GetEventName()] = make(map[EventFilter]Notification)
}
npui[n.GetUserId()][n.GetEventName()][EventFilter(n.GetEventFilter())] = n
}
@@ -344,7 +344,7 @@ func (n NotificationBaseImpl) GetUserId() UserId {
type Subscription struct {
ID *uint64 `db:"id,omitempty"`
UserID *UserId `db:"user_id,omitempty"`
- EventName string `db:"event_name"`
+ EventName EventName `db:"event_name"`
EventFilter string `db:"event_filter"`
LastSent *time.Time `db:"last_sent_ts"`
LastEpoch *uint64 `db:"last_sent_epoch"`
diff --git a/backend/pkg/notification/notifications.go b/backend/pkg/notification/notifications.go
index c81d29e6a..e803f8514 100644
--- a/backend/pkg/notification/notifications.go
+++ b/backend/pkg/notification/notifications.go
@@ -309,7 +309,9 @@ func collectNotifications(epoch uint64) (types.NotificationsPerUserId, error) {
}
// TODO: pass the validatorDashboardConfig to the notification collection functions
-
+ // The following functions will collect the notifications and add them to the
+ // notificationsByUserID map. The notifications will be queued and sent later
+ // by the notification sender process
err = collectAttestationAndOfflineValidatorNotifications(notificationsByUserID, epoch)
if err != nil {
metrics.Errors.WithLabelValues("notifications_collect_missed_attestation").Inc()
@@ -352,7 +354,7 @@ func collectNotifications(epoch uint64) (types.NotificationsPerUserId, error) {
}
log.Infof("collecting withdrawal notifications took: %v", time.Since(start))
- err = collectNetworkNotifications(notificationsByUserID, types.NetworkLivenessIncreasedEventName)
+ err = collectNetworkNotifications(notificationsByUserID)
if err != nil {
metrics.Errors.WithLabelValues("notifications_collect_network").Inc()
return nil, fmt.Errorf("error collecting network notifications: %v", err)
@@ -372,7 +374,7 @@ func collectNotifications(epoch uint64) (types.NotificationsPerUserId, error) {
return nil, fmt.Errorf("error collecting rocketpool notifications: %v", err)
}
} else {
- err = collectRocketpoolComissionNotifications(notificationsByUserID, types.RocketpoolCommissionThresholdEventName)
+ err = collectRocketpoolComissionNotifications(notificationsByUserID)
if err != nil {
//nolint:misspell
metrics.Errors.WithLabelValues("notifications_collect_rocketpool_comission").Inc()
@@ -380,7 +382,7 @@ func collectNotifications(epoch uint64) (types.NotificationsPerUserId, error) {
}
log.Infof("collecting rocketpool commissions took: %v", time.Since(start))
- err = collectRocketpoolRewardClaimRoundNotifications(notificationsByUserID, types.RocketpoolNewClaimRoundStartedEventName)
+ err = collectRocketpoolRewardClaimRoundNotifications(notificationsByUserID)
if err != nil {
metrics.Errors.WithLabelValues("notifications_collect_rocketpool_reward_claim").Inc()
return nil, fmt.Errorf("error collecting new rocketpool claim round: %v", err)
@@ -403,7 +405,7 @@ func collectNotifications(epoch uint64) (types.NotificationsPerUserId, error) {
}
}
- err = collectSyncCommittee(notificationsByUserID, types.SyncCommitteeSoon, epoch)
+ err = collectSyncCommittee(notificationsByUserID, epoch)
if err != nil {
metrics.Errors.WithLabelValues("notifications_collect_sync_committee").Inc()
return nil, fmt.Errorf("error collecting sync committee: %v", err)
@@ -446,14 +448,14 @@ func collectUserDbNotifications(epoch uint64) (types.NotificationsPerUserId, err
}
// New ETH clients
- err = collectEthClientNotifications(notificationsByUserID, types.EthClientUpdateEventName)
+ err = collectEthClientNotifications(notificationsByUserID)
if err != nil {
metrics.Errors.WithLabelValues("notifications_collect_eth_client").Inc()
return nil, fmt.Errorf("error collecting Eth client notifications: %v", err)
}
//Tax Report
- err = collectTaxReportNotificationNotifications(notificationsByUserID, types.TaxReportEventName)
+ err = collectTaxReportNotificationNotifications(notificationsByUserID)
if err != nil {
metrics.Errors.WithLabelValues("notifications_collect_tax_report").Inc()
return nil, fmt.Errorf("error collecting tax report notifications: %v", err)
@@ -735,6 +737,8 @@ func queueEmailNotifications(notificationsByUserID types.NotificationsPerUserId,
notificationTitles = append(notificationTitles, title)
}
+ // TODO: this is bad and will break in case there are a lot of unsubscribe hashes to generate
+ // the unsubscribe hash should be set when we add the subscription to the db
unsubHash := n.GetUnsubscribeHash()
if unsubHash == "" {
id := n.GetSubscriptionID()
@@ -760,10 +764,8 @@ func queueEmailNotifications(notificationsByUserID types.NotificationsPerUserId,
`, id)
if err != nil {
log.Error(err, "error getting user subscription by subscription id", 0)
- err = tx.Rollback()
- if err != nil {
- log.Error(err, "error rolling back transaction", 0)
- }
+ utils.Rollback(tx)
+ continue
}
raw := fmt.Sprintf("%v%v%v%v", sub.ID, sub.UserID, sub.EventName, sub.CreatedTime)
@@ -772,19 +774,15 @@ func queueEmailNotifications(notificationsByUserID types.NotificationsPerUserId,
_, err = tx.Exec("UPDATE users_subscriptions set unsubscribe_hash = $1 WHERE id = $2", digest[:], id)
if err != nil {
log.Error(err, "error updating users subscriptions table with unsubscribe hash", 0)
- err = tx.Rollback()
- if err != nil {
- log.Error(err, "error rolling back transaction", 0)
- }
+ utils.Rollback(tx)
+ continue
}
err = tx.Commit()
if err != nil {
log.Error(err, "error committing transaction to update users subscriptions with an unsubscribe hash", 0)
- err = tx.Rollback()
- if err != nil {
- log.Error(err, "error rolling back transaction", 0)
- }
+ utils.Rollback(tx)
+ continue
}
unsubHash = hex.EncodeToString(digest[:])
@@ -1323,7 +1321,7 @@ func collectBlockProposalNotifications(notificationsByUserID types.Notifications
SubscriptionID: *sub.ID,
UserID: *sub.UserID,
Epoch: epoch,
- EventName: eventName,
+ EventName: sub.EventName,
EventFilter: hex.EncodeToString(pubkey),
},
ValidatorIndex: event.Proposer,
@@ -1478,7 +1476,7 @@ func collectAttestationAndOfflineValidatorNotifications(notificationsByUserID ty
SubscriptionID: *sub.ID,
UserID: *sub.UserID,
Epoch: event.Epoch,
- EventName: types.ValidatorMissedAttestationEventName,
+ EventName: sub.EventName,
EventFilter: hex.EncodeToString(event.EventFilter),
},
ValidatorIndex: event.ValidatorIndex,
@@ -1583,9 +1581,10 @@ func collectAttestationAndOfflineValidatorNotifications(notificationsByUserID ty
NotificationBaseImpl: types.NotificationBaseImpl{
SubscriptionID: *sub.ID,
Epoch: epoch,
- EventName: types.ValidatorIsOfflineEventName,
+ EventName: sub.EventName,
LatestState: fmt.Sprint(epoch - 2), // first epoch the validator stopped attesting
EventFilter: hex.EncodeToString(validator.Pubkey),
+ UserID: *sub.UserID,
},
ValidatorIndex: validator.Index,
IsOffline: true,
@@ -1627,7 +1626,7 @@ func collectAttestationAndOfflineValidatorNotifications(notificationsByUserID ty
SubscriptionID: *sub.ID,
UserID: *sub.UserID,
Epoch: epoch,
- EventName: types.ValidatorIsOfflineEventName,
+ EventName: sub.EventName,
EventFilter: hex.EncodeToString(validator.Pubkey),
LatestState: "-",
},
@@ -1781,7 +1780,7 @@ func collectValidatorGotSlashedNotifications(notificationsByUserID types.Notific
resultsLen := len(dbResult)
for i, event := range dbResult {
// TODO: clarify why we need the id here?!
- query += fmt.Sprintf(`SELECT %d AS ref, id, user_id, ENCODE(unsubscribe_hash, 'hex') AS unsubscribe_hash from users_subscriptions where event_name = $1 AND event_filter = '%x'`, i, event.SlashedValidatorPubkey)
+ query += fmt.Sprintf(`SELECT %d AS ref, id, user_id, ENCODE(unsubscribe_hash, 'hex') AS unsubscribe_hash, event_name from users_subscriptions where event_name = $1 AND event_filter = '%x'`, i, event.SlashedValidatorPubkey)
if i < resultsLen-1 {
query += " UNION "
}
@@ -1792,10 +1791,11 @@ func collectValidatorGotSlashedNotifications(notificationsByUserID types.Notific
}
var subscribers []struct {
- Ref uint64 `db:"ref"`
- Id uint64 `db:"id"`
- UserId types.UserId `db:"user_id"`
- UnsubscribeHash sql.NullString `db:"unsubscribe_hash"`
+ Ref uint64 `db:"ref"`
+ Id uint64 `db:"id"`
+ UserId types.UserId `db:"user_id"`
+ UnsubscribeHash sql.NullString `db:"unsubscribe_hash"`
+ EventName types.EventName `db:"event_name"`
}
name := string(types.ValidatorGotSlashedEventName)
@@ -1819,6 +1819,7 @@ func collectValidatorGotSlashedNotifications(notificationsByUserID types.Notific
Epoch: event.Epoch,
EventFilter: hex.EncodeToString(event.SlashedValidatorPubkey),
UnsubscribeHash: sub.UnsubscribeHash,
+ EventName: sub.EventName,
},
Slasher: event.SlasherIndex,
Reason: event.Reason,
@@ -1897,6 +1898,7 @@ func collectWithdrawalNotifications(notificationsByUserID types.NotificationsPer
UserID: *sub.UserID,
EventFilter: hex.EncodeToString(event.Pubkey),
UnsubscribeHash: sub.UnsubscribeHash,
+ EventName: sub.EventName,
},
ValidatorIndex: event.ValidatorIndex,
Epoch: epoch,
@@ -1993,7 +1995,7 @@ func (n *ethClientNotification) GetInfoMarkdown() string {
return generalPart
}
-func collectEthClientNotifications(notificationsByUserID types.NotificationsPerUserId, eventName types.EventName) error {
+func collectEthClientNotifications(notificationsByUserID types.NotificationsPerUserId) error {
updatedClients := ethclients.GetUpdatedClients() //only check if there are new updates
for _, client := range updatedClients {
// err := db.FrontendWriterDB.Select(&dbResult, `
@@ -2009,7 +2011,7 @@ func collectEthClientNotifications(notificationsByUserID types.NotificationsPerU
// eventName, strings.ToLower(client.Name), client.Date.Unix()) // was last notification sent 2 days ago for this client
dbResult, err := GetSubsForEventFilter(
- eventName,
+ types.EthClientUpdateEventName,
"(us.last_sent_ts <= NOW() - INTERVAL '2 DAY' AND TO_TIMESTAMP(?) > us.last_sent_ts) OR us.last_sent_ts IS NULL",
[]interface{}{client.Date.Unix()},
[]string{strings.ToLower(client.Name)})
@@ -2026,6 +2028,7 @@ func collectEthClientNotifications(notificationsByUserID types.NotificationsPerU
Epoch: sub.CreatedEpoch,
EventFilter: sub.EventFilter,
UnsubscribeHash: sub.UnsubscribeHash,
+ EventName: sub.EventName,
},
EthClient: client.Name,
}
@@ -2220,9 +2223,10 @@ func collectMonitoringMachine(
NotificationBaseImpl: types.NotificationBaseImpl{
SubscriptionID: *r.ID,
UserID: *r.UserID,
- EventName: eventName,
+ EventName: r.EventName,
Epoch: epoch,
UnsubscribeHash: r.UnsubscribeHash,
+ EventFilter: r.EventFilter,
},
MachineName: r.EventFilter,
}
@@ -2348,7 +2352,7 @@ func (n *taxReportNotification) GetInfoMarkdown() string {
return n.GetInfo(false)
}
-func collectTaxReportNotificationNotifications(notificationsByUserID types.NotificationsPerUserId, eventName types.EventName) error {
+func collectTaxReportNotificationNotifications(notificationsByUserID types.NotificationsPerUserId) error {
lastStatsDay, err := cache.LatestExportedStatisticDay.GetOrDefault(db.GetLastExportedStatisticDay)
if err != nil {
@@ -2369,7 +2373,7 @@ func collectTaxReportNotificationNotifications(notificationsByUserID types.Notif
// name, firstDayOfMonth)
dbResults, err := GetSubsForEventFilter(
- eventName,
+ types.TaxReportEventName,
"us.last_sent_ts < ? OR (us.last_sent_ts IS NULL AND us.created_ts < ?)",
[]interface{}{firstDayOfMonth, firstDayOfMonth},
nil,
@@ -2387,6 +2391,7 @@ func collectTaxReportNotificationNotifications(notificationsByUserID types.Notif
Epoch: sub.CreatedEpoch,
EventFilter: sub.EventFilter,
UnsubscribeHash: sub.UnsubscribeHash,
+ EventName: sub.EventName,
},
}
notificationsByUserID.AddNotification(n)
@@ -2419,7 +2424,7 @@ func (n *networkNotification) GetInfoMarkdown() string {
return generalPart
}
-func collectNetworkNotifications(notificationsByUserID types.NotificationsPerUserId, eventName types.EventName) error {
+func collectNetworkNotifications(notificationsByUserID types.NotificationsPerUserId) error {
count := 0
err := db.WriterDb.Get(&count, `
SELECT count(ts) FROM network_liveness WHERE (headepoch-finalizedepoch) > 3 AND ts > now() - interval '60 minutes';
@@ -2438,7 +2443,7 @@ func collectNetworkNotifications(notificationsByUserID types.NotificationsPerUse
// utils.GetNetwork()+":"+string(eventName))
dbResult, err := GetSubsForEventFilter(
- eventName,
+ types.NetworkLivenessIncreasedEventName,
"us.last_sent_ts <= NOW() - INTERVAL '1 hour' OR us.last_sent_ts IS NULL",
nil,
nil,
@@ -2456,6 +2461,7 @@ func collectNetworkNotifications(notificationsByUserID types.NotificationsPerUse
Epoch: sub.CreatedEpoch,
EventFilter: sub.EventFilter,
UnsubscribeHash: sub.UnsubscribeHash,
+ EventName: sub.EventName,
},
}
@@ -2512,7 +2518,7 @@ func (n *rocketpoolNotification) GetInfoMarkdown() string {
return n.GetInfo(false)
}
-func collectRocketpoolComissionNotifications(notificationsByUserID types.NotificationsPerUserId, eventName types.EventName) error {
+func collectRocketpoolComissionNotifications(notificationsByUserID types.NotificationsPerUserId) error {
fee := 0.0
err := db.WriterDb.Get(&fee, `
select current_node_fee from rocketpool_network_stats order by id desc LIMIT 1;
@@ -2531,7 +2537,7 @@ func collectRocketpoolComissionNotifications(notificationsByUserID types.Notific
// utils.GetNetwork()+":"+string(eventName), fee)
dbResult, err := GetSubsForEventFilter(
- eventName,
+ types.RocketpoolCommissionThresholdEventName,
"(us.last_sent_ts <= NOW() - INTERVAL '8 hours' OR us.last_sent_ts IS NULL) AND (us.event_threshold <= ? OR (us.event_threshold < 0 AND us.event_threshold * -1 >= ?)",
[]interface{}{fee, fee},
nil,
@@ -2548,7 +2554,7 @@ func collectRocketpoolComissionNotifications(notificationsByUserID types.Notific
UserID: *sub.UserID,
Epoch: sub.CreatedEpoch,
EventFilter: sub.EventFilter,
- EventName: eventName,
+ EventName: sub.EventName,
UnsubscribeHash: sub.UnsubscribeHash,
},
ExtraData: strconv.FormatInt(int64(fee*100), 10) + "%",
@@ -2563,7 +2569,7 @@ func collectRocketpoolComissionNotifications(notificationsByUserID types.Notific
return nil
}
-func collectRocketpoolRewardClaimRoundNotifications(notificationsByUserID types.NotificationsPerUserId, eventName types.EventName) error {
+func collectRocketpoolRewardClaimRoundNotifications(notificationsByUserID types.NotificationsPerUserId) error {
var ts int64
err := db.WriterDb.Get(&ts, `
select date_part('epoch', claim_interval_time_start)::int from rocketpool_network_stats order by id desc LIMIT 1;
@@ -2584,7 +2590,7 @@ func collectRocketpoolRewardClaimRoundNotifications(notificationsByUserID types.
// utils.GetNetwork()+":"+string(eventName))
dbResult, err := GetSubsForEventFilter(
- eventName,
+ types.RocketpoolNewClaimRoundStartedEventName,
"us.last_sent_ts <= NOW() - INTERVAL '5 hours' OR us.last_sent_ts IS NULL",
nil,
nil,
@@ -2601,7 +2607,7 @@ func collectRocketpoolRewardClaimRoundNotifications(notificationsByUserID types.
UserID: *sub.UserID,
Epoch: sub.CreatedEpoch,
EventFilter: sub.EventFilter,
- EventName: eventName,
+ EventName: sub.EventName,
UnsubscribeHash: sub.UnsubscribeHash,
},
}
@@ -2736,7 +2742,7 @@ func collectRocketpoolRPLCollateralNotifications(notificationsByUserID types.Not
UserID: *sub.UserID,
Epoch: epoch,
EventFilter: sub.EventFilter,
- EventName: eventName,
+ EventName: sub.EventName,
UnsubscribeHash: sub.UnsubscribeHash,
},
ExtraData: strings.TrimRight(strings.TrimRight(fmt.Sprintf("%.2f", threshold*100), "0"), "."),
@@ -2790,7 +2796,7 @@ func bigFloat(x float64) *big.Float {
return new(big.Float).SetFloat64(x)
}
-func collectSyncCommittee(notificationsByUserID types.NotificationsPerUserId, eventName types.EventName, epoch uint64) error {
+func collectSyncCommittee(notificationsByUserID types.NotificationsPerUserId, epoch uint64) error {
slotsPerSyncCommittee := utils.SlotsPerSyncCommittee()
currentPeriod := epoch * utils.Config.Chain.ClConfig.SlotsPerEpoch / slotsPerSyncCommittee
nextPeriod := currentPeriod + 1
@@ -2816,7 +2822,7 @@ func collectSyncCommittee(notificationsByUserID types.NotificationsPerUserId, ev
pubKeys = append(pubKeys, val.PubKey)
}
- dbResult, err := GetSubsForEventFilter(eventName, "us.last_sent_ts <= NOW() - INTERVAL '26 hours' OR us.last_sent_ts IS NULL", nil, pubKeys)
+ dbResult, err := GetSubsForEventFilter(types.SyncCommitteeSoon, "us.last_sent_ts <= NOW() - INTERVAL '26 hours' OR us.last_sent_ts IS NULL", nil, pubKeys)
// err = db.FrontendWriterDB.Select(&dbResult, `
// SELECT us.id, us.user_id, us.event_filter, ENCODE(us.unsubscribe_hash, 'hex') as unsubscribe_hash
// FROM users_subscriptions AS us
@@ -2837,7 +2843,7 @@ func collectSyncCommittee(notificationsByUserID types.NotificationsPerUserId, ev
UserID: *sub.UserID,
Epoch: epoch,
EventFilter: sub.EventFilter,
- EventName: eventName,
+ EventName: sub.EventName,
UnsubscribeHash: sub.UnsubscribeHash,
},
ExtraData: fmt.Sprintf("%v|%v|%v", mapping[sub.EventFilter], nextPeriod*utils.Config.Chain.ClConfig.EpochsPerSyncCommitteePeriod, (nextPeriod+1)*utils.Config.Chain.ClConfig.EpochsPerSyncCommitteePeriod),
From 65f0c8f055cef326cb5b468fd20586185134ff08 Mon Sep 17 00:00:00 2001
From: peter <1674920+peterbitfly@users.noreply.github.com>
Date: Mon, 8 Jul 2024 13:48:31 +0200
Subject: [PATCH 11/39] remove direct email unsubscribe
---
backend/pkg/commons/types/frontend.go | 23 +--
backend/pkg/notification/db.go | 11 +-
backend/pkg/notification/notifications.go | 185 +++++++---------------
3 files changed, 66 insertions(+), 153 deletions(-)
diff --git a/backend/pkg/commons/types/frontend.go b/backend/pkg/commons/types/frontend.go
index 2a4f0d8ca..9c8f45c04 100644
--- a/backend/pkg/commons/types/frontend.go
+++ b/backend/pkg/commons/types/frontend.go
@@ -273,7 +273,6 @@ type Notification interface {
GetTitle() string
GetEventFilter() string
GetEmailAttachment() *EmailAttachment
- GetUnsubscribeHash() string
GetInfoMarkdown() string
GetUserId() UserId
}
@@ -287,7 +286,6 @@ type NotificationBaseImpl struct {
Title string
EventFilter string
EmailAttachment *EmailAttachment
- UnsubscribeHash sql.NullString
InfoMarkdown string
UserID UserId
}
@@ -324,13 +322,6 @@ func (n NotificationBaseImpl) GetEmailAttachment() *EmailAttachment {
return n.EmailAttachment
}
-func (n NotificationBaseImpl) GetUnsubscribeHash() string {
- if n.UnsubscribeHash.Valid {
- return n.UnsubscribeHash.String
- }
- return ""
-}
-
func (n NotificationBaseImpl) GetInfoMarkdown() string {
return n.InfoMarkdown
}
@@ -349,13 +340,12 @@ type Subscription struct {
LastSent *time.Time `db:"last_sent_ts"`
LastEpoch *uint64 `db:"last_sent_epoch"`
// Channels pq.StringArray `db:"channels"`
- CreatedTime time.Time `db:"created_ts"`
- CreatedEpoch uint64 `db:"created_epoch"`
- EventThreshold float64 `db:"event_threshold"`
- UnsubscribeHash sql.NullString `db:"unsubscribe_hash" swaggertype:"string"`
- State sql.NullString `db:"internal_state" swaggertype:"string"`
- GroupId *int64
- DashboardId *int64
+ CreatedTime time.Time `db:"created_ts"`
+ CreatedEpoch uint64 `db:"created_epoch"`
+ EventThreshold float64 `db:"event_threshold"`
+ State sql.NullString `db:"internal_state" swaggertype:"string"`
+ GroupId *int64
+ DashboardId *int64
}
type UserId uint64
@@ -562,7 +552,6 @@ type Email struct {
Title string
Body template.HTML
SubscriptionManageURL template.HTML
- UnsubURL template.HTML
}
type UserWebhook struct {
diff --git a/backend/pkg/notification/db.go b/backend/pkg/notification/db.go
index 36810d6b3..cbcb9d497 100644
--- a/backend/pkg/notification/db.go
+++ b/backend/pkg/notification/db.go
@@ -38,7 +38,6 @@ func GetSubsForEventFilter(eventName types.EventName, lastSentFilter string, las
goqu.C("last_sent_epoch"),
goqu.C("created_epoch"),
goqu.C("event_threshold"),
- goqu.L("ENCODE(unsubscribe_hash, 'hex') as unsubscribe_hash"),
goqu.C("internal_state"),
).Where(goqu.C("event_name").Eq(utils.GetNetwork() + ":" + string(eventName)))
@@ -68,15 +67,7 @@ func GetSubsForEventFilter(eventName types.EventName, lastSentFilter string, las
if _, ok := subMap[sub.EventFilter]; !ok {
subMap[sub.EventFilter] = make([]types.Subscription, 0)
}
- subMap[sub.EventFilter] = append(subMap[sub.EventFilter], types.Subscription{
- UserID: sub.UserID,
- ID: sub.ID,
- LastEpoch: sub.LastEpoch,
- EventFilter: sub.EventFilter,
- CreatedEpoch: sub.CreatedEpoch,
- EventThreshold: sub.EventThreshold,
- State: sub.State,
- })
+ subMap[sub.EventFilter] = append(subMap[sub.EventFilter], sub)
}
return subMap, nil
}
diff --git a/backend/pkg/notification/notifications.go b/backend/pkg/notification/notifications.go
index e803f8514..2d7b6ff7c 100644
--- a/backend/pkg/notification/notifications.go
+++ b/backend/pkg/notification/notifications.go
@@ -3,7 +3,6 @@ package notification
import (
"bytes"
"context"
- "crypto/sha256"
"database/sql"
"database/sql/driver"
"encoding/hex"
@@ -11,7 +10,6 @@ import (
"errors"
"fmt"
- "html"
"html/template"
"io"
"math/big"
@@ -598,6 +596,9 @@ func queuePushNotification(notificationsByUserID types.NotificationsPerUserId, u
continue
}
+ // todo: this looks like a flawed approach to queue the notifications
+ // this will issue one db write per user, which is not optimal
+ // we should batch the notifications and write them in one go
go func(userTokens []string, userNotifications map[types.EventName]map[types.EventFilter]types.Notification) {
var batch []*messaging.Message
for event, ns := range userNotifications {
@@ -727,7 +728,6 @@ func queueEmailNotifications(notificationsByUserID types.NotificationsPerUserId,
}
//nolint:gosec // this is a static string
msg.Body += template.HTML(fmt.Sprintf("%s
====
", types.EventLabel[event_title]))
- unsubURL := "https://" + utils.Config.Frontend.SiteDomain + "/notifications/unsubscribe"
i := 0
for _, n := range ns {
// Find all unique notification titles for the subject
@@ -737,64 +737,6 @@ func queueEmailNotifications(notificationsByUserID types.NotificationsPerUserId,
notificationTitles = append(notificationTitles, title)
}
- // TODO: this is bad and will break in case there are a lot of unsubscribe hashes to generate
- // the unsubscribe hash should be set when we add the subscription to the db
- unsubHash := n.GetUnsubscribeHash()
- if unsubHash == "" {
- id := n.GetSubscriptionID()
-
- tx, err := db.FrontendWriterDB.Beginx()
- if err != nil {
- log.Error(err, "error starting transaction", 0)
- }
- var sub types.Subscription
- err = tx.Get(&sub, `
- SELECT
- id,
- user_id,
- event_name,
- event_filter,
- last_sent_ts,
- last_sent_epoch,
- created_ts,
- created_epoch,
- event_threshold
- FROM users_subscriptions
- WHERE id = $1
- `, id)
- if err != nil {
- log.Error(err, "error getting user subscription by subscription id", 0)
- utils.Rollback(tx)
- continue
- }
-
- raw := fmt.Sprintf("%v%v%v%v", sub.ID, sub.UserID, sub.EventName, sub.CreatedTime)
- digest := sha256.Sum256([]byte(raw))
-
- _, err = tx.Exec("UPDATE users_subscriptions set unsubscribe_hash = $1 WHERE id = $2", digest[:], id)
- if err != nil {
- log.Error(err, "error updating users subscriptions table with unsubscribe hash", 0)
- utils.Rollback(tx)
- continue
- }
-
- err = tx.Commit()
- if err != nil {
- log.Error(err, "error committing transaction to update users subscriptions with an unsubscribe hash", 0)
- utils.Rollback(tx)
- continue
- }
-
- unsubHash = hex.EncodeToString(digest[:])
- }
- if i == 0 {
- unsubURL += "?hash=" + html.EscapeString(unsubHash)
- } else {
- unsubURL += "&hash=" + html.EscapeString(unsubHash)
- }
- //nolint:gosec // this is a static string
- msg.UnsubURL = template.HTML(fmt.Sprintf(`Unsubscribe`, unsubURL))
-
if event != types.SyncCommitteeSoon {
// SyncCommitteeSoon notifications are summed up in getEventInfo for all validators
//nolint:gosec // this is a static string
@@ -1150,6 +1092,8 @@ func sendDiscordNotifications(useDB *sqlx.DB) error {
notifMap[n.Content.Webhook.ID] = append(notifMap[n.Content.Webhook.ID], n)
}
for _, webhook := range webhookMap {
+ // todo: this has the potential to spin up thousands of go routines
+ // should use an errgroup instead if we decide to keep the aproach
go func(webhook types.UserWebhook, reqs []types.TransitDiscord) {
defer func() {
// update retries counters in db based on end result
@@ -1780,7 +1724,7 @@ func collectValidatorGotSlashedNotifications(notificationsByUserID types.Notific
resultsLen := len(dbResult)
for i, event := range dbResult {
// TODO: clarify why we need the id here?!
- query += fmt.Sprintf(`SELECT %d AS ref, id, user_id, ENCODE(unsubscribe_hash, 'hex') AS unsubscribe_hash, event_name from users_subscriptions where event_name = $1 AND event_filter = '%x'`, i, event.SlashedValidatorPubkey)
+ query += fmt.Sprintf(`SELECT %d AS ref, id, user_id, event_name from users_subscriptions where event_name = $1 AND event_filter = '%x'`, i, event.SlashedValidatorPubkey)
if i < resultsLen-1 {
query += " UNION "
}
@@ -1791,11 +1735,10 @@ func collectValidatorGotSlashedNotifications(notificationsByUserID types.Notific
}
var subscribers []struct {
- Ref uint64 `db:"ref"`
- Id uint64 `db:"id"`
- UserId types.UserId `db:"user_id"`
- UnsubscribeHash sql.NullString `db:"unsubscribe_hash"`
- EventName types.EventName `db:"event_name"`
+ Ref uint64 `db:"ref"`
+ Id uint64 `db:"id"`
+ UserId types.UserId `db:"user_id"`
+ EventName types.EventName `db:"event_name"`
}
name := string(types.ValidatorGotSlashedEventName)
@@ -1814,12 +1757,11 @@ func collectValidatorGotSlashedNotifications(notificationsByUserID types.Notific
n := &validatorGotSlashedNotification{
NotificationBaseImpl: types.NotificationBaseImpl{
- SubscriptionID: sub.Id,
- UserID: sub.UserId,
- Epoch: event.Epoch,
- EventFilter: hex.EncodeToString(event.SlashedValidatorPubkey),
- UnsubscribeHash: sub.UnsubscribeHash,
- EventName: sub.EventName,
+ SubscriptionID: sub.Id,
+ UserID: sub.UserId,
+ Epoch: event.Epoch,
+ EventFilter: hex.EncodeToString(event.SlashedValidatorPubkey),
+ EventName: sub.EventName,
},
Slasher: event.SlasherIndex,
Reason: event.Reason,
@@ -1894,11 +1836,10 @@ func collectWithdrawalNotifications(notificationsByUserID types.NotificationsPer
// log.Infof("creating %v notification for validator %v in epoch %v", types.ValidatorReceivedWithdrawalEventName, event.ValidatorIndex, epoch)
n := &validatorWithdrawalNotification{
NotificationBaseImpl: types.NotificationBaseImpl{
- SubscriptionID: *sub.ID,
- UserID: *sub.UserID,
- EventFilter: hex.EncodeToString(event.Pubkey),
- UnsubscribeHash: sub.UnsubscribeHash,
- EventName: sub.EventName,
+ SubscriptionID: *sub.ID,
+ UserID: *sub.UserID,
+ EventFilter: hex.EncodeToString(event.Pubkey),
+ EventName: sub.EventName,
},
ValidatorIndex: event.ValidatorIndex,
Epoch: epoch,
@@ -2023,12 +1964,11 @@ func collectEthClientNotifications(notificationsByUserID types.NotificationsPerU
for _, sub := range subs {
n := ðClientNotification{
NotificationBaseImpl: types.NotificationBaseImpl{
- SubscriptionID: *sub.ID,
- UserID: *sub.UserID,
- Epoch: sub.CreatedEpoch,
- EventFilter: sub.EventFilter,
- UnsubscribeHash: sub.UnsubscribeHash,
- EventName: sub.EventName,
+ SubscriptionID: *sub.ID,
+ UserID: *sub.UserID,
+ Epoch: sub.CreatedEpoch,
+ EventFilter: sub.EventFilter,
+ EventName: sub.EventName,
},
EthClient: client.Name,
}
@@ -2221,12 +2161,11 @@ func collectMonitoringMachine(
for _, r := range result {
n := &monitorMachineNotification{
NotificationBaseImpl: types.NotificationBaseImpl{
- SubscriptionID: *r.ID,
- UserID: *r.UserID,
- EventName: r.EventName,
- Epoch: epoch,
- UnsubscribeHash: r.UnsubscribeHash,
- EventFilter: r.EventFilter,
+ SubscriptionID: *r.ID,
+ UserID: *r.UserID,
+ EventName: r.EventName,
+ Epoch: epoch,
+ EventFilter: r.EventFilter,
},
MachineName: r.EventFilter,
}
@@ -2386,12 +2325,11 @@ func collectTaxReportNotificationNotifications(notificationsByUserID types.Notif
for _, sub := range subs {
n := &taxReportNotification{
NotificationBaseImpl: types.NotificationBaseImpl{
- SubscriptionID: *sub.ID,
- UserID: *sub.UserID,
- Epoch: sub.CreatedEpoch,
- EventFilter: sub.EventFilter,
- UnsubscribeHash: sub.UnsubscribeHash,
- EventName: sub.EventName,
+ SubscriptionID: *sub.ID,
+ UserID: *sub.UserID,
+ Epoch: sub.CreatedEpoch,
+ EventFilter: sub.EventFilter,
+ EventName: sub.EventName,
},
}
notificationsByUserID.AddNotification(n)
@@ -2456,12 +2394,11 @@ func collectNetworkNotifications(notificationsByUserID types.NotificationsPerUse
for _, sub := range subs {
n := &networkNotification{
NotificationBaseImpl: types.NotificationBaseImpl{
- SubscriptionID: *sub.ID,
- UserID: *sub.UserID,
- Epoch: sub.CreatedEpoch,
- EventFilter: sub.EventFilter,
- UnsubscribeHash: sub.UnsubscribeHash,
- EventName: sub.EventName,
+ SubscriptionID: *sub.ID,
+ UserID: *sub.UserID,
+ Epoch: sub.CreatedEpoch,
+ EventFilter: sub.EventFilter,
+ EventName: sub.EventName,
},
}
@@ -2550,12 +2487,11 @@ func collectRocketpoolComissionNotifications(notificationsByUserID types.Notific
for _, sub := range subs {
n := &rocketpoolNotification{
NotificationBaseImpl: types.NotificationBaseImpl{
- SubscriptionID: *sub.ID,
- UserID: *sub.UserID,
- Epoch: sub.CreatedEpoch,
- EventFilter: sub.EventFilter,
- EventName: sub.EventName,
- UnsubscribeHash: sub.UnsubscribeHash,
+ SubscriptionID: *sub.ID,
+ UserID: *sub.UserID,
+ Epoch: sub.CreatedEpoch,
+ EventFilter: sub.EventFilter,
+ EventName: sub.EventName,
},
ExtraData: strconv.FormatInt(int64(fee*100), 10) + "%",
}
@@ -2603,12 +2539,11 @@ func collectRocketpoolRewardClaimRoundNotifications(notificationsByUserID types.
for _, sub := range subs {
n := &rocketpoolNotification{
NotificationBaseImpl: types.NotificationBaseImpl{
- SubscriptionID: *sub.ID,
- UserID: *sub.UserID,
- Epoch: sub.CreatedEpoch,
- EventFilter: sub.EventFilter,
- EventName: sub.EventName,
- UnsubscribeHash: sub.UnsubscribeHash,
+ SubscriptionID: *sub.ID,
+ UserID: *sub.UserID,
+ Epoch: sub.CreatedEpoch,
+ EventFilter: sub.EventFilter,
+ EventName: sub.EventName,
},
}
@@ -2738,12 +2673,11 @@ func collectRocketpoolRPLCollateralNotifications(notificationsByUserID types.Not
n := &rocketpoolNotification{
NotificationBaseImpl: types.NotificationBaseImpl{
- SubscriptionID: *sub.ID,
- UserID: *sub.UserID,
- Epoch: epoch,
- EventFilter: sub.EventFilter,
- EventName: sub.EventName,
- UnsubscribeHash: sub.UnsubscribeHash,
+ SubscriptionID: *sub.ID,
+ UserID: *sub.UserID,
+ Epoch: epoch,
+ EventFilter: sub.EventFilter,
+ EventName: sub.EventName,
},
ExtraData: strings.TrimRight(strings.TrimRight(fmt.Sprintf("%.2f", threshold*100), "0"), "."),
}
@@ -2839,12 +2773,11 @@ func collectSyncCommittee(notificationsByUserID types.NotificationsPerUserId, ep
for _, sub := range subs {
n := &rocketpoolNotification{
NotificationBaseImpl: types.NotificationBaseImpl{
- SubscriptionID: *sub.ID,
- UserID: *sub.UserID,
- Epoch: epoch,
- EventFilter: sub.EventFilter,
- EventName: sub.EventName,
- UnsubscribeHash: sub.UnsubscribeHash,
+ SubscriptionID: *sub.ID,
+ UserID: *sub.UserID,
+ Epoch: epoch,
+ EventFilter: sub.EventFilter,
+ EventName: sub.EventName,
},
ExtraData: fmt.Sprintf("%v|%v|%v", mapping[sub.EventFilter], nextPeriod*utils.Config.Chain.ClConfig.EpochsPerSyncCommitteePeriod, (nextPeriod+1)*utils.Config.Chain.ClConfig.EpochsPerSyncCommitteePeriod),
}
From c85a5e5ff247b763c609fb46ad2d7e1a6a5f472f Mon Sep 17 00:00:00 2001
From: peter <1674920+peterbitfly@users.noreply.github.com>
Date: Tue, 9 Jul 2024 12:25:51 +0200
Subject: [PATCH 12/39] add handling of orphaned block notifications
---
backend/pkg/notification/notifications.go | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/backend/pkg/notification/notifications.go b/backend/pkg/notification/notifications.go
index 2d7b6ff7c..5ca1a1108 100644
--- a/backend/pkg/notification/notifications.go
+++ b/backend/pkg/notification/notifications.go
@@ -1306,6 +1306,8 @@ func (n *validatorProposalNotification) GetInfo(includeUrl bool) string {
generalPart = fmt.Sprintf(`Validator %s proposed block at slot %s with %v %v execution reward.`, vali, slot, n.Reward, utils.Config.Frontend.ElCurrency)
case 2:
generalPart = fmt.Sprintf(`Validator %s missed a block proposal at slot %s.`, vali, slot)
+ case 3:
+ generalPart = fmt.Sprintf(`Validator %s had an orphaned block proposal at slot %s.`, vali, slot)
}
return generalPart + suffix
}
@@ -1318,6 +1320,8 @@ func (n *validatorProposalNotification) GetTitle() string {
return "New Block Proposal"
case 2:
return "Block Proposal Missed"
+ case 3:
+ return "Block Proposal Missed (Orphaned)"
}
return "-"
}
@@ -1331,6 +1335,8 @@ func (n *validatorProposalNotification) GetInfoMarkdown() string {
generalPart = fmt.Sprintf(`Validator [%[2]v](https://%[1]v/validator/%[2]v) proposed a new block at slot [%[3]v](https://%[1]v/slot/%[3]v) with %[4]v %[5]v execution reward.`, utils.Config.Frontend.SiteDomain, n.ValidatorIndex, n.Slot, n.Reward, utils.Config.Frontend.ElCurrency)
case 2:
generalPart = fmt.Sprintf(`Validator [%[2]v](https://%[1]v/validator/%[2]v) missed a block proposal at slot [%[3]v](https://%[1]v/slot/%[3]v).`, utils.Config.Frontend.SiteDomain, n.ValidatorIndex, n.Slot)
+ case 3:
+ generalPart = fmt.Sprintf(`Validator [%[2]v](https://%[1]v/validator/%[2]v) had an orphaned block proposal at slot [%[3]v](https://%[1]v/slot/%[3]v).`, utils.Config.Frontend.SiteDomain, n.ValidatorIndex, n.Slot)
}
return generalPart
From 2ca40f7f1633ee5447e5bd81cb673d2b90cd9c33 Mon Sep 17 00:00:00 2001
From: peter <1674920+peterbitfly@users.noreply.github.com>
Date: Tue, 9 Jul 2024 12:50:44 +0200
Subject: [PATCH 13/39] implement code review changes
---
backend/pkg/commons/db/db.go | 18 +--
backend/pkg/commons/types/exporter.go | 9 ++
backend/pkg/commons/types/frontend.go | 7 +-
backend/pkg/notification/db.go | 1 +
backend/pkg/notification/notifications.go | 142 +++++++++++-----------
5 files changed, 88 insertions(+), 89 deletions(-)
diff --git a/backend/pkg/commons/db/db.go b/backend/pkg/commons/db/db.go
index f85f3641e..fe13e3e67 100644
--- a/backend/pkg/commons/db/db.go
+++ b/backend/pkg/commons/db/db.go
@@ -954,22 +954,8 @@ func GetTotalEligibleEther() (uint64, error) {
}
// GetValidatorsGotSlashed returns the validators that got slashed after `epoch` either by an attestation violation or a proposer violation
-func GetValidatorsGotSlashed(epoch uint64) ([]struct {
- Epoch uint64 `db:"epoch"`
- SlasherIndex uint64 `db:"slasher"`
- SlasherPubkey string `db:"slasher_pubkey"`
- SlashedValidatorIndex uint64 `db:"slashedvalidator"`
- SlashedValidatorPubkey []byte `db:"slashedvalidator_pubkey"`
- Reason string `db:"reason"`
-}, error) {
- var dbResult []struct {
- Epoch uint64 `db:"epoch"`
- SlasherIndex uint64 `db:"slasher"`
- SlasherPubkey string `db:"slasher_pubkey"`
- SlashedValidatorIndex uint64 `db:"slashedvalidator"`
- SlashedValidatorPubkey []byte `db:"slashedvalidator_pubkey"`
- Reason string `db:"reason"`
- }
+func GetValidatorsGotSlashed(epoch uint64) ([]*types.SlashingInfo, error) {
+ var dbResult []*types.SlashingInfo
err := ReaderDb.Select(&dbResult, `
WITH
slashings AS (
diff --git a/backend/pkg/commons/types/exporter.go b/backend/pkg/commons/types/exporter.go
index 5a3f3a397..197638472 100644
--- a/backend/pkg/commons/types/exporter.go
+++ b/backend/pkg/commons/types/exporter.go
@@ -709,3 +709,12 @@ type RedisCachedValidatorsMapping struct {
Epoch Epoch
Mapping []*CachedValidator
}
+
+type SlashingInfo struct {
+ Epoch uint64 `db:"epoch"`
+ SlasherIndex uint64 `db:"slasher"`
+ SlasherPubkey string `db:"slasher_pubkey"`
+ SlashedValidatorIndex uint64 `db:"slashedvalidator"`
+ SlashedValidatorPubkey []byte `db:"slashedvalidator_pubkey"`
+ Reason string `db:"reason"`
+}
diff --git a/backend/pkg/commons/types/frontend.go b/backend/pkg/commons/types/frontend.go
index 9c8f45c04..5c90a8be3 100644
--- a/backend/pkg/commons/types/frontend.go
+++ b/backend/pkg/commons/types/frontend.go
@@ -33,9 +33,10 @@ func (npui NotificationsPerUserId) AddNotification(n Notification) {
if n.GetEventName() == "" {
log.Fatal(fmt.Errorf("Notification event name is empty"), fmt.Sprintf("Notification: %v", n), 0)
}
- if n.GetEventFilter() == "" {
- log.Fatal(fmt.Errorf("Notification event filter is empty"), fmt.Sprintf("Notification: %v", n), 0)
- }
+ // next check is disabled as there are events that do not require a filter (rocketpool, network events)
+ // if n.GetEventFilter() == "" {
+ // log.Fatal(fmt.Errorf("Notification event filter is empty"), fmt.Sprintf("Notification: %v", n), 0)
+ // }
if _, ok := npui[n.GetUserId()]; !ok {
npui[n.GetUserId()] = make(map[EventName]map[EventFilter]Notification)
diff --git a/backend/pkg/notification/db.go b/backend/pkg/notification/db.go
index cbcb9d497..7b8948d34 100644
--- a/backend/pkg/notification/db.go
+++ b/backend/pkg/notification/db.go
@@ -12,6 +12,7 @@ import (
// Map key corresponds to the event filter which can be
// a validator pubkey or an eth1 address (for RPL notifications)
// or a list of validators for the tax report notifications
+// or a machine name for machine notifications or a eth client name for ethereum client update notifications
// optionally it is possible to set a filter on the last sent ts and the event filter
// fields
func GetSubsForEventFilter(eventName types.EventName, lastSentFilter string, lastSentFilterArgs []interface{}, eventFilters []string) (map[string][]types.Subscription, error) {
diff --git a/backend/pkg/notification/notifications.go b/backend/pkg/notification/notifications.go
index 5ca1a1108..6b6e0ea0c 100644
--- a/backend/pkg/notification/notifications.go
+++ b/backend/pkg/notification/notifications.go
@@ -1726,55 +1726,44 @@ func collectValidatorGotSlashedNotifications(notificationsByUserID types.Notific
if err != nil {
return fmt.Errorf("error getting slashed validators from database, err: %w", err)
}
- query := ""
- resultsLen := len(dbResult)
- for i, event := range dbResult {
- // TODO: clarify why we need the id here?!
- query += fmt.Sprintf(`SELECT %d AS ref, id, user_id, event_name from users_subscriptions where event_name = $1 AND event_filter = '%x'`, i, event.SlashedValidatorPubkey)
- if i < resultsLen-1 {
- query += " UNION "
- }
- }
-
- if query == "" {
- return nil
- }
-
- var subscribers []struct {
- Ref uint64 `db:"ref"`
- Id uint64 `db:"id"`
- UserId types.UserId `db:"user_id"`
- EventName types.EventName `db:"event_name"`
+ slashedPubkeys := make([]string, 0, len(dbResult))
+ pubkeyToSlashingInfoMap := make(map[string]*types.SlashingInfo)
+ for _, event := range dbResult {
+ pubkeyStr := hex.EncodeToString(event.SlashedValidatorPubkey)
+ slashedPubkeys = append(slashedPubkeys, pubkeyStr)
+ pubkeyToSlashingInfoMap[pubkeyStr] = event
}
- name := string(types.ValidatorGotSlashedEventName)
- if utils.Config.Chain.ClConfig.ConfigName != "" {
- name = utils.Config.Chain.ClConfig.ConfigName + ":" + name
- }
- err = db.FrontendWriterDB.Select(&subscribers, query, name)
+ subscribedUsers, err := GetSubsForEventFilter(types.ValidatorGotSlashedEventName, "", nil, slashedPubkeys)
if err != nil {
- return fmt.Errorf("error querying subscribers, err: %w", err)
+ return fmt.Errorf("failed to get subs for %v: %v", types.ValidatorGotSlashedEventName, err)
}
- for _, sub := range subscribers {
- event := dbResult[sub.Ref]
+ for _, subs := range subscribedUsers {
+ for _, sub := range subs {
- log.Infof("creating %v notification for validator %v in epoch %v", event.SlashedValidatorPubkey, event.Reason, epoch)
+ event := pubkeyToSlashingInfoMap[sub.EventFilter]
+ if event == nil {
+ log.Error(fmt.Errorf("error retrieving slashing info for public key %s", sub.EventFilter), "", 0)
+ continue
+ }
+ log.Infof("creating %v notification for validator %v in epoch %v", event.Reason, sub.EventFilter, epoch)
- n := &validatorGotSlashedNotification{
- NotificationBaseImpl: types.NotificationBaseImpl{
- SubscriptionID: sub.Id,
- UserID: sub.UserId,
- Epoch: event.Epoch,
- EventFilter: hex.EncodeToString(event.SlashedValidatorPubkey),
- EventName: sub.EventName,
- },
- Slasher: event.SlasherIndex,
- Reason: event.Reason,
- ValidatorIndex: event.SlashedValidatorIndex,
+ n := &validatorGotSlashedNotification{
+ NotificationBaseImpl: types.NotificationBaseImpl{
+ SubscriptionID: *sub.ID,
+ UserID: *sub.UserID,
+ Epoch: epoch,
+ EventFilter: sub.EventFilter,
+ EventName: sub.EventName,
+ },
+ Slasher: event.SlasherIndex,
+ Reason: event.Reason,
+ ValidatorIndex: event.SlashedValidatorIndex,
+ }
+ notificationsByUserID.AddNotification(n)
+ metrics.NotificationsCollected.WithLabelValues(string(n.GetEventName())).Inc()
}
- notificationsByUserID.AddNotification(n)
- metrics.NotificationsCollected.WithLabelValues(string(n.GetEventName())).Inc()
}
return nil
@@ -2077,28 +2066,39 @@ func collectMonitoringMachine(
notifyConditionFulfilled func(subscribeData *types.Subscription, machineData *types.MachineMetricSystemUser) bool,
epoch uint64,
) error {
- var allSubscribed []*types.Subscription
// event_filter == machine name
+
+ dbResult, err := GetSubsForEventFilter(
+ eventName,
+ "us.created_epoch <= ? AND (us.last_sent_epoch < (? - ?) OR us.last_sent_epoch IS NULL)",
+ []interface{}{epoch, epoch, epochWaitInBetween},
+ nil,
+ )
+
// TODO: clarify why we need grouping here?!
- err := db.FrontendWriterDB.Select(&allSubscribed,
- `SELECT
- us.user_id,
- max(us.id) AS id,
- ENCODE((array_agg(us.unsubscribe_hash))[1], 'hex') AS unsubscribe_hash,
- event_filter,
- COALESCE(event_threshold, 0) AS event_threshold
- FROM users_subscriptions us
- WHERE us.event_name = $1 AND us.created_epoch <= $2
- AND (us.last_sent_epoch < ($2 - $3) OR us.last_sent_epoch IS NULL)
- group by us.user_id, event_filter, event_threshold`,
- eventName, epoch, epochWaitInBetween)
+ // err := db.FrontendWriterDB.Select(&allSubscribed,
+ // `SELECT
+ // us.user_id,
+ // max(us.id) AS id,
+ // ENCODE((array_agg(us.unsubscribe_hash))[1], 'hex') AS unsubscribe_hash,
+ // event_filter,
+ // COALESCE(event_threshold, 0) AS event_threshold
+ // FROM users_subscriptions us
+ // WHERE us.event_name = $1 AND us.created_epoch <= $2
+ // AND (us.last_sent_epoch < ($2 - $3) OR us.last_sent_epoch IS NULL)
+ // group by us.user_id, event_filter, event_threshold`,
+ // eventName, epoch, epochWaitInBetween)
if err != nil {
return err
}
rowKeys := gcp_bigtable.RowList{}
- for _, data := range allSubscribed {
- rowKeys = append(rowKeys, db.BigtableClient.GetMachineRowKey(*data.UserID, "system", data.EventFilter))
+ totalSubscribed := 0
+ for _, data := range dbResult {
+ for _, sub := range data {
+ rowKeys = append(rowKeys, db.BigtableClient.GetMachineRowKey(*sub.UserID, "system", sub.EventFilter))
+ totalSubscribed++
+ }
}
machineDataOfSubscribed, err := db.BigtableClient.GetMachineMetricsForNotifications(rowKeys)
@@ -2107,20 +2107,22 @@ func collectMonitoringMachine(
}
var result []*types.Subscription
- for _, data := range allSubscribed {
- localData := data // Create a local copy of the data variable
- machineMap, found := machineDataOfSubscribed[*localData.UserID]
- if !found {
- continue
- }
- currentMachineData, found := machineMap[localData.EventFilter]
- if !found {
- continue
- }
+ for _, data := range dbResult {
+ for _, sub := range data {
+ localData := sub // Create a local copy of the data variable
+ machineMap, found := machineDataOfSubscribed[*localData.UserID]
+ if !found {
+ continue
+ }
+ currentMachineData, found := machineMap[localData.EventFilter]
+ if !found {
+ continue
+ }
- //logrus.Infof("currentMachineData %v | %v | %v | %v", currentMachine.CurrentDataInsertTs, currentMachine.CompareDataInsertTs, currentMachine.UserID, currentMachine.Machine)
- if notifyConditionFulfilled(localData, currentMachineData) {
- result = append(result, localData)
+ //logrus.Infof("currentMachineData %v | %v | %v | %v", currentMachine.CurrentDataInsertTs, currentMachine.CompareDataInsertTs, currentMachine.UserID, currentMachine.Machine)
+ if notifyConditionFulfilled(&localData, currentMachineData) {
+ result = append(result, &localData)
+ }
}
}
@@ -2158,7 +2160,7 @@ func collectMonitoringMachine(
subRatioThreshold = subFirstRatioThreshold
isFirstNotificationCheck = false
}
- if float64(len(result))/float64(len(allSubscribed)) >= subRatioThreshold {
+ if float64(len(result))/float64(totalSubscribed) >= subRatioThreshold {
log.Error(nil, fmt.Errorf("error too many users would be notified concerning: %v", eventName), 0)
return nil
}
From f1a2ef83d0f1c545354f8337402440b9cd621c5e Mon Sep 17 00:00:00 2001
From: peter <1674920+peterbitfly@users.noreply.github.com>
Date: Tue, 9 Jul 2024 12:53:53 +0200
Subject: [PATCH 14/39] please linter
---
backend/pkg/notification/notifications.go | 1 -
1 file changed, 1 deletion(-)
diff --git a/backend/pkg/notification/notifications.go b/backend/pkg/notification/notifications.go
index 6b6e0ea0c..51cb926ae 100644
--- a/backend/pkg/notification/notifications.go
+++ b/backend/pkg/notification/notifications.go
@@ -1741,7 +1741,6 @@ func collectValidatorGotSlashedNotifications(notificationsByUserID types.Notific
for _, subs := range subscribedUsers {
for _, sub := range subs {
-
event := pubkeyToSlashingInfoMap[sub.EventFilter]
if event == nil {
log.Error(fmt.Errorf("error retrieving slashing info for public key %s", sub.EventFilter), "", 0)
From 274816226cd18f5dc8e1cee2bab64fe6cad92883 Mon Sep 17 00:00:00 2001
From: peter <1674920+peterbitfly@users.noreply.github.com>
Date: Wed, 10 Jul 2024 10:29:46 +0200
Subject: [PATCH 15/39] remove internal state for notifications
---
backend/pkg/commons/types/frontend.go | 12 ++++----
backend/pkg/notification/db.go | 1 -
backend/pkg/notification/notifications.go | 35 ++++++++++++-----------
3 files changed, 24 insertions(+), 24 deletions(-)
diff --git a/backend/pkg/commons/types/frontend.go b/backend/pkg/commons/types/frontend.go
index 5c90a8be3..767aca38b 100644
--- a/backend/pkg/commons/types/frontend.go
+++ b/backend/pkg/commons/types/frontend.go
@@ -341,12 +341,12 @@ type Subscription struct {
LastSent *time.Time `db:"last_sent_ts"`
LastEpoch *uint64 `db:"last_sent_epoch"`
// Channels pq.StringArray `db:"channels"`
- CreatedTime time.Time `db:"created_ts"`
- CreatedEpoch uint64 `db:"created_epoch"`
- EventThreshold float64 `db:"event_threshold"`
- State sql.NullString `db:"internal_state" swaggertype:"string"`
- GroupId *int64
- DashboardId *int64
+ CreatedTime time.Time `db:"created_ts"`
+ CreatedEpoch uint64 `db:"created_epoch"`
+ EventThreshold float64 `db:"event_threshold"`
+ // State sql.NullString `db:"internal_state" swaggertype:"string"`
+ GroupId *int64
+ DashboardId *int64
}
type UserId uint64
diff --git a/backend/pkg/notification/db.go b/backend/pkg/notification/db.go
index 7b8948d34..4363c12f7 100644
--- a/backend/pkg/notification/db.go
+++ b/backend/pkg/notification/db.go
@@ -39,7 +39,6 @@ func GetSubsForEventFilter(eventName types.EventName, lastSentFilter string, las
goqu.C("last_sent_epoch"),
goqu.C("created_epoch"),
goqu.C("event_threshold"),
- goqu.C("internal_state"),
).Where(goqu.C("event_name").Eq(utils.GetNetwork() + ":" + string(eventName)))
if lastSentFilter != "" {
diff --git a/backend/pkg/notification/notifications.go b/backend/pkg/notification/notifications.go
index 51cb926ae..76bedf688 100644
--- a/backend/pkg/notification/notifications.go
+++ b/backend/pkg/notification/notifications.go
@@ -492,6 +492,8 @@ func queueNotifications(notificationsByUserID types.NotificationsPerUserId, useD
}
}
}
+
+ // obsolete as notifications are anyway sent on a per-epoch basis
for epoch, subIDs := range subByEpoch {
// update that we've queued the subscription (last sent rather means last queued)
err := db.UpdateSubscriptionsLastSent(subIDs, time.Now(), epoch, useDB)
@@ -520,6 +522,7 @@ func queueNotifications(notificationsByUserID types.NotificationsPerUserId, useD
}
}
+ // no need to batch here as the internal state will become obsolete
for state, subs := range stateToSub {
subArray := make([]int64, 0)
for subID := range subs {
@@ -1549,21 +1552,21 @@ func collectAttestationAndOfflineValidatorNotifications(notificationsByUserID ty
t := hex.EncodeToString(validator.Pubkey)
subs := subMap[t]
for _, sub := range subs {
- if sub.State.String == "" || sub.State.String == "-" { // discard online notifications that do not have a corresponding offline notification
- continue
- }
+ // if sub.State.String == "" || sub.State.String == "-" { // discard online notifications that do not have a corresponding offline notification
+ // continue
+ // }
- originalLastSeenEpoch, err := strconv.ParseUint(sub.State.String, 10, 64)
- if err != nil {
- // I have no idea what just happened.
- return fmt.Errorf("this should never happen. couldn't parse state as uint64: %v", err)
- }
+ // originalLastSeenEpoch, err := strconv.ParseUint(sub.State.String, 10, 64)
+ // if err != nil {
+ // // I have no idea what just happened.
+ // return fmt.Errorf("this should never happen. couldn't parse state as uint64: %v", err)
+ // }
- epochsSinceOffline := epoch - originalLastSeenEpoch
+ // epochsSinceOffline := epoch - originalLastSeenEpoch
- if epochsSinceOffline > epoch { // fix overflow
- epochsSinceOffline = 4
- }
+ // if epochsSinceOffline > epoch { // fix overflow
+ // epochsSinceOffline = 4
+ // }
if sub.UserID == nil || sub.ID == nil {
return fmt.Errorf("error expected userId and subId to be defined but got user: %v, sub: %v", sub.UserID, sub.ID)
@@ -1582,7 +1585,6 @@ func collectAttestationAndOfflineValidatorNotifications(notificationsByUserID ty
},
ValidatorIndex: validator.Index,
IsOffline: false,
- EpochsOffline: epochsSinceOffline,
}
notificationsByUserID.AddNotification(n)
@@ -1597,7 +1599,6 @@ type validatorIsOfflineNotification struct {
types.NotificationBaseImpl
ValidatorIndex uint64
- EpochsOffline uint64
IsOffline bool
}
@@ -1611,9 +1612,9 @@ func (n *validatorIsOfflineNotification) GetInfo(includeUrl bool) string {
}
} else {
if includeUrl {
- return fmt.Sprintf(`Validator %[1]v is back online since epoch %[2]v (was offline for %[4]v epoch(s)).`, n.ValidatorIndex, n.Epoch, utils.Config.Frontend.SiteDomain, n.EpochsOffline)
+ return fmt.Sprintf(`Validator %[1]v is back online since epoch %[2]v.`, n.ValidatorIndex, n.Epoch, utils.Config.Frontend.SiteDomain)
} else {
- return fmt.Sprintf(`Validator %v is back online since epoch %v (was offline for %v epoch(s)).`, n.ValidatorIndex, n.Epoch, n.EpochsOffline)
+ return fmt.Sprintf(`Validator %v is back online since epoch %v.`, n.ValidatorIndex, n.Epoch)
}
}
}
@@ -1630,7 +1631,7 @@ func (n *validatorIsOfflineNotification) GetInfoMarkdown() string {
if n.IsOffline {
return fmt.Sprintf(`Validator [%[1]v](https://%[3]v/validator/%[1]v) is offline since epoch [%[2]v](https://%[3]v/epoch/%[2]v).`, n.ValidatorIndex, n.Epoch, utils.Config.Frontend.SiteDomain)
} else {
- return fmt.Sprintf(`Validator [%[1]v](https://%[3]v/validator/%[1]v) is back online since epoch [%[2]v](https://%[3]v/epoch/%[2]v) (was offline for %[4]v epoch(s)).`, n.ValidatorIndex, n.Epoch, utils.Config.Frontend.SiteDomain, n.EpochsOffline)
+ return fmt.Sprintf(`Validator [%[1]v](https://%[3]v/validator/%[1]v) is back online since epoch [%[2]v](https://%[3]v/epoch/%[2]v).`, n.ValidatorIndex, n.Epoch, utils.Config.Frontend.SiteDomain)
}
}
From 161652041681b02afa609ed8620731b301d1ff58 Mon Sep 17 00:00:00 2001
From: peter <1674920+peterbitfly@users.noreply.github.com>
Date: Mon, 2 Sep 2024 14:46:24 +0200
Subject: [PATCH 16/39] fix(notifications): properly log error
---
backend/pkg/notification/notifications.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/backend/pkg/notification/notifications.go b/backend/pkg/notification/notifications.go
index 76bedf688..ba06f4132 100644
--- a/backend/pkg/notification/notifications.go
+++ b/backend/pkg/notification/notifications.go
@@ -166,7 +166,7 @@ func notificationSender() {
if err != nil {
log.Error(err, "error getting advisory lock from db", 0)
- conn.Close()
+ err := conn.Close()
if err != nil {
log.Error(err, "error returning connection to connection pool", 0)
}
From bc57bfd680e69bd97c75a239b659f35ca510f80b Mon Sep 17 00:00:00 2001
From: peter <1674920+peterbitfly@users.noreply.github.com>
Date: Mon, 9 Sep 2024 09:54:53 +0000
Subject: [PATCH 17/39] simplify extraction of user ids from the notification
map
---
backend/pkg/notification/notifications.go | 63 +++++++++++------------
1 file changed, 30 insertions(+), 33 deletions(-)
diff --git a/backend/pkg/notification/notifications.go b/backend/pkg/notification/notifications.go
index e68f5f3f6..71ec9e0eb 100644
--- a/backend/pkg/notification/notifications.go
+++ b/backend/pkg/notification/notifications.go
@@ -8,6 +8,8 @@ import (
"encoding/hex"
"encoding/json"
"errors"
+ "maps"
+ "slices"
"fmt"
"html/template"
@@ -283,28 +285,28 @@ func collectNotifications(epoch uint64) (types.NotificationsPerUserId, error) {
return nil, fmt.Errorf("error getting dashboard definitions: %v", err)
}
- // Now initialize the validator dashboard configuration map
- validatorDashboardConfig := &types.ValidatorDashboardConfig{
- DashboardsByUserId: make(map[types.UserId]map[types.DashboardId]*types.ValidatorDashboard),
- }
- for _, row := range dashboardDefinitions {
- if validatorDashboardConfig.DashboardsByUserId[row.UserId] == nil {
- validatorDashboardConfig.DashboardsByUserId[row.UserId] = make(map[types.DashboardId]*types.ValidatorDashboard)
- }
- if validatorDashboardConfig.DashboardsByUserId[row.UserId][row.DashboardId] == nil {
- validatorDashboardConfig.DashboardsByUserId[row.UserId][row.DashboardId] = &types.ValidatorDashboard{
- Name: row.DashboardName,
- Groups: make(map[types.DashboardGroupId]*types.ValidatorDashboardGroup),
- }
- }
- if validatorDashboardConfig.DashboardsByUserId[row.UserId][row.DashboardId].Groups[row.GroupId] == nil {
- validatorDashboardConfig.DashboardsByUserId[row.UserId][row.DashboardId].Groups[row.GroupId] = &types.ValidatorDashboardGroup{
- Name: row.GroupName,
- Validators: []uint64{},
- }
- }
- validatorDashboardConfig.DashboardsByUserId[row.UserId][row.DashboardId].Groups[row.GroupId].Validators = append(validatorDashboardConfig.DashboardsByUserId[row.UserId][row.DashboardId].Groups[row.GroupId].Validators, uint64(row.ValidatorIndex))
- }
+ // // Now initialize the validator dashboard configuration map
+ // validatorDashboardConfig := &types.ValidatorDashboardConfig{
+ // DashboardsByUserId: make(map[types.UserId]map[types.DashboardId]*types.ValidatorDashboard),
+ // }
+ // for _, row := range dashboardDefinitions {
+ // if validatorDashboardConfig.DashboardsByUserId[row.UserId] == nil {
+ // validatorDashboardConfig.DashboardsByUserId[row.UserId] = make(map[types.DashboardId]*types.ValidatorDashboard)
+ // }
+ // if validatorDashboardConfig.DashboardsByUserId[row.UserId][row.DashboardId] == nil {
+ // validatorDashboardConfig.DashboardsByUserId[row.UserId][row.DashboardId] = &types.ValidatorDashboard{
+ // Name: row.DashboardName,
+ // Groups: make(map[types.DashboardGroupId]*types.ValidatorDashboardGroup),
+ // }
+ // }
+ // if validatorDashboardConfig.DashboardsByUserId[row.UserId][row.DashboardId].Groups[row.GroupId] == nil {
+ // validatorDashboardConfig.DashboardsByUserId[row.UserId][row.DashboardId].Groups[row.GroupId] = &types.ValidatorDashboardGroup{
+ // Name: row.GroupName,
+ // Validators: []uint64{},
+ // }
+ // }
+ // validatorDashboardConfig.DashboardsByUserId[row.UserId][row.DashboardId].Groups[row.GroupId].Validators = append(validatorDashboardConfig.DashboardsByUserId[row.UserId][row.DashboardId].Groups[row.GroupId].Validators, uint64(row.ValidatorIndex))
+ // }
// TODO: pass the validatorDashboardConfig to the notification collection functions
// The following functions will collect the notifications and add them to the
@@ -526,7 +528,7 @@ func queueNotifications(notificationsByUserID types.NotificationsPerUserId, useD
for state, subs := range stateToSub {
subArray := make([]int64, 0)
for subID := range subs {
- subArray = append(subArray, int64(subID))
+ subArray = append(subArray, int64(subID)) //nolint:gosec
}
_, err := db.FrontendWriterDB.Exec(`UPDATE users_subscriptions SET internal_state = $1 WHERE id = ANY($2)`, state, pq.Int64Array(subArray))
if err != nil {
@@ -582,10 +584,7 @@ func getNetwork() string {
}
func queuePushNotification(notificationsByUserID types.NotificationsPerUserId, useDB *sqlx.DB) error {
- userIDs := []types.UserId{}
- for userID := range notificationsByUserID {
- userIDs = append(userIDs, userID)
- }
+ userIDs := slices.Collect(maps.Keys(notificationsByUserID))
tokensByUserID, err := GetUserPushTokenByIds(userIDs)
if err != nil {
@@ -690,10 +689,8 @@ func sendPushNotifications(useDB *sqlx.DB) error {
}
func queueEmailNotifications(notificationsByUserID types.NotificationsPerUserId, useDB *sqlx.DB) error {
- userIDs := []types.UserId{}
- for userID := range notificationsByUserID {
- userIDs = append(userIDs, userID)
- }
+ userIDs := slices.Collect(maps.Keys(notificationsByUserID))
+
emailsByUserID, err := GetUserEmailsByIds(userIDs)
if err != nil {
metrics.Errors.WithLabelValues("notifications_get_user_mail_by_id").Inc()
@@ -1009,7 +1006,7 @@ func sendWebhookNotifications(useDB *sqlx.DB) error {
go func(n types.TransitWebhook) {
if n.Content.Webhook.Retries > 0 {
- time.Sleep(time.Duration(n.Content.Webhook.Retries) * time.Second)
+ time.Sleep(time.Duration(n.Content.Webhook.Retries) * time.Second) //nolint:gosec
}
resp, err := client.Post(n.Content.Webhook.Url, "application/json", reqBody)
if err != nil {
@@ -1127,7 +1124,7 @@ func sendDiscordNotifications(useDB *sqlx.DB) error {
break // stop
}
// sleep between retries
- time.Sleep(time.Duration(webhook.Retries) * time.Second)
+ time.Sleep(time.Duration(webhook.Retries) * time.Second) //nolint:gosec
reqBody := new(bytes.Buffer)
err := json.NewEncoder(reqBody).Encode(reqs[i].Content.DiscordRequest)
From 3a148a7b108216aa7abf63aee42c5f84e62821bc Mon Sep 17 00:00:00 2001
From: peter <1674920+peterbitfly@users.noreply.github.com>
Date: Mon, 9 Sep 2024 09:58:32 +0000
Subject: [PATCH 18/39] chore(notifications): please linter
---
backend/pkg/notification/notifications.go | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/backend/pkg/notification/notifications.go b/backend/pkg/notification/notifications.go
index 71ec9e0eb..4b5512f86 100644
--- a/backend/pkg/notification/notifications.go
+++ b/backend/pkg/notification/notifications.go
@@ -528,7 +528,7 @@ func queueNotifications(notificationsByUserID types.NotificationsPerUserId, useD
for state, subs := range stateToSub {
subArray := make([]int64, 0)
for subID := range subs {
- subArray = append(subArray, int64(subID)) //nolint:gosec
+ subArray = append(subArray, int64(subID))
}
_, err := db.FrontendWriterDB.Exec(`UPDATE users_subscriptions SET internal_state = $1 WHERE id = ANY($2)`, state, pq.Int64Array(subArray))
if err != nil {
@@ -1006,7 +1006,7 @@ func sendWebhookNotifications(useDB *sqlx.DB) error {
go func(n types.TransitWebhook) {
if n.Content.Webhook.Retries > 0 {
- time.Sleep(time.Duration(n.Content.Webhook.Retries) * time.Second) //nolint:gosec
+ time.Sleep(time.Duration(n.Content.Webhook.Retries) * time.Second)
}
resp, err := client.Post(n.Content.Webhook.Url, "application/json", reqBody)
if err != nil {
@@ -1124,7 +1124,7 @@ func sendDiscordNotifications(useDB *sqlx.DB) error {
break // stop
}
// sleep between retries
- time.Sleep(time.Duration(webhook.Retries) * time.Second) //nolint:gosec
+ time.Sleep(time.Duration(webhook.Retries) * time.Second)
reqBody := new(bytes.Buffer)
err := json.NewEncoder(reqBody).Encode(reqs[i].Content.DiscordRequest)
From f8265c5851a59abf5a0ff668c08e522e4b4fcfd1 Mon Sep 17 00:00:00 2001
From: peter <1674920+peterbitfly@users.noreply.github.com>
Date: Mon, 9 Sep 2024 09:59:24 +0000
Subject: [PATCH 19/39] chore(notifications): disable loading dashboard
configurations
---
backend/pkg/notification/notifications.go | 42 +++++++++++------------
1 file changed, 21 insertions(+), 21 deletions(-)
diff --git a/backend/pkg/notification/notifications.go b/backend/pkg/notification/notifications.go
index 4b5512f86..59399f3b7 100644
--- a/backend/pkg/notification/notifications.go
+++ b/backend/pkg/notification/notifications.go
@@ -263,27 +263,27 @@ func collectNotifications(epoch uint64) (types.NotificationsPerUserId, error) {
ValidatorIndex types.ValidatorIndex `db:"validator_index"`
}
- log.Infof("retrieving dashboard definitions")
- // Retrieve all dashboard definitions to be able to retrieve validators included in
- // the group notification subscriptions
- // TODO: add a filter to retrieve only groups that have notifications enabled
- // Needs a new field in the db
- var dashboardDefinitions []dashboardDefinitionRow
- err = db.AlloyWriter.Select(&dashboardDefinitions, `
- select
- users_val_dashboards.id as dashboard_id,
- users_val_dashboards.name as dashboard_name,
- users_val_dashboards.user_id,
- users_val_dashboards_groups.id as group_id,
- users_val_dashboards_groups.name as group_name,
- users_val_dashboards_validators.validator_index
- from users_val_dashboards
- left join users_val_dashboards_groups on users_val_dashboards_groups.dashboard_id = users_val_dashboards.id
- left join users_val_dashboards_validators on users_val_dashboards_validators.dashboard_id = users_val_dashboards_groups.dashboard_id AND users_val_dashboards_validators.group_id = users_val_dashboards_groups.id;
- `)
- if err != nil {
- return nil, fmt.Errorf("error getting dashboard definitions: %v", err)
- }
+ // log.Infof("retrieving dashboard definitions")
+ // // Retrieve all dashboard definitions to be able to retrieve validators included in
+ // // the group notification subscriptions
+ // // TODO: add a filter to retrieve only groups that have notifications enabled
+ // // Needs a new field in the db
+ // var dashboardDefinitions []dashboardDefinitionRow
+ // err = db.AlloyWriter.Select(&dashboardDefinitions, `
+ // select
+ // users_val_dashboards.id as dashboard_id,
+ // users_val_dashboards.name as dashboard_name,
+ // users_val_dashboards.user_id,
+ // users_val_dashboards_groups.id as group_id,
+ // users_val_dashboards_groups.name as group_name,
+ // users_val_dashboards_validators.validator_index
+ // from users_val_dashboards
+ // left join users_val_dashboards_groups on users_val_dashboards_groups.dashboard_id = users_val_dashboards.id
+ // left join users_val_dashboards_validators on users_val_dashboards_validators.dashboard_id = users_val_dashboards_groups.dashboard_id AND users_val_dashboards_validators.group_id = users_val_dashboards_groups.id;
+ // `)
+ // if err != nil {
+ // return nil, fmt.Errorf("error getting dashboard definitions: %v", err)
+ // }
// // Now initialize the validator dashboard configuration map
// validatorDashboardConfig := &types.ValidatorDashboardConfig{
From 23ed6e285f69603811e1085f7bfaa7485428f2aa Mon Sep 17 00:00:00 2001
From: peter <1674920+peterbitfly@users.noreply.github.com>
Date: Mon, 9 Sep 2024 09:59:46 +0000
Subject: [PATCH 20/39] chore(notifications): remove unused code for dashboard
configurations
---
backend/pkg/notification/notifications.go | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/backend/pkg/notification/notifications.go b/backend/pkg/notification/notifications.go
index 59399f3b7..a8a6209eb 100644
--- a/backend/pkg/notification/notifications.go
+++ b/backend/pkg/notification/notifications.go
@@ -254,14 +254,14 @@ func collectNotifications(epoch uint64) (types.NotificationsPerUserId, error) {
log.Infof("started collecting notifications")
- type dashboardDefinitionRow struct {
- DashboardId types.DashboardId `db:"dashboard_id"`
- DashboardName string `db:"dashboard_name"`
- UserId types.UserId `db:"user_id"`
- GroupId types.DashboardGroupId `db:"group_id"`
- GroupName string `db:"group_name"`
- ValidatorIndex types.ValidatorIndex `db:"validator_index"`
- }
+ // type dashboardDefinitionRow struct {
+ // DashboardId types.DashboardId `db:"dashboard_id"`
+ // DashboardName string `db:"dashboard_name"`
+ // UserId types.UserId `db:"user_id"`
+ // GroupId types.DashboardGroupId `db:"group_id"`
+ // GroupName string `db:"group_name"`
+ // ValidatorIndex types.ValidatorIndex `db:"validator_index"`
+ // }
// log.Infof("retrieving dashboard definitions")
// // Retrieve all dashboard definitions to be able to retrieve validators included in
From c8d0e0f993ebc902d9d433c1a9f7e7c68feb83be Mon Sep 17 00:00:00 2001
From: peter <1674920+peterbitfly@users.noreply.github.com>
Date: Mon, 9 Sep 2024 12:14:42 +0000
Subject: [PATCH 21/39] feat(notifications): store queued notifications in
network db
---
backend/pkg/commons/db/subscriptions.go | 4 +-
backend/pkg/notification/notifications.go | 89 +++++++++++------------
2 files changed, 46 insertions(+), 47 deletions(-)
diff --git a/backend/pkg/commons/db/subscriptions.go b/backend/pkg/commons/db/subscriptions.go
index 3edbc3d5f..639f70c8b 100644
--- a/backend/pkg/commons/db/subscriptions.go
+++ b/backend/pkg/commons/db/subscriptions.go
@@ -261,8 +261,8 @@ func GetSubscriptions(filter GetSubscriptionsFilter) ([]*types.Subscription, err
}
// UpdateSubscriptionsLastSent updates `last_sent_ts` column of the `users_subscriptions` table.
-func UpdateSubscriptionsLastSent(subscriptionIDs []uint64, sent time.Time, epoch uint64, useDB *sqlx.DB) error {
- _, err := useDB.Exec(`
+func UpdateSubscriptionsLastSent(subscriptionIDs []uint64, sent time.Time, epoch uint64) error {
+ _, err := FrontendWriterDB.Exec(`
UPDATE users_subscriptions
SET last_sent_ts = TO_TIMESTAMP($1), last_sent_epoch = $2
WHERE id = ANY($3)`, sent.Unix(), epoch, pq.Array(subscriptionIDs))
diff --git a/backend/pkg/notification/notifications.go b/backend/pkg/notification/notifications.go
index a8a6209eb..7b148d0d5 100644
--- a/backend/pkg/notification/notifications.go
+++ b/backend/pkg/notification/notifications.go
@@ -34,7 +34,6 @@ import (
"github.com/gobitfly/beaconchain/pkg/commons/types"
"github.com/gobitfly/beaconchain/pkg/commons/utils"
- "github.com/jmoiron/sqlx"
"github.com/lib/pq"
"github.com/rocket-pool/rocketpool-go/utils/eth"
"golang.org/x/text/cases"
@@ -126,7 +125,7 @@ func notificationCollector() {
break
}
- queueNotifications(notifications, db.FrontendWriterDB) // this caused the collected notifications to be queued and sent
+ queueNotifications(notifications) // this caused the collected notifications to be queued and sent
// Network DB Notifications (user related, must only run on one instance ever!!!!)
if utils.Config.Notifications.UserDBNotifications {
@@ -139,7 +138,7 @@ func notificationCollector() {
continue
}
- queueNotifications(userNotifications, db.FrontendWriterDB)
+ queueNotifications(userNotifications)
}
log.InfoWithFields(log.Fields{"notifications": len(notifications), "duration": time.Since(start), "epoch": epoch}, "notifications completed")
@@ -177,12 +176,12 @@ func notificationSender() {
}
log.Infof("lock obtained")
- err = dispatchNotifications(db.FrontendWriterDB)
+ err = dispatchNotifications()
if err != nil {
log.Error(err, "error dispatching notifications", 0)
}
- err = garbageCollectNotificationQueue(db.FrontendWriterDB)
+ err = garbageCollectNotificationQueue()
if err != nil {
log.Error(err, "error garbage collecting notification queue", 0)
}
@@ -464,20 +463,20 @@ func collectUserDbNotifications(epoch uint64) (types.NotificationsPerUserId, err
return notificationsByUserID, nil
}
-func queueNotifications(notificationsByUserID types.NotificationsPerUserId, useDB *sqlx.DB) {
+func queueNotifications(notificationsByUserID types.NotificationsPerUserId) {
subByEpoch := map[uint64][]uint64{}
- err := queueEmailNotifications(notificationsByUserID, useDB)
+ err := queueEmailNotifications(notificationsByUserID)
if err != nil {
log.Error(err, "error queuing email notifications", 0)
}
- err = queuePushNotification(notificationsByUserID, useDB)
+ err = queuePushNotification(notificationsByUserID)
if err != nil {
log.Error(err, "error queuing push notifications", 0)
}
- err = queueWebhookNotifications(notificationsByUserID, useDB)
+ err = queueWebhookNotifications(notificationsByUserID)
if err != nil {
log.Error(err, "error queuing webhook notifications", 0)
}
@@ -498,7 +497,7 @@ func queueNotifications(notificationsByUserID types.NotificationsPerUserId, useD
// obsolete as notifications are anyway sent on a per-epoch basis
for epoch, subIDs := range subByEpoch {
// update that we've queued the subscription (last sent rather means last queued)
- err := db.UpdateSubscriptionsLastSent(subIDs, time.Now(), epoch, useDB)
+ err := db.UpdateSubscriptionsLastSent(subIDs, time.Now(), epoch)
if err != nil {
log.Error(err, "error updating sent-time of sent notifications", 0)
metrics.Errors.WithLabelValues("notifications_updating_sent_time").Inc()
@@ -537,23 +536,23 @@ func queueNotifications(notificationsByUserID types.NotificationsPerUserId, useD
}
}
-func dispatchNotifications(useDB *sqlx.DB) error {
- err := sendEmailNotifications(useDB)
+func dispatchNotifications() error {
+ err := sendEmailNotifications()
if err != nil {
return fmt.Errorf("error sending email notifications, err: %w", err)
}
- err = sendPushNotifications(useDB)
+ err = sendPushNotifications()
if err != nil {
return fmt.Errorf("error sending push notifications, err: %w", err)
}
- err = sendWebhookNotifications(useDB)
+ err = sendWebhookNotifications()
if err != nil {
return fmt.Errorf("error sending webhook notifications, err: %w", err)
}
- err = sendDiscordNotifications(useDB)
+ err = sendDiscordNotifications()
if err != nil {
return fmt.Errorf("error sending webhook discord notifications, err: %w", err)
}
@@ -562,8 +561,8 @@ func dispatchNotifications(useDB *sqlx.DB) error {
}
// garbageCollectNotificationQueue deletes entries from the notification queue that have been processed
-func garbageCollectNotificationQueue(useDB *sqlx.DB) error {
- rows, err := useDB.Exec(`DELETE FROM notification_queue WHERE (sent < now() - INTERVAL '30 minutes') OR (created < now() - INTERVAL '1 hour')`)
+func garbageCollectNotificationQueue() error {
+ rows, err := db.WriterDb.Exec(`DELETE FROM notification_queue WHERE (sent < now() - INTERVAL '30 minutes') OR (created < now() - INTERVAL '1 hour')`)
if err != nil {
return fmt.Errorf("error deleting from notification_queue %w", err)
}
@@ -583,7 +582,7 @@ func getNetwork() string {
return ""
}
-func queuePushNotification(notificationsByUserID types.NotificationsPerUserId, useDB *sqlx.DB) error {
+func queuePushNotification(notificationsByUserID types.NotificationsPerUserId) error {
userIDs := slices.Collect(maps.Keys(notificationsByUserID))
tokensByUserID, err := GetUserPushTokenByIds(userIDs)
@@ -636,7 +635,7 @@ func queuePushNotification(notificationsByUserID types.NotificationsPerUserId, u
Messages: batch,
}
- _, err = useDB.Exec(`INSERT INTO notification_queue (created, channel, content) VALUES ($1, 'push', $2)`, time.Now(), transitPushContent)
+ _, err = db.WriterDb.Exec(`INSERT INTO notification_queue (created, channel, content) VALUES ($1, 'push', $2)`, time.Now(), transitPushContent)
if err != nil {
log.Error(err, "error writing transit push notification to db", 0)
return
@@ -646,10 +645,10 @@ func queuePushNotification(notificationsByUserID types.NotificationsPerUserId, u
return nil
}
-func sendPushNotifications(useDB *sqlx.DB) error {
+func sendPushNotifications() error {
var notificationQueueItem []types.TransitPush
- err := useDB.Select(¬ificationQueueItem, `SELECT
+ err := db.WriterDb.Select(¬ificationQueueItem, `SELECT
id,
created,
sent,
@@ -679,7 +678,7 @@ func sendPushNotifications(useDB *sqlx.DB) error {
metrics.NotificationsSent.WithLabelValues("push", "200").Add(float64(len(n.Content.Messages)))
}
- _, err = useDB.Exec(`UPDATE notification_queue SET sent = now() WHERE id = $1`, n.Id)
+ _, err = db.WriterDb.Exec(`UPDATE notification_queue SET sent = now() WHERE id = $1`, n.Id)
if err != nil {
return fmt.Errorf("error updating sent status for push notification with id: %v, err: %w", n.Id, err)
}
@@ -688,7 +687,7 @@ func sendPushNotifications(useDB *sqlx.DB) error {
return nil
}
-func queueEmailNotifications(notificationsByUserID types.NotificationsPerUserId, useDB *sqlx.DB) error {
+func queueEmailNotifications(notificationsByUserID types.NotificationsPerUserId) error {
userIDs := slices.Collect(maps.Keys(notificationsByUserID))
emailsByUserID, err := GetUserEmailsByIds(userIDs)
@@ -777,7 +776,7 @@ func queueEmailNotifications(notificationsByUserID types.NotificationsPerUserId,
Attachments: attachments,
}
- _, err = useDB.Exec(`INSERT INTO notification_queue (created, channel, content) VALUES ($1, 'email', $2)`, time.Now(), transitEmailContent)
+ _, err = db.WriterDb.Exec(`INSERT INTO notification_queue (created, channel, content) VALUES ($1, 'email', $2)`, time.Now(), transitEmailContent)
if err != nil {
log.Error(err, "error writing transit email to db", 0)
}
@@ -786,10 +785,10 @@ func queueEmailNotifications(notificationsByUserID types.NotificationsPerUserId,
return nil
}
-func sendEmailNotifications(useDb *sqlx.DB) error {
+func sendEmailNotifications() error {
var notificationQueueItem []types.TransitEmail
- err := useDb.Select(¬ificationQueueItem, `SELECT
+ err := db.WriterDb.Select(¬ificationQueueItem, `SELECT
id,
created,
sent,
@@ -812,7 +811,7 @@ func sendEmailNotifications(useDb *sqlx.DB) error {
metrics.NotificationsSent.WithLabelValues("email", "200").Inc()
}
}
- _, err = useDb.Exec(`UPDATE notification_queue set sent = now() where id = $1`, n.Id)
+ _, err = db.WriterDb.Exec(`UPDATE notification_queue set sent = now() where id = $1`, n.Id)
if err != nil {
return fmt.Errorf("error updating sent status for email notification with id: %v, err: %w", n.Id, err)
}
@@ -820,10 +819,10 @@ func sendEmailNotifications(useDb *sqlx.DB) error {
return nil
}
-func queueWebhookNotifications(notificationsByUserID types.NotificationsPerUserId, useDB *sqlx.DB) error {
+func queueWebhookNotifications(notificationsByUserID types.NotificationsPerUserId) error {
for userID, userNotifications := range notificationsByUserID {
var webhooks []types.UserWebhook
- err := useDB.Select(&webhooks, `
+ err := db.FrontendWriterDB.Select(&webhooks, `
SELECT
id,
user_id,
@@ -861,7 +860,7 @@ func queueWebhookNotifications(notificationsByUserID types.NotificationsPerUserI
if len(notifications) > 0 {
// reset Retries
if w.Retries > 5 && w.LastSent.Valid && w.LastSent.Time.Add(time.Hour).Before(time.Now()) {
- _, err = useDB.Exec(`UPDATE users_webhooks SET retries = 0 WHERE id = $1;`, w.ID)
+ _, err = db.FrontendWriterDB.Exec(`UPDATE users_webhooks SET retries = 0 WHERE id = $1;`, w.ID)
if err != nil {
log.Error(err, "error updating users_webhooks table; setting retries to zero", 0)
continue
@@ -938,7 +937,7 @@ func queueWebhookNotifications(notificationsByUserID types.NotificationsPerUserI
}
// process notifs
for _, n := range notifs {
- _, err = useDB.Exec(`INSERT INTO notification_queue (created, channel, content) VALUES (now(), $1, $2);`, n.Channel, n.Content)
+ _, err = db.WriterDb.Exec(`INSERT INTO notification_queue (created, channel, content) VALUES (now(), $1, $2);`, n.Channel, n.Content)
if err != nil {
log.Error(err, "error inserting into webhooks_queue", 0)
} else {
@@ -948,7 +947,7 @@ func queueWebhookNotifications(notificationsByUserID types.NotificationsPerUserI
// process discord notifs
for _, dNotifs := range discordNotifMap {
for _, n := range dNotifs {
- _, err = useDB.Exec(`INSERT INTO notification_queue (created, channel, content) VALUES (now(), 'webhook_discord', $1);`, n)
+ _, err = db.WriterDb.Exec(`INSERT INTO notification_queue (created, channel, content) VALUES (now(), 'webhook_discord', $1);`, n)
if err != nil {
log.Error(err, "error inserting into webhooks_queue (discord)", 0)
continue
@@ -961,10 +960,10 @@ func queueWebhookNotifications(notificationsByUserID types.NotificationsPerUserI
return nil
}
-func sendWebhookNotifications(useDB *sqlx.DB) error {
+func sendWebhookNotifications() error {
var notificationQueueItem []types.TransitWebhook
- err := useDB.Select(¬ificationQueueItem, `SELECT
+ err := db.WriterDb.Select(¬ificationQueueItem, `SELECT
id,
created,
sent,
@@ -981,7 +980,7 @@ func sendWebhookNotifications(useDB *sqlx.DB) error {
for _, n := range notificationQueueItem {
// do not retry after 5 attempts
if n.Content.Webhook.Retries > 5 {
- _, err := db.FrontendWriterDB.Exec(`DELETE FROM notification_queue WHERE id = $1`, n.Id)
+ _, err := db.WriterDb.Exec(`DELETE FROM notification_queue WHERE id = $1`, n.Id)
if err != nil {
return fmt.Errorf("error deleting from notification queue: %w", err)
}
@@ -997,7 +996,7 @@ func sendWebhookNotifications(useDB *sqlx.DB) error {
_, err = url.Parse(n.Content.Webhook.Url)
if err != nil {
- _, err := db.FrontendWriterDB.Exec(`DELETE FROM notification_queue WHERE id = $1`, n.Id)
+ _, err := db.WriterDb.Exec(`DELETE FROM notification_queue WHERE id = $1`, n.Id)
if err != nil {
return fmt.Errorf("error deleting from notification queue: %w", err)
}
@@ -1017,14 +1016,14 @@ func sendWebhookNotifications(useDB *sqlx.DB) error {
}
defer resp.Body.Close()
- _, err = useDB.Exec(`UPDATE notification_queue SET sent = now() WHERE id = $1`, n.Id)
+ _, err = db.WriterDb.Exec(`UPDATE notification_queue SET sent = now() WHERE id = $1`, n.Id)
if err != nil {
log.Error(err, "error updating notification_queue table", 0)
return
}
if resp != nil && resp.StatusCode < 400 {
- _, err = useDB.Exec(`UPDATE users_webhooks SET retries = 0, last_sent = now() WHERE id = $1;`, n.Content.Webhook.ID)
+ _, err = db.FrontendWriterDB.Exec(`UPDATE users_webhooks SET retries = 0, last_sent = now() WHERE id = $1;`, n.Content.Webhook.ID)
if err != nil {
log.Error(err, "error updating users_webhooks table", 0)
return
@@ -1042,7 +1041,7 @@ func sendWebhookNotifications(useDB *sqlx.DB) error {
errResp.Body = string(b)
}
- _, err = useDB.Exec(`UPDATE users_webhooks SET retries = retries + 1, last_sent = now(), request = $2, response = $3 WHERE id = $1;`, n.Content.Webhook.ID, n.Content, errResp)
+ _, err = db.FrontendWriterDB.Exec(`UPDATE users_webhooks SET retries = retries + 1, last_sent = now(), request = $2, response = $3 WHERE id = $1;`, n.Content.Webhook.ID, n.Content, errResp)
if err != nil {
log.Error(err, "error updating users_webhooks table", 0)
return
@@ -1053,10 +1052,10 @@ func sendWebhookNotifications(useDB *sqlx.DB) error {
return nil
}
-func sendDiscordNotifications(useDB *sqlx.DB) error {
+func sendDiscordNotifications() error {
var notificationQueueItem []types.TransitDiscord
- err := useDB.Select(¬ificationQueueItem, `SELECT
+ err := db.WriterDb.Select(¬ificationQueueItem, `SELECT
id,
created,
sent,
@@ -1077,7 +1076,7 @@ func sendDiscordNotifications(useDB *sqlx.DB) error {
for _, n := range notificationQueueItem {
// purge the event from existence if the retry counter is over 5
if n.Content.Webhook.Retries > 5 {
- _, err = db.FrontendWriterDB.Exec(`DELETE FROM notification_queue where id = $1`, n.Id)
+ _, err = db.WriterDb.Exec(`DELETE FROM notification_queue where id = $1`, n.Id)
if err != nil {
log.Warnf("failed to delete notification from queue: %v", err)
}
@@ -1097,7 +1096,7 @@ func sendDiscordNotifications(useDB *sqlx.DB) error {
go func(webhook types.UserWebhook, reqs []types.TransitDiscord) {
defer func() {
// update retries counters in db based on end result
- _, err = useDB.Exec(`UPDATE users_webhooks SET retries = $1, last_sent = now() WHERE id = $2;`, webhook.Retries, webhook.ID)
+ _, err = db.FrontendWriterDB.Exec(`UPDATE users_webhooks SET retries = $1, last_sent = now() WHERE id = $2;`, webhook.Retries, webhook.ID)
if err != nil {
log.Warnf("failed to update retries counter to %v for webhook %v: %v", webhook.Retries, webhook.ID, err)
}
@@ -1107,7 +1106,7 @@ func sendDiscordNotifications(useDB *sqlx.DB) error {
for _, req := range reqs {
ids = append(ids, req.Id)
}
- _, err = db.FrontendWriterDB.Exec(`UPDATE notification_queue SET sent = now() where id = ANY($1)`, pq.Array(ids))
+ _, err = db.WriterDb.Exec(`UPDATE notification_queue SET sent = now() where id = ANY($1)`, pq.Array(ids))
if err != nil {
log.Warnf("failed to update sent for notifcations in queue: %v", err)
}
@@ -1161,7 +1160,7 @@ func sendDiscordNotifications(useDB *sqlx.DB) error {
} else {
log.Error(nil, "error pushing discord webhook", 0, map[string]interface{}{"errResp.Body": errResp.Body, "webhook.Url": webhook.Url})
}
- _, err = useDB.Exec(`UPDATE users_webhooks SET request = $2, response = $3 WHERE id = $1;`, webhook.ID, reqs[i].Content.DiscordRequest, errResp)
+ _, err = db.FrontendWriterDB.Exec(`UPDATE users_webhooks SET request = $2, response = $3 WHERE id = $1;`, webhook.ID, reqs[i].Content.DiscordRequest, errResp)
if err != nil {
log.Error(err, "error storing failure data in users_webhooks table", 0)
}
From 86da74c466e8e61e90e1b3e1bf7cc7744cc2963a Mon Sep 17 00:00:00 2001
From: peter <1674920+peterbitfly@users.noreply.github.com>
Date: Tue, 10 Sep 2024 10:27:46 +0000
Subject: [PATCH 22/39] fix(notifications): expand args in sql query
---
backend/pkg/notification/db.go | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/backend/pkg/notification/db.go b/backend/pkg/notification/db.go
index 4363c12f7..6e19acf3b 100644
--- a/backend/pkg/notification/db.go
+++ b/backend/pkg/notification/db.go
@@ -58,7 +58,7 @@ func GetSubsForEventFilter(eventName types.EventName, lastSentFilter string, las
}
subMap := make(map[string][]types.Subscription, 0)
- err = db.FrontendWriterDB.Select(&subs, query, args)
+ err = db.FrontendWriterDB.Select(&subs, query, args...)
if err != nil {
return nil, err
}
@@ -69,6 +69,7 @@ func GetSubsForEventFilter(eventName types.EventName, lastSentFilter string, las
}
subMap[sub.EventFilter] = append(subMap[sub.EventFilter], sub)
}
+
return subMap, nil
}
From 454534a2df918840e113c46b120e8f38a8e6c9d0 Mon Sep 17 00:00:00 2001
From: peter <1674920+peterbitfly@users.noreply.github.com>
Date: Tue, 10 Sep 2024 11:09:27 +0000
Subject: [PATCH 23/39] chore(notifications): add some util funcs
---
backend/cmd/misc/main.go | 60 ++++++++++++++---------
backend/pkg/commons/types/frontend.go | 4 +-
backend/pkg/notification/db.go | 6 ++-
backend/pkg/notification/notifications.go | 16 ++++--
4 files changed, 57 insertions(+), 29 deletions(-)
diff --git a/backend/cmd/misc/main.go b/backend/cmd/misc/main.go
index d7b9b77a1..8af9a3499 100644
--- a/backend/cmd/misc/main.go
+++ b/backend/cmd/misc/main.go
@@ -32,6 +32,7 @@ import (
edb "github.com/gobitfly/beaconchain/pkg/exporter/db"
"github.com/gobitfly/beaconchain/pkg/exporter/modules"
"github.com/gobitfly/beaconchain/pkg/exporter/services"
+ "github.com/gobitfly/beaconchain/pkg/notification"
_ "github.com/jackc/pgx/v5/stdlib"
"github.com/pkg/errors"
utilMath "github.com/protolambda/zrnt/eth2/util/math"
@@ -75,7 +76,7 @@ func Run() {
}
configPath := fs.String("config", "config/default.config.yml", "Path to the config file")
- fs.StringVar(&opts.Command, "command", "", "command to run, available: updateAPIKey, applyDbSchema, initBigtableSchema, epoch-export, debug-rewards, debug-blocks, clear-bigtable, index-old-eth1-blocks, update-aggregation-bits, historic-prices-export, index-missing-blocks, export-epoch-missed-slots, migrate-last-attestation-slot-bigtable, export-genesis-validators, update-block-finalization-sequentially, nameValidatorsByRanges, export-stats-totals, export-sync-committee-periods, export-sync-committee-validator-stats, partition-validator-stats, migrate-app-purchases")
+ fs.StringVar(&opts.Command, "command", "", "command to run, available: updateAPIKey, applyDbSchema, initBigtableSchema, epoch-export, debug-rewards, debug-blocks, clear-bigtable, index-old-eth1-blocks, update-aggregation-bits, historic-prices-export, index-missing-blocks, export-epoch-missed-slots, migrate-last-attestation-slot-bigtable, export-genesis-validators, update-block-finalization-sequentially, nameValidatorsByRanges, export-stats-totals, export-sync-committee-periods, export-sync-committee-validator-stats, partition-validator-stats, migrate-app-purchases, collect-notifications")
fs.Uint64Var(&opts.StartEpoch, "start-epoch", 0, "start epoch")
fs.Uint64Var(&opts.EndEpoch, "end-epoch", 0, "end epoch")
fs.Uint64Var(&opts.User, "user", 0, "user id")
@@ -181,27 +182,27 @@ func Run() {
defer db.FrontendWriterDB.Close()
// clickhouse
- db.ClickHouseWriter, db.ClickHouseReader = db.MustInitDB(&types.DatabaseConfig{
- Username: cfg.ClickHouse.WriterDatabase.Username,
- Password: cfg.ClickHouse.WriterDatabase.Password,
- Name: cfg.ClickHouse.WriterDatabase.Name,
- Host: cfg.ClickHouse.WriterDatabase.Host,
- Port: cfg.ClickHouse.WriterDatabase.Port,
- MaxOpenConns: cfg.ClickHouse.WriterDatabase.MaxOpenConns,
- SSL: true,
- MaxIdleConns: cfg.ClickHouse.WriterDatabase.MaxIdleConns,
- }, &types.DatabaseConfig{
- Username: cfg.ClickHouse.ReaderDatabase.Username,
- Password: cfg.ClickHouse.ReaderDatabase.Password,
- Name: cfg.ClickHouse.ReaderDatabase.Name,
- Host: cfg.ClickHouse.ReaderDatabase.Host,
- Port: cfg.ClickHouse.ReaderDatabase.Port,
- MaxOpenConns: cfg.ClickHouse.ReaderDatabase.MaxOpenConns,
- SSL: true,
- MaxIdleConns: cfg.ClickHouse.ReaderDatabase.MaxIdleConns,
- }, "clickhouse", "clickhouse")
- defer db.ClickHouseReader.Close()
- defer db.ClickHouseWriter.Close()
+ // db.ClickHouseWriter, db.ClickHouseReader = db.MustInitDB(&types.DatabaseConfig{
+ // Username: cfg.ClickHouse.WriterDatabase.Username,
+ // Password: cfg.ClickHouse.WriterDatabase.Password,
+ // Name: cfg.ClickHouse.WriterDatabase.Name,
+ // Host: cfg.ClickHouse.WriterDatabase.Host,
+ // Port: cfg.ClickHouse.WriterDatabase.Port,
+ // MaxOpenConns: cfg.ClickHouse.WriterDatabase.MaxOpenConns,
+ // SSL: true,
+ // MaxIdleConns: cfg.ClickHouse.WriterDatabase.MaxIdleConns,
+ // }, &types.DatabaseConfig{
+ // Username: cfg.ClickHouse.ReaderDatabase.Username,
+ // Password: cfg.ClickHouse.ReaderDatabase.Password,
+ // Name: cfg.ClickHouse.ReaderDatabase.Name,
+ // Host: cfg.ClickHouse.ReaderDatabase.Host,
+ // Port: cfg.ClickHouse.ReaderDatabase.Port,
+ // MaxOpenConns: cfg.ClickHouse.ReaderDatabase.MaxOpenConns,
+ // SSL: true,
+ // MaxIdleConns: cfg.ClickHouse.ReaderDatabase.MaxIdleConns,
+ // }, "clickhouse", "clickhouse")
+ // defer db.ClickHouseReader.Close()
+ // defer db.ClickHouseWriter.Close()
// Initialize the persistent redis client
rdc := redis.NewClient(&redis.Options{
@@ -456,6 +457,8 @@ func Run() {
err = fixEns(erigonClient)
case "fix-ens-addresses":
err = fixEnsAddresses(erigonClient)
+ case "collect-notifications":
+ err = collectNotifications(opts.StartEpoch, opts.EndEpoch)
default:
log.Fatal(nil, fmt.Sprintf("unknown command %s", opts.Command), 0)
}
@@ -467,6 +470,19 @@ func Run() {
}
}
+func collectNotifications(startEpoch, endEpoch uint64) error {
+ epoch := startEpoch
+
+ log.Infof("collecting notifications for epoch %v", epoch)
+ notifications, err := notification.GetNotificationsForEpoch(utils.Config.Notifications.PubkeyCachePath, epoch)
+ if err != nil {
+ return err
+ }
+
+ log.Infof("found %v notifications for epoch %v", len(notifications), epoch)
+ return nil
+}
+
func fixEns(erigonClient *rpc.ErigonClient) error {
log.Infof("command: fix-ens")
addrs := []struct {
diff --git a/backend/pkg/commons/types/frontend.go b/backend/pkg/commons/types/frontend.go
index 767aca38b..eb1c04472 100644
--- a/backend/pkg/commons/types/frontend.go
+++ b/backend/pkg/commons/types/frontend.go
@@ -28,10 +28,10 @@ type NotificationsPerUserId map[UserId]map[EventName]map[EventFilter]Notificatio
func (npui NotificationsPerUserId) AddNotification(n Notification) {
if n.GetUserId() == 0 {
- log.Fatal(fmt.Errorf("Notification user id is 0"), fmt.Sprintf("Notification: %v", n), 0)
+ log.Fatal(fmt.Errorf("Notification user id is 0"), fmt.Sprintf("Notification: %v", n), 1)
}
if n.GetEventName() == "" {
- log.Fatal(fmt.Errorf("Notification event name is empty"), fmt.Sprintf("Notification: %v", n), 0)
+ log.Fatal(fmt.Errorf("Notification event name is empty"), fmt.Sprintf("Notification: %v", n), 1)
}
// next check is disabled as there are events that do not require a filter (rocketpool, network events)
// if n.GetEventFilter() == "" {
diff --git a/backend/pkg/notification/db.go b/backend/pkg/notification/db.go
index 6e19acf3b..1f999a411 100644
--- a/backend/pkg/notification/db.go
+++ b/backend/pkg/notification/db.go
@@ -3,6 +3,7 @@ package notification
import (
"github.com/doug-martin/goqu/v9"
"github.com/gobitfly/beaconchain/pkg/commons/db"
+ "github.com/gobitfly/beaconchain/pkg/commons/log"
"github.com/gobitfly/beaconchain/pkg/commons/types"
"github.com/gobitfly/beaconchain/pkg/commons/utils"
"github.com/lib/pq"
@@ -39,7 +40,8 @@ func GetSubsForEventFilter(eventName types.EventName, lastSentFilter string, las
goqu.C("last_sent_epoch"),
goqu.C("created_epoch"),
goqu.C("event_threshold"),
- ).Where(goqu.C("event_name").Eq(utils.GetNetwork() + ":" + string(eventName)))
+ goqu.C("event_name"),
+ ).Where(goqu.L("(event_name = ? AND user_id <> 0)", utils.GetNetwork()+":"+string(eventName)))
if lastSentFilter != "" {
if len(lastSentFilterArgs) > 0 {
@@ -63,6 +65,8 @@ func GetSubsForEventFilter(eventName types.EventName, lastSentFilter string, las
return nil, err
}
+ log.Infof("Found %d subscriptions for event %s", len(subs), eventName)
+
for _, sub := range subs {
if _, ok := subMap[sub.EventFilter]; !ok {
subMap[sub.EventFilter] = make([]types.Subscription, 0)
diff --git a/backend/pkg/notification/notifications.go b/backend/pkg/notification/notifications.go
index 7b148d0d5..d7cb84e97 100644
--- a/backend/pkg/notification/notifications.go
+++ b/backend/pkg/notification/notifications.go
@@ -45,6 +45,14 @@ func InitNotificationSender() {
go notificationSender()
}
+func GetNotificationsForEpoch(pubkeyCachePath string, epoch uint64) (types.NotificationsPerUserId, error) {
+ err := initPubkeyCache(pubkeyCachePath)
+ if err != nil {
+ log.Fatal(err, "error initializing pubkey cache path for notifications", 0)
+ }
+ return collectNotifications(epoch)
+}
+
func InitNotificationCollector(pubkeyCachePath string) {
err := initPubkeyCache(pubkeyCachePath)
if err != nil {
@@ -1739,8 +1747,8 @@ func collectValidatorGotSlashedNotifications(notificationsByUserID types.Notific
for _, subs := range subscribedUsers {
for _, sub := range subs {
event := pubkeyToSlashingInfoMap[sub.EventFilter]
- if event == nil {
- log.Error(fmt.Errorf("error retrieving slashing info for public key %s", sub.EventFilter), "", 0)
+ if event == nil { // pubkey has not been slashed
+ //log.Error(fmt.Errorf("error retrieving slashing info for public key %s", sub.EventFilter), "", 0)
continue
}
log.Infof("creating %v notification for validator %v in epoch %v", event.Reason, sub.EventFilter, epoch)
@@ -2386,7 +2394,7 @@ func collectNetworkNotifications(notificationsByUserID types.NotificationsPerUse
dbResult, err := GetSubsForEventFilter(
types.NetworkLivenessIncreasedEventName,
- "us.last_sent_ts <= NOW() - INTERVAL '1 hour' OR us.last_sent_ts IS NULL",
+ "(last_sent_ts <= NOW() - INTERVAL '1 hour' OR last_sent_ts IS NULL)",
nil,
nil,
)
@@ -2760,7 +2768,7 @@ func collectSyncCommittee(notificationsByUserID types.NotificationsPerUserId, ep
pubKeys = append(pubKeys, val.PubKey)
}
- dbResult, err := GetSubsForEventFilter(types.SyncCommitteeSoon, "us.last_sent_ts <= NOW() - INTERVAL '26 hours' OR us.last_sent_ts IS NULL", nil, pubKeys)
+ dbResult, err := GetSubsForEventFilter(types.SyncCommitteeSoon, "(last_sent_ts <= NOW() - INTERVAL '26 hours' OR last_sent_ts IS NULL)", nil, pubKeys)
// err = db.FrontendWriterDB.Select(&dbResult, `
// SELECT us.id, us.user_id, us.event_filter, ENCODE(us.unsubscribe_hash, 'hex') as unsubscribe_hash
// FROM users_subscriptions AS us
From d8282b1130aaf0251e5bab103767e2066a3df80a Mon Sep 17 00:00:00 2001
From: peter <1674920+peterbitfly@users.noreply.github.com>
Date: Tue, 10 Sep 2024 11:13:44 +0000
Subject: [PATCH 24/39] chore(notifications): please linter
---
backend/cmd/misc/main.go | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/backend/cmd/misc/main.go b/backend/cmd/misc/main.go
index 8af9a3499..fd77d8217 100644
--- a/backend/cmd/misc/main.go
+++ b/backend/cmd/misc/main.go
@@ -458,7 +458,7 @@ func Run() {
case "fix-ens-addresses":
err = fixEnsAddresses(erigonClient)
case "collect-notifications":
- err = collectNotifications(opts.StartEpoch, opts.EndEpoch)
+ err = collectNotifications(opts.StartEpoch)
default:
log.Fatal(nil, fmt.Sprintf("unknown command %s", opts.Command), 0)
}
@@ -470,7 +470,7 @@ func Run() {
}
}
-func collectNotifications(startEpoch, endEpoch uint64) error {
+func collectNotifications(startEpoch uint64) error {
epoch := startEpoch
log.Infof("collecting notifications for epoch %v", epoch)
From 4467399f158602a575230cd39f294448c9beda37 Mon Sep 17 00:00:00 2001
From: peter <1674920+peterbitfly@users.noreply.github.com>
Date: Tue, 10 Sep 2024 11:31:13 +0000
Subject: [PATCH 25/39] chore(notification): update firebase sdk
---
backend/go.mod | 49 +++++-----
backend/go.sum | 109 ++++++++++++----------
backend/pkg/notification/firebase.go | 30 +++---
backend/pkg/notification/notifications.go | 2 +-
4 files changed, 104 insertions(+), 86 deletions(-)
diff --git a/backend/go.mod b/backend/go.mod
index b53006df9..25788bb93 100644
--- a/backend/go.mod
+++ b/backend/go.mod
@@ -6,6 +6,7 @@ require (
cloud.google.com/go/bigtable v1.21.0
cloud.google.com/go/secretmanager v1.11.5
firebase.google.com/go v3.13.0+incompatible
+ firebase.google.com/go/v4 v4.14.1
github.com/ClickHouse/clickhouse-go/v2 v2.17.1
github.com/Gurpartap/storekit-go v0.0.0-20201205024111-36b6cd5c6a21
github.com/alexedwards/scs/redisstore v0.0.0-20240316134038-7e11d57e8885
@@ -29,7 +30,7 @@ require (
github.com/gobitfly/eth.store v0.0.0-20240312111708-b43f13990280
github.com/golang-jwt/jwt v3.2.2+incompatible
github.com/golang-jwt/jwt/v4 v4.5.0
- github.com/golang/protobuf v1.5.3
+ github.com/golang/protobuf v1.5.4
github.com/gomodule/redigo v1.9.2
github.com/google/uuid v1.6.0
github.com/gorilla/csrf v1.7.2
@@ -69,26 +70,27 @@ require (
github.com/wealdtech/go-eth2-types/v2 v2.8.2
github.com/wealdtech/go-eth2-util v1.8.0
github.com/xeipuuv/gojsonschema v1.2.0
- golang.org/x/crypto v0.19.0
+ golang.org/x/crypto v0.21.0
golang.org/x/exp v0.0.0-20240213143201-ec583247a57a
golang.org/x/sync v0.6.0
golang.org/x/text v0.14.0
golang.org/x/time v0.5.0
golang.org/x/tools v0.18.0
- google.golang.org/api v0.164.0
- google.golang.org/protobuf v1.32.0
+ google.golang.org/api v0.170.0
+ google.golang.org/protobuf v1.33.0
gopkg.in/yaml.v2 v2.4.0
)
require (
- cloud.google.com/go v0.112.0 // indirect
- cloud.google.com/go/compute v1.23.3 // indirect
+ cloud.google.com/go v0.112.1 // indirect
+ cloud.google.com/go/compute v1.24.0 // indirect
cloud.google.com/go/compute/metadata v0.2.3 // indirect
- cloud.google.com/go/firestore v1.14.0 // indirect
- cloud.google.com/go/iam v1.1.5 // indirect
- cloud.google.com/go/longrunning v0.5.4 // indirect
- cloud.google.com/go/storage v1.36.0 // indirect
+ cloud.google.com/go/firestore v1.15.0 // indirect
+ cloud.google.com/go/iam v1.1.7 // indirect
+ cloud.google.com/go/longrunning v0.5.5 // indirect
+ cloud.google.com/go/storage v1.40.0 // indirect
github.com/ClickHouse/ch-go v0.58.2 // indirect
+ github.com/MicahParks/keyfunc v1.9.0 // indirect
github.com/Microsoft/go-winio v0.6.1 // indirect
github.com/TylerBrock/colorjson v0.0.0-20200706003622-8a50f05110d2 // indirect
github.com/ajg/form v1.5.1 // indirect
@@ -149,7 +151,7 @@ require (
github.com/google/go-querystring v1.1.0 // indirect
github.com/google/s2a-go v0.1.7 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect
- github.com/googleapis/gax-go/v2 v2.12.0 // indirect
+ github.com/googleapis/gax-go/v2 v2.12.3 // indirect
github.com/gorilla/securecookie v1.1.2 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.1 // indirect
github.com/herumi/bls-eth-go-binary v1.31.0 // indirect
@@ -241,24 +243,25 @@ require (
github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 // indirect
github.com/yusufpapurcu/wmi v1.2.3 // indirect
go.opencensus.io v0.24.0 // indirect
- go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.47.0 // indirect
- go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.47.0 // indirect
- go.opentelemetry.io/otel v1.23.0 // indirect
- go.opentelemetry.io/otel/metric v1.23.0 // indirect
- go.opentelemetry.io/otel/trace v1.23.0 // indirect
+ go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 // indirect
+ go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 // indirect
+ go.opentelemetry.io/otel v1.24.0 // indirect
+ go.opentelemetry.io/otel/metric v1.24.0 // indirect
+ go.opentelemetry.io/otel/trace v1.24.0 // indirect
go.uber.org/atomic v1.11.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.27.0 // indirect
golang.org/x/mod v0.15.0 // indirect
- golang.org/x/net v0.21.0 // indirect
- golang.org/x/oauth2 v0.17.0 // indirect
- golang.org/x/sys v0.17.0 // indirect
+ golang.org/x/net v0.23.0 // indirect
+ golang.org/x/oauth2 v0.18.0 // indirect
+ golang.org/x/sys v0.18.0 // indirect
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect
google.golang.org/appengine v1.6.8 // indirect
- google.golang.org/genproto v0.0.0-20240125205218-1f4bbc51befe // indirect
- google.golang.org/genproto/googleapis/api v0.0.0-20240125205218-1f4bbc51befe // indirect
- google.golang.org/genproto/googleapis/rpc v0.0.0-20240205150955-31a09d347014 // indirect
- google.golang.org/grpc v1.62.0 // indirect
+ google.golang.org/appengine/v2 v2.0.2 // indirect
+ google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9 // indirect
+ google.golang.org/genproto/googleapis/api v0.0.0-20240314234333-6e1732d8331c // indirect
+ google.golang.org/genproto/googleapis/rpc v0.0.0-20240311132316-a219d84964c2 // indirect
+ google.golang.org/grpc v1.62.1 // indirect
gopkg.in/cenkalti/backoff.v1 v1.1.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
lukechampine.com/blake3 v1.2.1 // indirect
diff --git a/backend/go.sum b/backend/go.sum
index 7d41b5693..a15806cb0 100644
--- a/backend/go.sum
+++ b/backend/go.sum
@@ -1,26 +1,28 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
-cloud.google.com/go v0.112.0 h1:tpFCD7hpHFlQ8yPwT3x+QeXqc2T6+n6T+hmABHfDUSM=
-cloud.google.com/go v0.112.0/go.mod h1:3jEEVwZ/MHU4djK5t5RHuKOA/GbLddgTdVubX1qnPD4=
+cloud.google.com/go v0.112.1 h1:uJSeirPke5UNZHIb4SxfZklVSiWWVqW4oXlETwZziwM=
+cloud.google.com/go v0.112.1/go.mod h1:+Vbu+Y1UU+I1rjmzeMOb/8RfkKJK2Gyxi1X6jJCZLo4=
cloud.google.com/go/bigtable v1.21.0 h1:BFN4jhkA9ULYYV2Ug7AeOtetVLnN2jKuIq5TcRc5C38=
cloud.google.com/go/bigtable v1.21.0/go.mod h1:V0sYNRtk0dgAKjyRr/MyBpHpSXqh+9P39euf820EZ74=
-cloud.google.com/go/compute v1.23.3 h1:6sVlXXBmbd7jNX0Ipq0trII3e4n1/MsADLK6a+aiVlk=
-cloud.google.com/go/compute v1.23.3/go.mod h1:VCgBUoMnIVIR0CscqQiPJLAG25E3ZRZMzcFZeQ+h8CI=
+cloud.google.com/go/compute v1.24.0 h1:phWcR2eWzRJaL/kOiJwfFsPs4BaKq1j6vnpZrc1YlVg=
+cloud.google.com/go/compute v1.24.0/go.mod h1:kw1/T+h/+tK2LJK0wiPPx1intgdAM3j/g3hFDlscY40=
cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY=
cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA=
-cloud.google.com/go/firestore v1.14.0 h1:8aLcKnMPoldYU3YHgu4t2exrKhLQkqaXAGqT0ljrFVw=
-cloud.google.com/go/firestore v1.14.0/go.mod h1:96MVaHLsEhbvkBEdZgfN+AS/GIkco1LRpH9Xp9YZfzQ=
-cloud.google.com/go/iam v1.1.5 h1:1jTsCu4bcsNsE4iiqNT5SHwrDRCfRmIaaaVFhRveTJI=
-cloud.google.com/go/iam v1.1.5/go.mod h1:rB6P/Ic3mykPbFio+vo7403drjlgvoWfYpJhMXEbzv8=
-cloud.google.com/go/longrunning v0.5.4 h1:w8xEcbZodnA2BbW6sVirkkoC+1gP8wS57EUUgGS0GVg=
-cloud.google.com/go/longrunning v0.5.4/go.mod h1:zqNVncI0BOP8ST6XQD1+VcvuShMmq7+xFSzOL++V0dI=
+cloud.google.com/go/firestore v1.15.0 h1:/k8ppuWOtNuDHt2tsRV42yI21uaGnKDEQnRFeBpbFF8=
+cloud.google.com/go/firestore v1.15.0/go.mod h1:GWOxFXcv8GZUtYpWHw/w6IuYNux/BtmeVTMmjrm4yhk=
+cloud.google.com/go/iam v1.1.7 h1:z4VHOhwKLF/+UYXAJDFwGtNF0b6gjsW1Pk9Ml0U/IoM=
+cloud.google.com/go/iam v1.1.7/go.mod h1:J4PMPg8TtyurAUvSmPj8FF3EDgY1SPRZxcUGrn7WXGA=
+cloud.google.com/go/longrunning v0.5.5 h1:GOE6pZFdSrTb4KAiKnXsJBtlE6mEyaW44oKyMILWnOg=
+cloud.google.com/go/longrunning v0.5.5/go.mod h1:WV2LAxD8/rg5Z1cNW6FJ/ZpX4E4VnDnoTk0yawPBB7s=
cloud.google.com/go/secretmanager v1.11.5 h1:82fpF5vBBvu9XW4qj0FU2C6qVMtj1RM/XHwKXUEAfYY=
cloud.google.com/go/secretmanager v1.11.5/go.mod h1:eAGv+DaCHkeVyQi0BeXgAHOU0RdrMeZIASKc+S7VqH4=
-cloud.google.com/go/storage v1.36.0 h1:P0mOkAcaJxhCTvAkMhxMfrTKiNcub4YmmPBtlhAyTr8=
-cloud.google.com/go/storage v1.36.0/go.mod h1:M6M/3V/D3KpzMTJyPOR/HU6n2Si5QdaXYEsng2xgOs8=
+cloud.google.com/go/storage v1.40.0 h1:VEpDQV5CJxFmJ6ueWNsKxcr1QAYOXEgxDa+sBbJahPw=
+cloud.google.com/go/storage v1.40.0/go.mod h1:Rrj7/hKlG87BLqDJYtwR0fbPld8uJPbQ2ucUMY7Ir0g=
contrib.go.opencensus.io/exporter/jaeger v0.2.1 h1:yGBYzYMewVL0yO9qqJv3Z5+IRhPdU7e9o/2oKpX4YvI=
contrib.go.opencensus.io/exporter/jaeger v0.2.1/go.mod h1:Y8IsLgdxqh1QxYxPC5IgXVmBaeLUeQFfBeBi9PbeZd0=
firebase.google.com/go v3.13.0+incompatible h1:3TdYC3DDi6aHn20qoRkxwGqNgdjtblwVAyRLQwGn/+4=
firebase.google.com/go v3.13.0+incompatible/go.mod h1:xlah6XbEyW6tbfSklcfe5FHJIwjt8toICdV5Wh9ptHs=
+firebase.google.com/go/v4 v4.14.1 h1:4qiUETaFRWoFGE1XP5VbcEdtPX93Qs+8B/7KvP2825g=
+firebase.google.com/go/v4 v4.14.1/go.mod h1:fgk2XshgNDEKaioKco+AouiegSI9oTWVqRaBdTTGBoM=
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0=
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
@@ -37,6 +39,8 @@ github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t
github.com/Gurpartap/storekit-go v0.0.0-20201205024111-36b6cd5c6a21 h1:HcdvlzaQ4CJfH7xbfJZ3ZHN//BTEpId46iKEMuP3wHE=
github.com/Gurpartap/storekit-go v0.0.0-20201205024111-36b6cd5c6a21/go.mod h1:7PODFS++oNZ6khojmPBvkrDeFO/hrc3jmvWvQAOXorw=
github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
+github.com/MicahParks/keyfunc v1.9.0 h1:lhKd5xrFHLNOWrDc4Tyb/Q1AJ4LCzQ48GVJyVIID3+o=
+github.com/MicahParks/keyfunc v1.9.0/go.mod h1:IdnCilugA0O/99dW+/MkvlyrsX8+L8+x95xuVNtM5jw=
github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw=
@@ -323,6 +327,7 @@ github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
+github.com/golang-jwt/jwt/v4 v4.4.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg=
github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
@@ -334,6 +339,7 @@ github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
@@ -345,8 +351,8 @@ github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
-github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
-github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
+github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
+github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
@@ -390,8 +396,8 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs=
github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0=
-github.com/googleapis/gax-go/v2 v2.12.0 h1:A+gCJKdRfqXkr+BIRGtZLibNXf0m1f9E4HG56etFpas=
-github.com/googleapis/gax-go/v2 v2.12.0/go.mod h1:y+aIqrI5eb1YGMVJfuV3185Ts/D7qKpsEkdD5+I6QGU=
+github.com/googleapis/gax-go/v2 v2.12.3 h1:5/zPPDvw8Q1SuXjrqrZslrqT7dL/uJT2CQii/cLCKqA=
+github.com/googleapis/gax-go/v2 v2.12.3/go.mod h1:AKloxT6GtNbaLm8QTNSidHUVsHYcBHwWRvkNFJUQcS4=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c h1:7lF+Vz0LqiRidnzC1Oq86fpX1q/iEv2KJdrCtttYjT4=
github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
@@ -979,18 +985,18 @@ github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxt
go.mongodb.org/mongo-driver v1.11.4/go.mod h1:PTSz5yu21bkT/wXpkS7WR5f0ddqw5quethTUn9WM+2g=
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
-go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.47.0 h1:UNQQKPfTDe1J81ViolILjTKPr9WetKW6uei2hFgJmFs=
-go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.47.0/go.mod h1:r9vWsPS/3AQItv3OSlEJ/E4mbrhUbbw18meOjArPtKQ=
-go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.47.0 h1:sv9kVfal0MK0wBMCOGr+HeJm9v803BkJxGrk2au7j08=
-go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.47.0/go.mod h1:SK2UL73Zy1quvRPonmOmRDiWk1KBV3LyIeeIxcEApWw=
-go.opentelemetry.io/otel v1.23.0 h1:Df0pqjqExIywbMCMTxkAwzjLZtRf+bBKLbUcpxO2C9E=
-go.opentelemetry.io/otel v1.23.0/go.mod h1:YCycw9ZeKhcJFrb34iVSkyT0iczq/zYDtZYFufObyB0=
-go.opentelemetry.io/otel/metric v1.23.0 h1:pazkx7ss4LFVVYSxYew7L5I6qvLXHA0Ap2pwV+9Cnpo=
-go.opentelemetry.io/otel/metric v1.23.0/go.mod h1:MqUW2X2a6Q8RN96E2/nqNoT+z9BSms20Jb7Bbp+HiTo=
-go.opentelemetry.io/otel/sdk v1.21.0 h1:FTt8qirL1EysG6sTQRZ5TokkU8d0ugCj8htOgThZXQ8=
-go.opentelemetry.io/otel/sdk v1.21.0/go.mod h1:Nna6Yv7PWTdgJHVRD9hIYywQBRx7pbox6nwBnZIxl/E=
-go.opentelemetry.io/otel/trace v1.23.0 h1:37Ik5Ib7xfYVb4V1UtnT97T1jI+AoIYkJyPkuL4iJgI=
-go.opentelemetry.io/otel/trace v1.23.0/go.mod h1:GSGTbIClEsuZrGIzoEHqsVfxgn5UkggkflQwDScNUsk=
+go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 h1:4Pp6oUg3+e/6M4C0A/3kJ2VYa++dsWVTtGgLVj5xtHg=
+go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0/go.mod h1:Mjt1i1INqiaoZOMGR1RIUJN+i3ChKoFRqzrRQhlkbs0=
+go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk=
+go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw=
+go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo=
+go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo=
+go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI=
+go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco=
+go.opentelemetry.io/otel/sdk v1.22.0 h1:6coWHw9xw7EfClIC/+O31R8IY3/+EiRFHevmHafB2Gw=
+go.opentelemetry.io/otel/sdk v1.22.0/go.mod h1:iu7luyVGYovrRpe2fmj3CVKouQNdTOkxtLzPvPz1DOc=
+go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI=
+go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU=
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
@@ -1032,8 +1038,8 @@ golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5y
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
-golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo=
-golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
+golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
+golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20240213143201-ec583247a57a h1:HinSgX1tJRX3KsL//Gxynpw5CTOAIPhgL4W8PNiIpVE=
golang.org/x/exp v0.0.0-20240213143201-ec583247a57a/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc=
@@ -1070,12 +1076,13 @@ golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
+golang.org/x/net v0.0.0-20220708220712-1185a9018129/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
-golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4=
-golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
+golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs=
+golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
-golang.org/x/oauth2 v0.17.0 h1:6m3ZPmLEFdVxKKWnKq4VqZ60gutO35zm+zrAHVmHyDQ=
-golang.org/x/oauth2 v0.17.0/go.mod h1:OzPDGQiuQMguemayvdylqddI7qcD9lnSDb+1FiwQ5HA=
+golang.org/x/oauth2 v0.18.0 h1:09qnuIAgzdx1XplqJvW6CQqMCtGZykZWcXzPMPUusvI=
+golang.org/x/oauth2 v0.18.0/go.mod h1:Wf7knwG0MPoWIMMBgFlEaSUDaKskp0dCfrlJRJXbBi8=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -1127,13 +1134,13 @@ golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
-golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
+golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
-golang.org/x/term v0.17.0 h1:mkTF7LCd6WGJNL3K1Ad7kwxNfYAW6a8a8QqtMblp/4U=
-golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
+golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8=
+golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
@@ -1175,28 +1182,30 @@ golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8T
golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU=
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90=
-google.golang.org/api v0.164.0 h1:of5G3oE2WRMVb2yoWKME4ZP8y8zpUKC6bMhxDr8ifyk=
-google.golang.org/api v0.164.0/go.mod h1:2OatzO7ZDQsoS7IFf3rvsE17/TldiU3F/zxFHeqUB5o=
+google.golang.org/api v0.170.0 h1:zMaruDePM88zxZBG+NG8+reALO2rfLhe/JShitLyT48=
+google.golang.org/api v0.170.0/go.mod h1:/xql9M2btF85xac/VAm4PsLMTLVGUOpq4BE9R8jyNy8=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM=
google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds=
+google.golang.org/appengine/v2 v2.0.2 h1:MSqyWy2shDLwG7chbwBJ5uMyw6SNqJzhJHNDwYB0Akk=
+google.golang.org/appengine/v2 v2.0.2/go.mod h1:PkgRUWz4o1XOvbqtWTkBtCitEJ5Tp4HoVEdMMYQR/8E=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
-google.golang.org/genproto v0.0.0-20240125205218-1f4bbc51befe h1:USL2DhxfgRchafRvt/wYyyQNzwgL7ZiURcozOE/Pkvo=
-google.golang.org/genproto v0.0.0-20240125205218-1f4bbc51befe/go.mod h1:cc8bqMqtv9gMOr0zHg2Vzff5ULhhL2IXP4sbcn32Dro=
-google.golang.org/genproto/googleapis/api v0.0.0-20240125205218-1f4bbc51befe h1:0poefMBYvYbs7g5UkjS6HcxBPaTRAmznle9jnxYoAI8=
-google.golang.org/genproto/googleapis/api v0.0.0-20240125205218-1f4bbc51befe/go.mod h1:4jWUdICTdgc3Ibxmr8nAJiiLHwQBY0UI0XZcEMaFKaA=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20240205150955-31a09d347014 h1:FSL3lRCkhaPFxqi0s9o+V4UI2WTzAVOvkgbd4kVV4Wg=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20240205150955-31a09d347014/go.mod h1:SaPjaZGWb0lPqs6Ittu0spdfrOArqji4ZdeP5IC/9N4=
+google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9 h1:9+tzLLstTlPTRyJTh+ah5wIMsBW5c4tQwGTN3thOW9Y=
+google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9/go.mod h1:mqHbVIp48Muh7Ywss/AD6I5kNVKZMmAa/QEW58Gxp2s=
+google.golang.org/genproto/googleapis/api v0.0.0-20240314234333-6e1732d8331c h1:kaI7oewGK5YnVwj+Y+EJBO/YN1ht8iTL9XkFHtVZLsc=
+google.golang.org/genproto/googleapis/api v0.0.0-20240314234333-6e1732d8331c/go.mod h1:VQW3tUculP/D4B+xVCo+VgSq8As6wA9ZjHl//pmk+6s=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20240311132316-a219d84964c2 h1:9IZDv+/GcI6u+a4jRFRLxQs0RUCfavGfoOgEW6jpkI0=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20240311132316-a219d84964c2/go.mod h1:UCOku4NytXMJuLQE5VuqA5lX3PcHCBo8pxNyvkf4xBs=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
-google.golang.org/grpc v1.62.0 h1:HQKZ/fa1bXkX1oFOvSjmZEUL8wLSaZTjCcLAlmZRtdk=
-google.golang.org/grpc v1.62.0/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE=
+google.golang.org/grpc v1.62.1 h1:B4n+nfKzOICUXMgyrNd19h/I9oH0L1pizfk1d4zSgTk=
+google.golang.org/grpc v1.62.1/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
@@ -1209,8 +1218,8 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
-google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I=
-google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
+google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
+google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
gopkg.in/cenkalti/backoff.v1 v1.1.0 h1:Arh75ttbsvlpVA7WtVpH4u9h6Zl46xuptxqLxPiSo4Y=
gopkg.in/cenkalti/backoff.v1 v1.1.0/go.mod h1:J6Vskwqd+OMVJl8C33mmtxTBs2gyzfv7UDAkHu8BrjI=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
diff --git a/backend/pkg/notification/firebase.go b/backend/pkg/notification/firebase.go
index 91291da54..9e42cc49a 100644
--- a/backend/pkg/notification/firebase.go
+++ b/backend/pkg/notification/firebase.go
@@ -2,12 +2,13 @@ package notification
import (
"context"
+ "fmt"
"strings"
"time"
- firebase "firebase.google.com/go"
"firebase.google.com/go/messaging"
+ firebase "firebase.google.com/go/v4"
"github.com/gobitfly/beaconchain/pkg/commons/log"
"github.com/gobitfly/beaconchain/pkg/commons/utils"
"google.golang.org/api/option"
@@ -24,10 +25,10 @@ func isRelevantError(response *messaging.SendResponse) bool {
return false
}
-func SendPushBatch(messages []*messaging.Message) error {
+func SendPushBatch(messages []*messaging.Message, dryRun bool) error {
credentialsPath := utils.Config.Notifications.FirebaseCredentialsPath
if credentialsPath == "" {
- log.Error(nil, "firebase credentials path not provided, disabling push notifications", 0)
+ log.Error(fmt.Errorf("firebase credentials path not provided, disabling push notifications"), "error initializing SendPushBatch", 0)
return nil
}
@@ -42,29 +43,32 @@ func SendPushBatch(messages []*messaging.Message) error {
app, err := firebase.NewApp(context.Background(), nil, opt)
if err != nil {
- log.Error(nil, "error initializing app", 0)
+ log.Error(err, "error initializing app", 0)
return err
}
client, err := app.Messaging(ctx)
if err != nil {
- log.Error(nil, "error initializing messaging", 0)
+ log.Error(err, "error initializing messaging", 0)
return err
}
- var waitBeforeTryInSeconds = []time.Duration{0 * time.Second, 2 * time.Second, 4 * time.Second, 8 * time.Second, 16 * time.Second}
+ var waitBeforeTryInSeconds = []time.Duration{0, 2, 4, 8, 16}
var resultSuccessCount, resultFailureCount int = 0, 0
var result *messaging.BatchResponse
currentMessages := messages
tries := 0
for _, s := range waitBeforeTryInSeconds {
- time.Sleep(s)
+ time.Sleep(s * time.Second)
tries++
-
- result, err = client.SendAll(context.Background(), currentMessages)
+ if dryRun {
+ result, err = client.SendEachDryRun(context.Background(), currentMessages)
+ } else {
+ result, err = client.SendEach(context.Background(), currentMessages)
+ }
if err != nil {
- log.Error(nil, "error sending push notifications", 0)
+ log.Error(err, "error sending push notifications", 0)
return err
}
@@ -74,7 +78,9 @@ func SendPushBatch(messages []*messaging.Message) error {
newMessages := make([]*messaging.Message, 0, result.FailureCount)
if result.FailureCount > 0 {
for i, response := range result.Responses {
+ logger.Info(response)
if isRelevantError(response) {
+ logger.Infof("retrying message %d", i)
newMessages = append(newMessages, currentMessages[i])
resultFailureCount--
}
@@ -90,12 +96,12 @@ func SendPushBatch(messages []*messaging.Message) error {
if len(currentMessages) > 0 {
for _, response := range result.Responses {
if isRelevantError(response) {
- log.Error(nil, "firebase error", 0, log.Fields{"MessageID": response.MessageID, "response": response.Error})
+ logger.WithError(response.Error).WithField("MessageID", response.MessageID).Errorf("firebase error")
resultFailureCount++
}
}
}
- log.Infof("sent %d firebase notifications in %d of %d tries. successful: %d | failed: %d", len(messages), tries, len(waitBeforeTryInSeconds), resultSuccessCount, resultFailureCount)
+ logger.Infof("sent %d firebase notifications in %d of %d tries. successful: %d | failed: %d", len(messages), tries, len(waitBeforeTryInSeconds), resultSuccessCount, resultFailureCount)
return nil
}
diff --git a/backend/pkg/notification/notifications.go b/backend/pkg/notification/notifications.go
index d7cb84e97..944e2aa99 100644
--- a/backend/pkg/notification/notifications.go
+++ b/backend/pkg/notification/notifications.go
@@ -678,7 +678,7 @@ func sendPushNotifications() error {
end = len(n.Content.Messages)
}
- err = SendPushBatch(n.Content.Messages[start:end])
+ err = SendPushBatch(n.Content.Messages[start:end], false)
if err != nil {
metrics.Errors.WithLabelValues("notifications_send_push_batch").Inc()
log.Error(err, "error sending firebase batch job", 0)
From 13780b3bd18e55c854f469d4bd0f65b906531fec Mon Sep 17 00:00:00 2001
From: peter <1674920+peterbitfly@users.noreply.github.com>
Date: Tue, 10 Sep 2024 11:37:15 +0000
Subject: [PATCH 26/39] chore(notifications): fix build errors
---
backend/pkg/commons/types/frontend.go | 2 +-
backend/pkg/notification/firebase.go | 10 +++++-----
backend/pkg/notification/notifications.go | 2 +-
3 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/backend/pkg/commons/types/frontend.go b/backend/pkg/commons/types/frontend.go
index eb1c04472..a7b637d8f 100644
--- a/backend/pkg/commons/types/frontend.go
+++ b/backend/pkg/commons/types/frontend.go
@@ -10,7 +10,7 @@ import (
"strings"
"time"
- "firebase.google.com/go/messaging"
+ "firebase.google.com/go/v4/messaging"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/gobitfly/beaconchain/pkg/commons/log"
diff --git a/backend/pkg/notification/firebase.go b/backend/pkg/notification/firebase.go
index 9e42cc49a..acdf303f4 100644
--- a/backend/pkg/notification/firebase.go
+++ b/backend/pkg/notification/firebase.go
@@ -7,8 +7,8 @@ import (
"strings"
"time"
- "firebase.google.com/go/messaging"
firebase "firebase.google.com/go/v4"
+ "firebase.google.com/go/v4/messaging"
"github.com/gobitfly/beaconchain/pkg/commons/log"
"github.com/gobitfly/beaconchain/pkg/commons/utils"
"google.golang.org/api/option"
@@ -78,9 +78,9 @@ func SendPushBatch(messages []*messaging.Message, dryRun bool) error {
newMessages := make([]*messaging.Message, 0, result.FailureCount)
if result.FailureCount > 0 {
for i, response := range result.Responses {
- logger.Info(response)
+ log.Info(response)
if isRelevantError(response) {
- logger.Infof("retrying message %d", i)
+ log.Infof("retrying message %d", i)
newMessages = append(newMessages, currentMessages[i])
resultFailureCount--
}
@@ -96,12 +96,12 @@ func SendPushBatch(messages []*messaging.Message, dryRun bool) error {
if len(currentMessages) > 0 {
for _, response := range result.Responses {
if isRelevantError(response) {
- logger.WithError(response.Error).WithField("MessageID", response.MessageID).Errorf("firebase error")
+ log.Error(fmt.Errorf("firebase error, message id: %d, error: %s", response.MessageID, response.Error), "error sending push notifications", 0)
resultFailureCount++
}
}
}
- logger.Infof("sent %d firebase notifications in %d of %d tries. successful: %d | failed: %d", len(messages), tries, len(waitBeforeTryInSeconds), resultSuccessCount, resultFailureCount)
+ log.Infof("sent %d firebase notifications in %d of %d tries. successful: %d | failed: %d", len(messages), tries, len(waitBeforeTryInSeconds), resultSuccessCount, resultFailureCount)
return nil
}
diff --git a/backend/pkg/notification/notifications.go b/backend/pkg/notification/notifications.go
index 944e2aa99..352b71ca9 100644
--- a/backend/pkg/notification/notifications.go
+++ b/backend/pkg/notification/notifications.go
@@ -22,7 +22,7 @@ import (
"time"
gcp_bigtable "cloud.google.com/go/bigtable"
- "firebase.google.com/go/messaging"
+ "firebase.google.com/go/v4/messaging"
"github.com/ethereum/go-ethereum/common"
"github.com/gobitfly/beaconchain/pkg/commons/cache"
"github.com/gobitfly/beaconchain/pkg/commons/db"
From 98f7a6303facfeb26e6cb97f22625f787ba326ba Mon Sep 17 00:00:00 2001
From: peter <1674920+peterbitfly@users.noreply.github.com>
Date: Tue, 10 Sep 2024 11:39:46 +0000
Subject: [PATCH 27/39] chore(notifications): fix relevant error messages
---
backend/pkg/notification/firebase.go | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/backend/pkg/notification/firebase.go b/backend/pkg/notification/firebase.go
index acdf303f4..cd1788da5 100644
--- a/backend/pkg/notification/firebase.go
+++ b/backend/pkg/notification/firebase.go
@@ -18,7 +18,9 @@ func isRelevantError(response *messaging.SendResponse) bool {
if !response.Success && response.Error != nil {
// Ignore https://stackoverflow.com/questions/58308835/using-firebase-for-notifications-getting-app-instance-has-been-unregistered
// Errors since they indicate that the user token is expired
- if !strings.Contains(response.Error.Error(), "registration-token-not-registered") {
+ if !strings.Contains(response.Error.Error(), "registration-token-not-registered") &&
+ !strings.Contains(response.Error.Error(), "Requested entity was not found.") &&
+ !strings.Contains(response.Error.Error(), "Request contains an invalid argument.") {
return true
}
}
From 4f4367f9eff5fd24053436a29b38c697198e6f38 Mon Sep 17 00:00:00 2001
From: peter <1674920+peterbitfly@users.noreply.github.com>
Date: Tue, 10 Sep 2024 11:41:30 +0000
Subject: [PATCH 28/39] chore(notifications): disable spammy log output
---
backend/pkg/notification/firebase.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/backend/pkg/notification/firebase.go b/backend/pkg/notification/firebase.go
index cd1788da5..44551b12c 100644
--- a/backend/pkg/notification/firebase.go
+++ b/backend/pkg/notification/firebase.go
@@ -80,7 +80,7 @@ func SendPushBatch(messages []*messaging.Message, dryRun bool) error {
newMessages := make([]*messaging.Message, 0, result.FailureCount)
if result.FailureCount > 0 {
for i, response := range result.Responses {
- log.Info(response)
+ //log.Info(response)
if isRelevantError(response) {
log.Infof("retrying message %d", i)
newMessages = append(newMessages, currentMessages[i])
From d3c3a1a44b61b6a87add9d383fa3ef5a9b8cd668 Mon Sep 17 00:00:00 2001
From: peter <1674920+peterbitfly@users.noreply.github.com>
Date: Tue, 10 Sep 2024 11:44:11 +0000
Subject: [PATCH 29/39] chore(notifications): please linter
---
backend/pkg/notification/firebase.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/backend/pkg/notification/firebase.go b/backend/pkg/notification/firebase.go
index 44551b12c..3b5264c38 100644
--- a/backend/pkg/notification/firebase.go
+++ b/backend/pkg/notification/firebase.go
@@ -98,7 +98,7 @@ func SendPushBatch(messages []*messaging.Message, dryRun bool) error {
if len(currentMessages) > 0 {
for _, response := range result.Responses {
if isRelevantError(response) {
- log.Error(fmt.Errorf("firebase error, message id: %d, error: %s", response.MessageID, response.Error), "error sending push notifications", 0)
+ log.Error(fmt.Errorf("firebase error, message id: %s, error: %s", response.MessageID, response.Error), "error sending push notifications", 0)
resultFailureCount++
}
}
From 8ed5ca29394cf519809fedec4f1c5d9e9bb7746a Mon Sep 17 00:00:00 2001
From: peter <1674920+peterbitfly@users.noreply.github.com>
Date: Tue, 10 Sep 2024 11:47:31 +0000
Subject: [PATCH 30/39] chore(notifications): please linter
---
backend/pkg/notification/firebase.go | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/backend/pkg/notification/firebase.go b/backend/pkg/notification/firebase.go
index 3b5264c38..b4a75a3d6 100644
--- a/backend/pkg/notification/firebase.go
+++ b/backend/pkg/notification/firebase.go
@@ -55,14 +55,14 @@ func SendPushBatch(messages []*messaging.Message, dryRun bool) error {
return err
}
- var waitBeforeTryInSeconds = []time.Duration{0, 2, 4, 8, 16}
+ var waitBeforeTryInSeconds = []int{0, 2, 4, 8, 16}
var resultSuccessCount, resultFailureCount int = 0, 0
var result *messaging.BatchResponse
currentMessages := messages
tries := 0
for _, s := range waitBeforeTryInSeconds {
- time.Sleep(s * time.Second)
+ time.Sleep(time.Duration(s) * time.Second)
tries++
if dryRun {
result, err = client.SendEachDryRun(context.Background(), currentMessages)
From 688c3997c1ed9f1ad2f7d2d67052ceedfe95b919 Mon Sep 17 00:00:00 2001
From: peter <1674920+peterbitfly@users.noreply.github.com>
Date: Mon, 16 Sep 2024 08:48:27 +0000
Subject: [PATCH 31/39] fix(notifications): correct wrong sql syntax
---
backend/pkg/notification/db.go | 2 ++
backend/pkg/notification/notifications.go | 10 +++++-----
2 files changed, 7 insertions(+), 5 deletions(-)
diff --git a/backend/pkg/notification/db.go b/backend/pkg/notification/db.go
index 1f999a411..d065f4e87 100644
--- a/backend/pkg/notification/db.go
+++ b/backend/pkg/notification/db.go
@@ -59,6 +59,8 @@ func GetSubsForEventFilter(eventName types.EventName, lastSentFilter string, las
return nil, err
}
+ log.Info(query)
+
subMap := make(map[string][]types.Subscription, 0)
err = db.FrontendWriterDB.Select(&subs, query, args...)
if err != nil {
diff --git a/backend/pkg/notification/notifications.go b/backend/pkg/notification/notifications.go
index 352b71ca9..03b27ef44 100644
--- a/backend/pkg/notification/notifications.go
+++ b/backend/pkg/notification/notifications.go
@@ -1952,7 +1952,7 @@ func collectEthClientNotifications(notificationsByUserID types.NotificationsPerU
dbResult, err := GetSubsForEventFilter(
types.EthClientUpdateEventName,
- "(us.last_sent_ts <= NOW() - INTERVAL '2 DAY' AND TO_TIMESTAMP(?) > us.last_sent_ts) OR us.last_sent_ts IS NULL",
+ "((last_sent_ts <= NOW() - INTERVAL '2 DAY' AND TO_TIMESTAMP(?) > last_sent_ts) OR last_sent_ts IS NULL)",
[]interface{}{client.Date.Unix()},
[]string{strings.ToLower(client.Name)})
if err != nil {
@@ -2074,7 +2074,7 @@ func collectMonitoringMachine(
dbResult, err := GetSubsForEventFilter(
eventName,
- "us.created_epoch <= ? AND (us.last_sent_epoch < (? - ?) OR us.last_sent_epoch IS NULL)",
+ "(created_epoch <= ? AND (last_sent_epoch < (? - ?) OR last_sent_epoch IS NULL))",
[]interface{}{epoch, epoch, epochWaitInBetween},
nil,
)
@@ -2325,7 +2325,7 @@ func collectTaxReportNotificationNotifications(notificationsByUserID types.Notif
dbResults, err := GetSubsForEventFilter(
types.TaxReportEventName,
- "us.last_sent_ts < ? OR (us.last_sent_ts IS NULL AND us.created_ts < ?)",
+ "(last_sent_ts < ? OR (last_sent_ts IS NULL AND created_ts < ?))",
[]interface{}{firstDayOfMonth, firstDayOfMonth},
nil,
)
@@ -2487,7 +2487,7 @@ func collectRocketpoolComissionNotifications(notificationsByUserID types.Notific
dbResult, err := GetSubsForEventFilter(
types.RocketpoolCommissionThresholdEventName,
- "(us.last_sent_ts <= NOW() - INTERVAL '8 hours' OR us.last_sent_ts IS NULL) AND (us.event_threshold <= ? OR (us.event_threshold < 0 AND us.event_threshold * -1 >= ?)",
+ "(last_sent_ts <= NOW() - INTERVAL '8 hours' OR last_sent_ts IS NULL) AND (event_threshold <= ? OR (event_threshold < 0 AND event_threshold * -1 >= ?))",
[]interface{}{fee, fee},
nil,
)
@@ -2539,7 +2539,7 @@ func collectRocketpoolRewardClaimRoundNotifications(notificationsByUserID types.
dbResult, err := GetSubsForEventFilter(
types.RocketpoolNewClaimRoundStartedEventName,
- "us.last_sent_ts <= NOW() - INTERVAL '5 hours' OR us.last_sent_ts IS NULL",
+ "(last_sent_ts <= NOW() - INTERVAL '5 hours' OR last_sent_ts IS NULL)",
nil,
nil,
)
From c141b4c79e7ee6ffac857ede972a48be72ef82b6 Mon Sep 17 00:00:00 2001
From: peter <1674920+peterbitfly@users.noreply.github.com>
Date: Tue, 17 Sep 2024 09:43:56 +0000
Subject: [PATCH 32/39] fix(notifications): add last sent field to webhook data
retrieval query
---
backend/pkg/notification/notifications.go | 1 +
1 file changed, 1 insertion(+)
diff --git a/backend/pkg/notification/notifications.go b/backend/pkg/notification/notifications.go
index 03b27ef44..357c81a35 100644
--- a/backend/pkg/notification/notifications.go
+++ b/backend/pkg/notification/notifications.go
@@ -837,6 +837,7 @@ func queueWebhookNotifications(notificationsByUserID types.NotificationsPerUserI
url,
retries,
event_names,
+ last_sent,
destination
FROM
users_webhooks
From 3ff4be3781d99f302204338d2727a3235154e73e Mon Sep 17 00:00:00 2001
From: Patrick Pfeiffer
Date: Tue, 17 Sep 2024 13:41:50 +0200
Subject: [PATCH 33/39] chore(notifications): better check for
webhook-ratelimit
---
backend/pkg/notification/notifications.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/backend/pkg/notification/notifications.go b/backend/pkg/notification/notifications.go
index 357c81a35..89ec6c858 100644
--- a/backend/pkg/notification/notifications.go
+++ b/backend/pkg/notification/notifications.go
@@ -1164,7 +1164,7 @@ func sendDiscordNotifications() error {
resp.Body.Close()
}
- if strings.Contains(errResp.Body, "You are being rate limited") {
+ if resp.StatusCode == http.StatusTooManyRequests {
log.Warnf("could not push to discord webhook due to rate limit. %v url: %v", errResp.Body, webhook.Url)
} else {
log.Error(nil, "error pushing discord webhook", 0, map[string]interface{}{"errResp.Body": errResp.Body, "webhook.Url": webhook.Url})
From d6ed420fc57f4fb8faef44ce113040d7f2d1c651 Mon Sep 17 00:00:00 2001
From: peter <1674920+peterbitfly@users.noreply.github.com>
Date: Mon, 23 Sep 2024 06:01:41 +0000
Subject: [PATCH 34/39] feat(notifications): make user db based notifications
work
---
backend/cmd/misc/main.go | 25 ++++++++++++++++++++++-
backend/pkg/commons/types/frontend.go | 10 +++++++++
backend/pkg/notification/db.go | 9 +++++---
backend/pkg/notification/notifications.go | 10 ++++++++-
4 files changed, 49 insertions(+), 5 deletions(-)
diff --git a/backend/cmd/misc/main.go b/backend/cmd/misc/main.go
index fd77d8217..abca7750f 100644
--- a/backend/cmd/misc/main.go
+++ b/backend/cmd/misc/main.go
@@ -76,7 +76,7 @@ func Run() {
}
configPath := fs.String("config", "config/default.config.yml", "Path to the config file")
- fs.StringVar(&opts.Command, "command", "", "command to run, available: updateAPIKey, applyDbSchema, initBigtableSchema, epoch-export, debug-rewards, debug-blocks, clear-bigtable, index-old-eth1-blocks, update-aggregation-bits, historic-prices-export, index-missing-blocks, export-epoch-missed-slots, migrate-last-attestation-slot-bigtable, export-genesis-validators, update-block-finalization-sequentially, nameValidatorsByRanges, export-stats-totals, export-sync-committee-periods, export-sync-committee-validator-stats, partition-validator-stats, migrate-app-purchases, collect-notifications")
+ fs.StringVar(&opts.Command, "command", "", "command to run, available: updateAPIKey, applyDbSchema, initBigtableSchema, epoch-export, debug-rewards, debug-blocks, clear-bigtable, index-old-eth1-blocks, update-aggregation-bits, historic-prices-export, index-missing-blocks, export-epoch-missed-slots, migrate-last-attestation-slot-bigtable, export-genesis-validators, update-block-finalization-sequentially, nameValidatorsByRanges, export-stats-totals, export-sync-committee-periods, export-sync-committee-validator-stats, partition-validator-stats, migrate-app-purchases, collect-notifications, collect-user-db-notifications")
fs.Uint64Var(&opts.StartEpoch, "start-epoch", 0, "start epoch")
fs.Uint64Var(&opts.EndEpoch, "end-epoch", 0, "end epoch")
fs.Uint64Var(&opts.User, "user", 0, "user id")
@@ -217,6 +217,14 @@ func Run() {
db.PersistentRedisDbClient = rdc
defer db.PersistentRedisDbClient.Close()
+ if utils.Config.TieredCacheProvider != "redis" {
+ log.Fatal(nil, "no cache provider set, please set TierdCacheProvider (redis)", 0)
+ }
+ if utils.Config.TieredCacheProvider == "redis" || len(utils.Config.RedisCacheEndpoint) != 0 {
+ cache.MustInitTieredCache(utils.Config.RedisCacheEndpoint)
+ log.Infof("tiered Cache initialized, latest finalized epoch: %v", cache.LatestFinalizedEpoch.Get())
+ }
+
switch opts.Command {
case "nameValidatorsByRanges":
err := nameValidatorsByRanges(opts.ValidatorNameRanges)
@@ -459,6 +467,8 @@ func Run() {
err = fixEnsAddresses(erigonClient)
case "collect-notifications":
err = collectNotifications(opts.StartEpoch)
+ case "collect-user-db-notifications":
+ err = collectUserDbNotifications(opts.StartEpoch)
default:
log.Fatal(nil, fmt.Sprintf("unknown command %s", opts.Command), 0)
}
@@ -483,6 +493,19 @@ func collectNotifications(startEpoch uint64) error {
return nil
}
+func collectUserDbNotifications(startEpoch uint64) error {
+ epoch := startEpoch
+
+ log.Infof("collecting notifications for epoch %v", epoch)
+ notifications, err := notification.GetUserNotificationsForEpoch(utils.Config.Notifications.PubkeyCachePath, epoch)
+ if err != nil {
+ return err
+ }
+
+ log.Infof("found %v notifications for epoch %v", len(notifications), epoch)
+ return nil
+}
+
func fixEns(erigonClient *rpc.ErigonClient) error {
log.Infof("command: fix-ens")
addrs := []struct {
diff --git a/backend/pkg/commons/types/frontend.go b/backend/pkg/commons/types/frontend.go
index a7b637d8f..83de47bd7 100644
--- a/backend/pkg/commons/types/frontend.go
+++ b/backend/pkg/commons/types/frontend.go
@@ -103,6 +103,16 @@ var UserIndexEvents = []EventName{
MonitoringMachineSwitchedToETH1FallbackEventName,
}
+var UserIndexEventsMap = map[EventName]struct{}{
+ EthClientUpdateEventName: {},
+ MonitoringMachineCpuLoadEventName: {},
+ MonitoringMachineOfflineEventName: {},
+ MonitoringMachineDiskAlmostFullEventName: {},
+ MonitoringMachineMemoryUsageEventName: {},
+ MonitoringMachineSwitchedToETH2FallbackEventName: {},
+ MonitoringMachineSwitchedToETH1FallbackEventName: {},
+}
+
var EventLabel map[EventName]string = map[EventName]string{
ValidatorBalanceDecreasedEventName: "Your validator(s) balance decreased",
ValidatorMissedProposalEventName: "Your validator(s) missed a proposal",
diff --git a/backend/pkg/notification/db.go b/backend/pkg/notification/db.go
index d065f4e87..7d68b125d 100644
--- a/backend/pkg/notification/db.go
+++ b/backend/pkg/notification/db.go
@@ -33,6 +33,11 @@ func GetSubsForEventFilter(eventName types.EventName, lastSentFilter string, las
// where event_name = $1
// `
+ eventNameForQuery := utils.GetNetwork() + ":" + string(eventName)
+
+ if _, ok := types.UserIndexEventsMap[eventName]; ok {
+ eventNameForQuery = string(eventName)
+ }
ds := goqu.Dialect("postgres").From("users_subscriptions").Select(
goqu.C("id"),
goqu.C("user_id"),
@@ -41,7 +46,7 @@ func GetSubsForEventFilter(eventName types.EventName, lastSentFilter string, las
goqu.C("created_epoch"),
goqu.C("event_threshold"),
goqu.C("event_name"),
- ).Where(goqu.L("(event_name = ? AND user_id <> 0)", utils.GetNetwork()+":"+string(eventName)))
+ ).Where(goqu.L("(event_name = ? AND user_id <> 0)", eventNameForQuery))
if lastSentFilter != "" {
if len(lastSentFilterArgs) > 0 {
@@ -59,8 +64,6 @@ func GetSubsForEventFilter(eventName types.EventName, lastSentFilter string, las
return nil, err
}
- log.Info(query)
-
subMap := make(map[string][]types.Subscription, 0)
err = db.FrontendWriterDB.Select(&subs, query, args...)
if err != nil {
diff --git a/backend/pkg/notification/notifications.go b/backend/pkg/notification/notifications.go
index 89ec6c858..47fc8491d 100644
--- a/backend/pkg/notification/notifications.go
+++ b/backend/pkg/notification/notifications.go
@@ -53,6 +53,14 @@ func GetNotificationsForEpoch(pubkeyCachePath string, epoch uint64) (types.Notif
return collectNotifications(epoch)
}
+func GetUserNotificationsForEpoch(pubkeyCachePath string, epoch uint64) (types.NotificationsPerUserId, error) {
+ err := initPubkeyCache(pubkeyCachePath)
+ if err != nil {
+ log.Fatal(err, "error initializing pubkey cache path for notifications", 0)
+ }
+ return collectUserDbNotifications(epoch)
+}
+
func InitNotificationCollector(pubkeyCachePath string) {
err := initPubkeyCache(pubkeyCachePath)
if err != nil {
@@ -2075,7 +2083,7 @@ func collectMonitoringMachine(
dbResult, err := GetSubsForEventFilter(
eventName,
- "(created_epoch <= ? AND (last_sent_epoch < (? - ?) OR last_sent_epoch IS NULL))",
+ "(created_epoch <= ? AND (last_sent_epoch < (?::int - ?::int) OR last_sent_epoch IS NULL))", // ::int is required here otherwise the generated goose query throw an error
[]interface{}{epoch, epoch, epochWaitInBetween},
nil,
)
From 8a3cc23df3632c05db3249fa87df58f0a1f82aeb Mon Sep 17 00:00:00 2001
From: peter <1674920+peterbitfly@users.noreply.github.com>
Date: Mon, 23 Sep 2024 06:21:25 +0000
Subject: [PATCH 35/39] chore(notifications): fix typo
---
backend/pkg/notification/notifications.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/backend/pkg/notification/notifications.go b/backend/pkg/notification/notifications.go
index 47fc8491d..4178ed2a9 100644
--- a/backend/pkg/notification/notifications.go
+++ b/backend/pkg/notification/notifications.go
@@ -2083,7 +2083,7 @@ func collectMonitoringMachine(
dbResult, err := GetSubsForEventFilter(
eventName,
- "(created_epoch <= ? AND (last_sent_epoch < (?::int - ?::int) OR last_sent_epoch IS NULL))", // ::int is required here otherwise the generated goose query throw an error
+ "(created_epoch <= ? AND (last_sent_epoch < (?::int - ?::int) OR last_sent_epoch IS NULL))", // ::int is required here otherwise the generated goqu query throw an error
[]interface{}{epoch, epoch, epochWaitInBetween},
nil,
)
From 03a730f4008b724059dfa8c045c6c2bd86622c4c Mon Sep 17 00:00:00 2001
From: peter <1674920+peterbitfly@users.noreply.github.com>
Date: Mon, 23 Sep 2024 06:23:10 +0000
Subject: [PATCH 36/39] chore(notifications): remove unused machine metrics
notification types
---
backend/pkg/commons/types/frontend.go | 116 ++++++++++------------
backend/pkg/notification/notifications.go | 4 -
2 files changed, 52 insertions(+), 68 deletions(-)
diff --git a/backend/pkg/commons/types/frontend.go b/backend/pkg/commons/types/frontend.go
index 83de47bd7..5a8485c24 100644
--- a/backend/pkg/commons/types/frontend.go
+++ b/backend/pkg/commons/types/frontend.go
@@ -48,29 +48,27 @@ func (npui NotificationsPerUserId) AddNotification(n Notification) {
}
const (
- ValidatorBalanceDecreasedEventName EventName = "validator_balance_decreased"
- ValidatorMissedProposalEventName EventName = "validator_proposal_missed"
- ValidatorExecutedProposalEventName EventName = "validator_proposal_submitted"
- ValidatorMissedAttestationEventName EventName = "validator_attestation_missed"
- ValidatorGotSlashedEventName EventName = "validator_got_slashed"
- ValidatorDidSlashEventName EventName = "validator_did_slash"
- ValidatorIsOfflineEventName EventName = "validator_is_offline"
- ValidatorReceivedWithdrawalEventName EventName = "validator_withdrawal"
- ValidatorReceivedDepositEventName EventName = "validator_received_deposit"
- NetworkSlashingEventName EventName = "network_slashing"
- NetworkValidatorActivationQueueFullEventName EventName = "network_validator_activation_queue_full"
- NetworkValidatorActivationQueueNotFullEventName EventName = "network_validator_activation_queue_not_full"
- NetworkValidatorExitQueueFullEventName EventName = "network_validator_exit_queue_full"
- NetworkValidatorExitQueueNotFullEventName EventName = "network_validator_exit_queue_not_full"
- NetworkLivenessIncreasedEventName EventName = "network_liveness_increased"
- EthClientUpdateEventName EventName = "eth_client_update"
- MonitoringMachineOfflineEventName EventName = "monitoring_machine_offline"
- MonitoringMachineDiskAlmostFullEventName EventName = "monitoring_hdd_almostfull"
- MonitoringMachineCpuLoadEventName EventName = "monitoring_cpu_load"
- MonitoringMachineMemoryUsageEventName EventName = "monitoring_memory_usage"
- MonitoringMachineSwitchedToETH2FallbackEventName EventName = "monitoring_fallback_eth2inuse"
- MonitoringMachineSwitchedToETH1FallbackEventName EventName = "monitoring_fallback_eth1inuse"
- TaxReportEventName EventName = "user_tax_report"
+ ValidatorBalanceDecreasedEventName EventName = "validator_balance_decreased"
+ ValidatorMissedProposalEventName EventName = "validator_proposal_missed"
+ ValidatorExecutedProposalEventName EventName = "validator_proposal_submitted"
+ ValidatorMissedAttestationEventName EventName = "validator_attestation_missed"
+ ValidatorGotSlashedEventName EventName = "validator_got_slashed"
+ ValidatorDidSlashEventName EventName = "validator_did_slash"
+ ValidatorIsOfflineEventName EventName = "validator_is_offline"
+ ValidatorReceivedWithdrawalEventName EventName = "validator_withdrawal"
+ ValidatorReceivedDepositEventName EventName = "validator_received_deposit"
+ NetworkSlashingEventName EventName = "network_slashing"
+ NetworkValidatorActivationQueueFullEventName EventName = "network_validator_activation_queue_full"
+ NetworkValidatorActivationQueueNotFullEventName EventName = "network_validator_activation_queue_not_full"
+ NetworkValidatorExitQueueFullEventName EventName = "network_validator_exit_queue_full"
+ NetworkValidatorExitQueueNotFullEventName EventName = "network_validator_exit_queue_not_full"
+ NetworkLivenessIncreasedEventName EventName = "network_liveness_increased"
+ EthClientUpdateEventName EventName = "eth_client_update"
+ MonitoringMachineOfflineEventName EventName = "monitoring_machine_offline"
+ MonitoringMachineDiskAlmostFullEventName EventName = "monitoring_hdd_almostfull"
+ MonitoringMachineCpuLoadEventName EventName = "monitoring_cpu_load"
+ MonitoringMachineMemoryUsageEventName EventName = "monitoring_memory_usage"
+ TaxReportEventName EventName = "user_tax_report"
//nolint:misspell
RocketpoolCommissionThresholdEventName EventName = "rocketpool_commision_threshold"
RocketpoolNewClaimRoundStartedEventName EventName = "rocketpool_new_claimround"
@@ -87,8 +85,6 @@ var MachineEvents = []EventName{
MonitoringMachineDiskAlmostFullEventName,
MonitoringMachineCpuLoadEventName,
MonitoringMachineMemoryUsageEventName,
- MonitoringMachineSwitchedToETH2FallbackEventName,
- MonitoringMachineSwitchedToETH1FallbackEventName,
}
var UserIndexEvents = []EventName{
@@ -99,49 +95,43 @@ var UserIndexEvents = []EventName{
MonitoringMachineDiskAlmostFullEventName,
MonitoringMachineCpuLoadEventName,
MonitoringMachineMemoryUsageEventName,
- MonitoringMachineSwitchedToETH2FallbackEventName,
- MonitoringMachineSwitchedToETH1FallbackEventName,
}
var UserIndexEventsMap = map[EventName]struct{}{
- EthClientUpdateEventName: {},
- MonitoringMachineCpuLoadEventName: {},
- MonitoringMachineOfflineEventName: {},
- MonitoringMachineDiskAlmostFullEventName: {},
- MonitoringMachineMemoryUsageEventName: {},
- MonitoringMachineSwitchedToETH2FallbackEventName: {},
- MonitoringMachineSwitchedToETH1FallbackEventName: {},
+ EthClientUpdateEventName: {},
+ MonitoringMachineCpuLoadEventName: {},
+ MonitoringMachineOfflineEventName: {},
+ MonitoringMachineDiskAlmostFullEventName: {},
+ MonitoringMachineMemoryUsageEventName: {},
}
var EventLabel map[EventName]string = map[EventName]string{
- ValidatorBalanceDecreasedEventName: "Your validator(s) balance decreased",
- ValidatorMissedProposalEventName: "Your validator(s) missed a proposal",
- ValidatorExecutedProposalEventName: "Your validator(s) submitted a proposal",
- ValidatorMissedAttestationEventName: "Your validator(s) missed an attestation",
- ValidatorGotSlashedEventName: "Your validator(s) got slashed",
- ValidatorDidSlashEventName: "Your validator(s) slashed another validator",
- ValidatorIsOfflineEventName: "Your validator(s) state changed",
- ValidatorReceivedDepositEventName: "Your validator(s) received a deposit",
- ValidatorReceivedWithdrawalEventName: "A withdrawal was initiated for your validators",
- NetworkSlashingEventName: "A slashing event has been registered by the network",
- NetworkValidatorActivationQueueFullEventName: "The activation queue is full",
- NetworkValidatorActivationQueueNotFullEventName: "The activation queue is empty",
- NetworkValidatorExitQueueFullEventName: "The validator exit queue is full",
- NetworkValidatorExitQueueNotFullEventName: "The validator exit queue is empty",
- NetworkLivenessIncreasedEventName: "The network is experiencing liveness issues",
- EthClientUpdateEventName: "An Ethereum client has a new update available",
- MonitoringMachineOfflineEventName: "Your machine(s) might be offline",
- MonitoringMachineDiskAlmostFullEventName: "Your machine(s) disk space is running low",
- MonitoringMachineCpuLoadEventName: "Your machine(s) has a high CPU load",
- MonitoringMachineMemoryUsageEventName: "Your machine(s) has a high memory load",
- MonitoringMachineSwitchedToETH2FallbackEventName: "Your machine(s) is using its consensus client fallback",
- MonitoringMachineSwitchedToETH1FallbackEventName: "Your machine(s) is using its execution client fallback",
- TaxReportEventName: "You have an available tax report",
- RocketpoolCommissionThresholdEventName: "Your configured Rocket Pool commission threshold is reached",
- RocketpoolNewClaimRoundStartedEventName: "Your Rocket Pool claim from last round is available",
- RocketpoolCollateralMinReached: "You reached the Rocket Pool min RPL collateral",
- RocketpoolCollateralMaxReached: "You reached the Rocket Pool max RPL collateral",
- SyncCommitteeSoon: "Your validator(s) will soon be part of the sync committee",
+ ValidatorBalanceDecreasedEventName: "Your validator(s) balance decreased",
+ ValidatorMissedProposalEventName: "Your validator(s) missed a proposal",
+ ValidatorExecutedProposalEventName: "Your validator(s) submitted a proposal",
+ ValidatorMissedAttestationEventName: "Your validator(s) missed an attestation",
+ ValidatorGotSlashedEventName: "Your validator(s) got slashed",
+ ValidatorDidSlashEventName: "Your validator(s) slashed another validator",
+ ValidatorIsOfflineEventName: "Your validator(s) state changed",
+ ValidatorReceivedDepositEventName: "Your validator(s) received a deposit",
+ ValidatorReceivedWithdrawalEventName: "A withdrawal was initiated for your validators",
+ NetworkSlashingEventName: "A slashing event has been registered by the network",
+ NetworkValidatorActivationQueueFullEventName: "The activation queue is full",
+ NetworkValidatorActivationQueueNotFullEventName: "The activation queue is empty",
+ NetworkValidatorExitQueueFullEventName: "The validator exit queue is full",
+ NetworkValidatorExitQueueNotFullEventName: "The validator exit queue is empty",
+ NetworkLivenessIncreasedEventName: "The network is experiencing liveness issues",
+ EthClientUpdateEventName: "An Ethereum client has a new update available",
+ MonitoringMachineOfflineEventName: "Your machine(s) might be offline",
+ MonitoringMachineDiskAlmostFullEventName: "Your machine(s) disk space is running low",
+ MonitoringMachineCpuLoadEventName: "Your machine(s) has a high CPU load",
+ MonitoringMachineMemoryUsageEventName: "Your machine(s) has a high memory load",
+ TaxReportEventName: "You have an available tax report",
+ RocketpoolCommissionThresholdEventName: "Your configured Rocket Pool commission threshold is reached",
+ RocketpoolNewClaimRoundStartedEventName: "Your Rocket Pool claim from last round is available",
+ RocketpoolCollateralMinReached: "You reached the Rocket Pool min RPL collateral",
+ RocketpoolCollateralMaxReached: "You reached the Rocket Pool max RPL collateral",
+ SyncCommitteeSoon: "Your validator(s) will soon be part of the sync committee",
}
func IsUserIndexed(event EventName) bool {
@@ -182,8 +172,6 @@ var EventNames = []EventName{
MonitoringMachineOfflineEventName,
MonitoringMachineDiskAlmostFullEventName,
MonitoringMachineCpuLoadEventName,
- MonitoringMachineSwitchedToETH2FallbackEventName,
- MonitoringMachineSwitchedToETH1FallbackEventName,
MonitoringMachineMemoryUsageEventName,
TaxReportEventName,
RocketpoolCommissionThresholdEventName,
diff --git a/backend/pkg/notification/notifications.go b/backend/pkg/notification/notifications.go
index 4178ed2a9..2a137b9a6 100644
--- a/backend/pkg/notification/notifications.go
+++ b/backend/pkg/notification/notifications.go
@@ -2235,10 +2235,6 @@ func (n *monitorMachineNotification) GetTitle() string {
return "Staking Machine Offline"
case types.MonitoringMachineCpuLoadEventName:
return "High CPU Load"
- case types.MonitoringMachineSwitchedToETH1FallbackEventName:
- return "ETH1 Fallback Active"
- case types.MonitoringMachineSwitchedToETH2FallbackEventName:
- return "ETH2 Fallback Active"
case types.MonitoringMachineMemoryUsageEventName:
return "Memory Warning"
}
From ab7409da6862d80e296a6c60bcf150ad21e37ca9 Mon Sep 17 00:00:00 2001
From: peter <1674920+peterbitfly@users.noreply.github.com>
Date: Mon, 23 Sep 2024 06:25:33 +0000
Subject: [PATCH 37/39] chore(notifications): remove unused machine metrics
notification types
---
backend/pkg/notification/notifications.go | 4 ----
1 file changed, 4 deletions(-)
diff --git a/backend/pkg/notification/notifications.go b/backend/pkg/notification/notifications.go
index 2a137b9a6..1aa6d05a0 100644
--- a/backend/pkg/notification/notifications.go
+++ b/backend/pkg/notification/notifications.go
@@ -2217,10 +2217,6 @@ func (n *monitorMachineNotification) GetInfo(includeUrl bool) string {
return fmt.Sprintf(`Your staking machine "%v" might be offline. It has not been seen for a couple minutes now.`, n.MachineName)
case types.MonitoringMachineCpuLoadEventName:
return fmt.Sprintf(`Your staking machine "%v" has reached your configured CPU usage threshold.`, n.MachineName)
- case types.MonitoringMachineSwitchedToETH1FallbackEventName:
- return fmt.Sprintf(`Your staking machine "%v" has switched to your configured ETH1 fallback`, n.MachineName)
- case types.MonitoringMachineSwitchedToETH2FallbackEventName:
- return fmt.Sprintf(`Your staking machine "%v" has switched to your configured ETH2 fallback`, n.MachineName)
case types.MonitoringMachineMemoryUsageEventName:
return fmt.Sprintf(`Your staking machine "%v" has reached your configured RAM threshold.`, n.MachineName)
}
From 4f086dd3d02aa636f8d756a31ca8d395500e2c51 Mon Sep 17 00:00:00 2001
From: peter <1674920+peterbitfly@users.noreply.github.com>
Date: Tue, 24 Sep 2024 05:45:03 +0000
Subject: [PATCH 38/39] fix(notifications): properly remove network name from
event name in subs
---
backend/cmd/misc/main.go | 6 +++++-
backend/pkg/notification/db.go | 3 +++
2 files changed, 8 insertions(+), 1 deletion(-)
diff --git a/backend/cmd/misc/main.go b/backend/cmd/misc/main.go
index abca7750f..e2fe9e1c7 100644
--- a/backend/cmd/misc/main.go
+++ b/backend/cmd/misc/main.go
@@ -18,6 +18,7 @@ import (
"time"
"github.com/coocood/freecache"
+ "github.com/davecgh/go-spew/spew"
"github.com/ethereum/go-ethereum/common"
"github.com/go-redis/redis/v8"
"github.com/gobitfly/beaconchain/cmd/misc/commands"
@@ -489,7 +490,10 @@ func collectNotifications(startEpoch uint64) error {
return err
}
- log.Infof("found %v notifications for epoch %v", len(notifications), epoch)
+ log.Infof("found %v notifications for epoch %v with %v notifications for user 0", len(notifications), epoch, len(notifications[0]))
+ if len(notifications[0]) > 0 {
+ spew.Dump(notifications[0])
+ }
return nil
}
diff --git a/backend/pkg/notification/db.go b/backend/pkg/notification/db.go
index 7d68b125d..c2e2b3cec 100644
--- a/backend/pkg/notification/db.go
+++ b/backend/pkg/notification/db.go
@@ -1,6 +1,8 @@
package notification
import (
+ "strings"
+
"github.com/doug-martin/goqu/v9"
"github.com/gobitfly/beaconchain/pkg/commons/db"
"github.com/gobitfly/beaconchain/pkg/commons/log"
@@ -73,6 +75,7 @@ func GetSubsForEventFilter(eventName types.EventName, lastSentFilter string, las
log.Infof("Found %d subscriptions for event %s", len(subs), eventName)
for _, sub := range subs {
+ sub.EventName = types.EventName(strings.Replace(string(sub.EventName), utils.GetNetwork()+":", "", 1)) // remove the network name from the event name
if _, ok := subMap[sub.EventFilter]; !ok {
subMap[sub.EventFilter] = make([]types.Subscription, 0)
}
From 1ef7ac8729c98e44f2cb7bf699b7b86e56ab0d7f Mon Sep 17 00:00:00 2001
From: Patrick
Date: Tue, 24 Sep 2024 11:14:07 +0200
Subject: [PATCH 39/39] fix(notifications): fix panic when logging failed
discord-webhook (#878)
---
backend/pkg/notification/notifications.go | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/backend/pkg/notification/notifications.go b/backend/pkg/notification/notifications.go
index 1aa6d05a0..60b6a8769 100644
--- a/backend/pkg/notification/notifications.go
+++ b/backend/pkg/notification/notifications.go
@@ -1170,13 +1170,14 @@ func sendDiscordNotifications() error {
}
errResp.Status = resp.Status
resp.Body.Close()
- }
- if resp.StatusCode == http.StatusTooManyRequests {
- log.Warnf("could not push to discord webhook due to rate limit. %v url: %v", errResp.Body, webhook.Url)
- } else {
- log.Error(nil, "error pushing discord webhook", 0, map[string]interface{}{"errResp.Body": errResp.Body, "webhook.Url": webhook.Url})
+ if resp.StatusCode == http.StatusTooManyRequests {
+ log.Warnf("could not push to discord webhook due to rate limit. %v url: %v", errResp.Body, webhook.Url)
+ } else {
+ log.Error(nil, "error pushing discord webhook", 0, map[string]interface{}{"errResp.Body": errResp.Body, "webhook.Url": webhook.Url})
+ }
}
+
_, err = db.FrontendWriterDB.Exec(`UPDATE users_webhooks SET request = $2, response = $3 WHERE id = $1;`, webhook.ID, reqs[i].Content.DiscordRequest, errResp)
if err != nil {
log.Error(err, "error storing failure data in users_webhooks table", 0)