66 "encoding/hex"
77 "fmt"
88 "math/big"
9+ "slices"
910 "sort"
1011 "strconv"
1112 "strings"
@@ -15,7 +16,6 @@ import (
1516 "github.com/ethereum/go-ethereum/common/hexutil"
1617 "github.com/gobitfly/beaconchain/pkg/api/enums"
1718 t "github.com/gobitfly/beaconchain/pkg/api/types"
18- "github.com/gobitfly/beaconchain/pkg/commons/log"
1919 "github.com/gobitfly/beaconchain/pkg/commons/utils"
2020 constypes "github.com/gobitfly/beaconchain/pkg/consapi/types"
2121 "github.com/lib/pq"
@@ -790,21 +790,6 @@ func (d *DataAccessService) GetValidatorDashboardGroupExists(ctx context.Context
790790 return groupExists , err
791791}
792792
793- // return how many of the passed validators are already in the dashboard
794- func (d * DataAccessService ) GetValidatorDashboardExistingValidatorCount (ctx context.Context , dashboardId t.VDBIdPrimary , validators []t.VDBValidator ) (uint64 , error ) {
795- if len (validators ) == 0 {
796- return 0 , nil
797- }
798-
799- var count uint64
800- err := d .alloyReader .GetContext (ctx , & count , `
801- SELECT COUNT(*)
802- FROM users_val_dashboards_validators
803- WHERE dashboard_id = $1 AND validator_index = ANY($2)
804- ` , dashboardId , pq .Array (validators ))
805- return count , err
806- }
807-
808793func (d * DataAccessService ) AddValidatorDashboardValidators (ctx context.Context , dashboardId t.VDBIdPrimary , groupId uint64 , validators []t.VDBValidator ) ([]t.VDBPostValidatorsData , error ) {
809794 if len (validators ) == 0 {
810795 // No validators to add
@@ -889,191 +874,145 @@ func (d *DataAccessService) AddValidatorDashboardValidators(ctx context.Context,
889874 return result , nil
890875}
891876
877+ // Updates the group for validators already in the dashboard linked to the deposit address.
878+ // Adds up to limit new validators associated with the deposit address, if not already in the dashboard.
892879func (d * DataAccessService ) AddValidatorDashboardValidatorsByDepositAddress (ctx context.Context , dashboardId t.VDBIdPrimary , groupId uint64 , address string , limit uint64 ) ([]t.VDBPostValidatorsData , error ) {
893- // for all validators already in the dashboard that are associated with the deposit address, update the group
894- // then add no more than `limit` validators associated with the deposit address to the dashboard
895880 addressParsed , err := hex .DecodeString (strings .TrimPrefix (address , "0x" ))
896881 if err != nil {
897882 return nil , err
898883 }
899884
900- if len (addressParsed ) != 20 {
901- return nil , fmt .Errorf ("invalid deposit address: %s" , address )
902- }
903- var validatorIndicesToAdd []uint64
904- err = d .readerDb .SelectContext (ctx , & validatorIndicesToAdd , "SELECT validatorindex FROM validators WHERE pubkey IN (SELECT publickey FROM eth1_deposits WHERE from_address = $1) ORDER BY validatorindex LIMIT $2;" , addressParsed , limit )
905- if err != nil {
906- return nil , err
907- }
885+ g , gCtx := errgroup .WithContext (ctx )
908886
909- // retrieve the existing validators
910- var existingValidators []uint64
911- err = d .alloyWriter .SelectContext (ctx , & existingValidators , "SELECT validator_index FROM users_val_dashboards_validators WHERE dashboard_id = $1" , dashboardId )
912- if err != nil {
913- return nil , err
914- }
915- existingValidatorsMap := make (map [uint64 ]bool , len (existingValidators ))
916- for _ , validatorIndex := range existingValidators {
917- existingValidatorsMap [validatorIndex ] = true
918- }
919-
920- // filter out the validators that are already in the dashboard
887+ // fetch validators that are already in the dashboard and associated with the deposit address
921888 var validatorIndicesToUpdate []uint64
889+
890+ g .Go (func () error {
891+ return d .readerDb .SelectContext (gCtx , & validatorIndicesToUpdate , `
892+ SELECT DISTINCT uvdv.validator_index
893+ FROM validators v
894+ JOIN eth1_deposits d ON v.pubkey = d.publickey
895+ JOIN users_val_dashboards_validators uvdv ON v.validatorindex = uvdv.validator_index
896+ WHERE uvdv.dashboard_id = $1 AND d.from_address = $2;
897+ ` , dashboardId , addressParsed )
898+ })
899+
900+ // fetch validators that are not yet in the dashboard and associated with the deposit address, up to the limit
922901 var validatorIndicesToInsert []uint64
923- for _ , validatorIndex := range validatorIndicesToAdd {
924- if _ , ok := existingValidatorsMap [validatorIndex ]; ok {
925- validatorIndicesToUpdate = append (validatorIndicesToUpdate , validatorIndex )
926- } else {
927- validatorIndicesToInsert = append (validatorIndicesToInsert , validatorIndex )
928- }
929- }
902+ g .Go (func () error {
903+ return d .readerDb .SelectContext (gCtx , & validatorIndicesToInsert , `
904+ SELECT DISTINCT v.validatorindex
905+ FROM validators v
906+ JOIN eth1_deposits d ON v.pubkey = d.publickey
907+ LEFT JOIN users_val_dashboards_validators uvdv ON v.validatorindex = uvdv.validator_index AND uvdv.dashboard_id = $1
908+ WHERE d.from_address = $2 AND uvdv.validator_index IS NULL
909+ ORDER BY v.validatorindex
910+ LIMIT $3;
911+ ` , dashboardId , addressParsed , limit )
912+ })
930913
931- // update the group for all existing validators
932- validatorIndices := make ([]uint64 , 0 , int (limit ))
933- validatorIndices = append (validatorIndices , validatorIndicesToUpdate ... )
934-
935- // insert the new validators up to the allowed user max limit taking into account how many validators are already in the dashboard
936- if len (validatorIndicesToInsert ) > 0 {
937- freeSpace := int (limit ) - len (existingValidators )
938- if freeSpace > 0 {
939- if len (validatorIndicesToInsert ) > freeSpace { // cap inserts to the amount of free space available
940- log .Infof ("limiting the number of validators to insert to %d" , freeSpace )
941- validatorIndicesToInsert = validatorIndicesToInsert [:freeSpace ]
942- }
943- validatorIndices = append (validatorIndices , validatorIndicesToInsert ... )
944- }
914+ err = g .Wait ()
915+ if err != nil {
916+ return nil , err
945917 }
946918
947- if len (validatorIndices ) == 0 {
948- // no validators to add
949- return []t.VDBPostValidatorsData {}, nil
950- }
951- log .Infof ("inserting %d new validators and updating %d validators of dashboard %d, limit is %d" , len (validatorIndicesToInsert ), len (validatorIndicesToUpdate ), dashboardId , limit )
919+ validatorIndices := slices .Concat (validatorIndicesToUpdate , validatorIndicesToInsert )
920+
952921 return d .AddValidatorDashboardValidators (ctx , dashboardId , groupId , validatorIndices )
953922}
954923
924+ // Updates the group for validators already in the dashboard linked to the withdrawal address.
925+ // Adds up to limit new validators associated with the withdrawal address, if not already in the dashboard.
955926func (d * DataAccessService ) AddValidatorDashboardValidatorsByWithdrawalAddress (ctx context.Context , dashboardId t.VDBIdPrimary , groupId uint64 , address string , limit uint64 ) ([]t.VDBPostValidatorsData , error ) {
956- // for all validators already in the dashboard that are associated with the withdrawal address, update the group
957- // then add no more than `limit` validators associated with the deposit address to the dashboard
958927 addressParsed , err := hex .DecodeString (strings .TrimPrefix (address , "0x" ))
959928 if err != nil {
960929 return nil , err
961930 }
962- var validatorIndicesToAdd []uint64
963- err = d .readerDb .SelectContext (ctx , & validatorIndicesToAdd , "SELECT validatorindex FROM validators WHERE withdrawalcredentials = $1 ORDER BY validatorindex LIMIT $2;" , addressParsed , limit )
964- if err != nil {
965- return nil , err
966- }
967931
968- // retrieve the existing validators
969- var existingValidators []uint64
970- err = d .alloyWriter .SelectContext (ctx , & existingValidators , "SELECT validator_index FROM users_val_dashboards_validators WHERE dashboard_id = $1" , dashboardId )
971- if err != nil {
972- return nil , err
973- }
974- existingValidatorsMap := make (map [uint64 ]bool , len (existingValidators ))
975- for _ , validatorIndex := range existingValidators {
976- existingValidatorsMap [validatorIndex ] = true
977- }
932+ g , gCtx := errgroup .WithContext (ctx )
978933
979- // filter out the validators that are already in the dashboard
934+ // fetch validators that are already in the dashboard and associated with the withdrawal address
980935 var validatorIndicesToUpdate []uint64
936+ g .Go (func () error {
937+ return d .readerDb .SelectContext (gCtx , & validatorIndicesToUpdate , `
938+ SELECT DISTINCT uvdv.validator_index
939+ FROM validators v
940+ JOIN users_val_dashboards_validators uvdv ON v.validatorindex = uvdv.validator_index
941+ WHERE uvdv.dashboard_id = $1 AND v.withdrawalcredentials = $2 AND uvdv.dashboard_id = $2;
942+ ` , dashboardId , addressParsed )
943+ })
944+
945+ // fetch validators that are not yet in the dashboard and associated with the withdrawal address, up to the limit
981946 var validatorIndicesToInsert []uint64
982- for _ , validatorIndex := range validatorIndicesToAdd {
983- if _ , ok := existingValidatorsMap [validatorIndex ]; ok {
984- validatorIndicesToUpdate = append (validatorIndicesToUpdate , validatorIndex )
985- } else {
986- validatorIndicesToInsert = append (validatorIndicesToInsert , validatorIndex )
987- }
988- }
947+ g .Go (func () error {
948+ return d .readerDb .SelectContext (gCtx , & validatorIndicesToInsert , `
949+ SELECT DISTINCT v.validatorindex
950+ FROM validators v
951+ LEFT JOIN users_val_dashboards_validators uvdv ON v.validatorindex = uvdv.validator_index AND uvdv.dashboard_id = $1
952+ WHERE v.withdrawalcredentials = $2 AND uvdv.validator_index IS NULL
953+ ORDER BY v.validatorindex
954+ LIMIT $3;
955+ ` , dashboardId , addressParsed , limit )
956+ })
989957
990- // update the group for all existing validators
991- validatorIndices := make ([]uint64 , 0 , int (limit ))
992- validatorIndices = append (validatorIndices , validatorIndicesToUpdate ... )
993-
994- // insert the new validators up to the allowed user max limit taking into account how many validators are already in the dashboard
995- if len (validatorIndicesToInsert ) > 0 {
996- freeSpace := int (limit ) - len (existingValidators )
997- if freeSpace > 0 {
998- if len (validatorIndicesToInsert ) > freeSpace { // cap inserts to the amount of free space available
999- log .Infof ("limiting the number of validators to insert to %d" , freeSpace )
1000- validatorIndicesToInsert = validatorIndicesToInsert [:freeSpace ]
1001- }
1002- validatorIndices = append (validatorIndices , validatorIndicesToInsert ... )
1003- }
958+ err = g .Wait ()
959+ if err != nil {
960+ return nil , err
1004961 }
1005962
1006- if len (validatorIndices ) == 0 {
1007- // no validators to add
1008- return []t.VDBPostValidatorsData {}, nil
1009- }
1010- log .Infof ("inserting %d new validators and updating %d validators of dashboard %d, limit is %d" , len (validatorIndicesToInsert ), len (validatorIndicesToUpdate ), dashboardId , limit )
963+ validatorIndices := slices .Concat (validatorIndicesToUpdate , validatorIndicesToInsert )
964+
1011965 return d .AddValidatorDashboardValidators (ctx , dashboardId , groupId , validatorIndices )
1012966}
1013967
968+ // Update the group for validators already in the dashboard linked to the graffiti (via produced block).
969+ // Add up to limit new validators associated with the graffiti, if not already in the dashboard.
1014970func (d * DataAccessService ) AddValidatorDashboardValidatorsByGraffiti (ctx context.Context , dashboardId t.VDBIdPrimary , groupId uint64 , graffiti string , limit uint64 ) ([]t.VDBPostValidatorsData , error ) {
1015- // for all validators already in the dashboard that are associated with the graffiti (by produced block), update the group
1016- // then add no more than `limit` validators associated with the deposit address to the dashboard
1017- var validatorIndicesToAdd []uint64
1018- err := d .readerDb .SelectContext (ctx , & validatorIndicesToAdd , "SELECT DISTINCT proposer FROM blocks WHERE graffiti_text = $1 ORDER BY proposer LIMIT $2;" , graffiti , limit )
1019- if err != nil {
1020- return nil , err
1021- }
971+ g , gCtx := errgroup .WithContext (ctx )
1022972
1023- // retrieve the existing validators
1024- var existingValidators []uint64
1025- err = d .alloyWriter .SelectContext (ctx , & existingValidators , "SELECT validator_index FROM users_val_dashboards_validators WHERE dashboard_id = $1" , dashboardId )
1026- if err != nil {
1027- return nil , err
1028- }
1029- existingValidatorsMap := make (map [uint64 ]bool , len (existingValidators ))
1030- for _ , validatorIndex := range existingValidators {
1031- existingValidatorsMap [validatorIndex ] = true
1032- }
1033-
1034- // filter out the validators that are already in the dashboard
973+ // fetch validators that are already in the dashboard and associated with the graffiti
1035974 var validatorIndicesToUpdate []uint64
975+ g .Go (func () error {
976+ return d .readerDb .SelectContext (gCtx , & validatorIndicesToUpdate , `
977+ SELECT DISTINCT uvdv.validator_index
978+ FROM blocks b
979+ JOIN users_val_dashboards_validators uvdv ON b.proposer = uvdv.validator_index
980+ WHERE uvdv.dashboard_id = $1 AND b.graffiti_text = $2;
981+ ` , dashboardId , graffiti )
982+ })
983+
984+ // fetch validators that are not yet in the dashboard and associated with the graffiti, up to the limit
1036985 var validatorIndicesToInsert []uint64
1037- for _ , validatorIndex := range validatorIndicesToAdd {
1038- if _ , ok := existingValidatorsMap [validatorIndex ]; ok {
1039- validatorIndicesToUpdate = append (validatorIndicesToUpdate , validatorIndex )
1040- } else {
1041- validatorIndicesToInsert = append (validatorIndicesToInsert , validatorIndex )
1042- }
1043- }
986+ g .Go (func () error {
987+ return d .readerDb .SelectContext (gCtx , & validatorIndicesToInsert , `
988+ SELECT DISTINCT b.proposer
989+ FROM blocks b
990+ LEFT JOIN users_val_dashboards_validators uvdv ON b.proposer = uvdv.validator_index AND uvdv.dashboard_id = $1
991+ WHERE b.graffiti_text = $2 AND uvdv.validator_index IS NULL
992+ ORDER BY b.proposer
993+ LIMIT $3;
994+ ` , dashboardId , graffiti , limit )
995+ })
1044996
1045- // update the group for all existing validators
1046- validatorIndices := make ([]uint64 , 0 , int (limit ))
1047- validatorIndices = append (validatorIndices , validatorIndicesToUpdate ... )
1048-
1049- // insert the new validators up to the allowed user max limit taking into account how many validators are already in the dashboard
1050- if len (validatorIndicesToInsert ) > 0 {
1051- freeSpace := int (limit ) - len (existingValidators )
1052- if freeSpace > 0 {
1053- if len (validatorIndicesToInsert ) > freeSpace { // cap inserts to the amount of free space available
1054- log .Infof ("limiting the number of validators to insert to %d" , freeSpace )
1055- validatorIndicesToInsert = validatorIndicesToInsert [:freeSpace ]
1056- }
1057- validatorIndices = append (validatorIndices , validatorIndicesToInsert ... )
1058- }
997+ err := g .Wait ()
998+ if err != nil {
999+ return nil , err
10591000 }
10601001
1061- if len (validatorIndices ) == 0 {
1062- // no validators to add
1063- return []t.VDBPostValidatorsData {}, nil
1064- }
1065- log .Infof ("inserting %d new validators and updating %d validators of dashboard %d, limit is %d" , len (validatorIndicesToInsert ), len (validatorIndicesToUpdate ), dashboardId , limit )
1002+ validatorIndices := slices .Concat (validatorIndicesToUpdate , validatorIndicesToInsert )
1003+
10661004 return d .AddValidatorDashboardValidators (ctx , dashboardId , groupId , validatorIndices )
10671005}
10681006
10691007func (d * DataAccessService ) RemoveValidatorDashboardValidators (ctx context.Context , dashboardId t.VDBIdPrimary , validators []t.VDBValidator ) error {
10701008 if len (validators ) == 0 {
1071- // // Remove all validators for the dashboard
1072- // _, err := d.alloyWriter.ExecContext(ctx, `
1073- // DELETE FROM users_val_dashboards_validators
1074- // WHERE dashboard_id = $1
1075- // `, dashboardId)
1076- return fmt .Errorf ("calling RemoveValidatorDashboardValidators with empty validators list is not allowed" )
1009+ // Remove all validators for the dashboard
1010+ // This is usually forbidden by API validation
1011+ _ , err := d .alloyWriter .ExecContext (ctx , `
1012+ DELETE FROM users_val_dashboards_validators
1013+ WHERE dashboard_id = $1
1014+ ` , dashboardId )
1015+ return err
10771016 }
10781017
10791018 //Create the query to delete validators
0 commit comments