Skip to content

Commit

Permalink
Payload bodies for the HTTP API
Browse files Browse the repository at this point in the history
  • Loading branch information
michaelsproul committed Apr 17, 2023
1 parent dd124b2 commit cdef32e
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 21 deletions.
2 changes: 1 addition & 1 deletion beacon_node/beacon_chain/src/beacon_chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1043,7 +1043,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
.execution_layer
.as_ref()
.ok_or(Error::ExecutionLayerMissing)?
.get_payload_by_block_hash(exec_block_hash, fork)
.get_payload_for_header(&execution_payload_header, fork)
.await
.map_err(|e| {
Error::ExecutionLayerErrorPayloadReconstruction(exec_block_hash, Box::new(e))
Expand Down
44 changes: 40 additions & 4 deletions beacon_node/execution_layer/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1602,22 +1602,58 @@ impl<T: EthSpec> ExecutionLayer<T> {
.map_err(Error::EngineError)
}

pub async fn get_payload_by_block_hash(
pub async fn get_payload_for_header(
&self,
header: &ExecutionPayloadHeader<T>,
fork: ForkName,
) -> Result<Option<ExecutionPayload<T>>, Error> {
let hash = header.block_hash();
let block_number = header.block_number();

// Use efficient payload bodies by range method if supported.
let capabilities = self.get_engine_capabilities(None).await?;
if capabilities.get_payload_bodies_by_range_v1 {
let mut payload_bodies = self.get_payload_bodies_by_range(block_number, 1).await?;

if payload_bodies.len() != 1 {
return Ok(None);
}

// FIXME(sproul): error properly
let opt_payload_body = payload_bodies.pop().flatten();
Ok(opt_payload_body.and_then(|body| {
body.to_payload(header.clone())
.map_err(|e| {
warn!(
self.inner.log,
"Payload reconstruction failed";
"error" => e,
);
})
.ok()
}))
} else {
// Fall back to eth_blockByHash.
self.get_payload_by_hash_legacy(hash, fork).await
}
}

pub async fn get_payload_by_hash_legacy(
&self,
hash: ExecutionBlockHash,
fork: ForkName,
) -> Result<Option<ExecutionPayload<T>>, Error> {
self.engine()
.request(|engine| async move {
self.get_payload_by_block_hash_from_engine(engine, hash, fork)
self.get_payload_by_hash_from_engine(engine, hash, fork)
.await
})
.await
.map_err(Box::new)
.map_err(Error::EngineError)
}

async fn get_payload_by_block_hash_from_engine(
async fn get_payload_by_hash_from_engine(
&self,
engine: &Engine,
hash: ExecutionBlockHash,
Expand All @@ -1630,7 +1666,7 @@ impl<T: EthSpec> ExecutionLayer<T> {
ForkName::Merge => Ok(Some(ExecutionPayloadMerge::default().into())),
ForkName::Capella => Ok(Some(ExecutionPayloadCapella::default().into())),
ForkName::Base | ForkName::Altair => Err(ApiError::UnsupportedForkVariant(
format!("called get_payload_by_block_hash_from_engine with {}", fork),
format!("called get_payload_by_hash_from_engine with {}", fork),
)),
};
}
Expand Down
33 changes: 17 additions & 16 deletions testing/execution_engine_integration/src/test_rig.rs
Original file line number Diff line number Diff line change
Expand Up @@ -626,34 +626,35 @@ async fn check_payload_reconstruction<E: GenericExecutionEngine>(
ee: &ExecutionPair<E, MainnetEthSpec>,
payload: &ExecutionPayload<MainnetEthSpec>,
) {
let reconstructed = ee
.execution_layer
.get_payload_by_block_hash(payload.block_hash(), payload.fork_name())
.await
.unwrap()
.unwrap();
assert_eq!(reconstructed, *payload);
// also check via payload bodies method
// check that the engine supports the payload bodies methods
let capabilities = ee
.execution_layer
.get_engine_capabilities(None)
.await
.unwrap();
assert!(
// if the engine doesn't have these capabilities, we need to update the client in our tests
capabilities.get_payload_bodies_by_hash_v1 && capabilities.get_payload_bodies_by_range_v1,
"Testing engine does not support payload bodies methods"
);
let mut bodies = ee

// reconstruct using `get_payload_for_header`, which will use `getPayloadBodiesByRange`
let header = ExecutionPayloadHeader::from(payload.to_ref());
let reconstructed = ee
.execution_layer
.get_payload_bodies_by_hash(vec![payload.block_hash()])
.get_payload_for_header(&header, payload.fork_name())
.await
.unwrap()
.unwrap();
assert_eq!(bodies.len(), 1);
let body = bodies.pop().unwrap().unwrap();
let header = ExecutionPayloadHeader::from(payload.to_ref());
let reconstructed_from_body = body.to_payload(header).unwrap();
assert_eq!(reconstructed_from_body, *payload);
assert_eq!(reconstructed, *payload);

// also check via legacy `getBlockByHash` method
let reconstructed_by_hash = ee
.execution_layer
.get_payload_by_hash_legacy(payload.block_hash(), payload.fork_name())
.await
.unwrap()
.unwrap();
assert_eq!(reconstructed_by_hash, *payload);
}

/// Returns the duration since the unix epoch.
Expand Down

0 comments on commit cdef32e

Please sign in to comment.