Skip to content

Commit 1d92e3f

Browse files
committed
Use efficient payload reconstruction for HTTP API (#4102)
## Proposed Changes Builds on #4028 to use the new payload bodies methods in the HTTP API as well. ## Caveats The payloads by range method only works for the finalized chain, so it can't be used in the execution engine integration tests because we try to reconstruct unfinalized payloads there.
1 parent dd124b2 commit 1d92e3f

File tree

3 files changed

+54
-6
lines changed

3 files changed

+54
-6
lines changed

beacon_node/beacon_chain/src/beacon_chain.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1043,7 +1043,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
10431043
.execution_layer
10441044
.as_ref()
10451045
.ok_or(Error::ExecutionLayerMissing)?
1046-
.get_payload_by_block_hash(exec_block_hash, fork)
1046+
.get_payload_for_header(&execution_payload_header, fork)
10471047
.await
10481048
.map_err(|e| {
10491049
Error::ExecutionLayerErrorPayloadReconstruction(exec_block_hash, Box::new(e))

beacon_node/execution_layer/src/lib.rs

Lines changed: 51 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,8 @@ pub enum Error {
103103
transactions_root: Hash256,
104104
},
105105
InvalidJWTSecret(String),
106+
InvalidForkForPayload,
107+
InvalidPayloadBody(String),
106108
BeaconStateError(BeaconStateError),
107109
}
108110

@@ -1602,22 +1604,67 @@ impl<T: EthSpec> ExecutionLayer<T> {
16021604
.map_err(Error::EngineError)
16031605
}
16041606

1605-
pub async fn get_payload_by_block_hash(
1607+
/// Fetch a full payload from the execution node.
1608+
///
1609+
/// This will fail if the payload is not from the finalized portion of the chain.
1610+
pub async fn get_payload_for_header(
1611+
&self,
1612+
header: &ExecutionPayloadHeader<T>,
1613+
fork: ForkName,
1614+
) -> Result<Option<ExecutionPayload<T>>, Error> {
1615+
let hash = header.block_hash();
1616+
let block_number = header.block_number();
1617+
1618+
// Handle default payload body.
1619+
if header.block_hash() == ExecutionBlockHash::zero() {
1620+
let payload = match fork {
1621+
ForkName::Merge => ExecutionPayloadMerge::default().into(),
1622+
ForkName::Capella => ExecutionPayloadCapella::default().into(),
1623+
ForkName::Base | ForkName::Altair => {
1624+
return Err(Error::InvalidForkForPayload);
1625+
}
1626+
};
1627+
return Ok(Some(payload));
1628+
}
1629+
1630+
// Use efficient payload bodies by range method if supported.
1631+
let capabilities = self.get_engine_capabilities(None).await?;
1632+
if capabilities.get_payload_bodies_by_range_v1 {
1633+
let mut payload_bodies = self.get_payload_bodies_by_range(block_number, 1).await?;
1634+
1635+
if payload_bodies.len() != 1 {
1636+
return Ok(None);
1637+
}
1638+
1639+
let opt_payload_body = payload_bodies.pop().flatten();
1640+
opt_payload_body
1641+
.map(|body| {
1642+
body.to_payload(header.clone())
1643+
.map_err(Error::InvalidPayloadBody)
1644+
})
1645+
.transpose()
1646+
} else {
1647+
// Fall back to eth_blockByHash.
1648+
self.get_payload_by_hash_legacy(hash, fork).await
1649+
}
1650+
}
1651+
1652+
pub async fn get_payload_by_hash_legacy(
16061653
&self,
16071654
hash: ExecutionBlockHash,
16081655
fork: ForkName,
16091656
) -> Result<Option<ExecutionPayload<T>>, Error> {
16101657
self.engine()
16111658
.request(|engine| async move {
1612-
self.get_payload_by_block_hash_from_engine(engine, hash, fork)
1659+
self.get_payload_by_hash_from_engine(engine, hash, fork)
16131660
.await
16141661
})
16151662
.await
16161663
.map_err(Box::new)
16171664
.map_err(Error::EngineError)
16181665
}
16191666

1620-
async fn get_payload_by_block_hash_from_engine(
1667+
async fn get_payload_by_hash_from_engine(
16211668
&self,
16221669
engine: &Engine,
16231670
hash: ExecutionBlockHash,
@@ -1630,7 +1677,7 @@ impl<T: EthSpec> ExecutionLayer<T> {
16301677
ForkName::Merge => Ok(Some(ExecutionPayloadMerge::default().into())),
16311678
ForkName::Capella => Ok(Some(ExecutionPayloadCapella::default().into())),
16321679
ForkName::Base | ForkName::Altair => Err(ApiError::UnsupportedForkVariant(
1633-
format!("called get_payload_by_block_hash_from_engine with {}", fork),
1680+
format!("called get_payload_by_hash_from_engine with {}", fork),
16341681
)),
16351682
};
16361683
}

testing/execution_engine_integration/src/test_rig.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -626,9 +626,10 @@ async fn check_payload_reconstruction<E: GenericExecutionEngine>(
626626
ee: &ExecutionPair<E, MainnetEthSpec>,
627627
payload: &ExecutionPayload<MainnetEthSpec>,
628628
) {
629+
// check via legacy eth_getBlockByHash
629630
let reconstructed = ee
630631
.execution_layer
631-
.get_payload_by_block_hash(payload.block_hash(), payload.fork_name())
632+
.get_payload_by_hash_legacy(payload.block_hash(), payload.fork_name())
632633
.await
633634
.unwrap()
634635
.unwrap();

0 commit comments

Comments
 (0)