@@ -832,122 +832,188 @@ func (m *ApiService) handleValidatorRelayers(w http.ResponseWriter, req *http.Re
832832 vars := mux .Vars (req )
833833 valPubKeys := vars ["valpubkey" ]
834834 if valPubKeys == "" {
835- m .respondError (w , http .StatusBadRequest , "no validator pubkey provided" )
835+ m .respondError (w , http .StatusBadRequest , "No validator pubkey provided! " )
836836 return
837837 }
838838
839- // Split the valPubKeys into individual keys (assuming they are comma-separated)
840839 keys := strings .Split (valPubKeys , "," )
841- // Check if the number of pubkeys exceeds the maximum limit (50 in this case)
842840 if len (keys ) > 50 {
843- m .respondError (w , http .StatusBadRequest , "maximum number of pubkeys exceeded (max: 50)" )
841+ m .respondError (w , http .StatusBadRequest , "Maximum number of pubkeys exceeded (max: 50)" )
844842 return
845843 }
844+
845+ for _ , key := range keys {
846+ if ! IsValidPubkey (key ) {
847+ m .respondError (w , http .StatusBadRequest , "Invalid validator pubkey format: " + key )
848+ return
849+ }
850+ }
851+
852+ results , allValid , err := m .processValidatorsConcurrently (keys )
853+ if err != nil {
854+ m .respondError (w , http .StatusInternalServerError , err .Error ())
855+ return
856+ }
857+
858+ response := struct {
859+ Validators []httpOkRelayersState
860+ AllValidatorsCorrect bool
861+ IncorrectValidators []string
862+ }{
863+ Validators : results ,
864+ AllValidatorsCorrect : allValid ,
865+ IncorrectValidators : m .extractIncorrectValidators (results ),
866+ }
867+
868+ m .respondOK (w , response )
869+ }
870+
871+ func (m * ApiService ) processValidatorsConcurrently (keys []string ) ([]httpOkRelayersState , bool , error ) {
846872 var results []httpOkRelayersState
873+ allValidatorsRegisteredCorrectFee := true
874+ resultsChan := make (chan ValidatorRelayResult , len (keys ))
847875
848- allValidatorsRegisteredCorrectFee := true // Assume all validators have correct fee registrations by default
849- var incorrectValidators []string // Initialize an array to store incorrect validators
876+ for i , key := range keys {
877+ go m .processSingleValidator (i , key , resultsChan )
878+ }
850879
851- for _ , valPubKey := range keys {
852- if ! IsValidPubkey ( valPubKey ) {
853- m . respondError ( w , http . StatusInternalServerError , fmt . Sprintf ( "invalid validator pubkey format: %s" , valPubKey ))
854- return
880+ for range keys {
881+ res := <- resultsChan
882+ if res . Err != nil {
883+ return nil , false , res . Err
855884 }
856- var correctFeeRelays []httpRelay
857- var wrongFeeRelays []httpRelay
858- var unregisteredRelays []httpRelay
859- registeredCorrectFee := false
860- var relays []string
861-
862- if m .Network == "mainnet" {
863- relays = config .MainnetRelays
864- } else if m .Network == "goerli" {
865- relays = config .GoerliRelays
866- } else {
867- m .respondError (w , http .StatusInternalServerError , fmt .Sprintf ("invalid network: %s" , m .Network ))
868- return
885+ if ! res .IsValidatorValid {
886+ allValidatorsRegisteredCorrectFee = false
869887 }
888+ results = append (results , res .ValidatorResult )
889+ }
890+ close (resultsChan )
870891
871- // Iterate through all the relays and check if the validator has registered with the correct fee
872- // on any of them
873- for _ , relay := range relays {
874- url := fmt .Sprintf ("https://%s/relay/v1/data/validator_registration?pubkey=%s" , relay , valPubKey )
875- resp , err := http .Get (url )
876- if err != nil {
877- m .respondError (w , http .StatusInternalServerError , "could not call relayer endpoint: " + err .Error ())
878- return
879- }
880- defer resp .Body .Close ()
892+ sort .Slice (results , func (i , j int ) bool {
893+ return results [i ].ValPubKey < results [j ].ValPubKey
894+ })
881895
882- if resp . StatusCode == http . StatusOK {
883- signedRegistration := & builderApiV1. SignedValidatorRegistration { }
896+ return results , allValidatorsRegisteredCorrectFee , nil
897+ }
884898
885- bodyBytes , err := io .ReadAll (resp .Body )
886- if err != nil {
887- m .respondError (w , http .StatusInternalServerError , "could not call relayer endpoint: " + err .Error ())
888- return
889- }
899+ func (m * ApiService ) processSingleValidator (idx int , valPubKey string , resultsChan chan ValidatorRelayResult ) {
900+ var correctFeeRelays []httpRelay
901+ var wrongFeeRelays []httpRelay
902+ var unregisteredRelays []httpRelay
903+ registeredCorrectFee := false
904+ var relays []string
905+
906+ if m .Network == "mainnet" {
907+ relays = config .MainnetRelays
908+ } else if m .Network == "goerli" {
909+ relays = config .GoerliRelays
910+ } else {
911+ resultsChan <- ValidatorRelayResult {
912+ Index : idx ,
913+ Err : fmt .Errorf ("invalid network: %s" , m .Network ),
914+ }
915+ return
916+ }
890917
891- if err = json .Unmarshal (bodyBytes , signedRegistration ); err != nil {
892- m .respondError (w , http .StatusInternalServerError , "could not call relayer endpoint: " + err .Error ())
893- return
894- }
918+ for _ , relay := range relays {
919+ url := fmt .Sprintf ("https://%s/relay/v1/data/validator_registration?pubkey=%s" , relay , valPubKey )
920+ resp , err := http .Get (url )
921+ if err != nil {
922+ resultsChan <- ValidatorRelayResult {
923+ Index : idx ,
924+ Err : fmt .Errorf ("error calling relayer %s for validator %s: %v" , relay , valPubKey , err ),
925+ }
926+ return
927+ }
895928
896- relayRegistration := httpRelay {
897- RelayAddress : relay ,
898- FeeRecipient : signedRegistration .Message .FeeRecipient .String (),
899- Timestamp : fmt .Sprintf ("%d" , signedRegistration .Message .Timestamp .UnixNano ()),
900- }
929+ bodyBytes , err := io .ReadAll (resp .Body )
930+ resp .Body .Close ()
931+ if err != nil {
932+ resultsChan <- ValidatorRelayResult {
933+ Index : idx ,
934+ Err : fmt .Errorf ("error reading response from relayer %s for validator %s: %v" , relay , valPubKey , err ),
935+ }
936+ return
937+ }
901938
902- if utils .Equals (signedRegistration .Message .FeeRecipient .String (), m .Onchain .PoolAddress ) {
903- correctFeeRelays = append (correctFeeRelays , relayRegistration )
904- } else {
905- wrongFeeRelays = append (wrongFeeRelays , relayRegistration )
906- registeredCorrectFee = false // Set to false if any wrong fee registration is found
939+ // If the validator is or has been registered, the relayer will return a 200 message
940+ // with the signed registration message. If the validator has never been registered,
941+ // the relayer will return code 400 or 404 (depending on the relay) with the following message:
942+ // {
943+ // "code": 404,
944+ // "message": "no registration found for validator 0xafcdacfb67396a41a72676f3b064bcf62e977e5ef1d8aebadeed06e97156d4f640516fb205d12211ada9a54fcc26cc58"
945+ // }
946+ // https://flashbots.github.io/relay-specs/#/Data/getValidatorRegistration
947+ if resp .StatusCode == http .StatusOK {
948+ signedRegistration := & builderApiV1.SignedValidatorRegistration {}
949+
950+ if err = json .Unmarshal (bodyBytes , signedRegistration ); err != nil {
951+ resultsChan <- ValidatorRelayResult {
952+ Index : idx ,
953+ Err : fmt .Errorf ("error unmarshalling relay response from relayer %s for validator %s: %v" , relay , valPubKey , err ),
907954 }
955+ return
956+ }
957+
958+ relayRegistration := httpRelay {
959+ RelayAddress : relay ,
960+ FeeRecipient : signedRegistration .Message .FeeRecipient .String (),
961+ Timestamp : fmt .Sprintf ("%d" , signedRegistration .Message .Timestamp .UnixNano ()),
962+ }
963+
964+ // If the fee recipient matches the pool address, the relayer is registered
965+ if utils .Equals (signedRegistration .Message .FeeRecipient .String (), m .Onchain .PoolAddress ) {
966+ correctFeeRelays = append (correctFeeRelays , relayRegistration )
908967 } else {
909- unregisteredRelays = append (unregisteredRelays , httpRelay {
910- RelayAddress : relay ,
911- })
968+ // if the fee recipient does not match the pool address, the relayer is registered but with the wrong fee recipient
969+ wrongFeeRelays = append (wrongFeeRelays , relayRegistration )
912970 }
913- }
914971
915- // Only if there are some correct registrations and no invalid ones, it's ok
916- if len ( wrongFeeRelays ) == 0 && len ( correctFeeRelays ) > 0 {
917- registeredCorrectFee = true
918- }
972+ // else if (signedRegistration.Message.FeeRecipient.String() != m.Onchain.PoolAddress) && (signedRegistration.Message.FeeRecipient.String() != "") {
973+ // // If the fee recipient does not match the pool address, the relayer is registered but with the wrong fee recipient
974+ // wrongFeeRelays = append(wrongFeeRelays, relayRegistration)
975+ // }
919976
920- // If the validator is incorrect, add its pubkey to the incorrectValidators array
921- if ! registeredCorrectFee {
922- incorrectValidators = append (incorrectValidators , valPubKey )
977+ } else if resp .StatusCode == http .StatusBadRequest || resp .StatusCode == http .StatusNotFound {
978+ // the validator is not registered with the relayer
979+ unregisteredRelays = append (unregisteredRelays , httpRelay {RelayAddress : relay })
980+ } else {
981+ // there was an error calling the relayer, so we couldnt check if the validator is/was registered with the correct
982+ // fee recipient, so we return an error.
983+ resultsChan <- ValidatorRelayResult {
984+ Index : idx ,
985+ Err : fmt .Errorf ("error calling relayer %s for validator %s: %v" , relay , valPubKey , string (bodyBytes )),
986+ }
923987 }
988+ }
989+
990+ // If there are no wrong fee relays and there are correct fee relays, the validator is registered with the correct fee recipient
991+ // we do not accept validators that have not registered to any relay
992+ if len (wrongFeeRelays ) == 0 && len (correctFeeRelays ) > 0 {
993+ registeredCorrectFee = true
994+ }
924995
925- results = append (results , httpOkRelayersState {
996+ resultsChan <- ValidatorRelayResult {
997+ Index : idx ,
998+ ValidatorResult : httpOkRelayersState {
926999 ValPubKey : valPubKey ,
9271000 CorrectFeeRecipients : registeredCorrectFee ,
9281001 CorrectFeeRelays : correctFeeRelays ,
9291002 WrongFeeRelays : wrongFeeRelays ,
9301003 UnregisteredRelays : unregisteredRelays ,
931- })
932-
933- // Update the allValidatorsRegisteredCorrectFee status
934- if ! registeredCorrectFee {
935- allValidatorsRegisteredCorrectFee = false
936- }
1004+ },
1005+ IsValidatorValid : registeredCorrectFee ,
9371006 }
1007+ }
9381008
939- // Define and populate the response struct.
940- response := struct {
941- Validators []httpOkRelayersState
942- AllValidatorsCorrect bool
943- IncorrectValidators []string
944- }{
945- Validators : results ,
946- AllValidatorsCorrect : allValidatorsRegisteredCorrectFee ,
947- IncorrectValidators : incorrectValidators ,
1009+ func (m * ApiService ) extractIncorrectValidators (results []httpOkRelayersState ) []string {
1010+ var incorrectValidators []string
1011+ for _ , result := range results {
1012+ if ! result .CorrectFeeRecipients {
1013+ incorrectValidators = append (incorrectValidators , result .ValPubKey )
1014+ }
9481015 }
949-
950- m .respondOK (w , response )
1016+ return incorrectValidators
9511017}
9521018
9531019func (m * ApiService ) handleState (w http.ResponseWriter , req * http.Request ) {
@@ -976,6 +1042,8 @@ func IsValidAddress(v string) bool {
9761042 return re .MatchString (v )
9771043}
9781044
1045+ // The validator's BLS public key, uniquely identifying them. 48-bytes, hex encoded with 0x prefix, case insensitive.
1046+ // example: example: 0x93247f2209abcacf57b75a51dafae777f9dd38bc7053d1af526f220a7445a6d1a2753e5f3e8b1cfe39b46f43611ef74a
9791047func IsValidPubkey (v string ) bool {
9801048 re := regexp .MustCompile ("^0x[0-9a-fA-f]{96}$" )
9811049 return re .MatchString (v )
0 commit comments