@@ -46,7 +46,7 @@ async fn test_register_validators() -> Result<()> {
4646 "message": {
4747 "fee_recipient": "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
4848 "gas_limit": "100000",
49- "timestamp": "1000000",
49+ "timestamp": "1000000",
5050 "pubkey": "0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
5151 },
5252 "signature": "0xcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc"
@@ -93,7 +93,7 @@ async fn test_register_validators_returns_422_if_request_is_malformed() -> Resul
9393 "message": {
9494 "fee_recipient": "0xaa",
9595 "gas_limit": "100000",
96- "timestamp": "1000000",
96+ "timestamp": "1000000",
9797 "pubkey": "0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
9898 },
9999 "signature": "0xcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc"
@@ -115,7 +115,7 @@ async fn test_register_validators_returns_422_if_request_is_malformed() -> Resul
115115 "message": {
116116 "fee_recipient": "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
117117 "gas_limit": "100000",
118- "timestamp": "1000000",
118+ "timestamp": "1000000",
119119 "pubkey": "0xbbb"
120120 },
121121 "signature": "0xcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc"
@@ -137,7 +137,7 @@ async fn test_register_validators_returns_422_if_request_is_malformed() -> Resul
137137 "message": {
138138 "fee_recipient": "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
139139 "gas_limit": "100000",
140- "timestamp": "1000000",
140+ "timestamp": "1000000",
141141 "pubkey": "0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
142142 },
143143 "signature": "0xcccc"
@@ -159,7 +159,7 @@ async fn test_register_validators_returns_422_if_request_is_malformed() -> Resul
159159 "message": {
160160 "fee_recipient": "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
161161 "gas_limit": "10000000000000000000000000000000000000000000000000000000",
162- "timestamp": "1000000",
162+ "timestamp": "1000000",
163163 "pubkey": "0xcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc"
164164 },
165165 "signature": "0xcccc"
@@ -181,7 +181,7 @@ async fn test_register_validators_returns_422_if_request_is_malformed() -> Resul
181181 "message": {
182182 "fee_recipient": "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
183183 "gas_limit": "1000000",
184- "timestamp": "10000000000000000000000000000000000000000000000000000000",
184+ "timestamp": "10000000000000000000000000000000000000000000000000000000",
185185 "pubkey": "0xcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc"
186186 },
187187 "signature": "0xcccc"
@@ -201,3 +201,106 @@ async fn test_register_validators_returns_422_if_request_is_malformed() -> Resul
201201 assert_eq ! ( mock_state. received_register_validator( ) , 0 ) ;
202202 Ok ( ( ) )
203203}
204+
205+ #[ tokio:: test]
206+ async fn test_register_validators_does_not_retry_on_429 ( ) -> Result < ( ) > {
207+ setup_test_env ( ) ;
208+ let signer = random_secret ( ) ;
209+ let pubkey: BlsPublicKey = blst_pubkey_to_alloy ( & signer. sk_to_pk ( ) ) . into ( ) ;
210+
211+ let chain = Chain :: Holesky ;
212+ let pbs_port = 4200 ;
213+
214+ // Set up mock relay state and override response to 429
215+ let mock_state = Arc :: new ( MockRelayState :: new ( chain, signer) ) ;
216+ mock_state. set_response_override ( StatusCode :: TOO_MANY_REQUESTS ) ;
217+
218+ // Run a mock relay
219+ let relays = vec ! [ generate_mock_relay( pbs_port + 1 , pubkey) ?] ;
220+ tokio:: spawn ( start_mock_relay_service ( mock_state. clone ( ) , pbs_port + 1 ) ) ;
221+
222+ // Run the PBS service
223+ let config = to_pbs_config ( chain, get_pbs_static_config ( pbs_port) , relays) ;
224+ let state = PbsState :: new ( config) ;
225+ tokio:: spawn ( PbsService :: run :: < ( ) , DefaultBuilderApi > ( state. clone ( ) ) ) ;
226+
227+ // Leave some time to start servers
228+ tokio:: time:: sleep ( Duration :: from_millis ( 100 ) ) . await ;
229+
230+ let mock_validator = MockValidator :: new ( pbs_port) ?;
231+ info ! ( "Sending register validator to test 429 response" ) ;
232+
233+ let registration: ValidatorRegistration = serde_json:: from_str (
234+ r#"{
235+ "message": {
236+ "fee_recipient": "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
237+ "gas_limit": "100000",
238+ "timestamp": "1000000",
239+ "pubkey": "0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
240+ },
241+ "signature": "0xcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc"
242+ }"# ,
243+ ) ?;
244+
245+ let registrations = vec ! [ registration] ;
246+ let res = mock_validator. do_register_custom_validators ( registrations) . await ?;
247+
248+ // Should only be called once (no retry)
249+ assert_eq ! ( mock_state. received_register_validator( ) , 1 ) ;
250+ // Expected to return 429 status code
251+ // But it returns `No relay passed register_validator successfully` with 502
252+ // status code
253+ assert_eq ! ( res. status( ) , StatusCode :: BAD_GATEWAY ) ;
254+
255+ Ok ( ( ) )
256+ }
257+
258+ #[ tokio:: test]
259+ async fn test_register_validators_retries_on_500 ( ) -> Result < ( ) > {
260+ setup_test_env ( ) ;
261+ let signer = random_secret ( ) ;
262+ let pubkey: BlsPublicKey = blst_pubkey_to_alloy ( & signer. sk_to_pk ( ) ) . into ( ) ;
263+
264+ let chain = Chain :: Holesky ;
265+ let pbs_port = 4300 ;
266+
267+ // Set up internal mock relay with 500 response override
268+ let mock_state = Arc :: new ( MockRelayState :: new ( chain, signer) ) ;
269+ mock_state. set_response_override ( StatusCode :: INTERNAL_SERVER_ERROR ) ; // 500
270+
271+ let relays = vec ! [ generate_mock_relay( pbs_port + 1 , pubkey) ?] ;
272+ tokio:: spawn ( start_mock_relay_service ( mock_state. clone ( ) , pbs_port + 1 ) ) ;
273+
274+ // Set retry limit to 3
275+ let mut pbs_config = get_pbs_static_config ( pbs_port) ;
276+ pbs_config. register_validator_retry_limit = 3 ;
277+
278+ let config = to_pbs_config ( chain, pbs_config, relays) ;
279+ let state = PbsState :: new ( config) ;
280+ tokio:: spawn ( PbsService :: run :: < ( ) , DefaultBuilderApi > ( state. clone ( ) ) ) ;
281+
282+ tokio:: time:: sleep ( Duration :: from_millis ( 100 ) ) . await ;
283+
284+ let mock_validator = MockValidator :: new ( pbs_port) ?;
285+ info ! ( "Sending register validator to test retry on 500" ) ;
286+
287+ let registration: ValidatorRegistration = serde_json:: from_str (
288+ r#"{
289+ "message": {
290+ "fee_recipient": "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
291+ "gas_limit": "100000",
292+ "timestamp": "1000000",
293+ "pubkey": "0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
294+ },
295+ "signature": "0xcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc"
296+ }"# ,
297+ ) ?;
298+
299+ let registrations = vec ! [ registration] ;
300+ let _ = mock_validator. do_register_custom_validators ( registrations) . await ;
301+
302+ // Should retry 3 times (0, 1, 2) → total 3 calls
303+ assert_eq ! ( mock_state. received_register_validator( ) , 3 ) ;
304+
305+ Ok ( ( ) )
306+ }
0 commit comments