Skip to content

Commit a6cfd0e

Browse files
authored
Merge of #7006
2 parents 3a555f5 + fc5a700 commit a6cfd0e

File tree

3 files changed

+177
-0
lines changed

3 files changed

+177
-0
lines changed

beacon_node/http_api/src/lib.rs

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1119,6 +1119,72 @@ pub fn serve<T: BeaconChainTypes>(
11191119
},
11201120
);
11211121

1122+
// GET beacon/states/{state_id}/pending_deposits
1123+
let get_beacon_state_pending_deposits = beacon_states_path
1124+
.clone()
1125+
.and(warp::path("pending_deposits"))
1126+
.and(warp::path::end())
1127+
.then(
1128+
|state_id: StateId,
1129+
task_spawner: TaskSpawner<T::EthSpec>,
1130+
chain: Arc<BeaconChain<T>>| {
1131+
task_spawner.blocking_json_task(Priority::P1, move || {
1132+
let (data, execution_optimistic, finalized) = state_id
1133+
.map_state_and_execution_optimistic_and_finalized(
1134+
&chain,
1135+
|state, execution_optimistic, finalized| {
1136+
let Ok(deposits) = state.pending_deposits() else {
1137+
return Err(warp_utils::reject::custom_bad_request(
1138+
"Pending deposits not found".to_string(),
1139+
));
1140+
};
1141+
1142+
Ok((deposits.clone(), execution_optimistic, finalized))
1143+
},
1144+
)?;
1145+
1146+
Ok(api_types::ExecutionOptimisticFinalizedResponse {
1147+
data,
1148+
execution_optimistic: Some(execution_optimistic),
1149+
finalized: Some(finalized),
1150+
})
1151+
})
1152+
},
1153+
);
1154+
1155+
// GET beacon/states/{state_id}/pending_partial_withdrawals
1156+
let get_beacon_state_pending_partial_withdrawals = beacon_states_path
1157+
.clone()
1158+
.and(warp::path("pending_partial_withdrawals"))
1159+
.and(warp::path::end())
1160+
.then(
1161+
|state_id: StateId,
1162+
task_spawner: TaskSpawner<T::EthSpec>,
1163+
chain: Arc<BeaconChain<T>>| {
1164+
task_spawner.blocking_json_task(Priority::P1, move || {
1165+
let (data, execution_optimistic, finalized) = state_id
1166+
.map_state_and_execution_optimistic_and_finalized(
1167+
&chain,
1168+
|state, execution_optimistic, finalized| {
1169+
let Ok(withdrawals) = state.pending_partial_withdrawals() else {
1170+
return Err(warp_utils::reject::custom_bad_request(
1171+
"Pending withdrawals not found".to_string(),
1172+
));
1173+
};
1174+
1175+
Ok((withdrawals.clone(), execution_optimistic, finalized))
1176+
},
1177+
)?;
1178+
1179+
Ok(api_types::ExecutionOptimisticFinalizedResponse {
1180+
data,
1181+
execution_optimistic: Some(execution_optimistic),
1182+
finalized: Some(finalized),
1183+
})
1184+
})
1185+
},
1186+
);
1187+
11221188
// GET beacon/headers
11231189
//
11241190
// Note: this endpoint only returns information about blocks in the canonical chain. Given that
@@ -4667,6 +4733,8 @@ pub fn serve<T: BeaconChainTypes>(
46674733
.uor(get_beacon_state_committees)
46684734
.uor(get_beacon_state_sync_committees)
46694735
.uor(get_beacon_state_randao)
4736+
.uor(get_beacon_state_pending_deposits)
4737+
.uor(get_beacon_state_pending_partial_withdrawals)
46704738
.uor(get_beacon_headers)
46714739
.uor(get_beacon_headers_block_id)
46724740
.uor(get_beacon_block)

beacon_node/http_api/tests/tests.rs

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1192,6 +1192,60 @@ impl ApiTester {
11921192
self
11931193
}
11941194

1195+
pub async fn test_beacon_states_pending_deposits(self) -> Self {
1196+
for state_id in self.interesting_state_ids() {
1197+
let mut state_opt = state_id
1198+
.state(&self.chain)
1199+
.ok()
1200+
.map(|(state, _execution_optimistic, _finalized)| state);
1201+
1202+
let result = self
1203+
.client
1204+
.get_beacon_states_pending_deposits(state_id.0)
1205+
.await
1206+
.unwrap()
1207+
.map(|res| res.data);
1208+
1209+
if result.is_none() && state_opt.is_none() {
1210+
continue;
1211+
}
1212+
1213+
let state = state_opt.as_mut().expect("result should be none");
1214+
let expected = state.pending_deposits().unwrap();
1215+
1216+
assert_eq!(result.unwrap(), expected.to_vec());
1217+
}
1218+
1219+
self
1220+
}
1221+
1222+
pub async fn test_beacon_states_pending_partial_withdrawals(self) -> Self {
1223+
for state_id in self.interesting_state_ids() {
1224+
let mut state_opt = state_id
1225+
.state(&self.chain)
1226+
.ok()
1227+
.map(|(state, _execution_optimistic, _finalized)| state);
1228+
1229+
let result = self
1230+
.client
1231+
.get_beacon_states_pending_partial_withdrawals(state_id.0)
1232+
.await
1233+
.unwrap()
1234+
.map(|res| res.data);
1235+
1236+
if result.is_none() && state_opt.is_none() {
1237+
continue;
1238+
}
1239+
1240+
let state = state_opt.as_mut().expect("result should be none");
1241+
let expected = state.pending_partial_withdrawals().unwrap();
1242+
1243+
assert_eq!(result.unwrap(), expected.to_vec());
1244+
}
1245+
1246+
self
1247+
}
1248+
11951249
pub async fn test_beacon_headers_all_slots(self) -> Self {
11961250
for slot in 0..CHAIN_LENGTH {
11971251
let slot = Slot::from(slot);
@@ -6316,6 +6370,22 @@ async fn beacon_get_state_info() {
63166370
.await;
63176371
}
63186372

6373+
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
6374+
async fn beacon_get_state_info_electra() {
6375+
let mut config = ApiTesterConfig::default();
6376+
config.spec.altair_fork_epoch = Some(Epoch::new(0));
6377+
config.spec.bellatrix_fork_epoch = Some(Epoch::new(0));
6378+
config.spec.capella_fork_epoch = Some(Epoch::new(0));
6379+
config.spec.deneb_fork_epoch = Some(Epoch::new(0));
6380+
config.spec.electra_fork_epoch = Some(Epoch::new(0));
6381+
ApiTester::new_from_config(config)
6382+
.await
6383+
.test_beacon_states_pending_deposits()
6384+
.await
6385+
.test_beacon_states_pending_partial_withdrawals()
6386+
.await;
6387+
}
6388+
63196389
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
63206390
async fn beacon_get_blocks() {
63216391
ApiTester::new()

common/eth2/src/lib.rs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -782,6 +782,45 @@ impl BeaconNodeHttpClient {
782782
self.get_opt(path).await
783783
}
784784

785+
/// `GET beacon/states/{state_id}/pending_deposits`
786+
///
787+
/// Returns `Ok(None)` on a 404 error.
788+
pub async fn get_beacon_states_pending_deposits(
789+
&self,
790+
state_id: StateId,
791+
) -> Result<Option<ExecutionOptimisticFinalizedResponse<Vec<PendingDeposit>>>, Error> {
792+
let mut path = self.eth_path(V1)?;
793+
794+
path.path_segments_mut()
795+
.map_err(|()| Error::InvalidUrl(self.server.clone()))?
796+
.push("beacon")
797+
.push("states")
798+
.push(&state_id.to_string())
799+
.push("pending_deposits");
800+
801+
self.get_opt(path).await
802+
}
803+
804+
/// `GET beacon/states/{state_id}/pending_partial_withdrawals`
805+
///
806+
/// Returns `Ok(None)` on a 404 error.
807+
pub async fn get_beacon_states_pending_partial_withdrawals(
808+
&self,
809+
state_id: StateId,
810+
) -> Result<Option<ExecutionOptimisticFinalizedResponse<Vec<PendingPartialWithdrawal>>>, Error>
811+
{
812+
let mut path = self.eth_path(V1)?;
813+
814+
path.path_segments_mut()
815+
.map_err(|()| Error::InvalidUrl(self.server.clone()))?
816+
.push("beacon")
817+
.push("states")
818+
.push(&state_id.to_string())
819+
.push("pending_partial_withdrawals");
820+
821+
self.get_opt(path).await
822+
}
823+
785824
/// `GET beacon/light_client/updates`
786825
///
787826
/// Returns `Ok(None)` on a 404 error.

0 commit comments

Comments
 (0)