1+ from eth_typing import (
2+ URI ,
3+ )
4+ from eth_utils import (
5+ to_dict ,
6+ )
17import logging
8+ import random
9+ from requests import (
10+ RequestException ,
11+ )
212from typing import (
313 Any ,
414 Dict ,
818 Union ,
919)
1020
11- from eth_typing import (
12- URI ,
13- )
14- from eth_utils import (
15- to_dict ,
16- )
17-
1821from web3 ._utils .http import (
1922 construct_user_agent ,
2023)
2629from web3 .datastructures import (
2730 NamedElementOnion ,
2831)
32+ from web3 .exceptions import (
33+ CannotHandleRequest ,
34+ )
2935from web3 .middleware import (
3036 http_retry_request_middleware ,
3137)
38+ from web3 .providers import (
39+ BaseProvider ,
40+ )
3241from web3 .types import (
3342 Middleware ,
3443 RPCEndpoint ,
4251
4352class HTTPProvider (JSONBaseProvider ):
4453 logger = logging .getLogger ("web3.providers.HTTPProvider" )
45- endpoint_uri = None
54+ providers = None
4655 _request_args = None
4756 _request_kwargs = None
4857 # type ignored b/c conflict with _middlewares attr on BaseProvider
4958 _middlewares : Tuple [Middleware , ...] = NamedElementOnion ([(http_retry_request_middleware , "http_retry_request" )]) # type: ignore # noqa: E501
5059
5160 def __init__ (
5261 self ,
53- endpoint_uri : Optional [Union [URI , str ]] = None ,
62+ providers : Union [list , str ],
63+ randomize : Optional [bool ] = False ,
5464 request_kwargs : Optional [Any ] = None ,
5565 session : Optional [Any ] = None ,
5666 ) -> None :
57- if endpoint_uri is None :
58- self .endpoint_uri = get_default_http_endpoint ()
59- else :
60- self .endpoint_uri = URI (endpoint_uri )
61-
67+ if isinstance (providers , str ):
68+ providers = [
69+ providers ,
70+ ]
71+ self .randomize = randomize
72+ self .providers = providers
6273 self ._request_kwargs = request_kwargs or {}
6374
6475 if session :
65- cache_and_return_session (self .endpoint_uri , session )
76+ cache_and_return_session (self .providers [ 0 ] , session )
6677
6778 super ().__init__ ()
6879
6980 def __str__ (self ) -> str :
70- return f "RPC connection { self . endpoint_uri } "
81+ return "RPC connection {0}" . format ( self . providers )
7182
7283 @to_dict
7384 def get_request_kwargs (self ) -> Iterable [Tuple [str , Any ]]:
@@ -83,16 +94,27 @@ def get_request_headers(self) -> Dict[str, str]:
8394 }
8495
8596 def make_request (self , method : RPCEndpoint , params : Any ) -> RPCResponse :
86- self .logger .debug (
87- f"Making request HTTP. URI: { self .endpoint_uri } , Method: { method } "
88- )
8997 request_data = self .encode_rpc_request (method , params )
90- raw_response = make_post_request (
91- self .endpoint_uri , request_data , ** self .get_request_kwargs ()
92- )
93- response = self .decode_rpc_response (raw_response )
94- self .logger .debug (
95- f"Getting response HTTP. URI: { self .endpoint_uri } , "
96- f"Method: { method } , Response: { response } "
97- )
98- return response
98+ if self .randomize :
99+ random .shuffle (self .providers )
100+ for provider in self .providers :
101+ provider_uri = URI (provider )
102+ self .logger .debug (
103+ "Making request HTTP. URI: %s, Method: %s" , provider_uri , method
104+ )
105+ try :
106+ raw_response = make_post_request (
107+ provider_uri , request_data , ** self .get_request_kwargs ()
108+ )
109+ response = self .decode_rpc_response (raw_response )
110+ self .logger .debug (
111+ "Getting response HTTP. URI: %s, " "Method: %s, Response: %s" ,
112+ provider_uri ,
113+ method ,
114+ response ,
115+ )
116+ return response
117+ except RequestException :
118+ pass
119+ else :
120+ raise CannotHandleRequest
0 commit comments