Skip to content

Commit 036b797

Browse files
Add finalized to HTTP API responses (#3753)
## Issue Addressed #3708 ## Proposed Changes - Add `is_finalized_block` method to `BeaconChain` in `beacon_node/beacon_chain/src/beacon_chain.rs`. - Add `is_finalized_state` method to `BeaconChain` in `beacon_node/beacon_chain/src/beacon_chain.rs`. - Add `fork_and_execution_optimistic_and_finalized` in `beacon_node/http_api/src/state_id.rs`. - Add `ExecutionOptimisticFinalizedForkVersionedResponse` type in `consensus/types/src/fork_versioned_response.rs`. - Add `execution_optimistic_finalized_fork_versioned_response`function in `beacon_node/http_api/src/version.rs`. - Add `ExecutionOptimisticFinalizedResponse` type in `common/eth2/src/types.rs`. - Add `add_execution_optimistic_finalized` method in `common/eth2/src/types.rs`. - Update API response methods to include finalized. - Remove `execution_optimistic_fork_versioned_response` Co-authored-by: Michael Sproul <michael@sigmaprime.io>
1 parent 12205a8 commit 036b797

File tree

16 files changed

+1118
-571
lines changed

16 files changed

+1118
-571
lines changed

Cargo.lock

Lines changed: 402 additions & 339 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

beacon_node/beacon_chain/src/beacon_chain.rs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -432,6 +432,46 @@ pub struct BeaconChain<T: BeaconChainTypes> {
432432
type BeaconBlockAndState<T, Payload> = (BeaconBlock<T, Payload>, BeaconState<T>);
433433

434434
impl<T: BeaconChainTypes> BeaconChain<T> {
435+
/// Checks if a block is finalized.
436+
/// The finalization check is done with the block slot. The block root is used to verify that
437+
/// the finalized slot is in the canonical chain.
438+
pub fn is_finalized_block(
439+
&self,
440+
block_root: &Hash256,
441+
block_slot: Slot,
442+
) -> Result<bool, Error> {
443+
let finalized_slot = self
444+
.canonical_head
445+
.cached_head()
446+
.finalized_checkpoint()
447+
.epoch
448+
.start_slot(T::EthSpec::slots_per_epoch());
449+
let is_canonical = self
450+
.block_root_at_slot(block_slot, WhenSlotSkipped::None)?
451+
.map_or(false, |canonical_root| block_root == &canonical_root);
452+
Ok(block_slot <= finalized_slot && is_canonical)
453+
}
454+
455+
/// Checks if a state is finalized.
456+
/// The finalization check is done with the slot. The state root is used to verify that
457+
/// the finalized state is in the canonical chain.
458+
pub fn is_finalized_state(
459+
&self,
460+
state_root: &Hash256,
461+
state_slot: Slot,
462+
) -> Result<bool, Error> {
463+
let finalized_slot = self
464+
.canonical_head
465+
.cached_head()
466+
.finalized_checkpoint()
467+
.epoch
468+
.start_slot(T::EthSpec::slots_per_epoch());
469+
let is_canonical = self
470+
.state_root_at_slot(state_slot)?
471+
.map_or(false, |canonical_root| state_root == &canonical_root);
472+
Ok(state_slot <= finalized_slot && is_canonical)
473+
}
474+
435475
/// Persists the head tracker and fork choice.
436476
///
437477
/// We do it atomically even though no guarantees need to be made about blocks from

beacon_node/http_api/src/attester_duties.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,8 +114,10 @@ fn compute_historic_attester_duties<T: BeaconChainTypes>(
114114
)?;
115115
(state, execution_optimistic)
116116
} else {
117-
StateId::from_slot(request_epoch.start_slot(T::EthSpec::slots_per_epoch()))
118-
.state(chain)?
117+
let (state, execution_optimistic, _finalized) =
118+
StateId::from_slot(request_epoch.start_slot(T::EthSpec::slots_per_epoch()))
119+
.state(chain)?;
120+
(state, execution_optimistic)
119121
};
120122

121123
// Sanity-check the state lookup.

beacon_node/http_api/src/block_id.rs

Lines changed: 56 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,15 @@ use eth2::types::BlockId as CoreBlockId;
44
use std::fmt;
55
use std::str::FromStr;
66
use std::sync::Arc;
7-
use types::{Hash256, SignedBeaconBlock, SignedBlindedBeaconBlock, Slot};
7+
use types::{EthSpec, Hash256, SignedBeaconBlock, SignedBlindedBeaconBlock, Slot};
88

99
/// Wraps `eth2::types::BlockId` and provides a simple way to obtain a block or root for a given
1010
/// `BlockId`.
1111
#[derive(Debug)]
1212
pub struct BlockId(pub CoreBlockId);
1313

14+
type Finalized = bool;
15+
1416
impl BlockId {
1517
pub fn from_slot(slot: Slot) -> Self {
1618
Self(CoreBlockId::Slot(slot))
@@ -24,7 +26,7 @@ impl BlockId {
2426
pub fn root<T: BeaconChainTypes>(
2527
&self,
2628
chain: &BeaconChain<T>,
27-
) -> Result<(Hash256, ExecutionOptimistic), warp::Rejection> {
29+
) -> Result<(Hash256, ExecutionOptimistic, Finalized), warp::Rejection> {
2830
match &self.0 {
2931
CoreBlockId::Head => {
3032
let (cached_head, execution_status) = chain
@@ -34,22 +36,23 @@ impl BlockId {
3436
Ok((
3537
cached_head.head_block_root(),
3638
execution_status.is_optimistic_or_invalid(),
39+
false,
3740
))
3841
}
39-
CoreBlockId::Genesis => Ok((chain.genesis_block_root, false)),
42+
CoreBlockId::Genesis => Ok((chain.genesis_block_root, false, true)),
4043
CoreBlockId::Finalized => {
4144
let finalized_checkpoint =
4245
chain.canonical_head.cached_head().finalized_checkpoint();
4346
let (_slot, execution_optimistic) =
4447
checkpoint_slot_and_execution_optimistic(chain, finalized_checkpoint)?;
45-
Ok((finalized_checkpoint.root, execution_optimistic))
48+
Ok((finalized_checkpoint.root, execution_optimistic, true))
4649
}
4750
CoreBlockId::Justified => {
4851
let justified_checkpoint =
4952
chain.canonical_head.cached_head().justified_checkpoint();
5053
let (_slot, execution_optimistic) =
5154
checkpoint_slot_and_execution_optimistic(chain, justified_checkpoint)?;
52-
Ok((justified_checkpoint.root, execution_optimistic))
55+
Ok((justified_checkpoint.root, execution_optimistic, false))
5356
}
5457
CoreBlockId::Slot(slot) => {
5558
let execution_optimistic = chain
@@ -66,7 +69,14 @@ impl BlockId {
6669
))
6770
})
6871
})?;
69-
Ok((root, execution_optimistic))
72+
let finalized = *slot
73+
<= chain
74+
.canonical_head
75+
.cached_head()
76+
.finalized_checkpoint()
77+
.epoch
78+
.start_slot(T::EthSpec::slots_per_epoch());
79+
Ok((root, execution_optimistic, finalized))
7080
}
7181
CoreBlockId::Root(root) => {
7282
// This matches the behaviour of other consensus clients (e.g. Teku).
@@ -88,7 +98,20 @@ impl BlockId {
8898
.is_optimistic_or_invalid_block(root)
8999
.map_err(BeaconChainError::ForkChoiceError)
90100
.map_err(warp_utils::reject::beacon_chain_error)?;
91-
Ok((*root, execution_optimistic))
101+
let blinded_block = chain
102+
.get_blinded_block(root)
103+
.map_err(warp_utils::reject::beacon_chain_error)?
104+
.ok_or_else(|| {
105+
warp_utils::reject::custom_not_found(format!(
106+
"beacon block with root {}",
107+
root
108+
))
109+
})?;
110+
let block_slot = blinded_block.slot();
111+
let finalized = chain
112+
.is_finalized_block(root, block_slot)
113+
.map_err(warp_utils::reject::beacon_chain_error)?;
114+
Ok((*root, execution_optimistic, finalized))
92115
} else {
93116
Err(warp_utils::reject::custom_not_found(format!(
94117
"beacon block with root {}",
@@ -103,7 +126,14 @@ impl BlockId {
103126
pub fn blinded_block<T: BeaconChainTypes>(
104127
&self,
105128
chain: &BeaconChain<T>,
106-
) -> Result<(SignedBlindedBeaconBlock<T::EthSpec>, ExecutionOptimistic), warp::Rejection> {
129+
) -> Result<
130+
(
131+
SignedBlindedBeaconBlock<T::EthSpec>,
132+
ExecutionOptimistic,
133+
Finalized,
134+
),
135+
warp::Rejection,
136+
> {
107137
match &self.0 {
108138
CoreBlockId::Head => {
109139
let (cached_head, execution_status) = chain
@@ -113,10 +143,11 @@ impl BlockId {
113143
Ok((
114144
cached_head.snapshot.beacon_block.clone_as_blinded(),
115145
execution_status.is_optimistic_or_invalid(),
146+
false,
116147
))
117148
}
118149
CoreBlockId::Slot(slot) => {
119-
let (root, execution_optimistic) = self.root(chain)?;
150+
let (root, execution_optimistic, finalized) = self.root(chain)?;
120151
chain
121152
.get_blinded_block(&root)
122153
.map_err(warp_utils::reject::beacon_chain_error)
@@ -128,7 +159,7 @@ impl BlockId {
128159
slot
129160
)));
130161
}
131-
Ok((block, execution_optimistic))
162+
Ok((block, execution_optimistic, finalized))
132163
}
133164
None => Err(warp_utils::reject::custom_not_found(format!(
134165
"beacon block with root {}",
@@ -137,7 +168,7 @@ impl BlockId {
137168
})
138169
}
139170
_ => {
140-
let (root, execution_optimistic) = self.root(chain)?;
171+
let (root, execution_optimistic, finalized) = self.root(chain)?;
141172
let block = chain
142173
.get_blinded_block(&root)
143174
.map_err(warp_utils::reject::beacon_chain_error)
@@ -149,7 +180,7 @@ impl BlockId {
149180
))
150181
})
151182
})?;
152-
Ok((block, execution_optimistic))
183+
Ok((block, execution_optimistic, finalized))
153184
}
154185
}
155186
}
@@ -158,7 +189,14 @@ impl BlockId {
158189
pub async fn full_block<T: BeaconChainTypes>(
159190
&self,
160191
chain: &BeaconChain<T>,
161-
) -> Result<(Arc<SignedBeaconBlock<T::EthSpec>>, ExecutionOptimistic), warp::Rejection> {
192+
) -> Result<
193+
(
194+
Arc<SignedBeaconBlock<T::EthSpec>>,
195+
ExecutionOptimistic,
196+
Finalized,
197+
),
198+
warp::Rejection,
199+
> {
162200
match &self.0 {
163201
CoreBlockId::Head => {
164202
let (cached_head, execution_status) = chain
@@ -168,10 +206,11 @@ impl BlockId {
168206
Ok((
169207
cached_head.snapshot.beacon_block.clone(),
170208
execution_status.is_optimistic_or_invalid(),
209+
false,
171210
))
172211
}
173212
CoreBlockId::Slot(slot) => {
174-
let (root, execution_optimistic) = self.root(chain)?;
213+
let (root, execution_optimistic, finalized) = self.root(chain)?;
175214
chain
176215
.get_block(&root)
177216
.await
@@ -184,7 +223,7 @@ impl BlockId {
184223
slot
185224
)));
186225
}
187-
Ok((Arc::new(block), execution_optimistic))
226+
Ok((Arc::new(block), execution_optimistic, finalized))
188227
}
189228
None => Err(warp_utils::reject::custom_not_found(format!(
190229
"beacon block with root {}",
@@ -193,14 +232,14 @@ impl BlockId {
193232
})
194233
}
195234
_ => {
196-
let (root, execution_optimistic) = self.root(chain)?;
235+
let (root, execution_optimistic, finalized) = self.root(chain)?;
197236
chain
198237
.get_block(&root)
199238
.await
200239
.map_err(warp_utils::reject::beacon_chain_error)
201240
.and_then(|block_opt| {
202241
block_opt
203-
.map(|block| (Arc::new(block), execution_optimistic))
242+
.map(|block| (Arc::new(block), execution_optimistic, finalized))
204243
.ok_or_else(|| {
205244
warp_utils::reject::custom_not_found(format!(
206245
"beacon block with root {}",

0 commit comments

Comments
 (0)