11from http import HTTPStatus
2- from typing import Literal , cast
2+ from typing import Any , Literal , cast
33
44from src import variables
55from src .metrics .logging import logging
2020 SyncCommittee ,
2121 Validator ,
2222)
23- from src .providers .http_provider import HTTPProvider , NotOkResponse
23+ from src .providers .http_provider import (
24+ HTTPProvider ,
25+ NotOkResponse ,
26+ data_is_dict ,
27+ data_is_list ,
28+ data_is_transient_dict ,
29+ )
2430from src .types import BlockRoot , BlockStamp , EpochNumber , SlotNumber , StateRoot
2531from src .utils .cache import global_lru_cache as lru_cache
2632from src .utils .dataclass import list_of_dataclasses
@@ -59,14 +65,14 @@ class ConsensusClient(HTTPProvider):
5965
6066 def get_config_spec (self ) -> BeaconSpecResponse :
6167 """Spec: https://ethereum.github.io/beacon-APIs/#/Config/getSpec"""
62- data , _ = self ._get (self .API_GET_SPEC , is_dict = True )
68+ data , _ = self ._get (self .API_GET_SPEC , retval_validator = data_is_dict )
6369 return BeaconSpecResponse .from_response (** data )
6470
6571 def get_genesis (self ):
6672 """
6773 Spec: https://ethereum.github.io/beacon-APIs/#/Beacon/getGenesis
6874 """
69- data , _ = self ._get (self .API_GET_GENESIS , is_dict = True )
75+ data , _ = self ._get (self .API_GET_GENESIS , retval_validator = data_is_dict )
7076 return GenesisResponse .from_response (** data )
7177
7278 def get_block_root (self , state_id : SlotNumber | BlockRoot | LiteralState ) -> BlockRootResponse :
@@ -79,7 +85,7 @@ def get_block_root(self, state_id: SlotNumber | BlockRoot | LiteralState) -> Blo
7985 self .API_GET_BLOCK_ROOT ,
8086 path_params = (state_id ,),
8187 force_raise = self .__raise_last_missed_slot_error ,
82- is_dict = True ,
88+ retval_validator = data_is_dict ,
8389 )
8490 return BlockRootResponse .from_response (** data )
8591
@@ -90,7 +96,7 @@ def get_block_header(self, state_id: SlotNumber | BlockRoot) -> BlockHeaderFullR
9096 self .API_GET_BLOCK_HEADER ,
9197 path_params = (state_id ,),
9298 force_raise = self .__raise_last_missed_slot_error ,
93- is_dict = True ,
99+ retval_validator = data_is_dict ,
94100 )
95101 resp = BlockHeaderFullResponse .from_response (data = BlockHeaderResponseData .from_response (** data ), ** meta_data )
96102 return resp
@@ -102,7 +108,7 @@ def get_block_details(self, state_id: SlotNumber | BlockRoot) -> BlockDetailsRes
102108 self .API_GET_BLOCK_DETAILS ,
103109 path_params = (state_id ,),
104110 force_raise = self .__raise_last_missed_slot_error ,
105- is_dict = True ,
111+ retval_validator = data_is_dict ,
106112 )
107113 return BlockDetailsResponse .from_response (** data )
108114
@@ -115,7 +121,7 @@ def get_block_attestations_and_sync(
115121 self .API_GET_BLOCK_DETAILS ,
116122 path_params = (state_id ,),
117123 force_raise = self .__raise_last_missed_slot_error ,
118- is_dict = True ,
124+ retval_validator = data_is_dict ,
119125 )
120126
121127 attestations = [
@@ -141,7 +147,7 @@ def get_attestation_committees(
141147 path_params = (blockstamp .state_root ,),
142148 query_params = {'epoch' : epoch , 'index' : committee_index , 'slot' : slot },
143149 force_raise = self .__raise_on_prysm_error ,
144- is_list = True ,
150+ retval_validator = data_is_list ,
145151 )
146152 except NotOkResponse as error :
147153 if self .PRYSM_STATE_NOT_FOUND_ERROR in error .text :
@@ -162,36 +168,40 @@ def get_sync_committee(self, blockstamp: BlockStamp, epoch: EpochNumber) -> Sync
162168 path_params = (blockstamp .state_root ,),
163169 query_params = {'epoch' : epoch },
164170 force_raise = self .__raise_on_prysm_error ,
165- is_dict = True ,
171+ retval_validator = data_is_dict ,
166172 )
167173 return SyncCommittee .from_response (** data )
168174
169175 @list_of_dataclasses (ProposerDuties .from_response )
170176 def get_proposer_duties (self , epoch : EpochNumber , expected_dependent_root : BlockRoot ) -> list [ProposerDuties ]:
171177 """Spec: https://ethereum.github.io/beacon-APIs/#/Validator/getProposerDuties"""
172- # It is recommended by spec to use the dependent root to ensure the epoch is correct
173- proposer_data , proposer_meta = self ._get (
178+
179+ def data_is_list_and_dependent_root_matches (data : Any , meta : dict , endpoint : str ):
180+ data_is_list (data , meta , endpoint = endpoint )
181+ # It is recommended by spec to use the dependent root to ensure the epoch is correct
182+ if meta ["dependent_root" ] != expected_dependent_root :
183+ raise ValueError (
184+ "Dependent root for proposer duties request mismatch: "
185+ f"{ meta ['dependent_root' ]= } is not { expected_dependent_root = } . "
186+ "Probably, CL node is not fully synced."
187+ )
188+
189+ data , _ = self ._get (
174190 self .API_GET_PROPOSER_DUTIES ,
175191 path_params = (epoch ,),
176- is_list = True ,
192+ retval_validator = data_is_list_and_dependent_root_matches ,
177193 )
178- response_dependent_root = proposer_meta ['dependent_root' ]
179- if response_dependent_root != expected_dependent_root :
180- raise ValueError (
181- "Dependent root for proposer duties request mismatch: "
182- f"{ response_dependent_root = } is not { expected_dependent_root = } . Probably, CL node is not fully synced"
183- )
184- return proposer_data
194+ return data
185195
186196 @lru_cache (maxsize = 1 )
187197 def get_state_block_roots (self , state_id : SlotNumber ) -> list [BlockRoot ]:
188- streamed_json = self ._get (
198+ data , _ = self ._get (
189199 self .API_GET_STATE ,
190200 path_params = (state_id ,),
191201 stream = True ,
192- is_dict = True ,
202+ retval_validator = data_is_transient_dict ,
193203 )
194- return list (streamed_json [ ' data' ][ ' block_roots' ])
204+ return list (data [ " block_roots" ])
195205
196206 def get_validators (self , blockstamp : BlockStamp ) -> list [Validator ]:
197207 return self .get_state_view (blockstamp ).indexed_validators
@@ -232,7 +242,7 @@ def _get_state_by_state_id(self, state_id: StateRoot | SlotNumber) -> dict:
232242 self .API_GET_STATE ,
233243 path_params = (state_id ,),
234244 force_raise = self .__raise_on_prysm_error ,
235- is_dict = True ,
245+ retval_validator = data_is_dict ,
236246 )
237247 return data
238248
@@ -260,7 +270,7 @@ def _get_attestation_committees_with_prysm(
260270 self .API_GET_ATTESTATION_COMMITTEES ,
261271 path_params = (blockstamp .slot_number ,),
262272 query_params = {'epoch' : epoch , 'index' : index , 'slot' : slot },
263- is_list = True ,
273+ retval_validator = data_is_dict ,
264274 )
265275 return data
266276
@@ -280,6 +290,6 @@ def _get_chain_id_with_provider(self, provider_index: int) -> int:
280290 data , _ = self ._get_without_fallbacks (
281291 self .hosts [provider_index ],
282292 self .API_GET_SPEC ,
283- is_dict = True ,
293+ retval_validator = data_is_dict ,
284294 )
285295 return BeaconSpecResponse .from_response (** data ).DEPOSIT_CHAIN_ID
0 commit comments