mirror of
https://github.com/sigp/lighthouse.git
synced 2026-03-14 18:32:42 +00:00
Add execution_optimistic flag to HTTP responses (#3070)
## Issue Addressed #3031 ## Proposed Changes Updates the following API endpoints to conform with https://github.com/ethereum/beacon-APIs/pull/190 and https://github.com/ethereum/beacon-APIs/pull/196 - [x] `beacon/states/{state_id}/root` - [x] `beacon/states/{state_id}/fork` - [x] `beacon/states/{state_id}/finality_checkpoints` - [x] `beacon/states/{state_id}/validators` - [x] `beacon/states/{state_id}/validators/{validator_id}` - [x] `beacon/states/{state_id}/validator_balances` - [x] `beacon/states/{state_id}/committees` - [x] `beacon/states/{state_id}/sync_committees` - [x] `beacon/headers` - [x] `beacon/headers/{block_id}` - [x] `beacon/blocks/{block_id}` - [x] `beacon/blocks/{block_id}/root` - [x] `beacon/blocks/{block_id}/attestations` - [x] `debug/beacon/states/{state_id}` - [x] `debug/beacon/heads` - [x] `validator/duties/attester/{epoch}` - [x] `validator/duties/proposer/{epoch}` - [x] `validator/duties/sync/{epoch}` Updates the following Server-Sent Events: - [x] `events?topics=head` - [x] `events?topics=block` - [x] `events?topics=finalized_checkpoint` - [x] `events?topics=chain_reorg` ## Backwards Incompatible There is a very minor breaking change with the way the API now handles requests to `beacon/blocks/{block_id}/root` and `beacon/states/{state_id}/root` when `block_id` or `state_id` is the `Root` variant of `BlockId` and `StateId` respectively. Previously a request to a non-existent root would simply echo the root back to the requester: ``` curl "http://localhost:5052/eth/v1/beacon/states/0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/root" {"data":{"root":"0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"}} ``` Now it will return a `404`: ``` curl "http://localhost:5052/eth/v1/beacon/blocks/0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/root" {"code":404,"message":"NOT_FOUND: beacon block with root 0xaaaa…aaaa","stacktraces":[]} ``` In addition to this is the block root `0x0000000000000000000000000000000000000000000000000000000000000000` previously would return the genesis block. It will now return a `404`: ``` curl "http://localhost:5052/eth/v1/beacon/blocks/0x0000000000000000000000000000000000000000000000000000000000000000" {"code":404,"message":"NOT_FOUND: beacon block with root 0x0000…0000","stacktraces":[]} ``` ## Additional Info - `execution_optimistic` is always set, and will return `false` pre-Bellatrix. I am also open to the idea of doing something like `#[serde(skip_serializing_if = "Option::is_none")]`. - The value of `execution_optimistic` is set to `false` where possible. Any computation that is reliant on the `head` will simply use the `ExecutionStatus` of the head (unless the head block is pre-Bellatrix). Co-authored-by: Paul Hauner <paul@paulhauner.com>
This commit is contained in:
@@ -1,8 +1,10 @@
|
||||
use beacon_chain::{BeaconChain, BeaconChainTypes, WhenSlotSkipped};
|
||||
use crate::{state_id::checkpoint_slot_and_execution_optimistic, ExecutionOptimistic};
|
||||
use beacon_chain::{BeaconChain, BeaconChainError, BeaconChainTypes, WhenSlotSkipped};
|
||||
use eth2::types::BlockId as CoreBlockId;
|
||||
use std::fmt;
|
||||
use std::str::FromStr;
|
||||
use std::sync::Arc;
|
||||
use types::{BlindedPayload, Hash256, SignedBeaconBlock, Slot};
|
||||
use types::{Hash256, SignedBeaconBlock, SignedBlindedBeaconBlock, Slot};
|
||||
|
||||
/// Wraps `eth2::types::BlockId` and provides a simple way to obtain a block or root for a given
|
||||
/// `BlockId`.
|
||||
@@ -22,32 +24,78 @@ impl BlockId {
|
||||
pub fn root<T: BeaconChainTypes>(
|
||||
&self,
|
||||
chain: &BeaconChain<T>,
|
||||
) -> Result<Hash256, warp::Rejection> {
|
||||
) -> Result<(Hash256, ExecutionOptimistic), warp::Rejection> {
|
||||
match &self.0 {
|
||||
CoreBlockId::Head => Ok(chain.canonical_head.cached_head().head_block_root()),
|
||||
CoreBlockId::Genesis => Ok(chain.genesis_block_root),
|
||||
CoreBlockId::Finalized => Ok(chain
|
||||
.canonical_head
|
||||
.cached_head()
|
||||
.finalized_checkpoint()
|
||||
.root),
|
||||
CoreBlockId::Justified => Ok(chain
|
||||
.canonical_head
|
||||
.cached_head()
|
||||
.justified_checkpoint()
|
||||
.root),
|
||||
CoreBlockId::Slot(slot) => chain
|
||||
.block_root_at_slot(*slot, WhenSlotSkipped::None)
|
||||
.map_err(warp_utils::reject::beacon_chain_error)
|
||||
.and_then(|root_opt| {
|
||||
root_opt.ok_or_else(|| {
|
||||
warp_utils::reject::custom_not_found(format!(
|
||||
"beacon block at slot {}",
|
||||
slot
|
||||
))
|
||||
})
|
||||
}),
|
||||
CoreBlockId::Root(root) => Ok(*root),
|
||||
CoreBlockId::Head => {
|
||||
let (cached_head, execution_status) = chain
|
||||
.canonical_head
|
||||
.head_and_execution_status()
|
||||
.map_err(warp_utils::reject::beacon_chain_error)?;
|
||||
Ok((
|
||||
cached_head.head_block_root(),
|
||||
execution_status.is_optimistic(),
|
||||
))
|
||||
}
|
||||
CoreBlockId::Genesis => Ok((chain.genesis_block_root, false)),
|
||||
CoreBlockId::Finalized => {
|
||||
let finalized_checkpoint =
|
||||
chain.canonical_head.cached_head().finalized_checkpoint();
|
||||
let (_slot, execution_optimistic) =
|
||||
checkpoint_slot_and_execution_optimistic(chain, finalized_checkpoint)?;
|
||||
Ok((finalized_checkpoint.root, execution_optimistic))
|
||||
}
|
||||
CoreBlockId::Justified => {
|
||||
let justified_checkpoint =
|
||||
chain.canonical_head.cached_head().justified_checkpoint();
|
||||
let (_slot, execution_optimistic) =
|
||||
checkpoint_slot_and_execution_optimistic(chain, justified_checkpoint)?;
|
||||
Ok((justified_checkpoint.root, execution_optimistic))
|
||||
}
|
||||
CoreBlockId::Slot(slot) => {
|
||||
let execution_optimistic = chain
|
||||
.is_optimistic_head()
|
||||
.map_err(warp_utils::reject::beacon_chain_error)?;
|
||||
let root = chain
|
||||
.block_root_at_slot(*slot, WhenSlotSkipped::None)
|
||||
.map_err(warp_utils::reject::beacon_chain_error)
|
||||
.and_then(|root_opt| {
|
||||
root_opt.ok_or_else(|| {
|
||||
warp_utils::reject::custom_not_found(format!(
|
||||
"beacon block at slot {}",
|
||||
slot
|
||||
))
|
||||
})
|
||||
})?;
|
||||
Ok((root, execution_optimistic))
|
||||
}
|
||||
CoreBlockId::Root(root) => {
|
||||
// This matches the behaviour of other consensus clients (e.g. Teku).
|
||||
if root == &Hash256::zero() {
|
||||
return Err(warp_utils::reject::custom_not_found(format!(
|
||||
"beacon block with root {}",
|
||||
root
|
||||
)));
|
||||
};
|
||||
if chain
|
||||
.store
|
||||
.block_exists(root)
|
||||
.map_err(BeaconChainError::DBError)
|
||||
.map_err(warp_utils::reject::beacon_chain_error)?
|
||||
{
|
||||
let execution_optimistic = chain
|
||||
.canonical_head
|
||||
.fork_choice_read_lock()
|
||||
.is_optimistic_block(root)
|
||||
.map_err(BeaconChainError::ForkChoiceError)
|
||||
.map_err(warp_utils::reject::beacon_chain_error)?;
|
||||
Ok((*root, execution_optimistic))
|
||||
} else {
|
||||
return Err(warp_utils::reject::custom_not_found(format!(
|
||||
"beacon block with root {}",
|
||||
root
|
||||
)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,11 +103,20 @@ impl BlockId {
|
||||
pub fn blinded_block<T: BeaconChainTypes>(
|
||||
&self,
|
||||
chain: &BeaconChain<T>,
|
||||
) -> Result<SignedBeaconBlock<T::EthSpec, BlindedPayload<T::EthSpec>>, warp::Rejection> {
|
||||
) -> Result<(SignedBlindedBeaconBlock<T::EthSpec>, ExecutionOptimistic), warp::Rejection> {
|
||||
match &self.0 {
|
||||
CoreBlockId::Head => Ok(chain.head_beacon_block().clone_as_blinded()),
|
||||
CoreBlockId::Head => {
|
||||
let (cached_head, execution_status) = chain
|
||||
.canonical_head
|
||||
.head_and_execution_status()
|
||||
.map_err(warp_utils::reject::beacon_chain_error)?;
|
||||
Ok((
|
||||
cached_head.snapshot.beacon_block.clone_as_blinded(),
|
||||
execution_status.is_optimistic(),
|
||||
))
|
||||
}
|
||||
CoreBlockId::Slot(slot) => {
|
||||
let root = self.root(chain)?;
|
||||
let (root, execution_optimistic) = self.root(chain)?;
|
||||
chain
|
||||
.get_blinded_block(&root)
|
||||
.map_err(warp_utils::reject::beacon_chain_error)
|
||||
@@ -71,7 +128,7 @@ impl BlockId {
|
||||
slot
|
||||
)));
|
||||
}
|
||||
Ok(block)
|
||||
Ok((block, execution_optimistic))
|
||||
}
|
||||
None => Err(warp_utils::reject::custom_not_found(format!(
|
||||
"beacon block with root {}",
|
||||
@@ -80,8 +137,8 @@ impl BlockId {
|
||||
})
|
||||
}
|
||||
_ => {
|
||||
let root = self.root(chain)?;
|
||||
chain
|
||||
let (root, execution_optimistic) = self.root(chain)?;
|
||||
let block = chain
|
||||
.get_blinded_block(&root)
|
||||
.map_err(warp_utils::reject::beacon_chain_error)
|
||||
.and_then(|root_opt| {
|
||||
@@ -91,7 +148,8 @@ impl BlockId {
|
||||
root
|
||||
))
|
||||
})
|
||||
})
|
||||
})?;
|
||||
Ok((block, execution_optimistic))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -100,11 +158,20 @@ impl BlockId {
|
||||
pub async fn full_block<T: BeaconChainTypes>(
|
||||
&self,
|
||||
chain: &BeaconChain<T>,
|
||||
) -> Result<Arc<SignedBeaconBlock<T::EthSpec>>, warp::Rejection> {
|
||||
) -> Result<(Arc<SignedBeaconBlock<T::EthSpec>>, ExecutionOptimistic), warp::Rejection> {
|
||||
match &self.0 {
|
||||
CoreBlockId::Head => Ok(chain.head_beacon_block()),
|
||||
CoreBlockId::Head => {
|
||||
let (cached_head, execution_status) = chain
|
||||
.canonical_head
|
||||
.head_and_execution_status()
|
||||
.map_err(warp_utils::reject::beacon_chain_error)?;
|
||||
Ok((
|
||||
cached_head.snapshot.beacon_block.clone(),
|
||||
execution_status.is_optimistic(),
|
||||
))
|
||||
}
|
||||
CoreBlockId::Slot(slot) => {
|
||||
let root = self.root(chain)?;
|
||||
let (root, execution_optimistic) = self.root(chain)?;
|
||||
chain
|
||||
.get_block(&root)
|
||||
.await
|
||||
@@ -117,7 +184,7 @@ impl BlockId {
|
||||
slot
|
||||
)));
|
||||
}
|
||||
Ok(Arc::new(block))
|
||||
Ok((Arc::new(block), execution_optimistic))
|
||||
}
|
||||
None => Err(warp_utils::reject::custom_not_found(format!(
|
||||
"beacon block with root {}",
|
||||
@@ -126,18 +193,20 @@ impl BlockId {
|
||||
})
|
||||
}
|
||||
_ => {
|
||||
let root = self.root(chain)?;
|
||||
let (root, execution_optimistic) = self.root(chain)?;
|
||||
chain
|
||||
.get_block(&root)
|
||||
.await
|
||||
.map_err(warp_utils::reject::beacon_chain_error)
|
||||
.and_then(|block_opt| {
|
||||
block_opt.map(Arc::new).ok_or_else(|| {
|
||||
warp_utils::reject::custom_not_found(format!(
|
||||
"beacon block with root {}",
|
||||
root
|
||||
))
|
||||
})
|
||||
block_opt
|
||||
.map(|block| (Arc::new(block), execution_optimistic))
|
||||
.ok_or_else(|| {
|
||||
warp_utils::reject::custom_not_found(format!(
|
||||
"beacon block with root {}",
|
||||
root
|
||||
))
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -151,3 +220,9 @@ impl FromStr for BlockId {
|
||||
CoreBlockId::from_str(s).map(Self)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for BlockId {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user