2626)
2727
2828logger = get_logger (__name__ )
29-
3029BlockNumberType = int | Literal ["latest" , "earliest" , "pending" ]
3130
3231
@@ -79,19 +78,25 @@ def __init_subclass__(cls, namespace: str | None = None) -> None:
7978
8079 def post_request (
8180 self ,
81+ * ,
8282 method : str ,
83- * params : Any ,
83+ params : List [ Any ] | None = None ,
8484 extra_headers : Dict | None = None ,
8585 request_id : int | str | None = None ,
86+ timeout : int | None = None ,
8687 ) -> Any :
8788 """Send JSON-RPC POST request to the client RPC server at port defined in the url."""
8889 if extra_headers is None :
8990 extra_headers = {}
91+ if params is None :
92+ params = []
93+
9094 assert self .namespace , "RPC namespace not set"
9195
9296 next_request_id_counter = next (self .request_id_counter )
9397 if request_id is None :
9498 request_id = next_request_id_counter
99+
95100 payload = {
96101 "jsonrpc" : "2.0" ,
97102 "method" : f"{ self .namespace } _{ method } " ,
@@ -103,7 +108,8 @@ def post_request(
103108 }
104109 headers = base_header | extra_headers
105110
106- response = requests .post (self .url , json = payload , headers = headers )
111+ logger .debug (f"Sending RPC request, timeout is set to { timeout } ..." )
112+ response = requests .post (self .url , json = payload , headers = headers , timeout = timeout )
107113 response .raise_for_status ()
108114 response_json = response .json ()
109115
@@ -135,53 +141,79 @@ def __init__(
135141 super ().__init__ (* args , ** kwargs )
136142 self .transaction_wait_timeout = transaction_wait_timeout
137143
138- def config (self ):
144+ def config (self , timeout : int | None = None ):
139145 """`eth_config`: Returns information about a fork configuration of the client."""
140146 try :
141- response = self .post_request ("config" )
147+ response = self .post_request (method = "config" , timeout = timeout )
142148 if response is None :
149+ logger .warning ("eth_config request: failed to get response" )
143150 return None
144151 return EthConfigResponse .model_validate (
145152 response , context = self .response_validation_context
146153 )
147154 except ValidationError as e :
148155 pprint (e .errors ())
149156 raise e
157+ except Exception as e :
158+ logger .debug (f"exception occurred when sending JSON-RPC request: { e } " )
159+ raise e
150160
151161 def chain_id (self ) -> int :
152162 """`eth_chainId`: Returns the current chain id."""
153- return int (self .post_request ("chainId" ), 16 )
163+ response = self .post_request (method = "chainId" , timeout = 10 )
164+
165+ return int (response , 16 )
154166
155167 def get_block_by_number (self , block_number : BlockNumberType = "latest" , full_txs : bool = True ):
156168 """`eth_getBlockByNumber`: Returns information about a block by block number."""
157169 block = hex (block_number ) if isinstance (block_number , int ) else block_number
158- return self .post_request ("getBlockByNumber" , block , full_txs )
170+ params = [block , full_txs ]
171+ response = self .post_request (method = "getBlockByNumber" , params = params )
172+
173+ return response
159174
160175 def get_block_by_hash (self , block_hash : Hash , full_txs : bool = True ):
161176 """`eth_getBlockByHash`: Returns information about a block by hash."""
162- return self .post_request ("getBlockByHash" , f"{ block_hash } " , full_txs )
177+ params = [f"{ block_hash } " , full_txs ]
178+ response = self .post_request (method = "getBlockByHash" , params = params )
179+
180+ return response
163181
164182 def get_balance (self , address : Address , block_number : BlockNumberType = "latest" ) -> int :
165183 """`eth_getBalance`: Returns the balance of the account of given address."""
166184 block = hex (block_number ) if isinstance (block_number , int ) else block_number
167- return int (self .post_request ("getBalance" , f"{ address } " , block ), 16 )
185+ params = [f"{ address } " , block ]
186+
187+ response = self .post_request (method = "getBalance" , params = params )
188+
189+ return int (response , 16 )
168190
169191 def get_code (self , address : Address , block_number : BlockNumberType = "latest" ) -> Bytes :
170192 """`eth_getCode`: Returns code at a given address."""
171193 block = hex (block_number ) if isinstance (block_number , int ) else block_number
172- return Bytes (self .post_request ("getCode" , f"{ address } " , block ))
194+ params = [f"{ address } " , block ]
195+
196+ response = self .post_request (method = "getCode" , params = params )
197+
198+ return Bytes (response )
173199
174200 def get_transaction_count (
175201 self , address : Address , block_number : BlockNumberType = "latest"
176202 ) -> int :
177203 """`eth_getTransactionCount`: Returns the number of transactions sent from an address."""
178204 block = hex (block_number ) if isinstance (block_number , int ) else block_number
179- return int (self .post_request ("getTransactionCount" , f"{ address } " , block ), 16 )
205+ params = [f"{ address } " , block ]
206+
207+ response = self .post_request (method = "getTransactionCount" , params = params )
208+
209+ return int (response , 16 )
180210
181211 def get_transaction_by_hash (self , transaction_hash : Hash ) -> TransactionByHashResponse | None :
182212 """`eth_getTransactionByHash`: Returns transaction details."""
183213 try :
184- response = self .post_request ("getTransactionByHash" , f"{ transaction_hash } " )
214+ response = self .post_request (
215+ method = "getTransactionByHash" , params = [f"{ transaction_hash } " ]
216+ )
185217 if response is None :
186218 return None
187219 return TransactionByHashResponse .model_validate (
@@ -196,37 +228,45 @@ def get_storage_at(
196228 ) -> Hash :
197229 """`eth_getStorageAt`: Returns the value from a storage position at a given address."""
198230 block = hex (block_number ) if isinstance (block_number , int ) else block_number
199- return Hash (self .post_request ("getStorageAt" , f"{ address } " , f"{ position } " , block ))
231+ params = [f"{ address } " , f"{ position } " , block ]
232+
233+ response = self .post_request (method = "getStorageAt" , params = params )
234+ return Hash (response )
200235
201236 def gas_price (self ) -> int :
202237 """`eth_gasPrice`: Returns the number of transactions sent from an address."""
203- return int (self .post_request ("gasPrice" ), 16 )
238+ response = self .post_request (method = "gasPrice" )
239+
240+ return int (response , 16 )
204241
205242 def send_raw_transaction (
206243 self , transaction_rlp : Bytes , request_id : int | str | None = None
207244 ) -> Hash :
208245 """`eth_sendRawTransaction`: Send a transaction to the client."""
209246 try :
210- result_hash = Hash (
211- self . post_request (
212- "sendRawTransaction" , f" { transaction_rlp .hex ()} " , request_id = request_id
213- ),
247+ response = self . post_request (
248+ method = "sendRawTransaction" ,
249+ params = [ transaction_rlp .hex ()],
250+ request_id = request_id , # noqa: E501
214251 )
252+
253+ result_hash = Hash (response )
215254 assert result_hash is not None
216255 return result_hash
217256 except Exception as e :
218257 raise SendTransactionExceptionError (str (e ), tx_rlp = transaction_rlp ) from e
219258
220259 def send_transaction (self , transaction : Transaction ) -> Hash :
221260 """`eth_sendRawTransaction`: Send a transaction to the client."""
261+ # TODO: is this a copypaste error from above?
222262 try :
223- result_hash = Hash (
224- self .post_request (
225- "sendRawTransaction" ,
226- f"{ transaction .rlp ().hex ()} " ,
227- request_id = transaction .metadata_string (),
228- )
263+ response = self .post_request (
264+ method = "sendRawTransaction" ,
265+ params = [transaction .rlp ().hex ()],
266+ request_id = transaction .metadata_string (), # noqa: E501
229267 )
268+
269+ result_hash = Hash (response )
230270 assert result_hash == transaction .hash
231271 assert result_hash is not None
232272 return transaction .hash
@@ -318,7 +358,8 @@ class DebugRPC(EthRPC):
318358
319359 def trace_call (self , tr : dict [str , str ], block_number : str ):
320360 """`debug_traceCall`: Returns pre state required for transaction."""
321- return self .post_request ("traceCall" , tr , block_number , {"tracer" : "prestateTracer" })
361+ params = [tr , block_number , {"tracer" : "prestateTracer" }]
362+ return self .post_request (method = "traceCall" , params = params )
322363
323364
324365class EngineRPC (BaseRPC ):
@@ -341,10 +382,12 @@ def __init__(
341382
342383 def post_request (
343384 self ,
385+ * ,
344386 method : str ,
345- * params : Any ,
387+ params : Any | None = None ,
346388 extra_headers : Dict | None = None ,
347389 request_id : int | str | None = None ,
390+ timeout : int | None = None ,
348391 ) -> Any :
349392 """Send JSON-RPC POST request to the client RPC server at port defined in the url."""
350393 if extra_headers is None :
@@ -357,14 +400,22 @@ def post_request(
357400 extra_headers = {
358401 "Authorization" : f"Bearer { jwt_token } " ,
359402 } | extra_headers
403+
360404 return super ().post_request (
361- method , * params , extra_headers = extra_headers , request_id = request_id
405+ method = method ,
406+ params = params ,
407+ extra_headers = extra_headers ,
408+ timeout = timeout ,
409+ request_id = request_id ,
362410 )
363411
364412 def new_payload (self , * params : Any , version : int ) -> PayloadStatus :
365413 """`engine_newPayloadVX`: Attempts to execute the given payload on an execution client."""
414+ method = f"newPayloadV{ version } "
415+ params_list = [to_json (param ) for param in params ]
416+
366417 return PayloadStatus .model_validate (
367- self .post_request (f"newPayloadV { version } " , * [ to_json ( param ) for param in params ] ),
418+ self .post_request (method = method , params = params_list ),
368419 context = self .response_validation_context ,
369420 )
370421
@@ -376,11 +427,17 @@ def forkchoice_updated(
376427 version : int ,
377428 ) -> ForkchoiceUpdateResponse :
378429 """`engine_forkchoiceUpdatedVX`: Updates the forkchoice state of the execution client."""
430+ method = f"forkchoiceUpdatedV{ version } "
431+
432+ if payload_attributes is None :
433+ params = [to_json (forkchoice_state ), None ]
434+ else :
435+ params = [to_json (forkchoice_state ), to_json (payload_attributes )]
436+
379437 return ForkchoiceUpdateResponse .model_validate (
380438 self .post_request (
381- f"forkchoiceUpdatedV{ version } " ,
382- to_json (forkchoice_state ),
383- to_json (payload_attributes ) if payload_attributes is not None else None ,
439+ method = method ,
440+ params = params ,
384441 ),
385442 context = self .response_validation_context ,
386443 )
@@ -395,10 +452,12 @@ def get_payload(
395452 `engine_getPayloadVX`: Retrieves a payload that was requested through
396453 `engine_forkchoiceUpdatedVX`.
397454 """
455+ method = f"getPayloadV{ version } "
456+
398457 return GetPayloadResponse .model_validate (
399458 self .post_request (
400- f"getPayloadV { version } " ,
401- f"{ payload_id } " ,
459+ method = method ,
460+ params = [ f"{ payload_id } " ] ,
402461 ),
403462 context = self .response_validation_context ,
404463 )
@@ -410,9 +469,12 @@ def get_blobs(
410469 version : int ,
411470 ) -> GetBlobsResponse | None :
412471 """`engine_getBlobsVX`: Retrieves blobs from an execution layers tx pool."""
472+ method = f"getBlobsV{ version } "
473+ params = [f"{ h } " for h in versioned_hashes ]
474+
413475 response = self .post_request (
414- f"getBlobsV { version } " ,
415- [ f" { h } " for h in versioned_hashes ],
476+ method = method ,
477+ params = [ params ],
416478 )
417479 if response is None : # for tests that request non-existing blobs
418480 logger .debug ("get_blobs response received but it has value: None" )
@@ -429,7 +491,7 @@ class NetRPC(BaseRPC):
429491
430492 def peer_count (self ) -> int :
431493 """`net_peerCount`: Get the number of peers connected to the client."""
432- response = self .post_request ("peerCount" )
494+ response = self .post_request (method = "peerCount" )
433495 return int (response , 16 ) # hex -> int
434496
435497
@@ -438,4 +500,4 @@ class AdminRPC(BaseRPC):
438500
439501 def add_peer (self , enode : str ) -> bool :
440502 """`admin_addPeer`: Add a peer by enode URL."""
441- return self .post_request ("addPeer" , enode )
503+ return self .post_request (method = "addPeer" , params = [ enode ] )
0 commit comments