4040//! END
4141//!
4242//! ```
43+ use crate :: execution_payload:: {
44+ execute_payload, validate_execution_payload_for_gossip, validate_merge_block,
45+ } ;
4346use crate :: snapshot_cache:: PreProcessingSnapshot ;
4447use crate :: validator_monitor:: HISTORIC_EPOCHS as VALIDATOR_MONITOR_HISTORIC_EPOCHS ;
4548use crate :: validator_pubkey_cache:: ValidatorPubkeyCache ;
@@ -50,15 +53,14 @@ use crate::{
5053 } ,
5154 metrics, BeaconChain , BeaconChainError , BeaconChainTypes ,
5255} ;
53- use execution_layer:: ExecutePayloadResponseStatus ;
5456use fork_choice:: { ForkChoice , ForkChoiceStore , PayloadVerificationStatus } ;
5557use parking_lot:: RwLockReadGuard ;
56- use proto_array:: { Block as ProtoBlock , ExecutionStatus } ;
58+ use proto_array:: Block as ProtoBlock ;
5759use safe_arith:: ArithError ;
58- use slog:: { debug, error, info , Logger } ;
60+ use slog:: { debug, error, Logger } ;
5961use slot_clock:: SlotClock ;
6062use ssz:: Encode ;
61- use state_processing:: per_block_processing:: { is_execution_enabled , is_merge_block} ;
63+ use state_processing:: per_block_processing:: is_merge_block;
6264use state_processing:: {
6365 block_signature_verifier:: { BlockSignatureVerifier , Error as BlockSignatureVerifierError } ,
6466 per_block_processing, per_slot_processing,
@@ -71,9 +73,9 @@ use std::io::Write;
7173use store:: { Error as DBError , HotColdDB , HotStateSummary , KeyValueStore , StoreOp } ;
7274use tree_hash:: TreeHash ;
7375use types:: {
74- BeaconBlockRef , BeaconState , BeaconStateError , ChainSpec , CloneConfig , Epoch , EthSpec ,
75- ExecutionPayload , Hash256 , InconsistentFork , PublicKey , PublicKeyBytes , RelativeEpoch ,
76- SignedBeaconBlock , SignedBeaconBlockHeader , Slot ,
76+ BeaconBlockRef , BeaconState , BeaconStateError , ChainSpec , CloneConfig , Epoch , EthSpec , Hash256 ,
77+ InconsistentFork , PublicKey , PublicKeyBytes , RelativeEpoch , SignedBeaconBlock ,
78+ SignedBeaconBlockHeader , Slot ,
7779} ;
7880
7981/// Maximum block slot number. Block with slots bigger than this constant will NOT be processed.
@@ -266,38 +268,47 @@ pub enum ExecutionPayloadError {
266268 ///
267269 /// The block is invalid and the peer is faulty
268270 RejectedByExecutionEngine ,
269- /// The execution engine returned SYNCING for the payload
270- ///
271- /// ## Peer scoring
272- ///
273- /// It is not known if the block is valid or invalid.
274- ExecutionEngineIsSyncing ,
275271 /// The execution payload timestamp does not match the slot
276272 ///
277273 /// ## Peer scoring
278274 ///
279275 /// The block is invalid and the peer is faulty
280276 InvalidPayloadTimestamp { expected : u64 , found : u64 } ,
281- /// The execution payload transaction list data exceeds size limits
277+ /// The execution payload references an execution block that cannot trigger the merge.
282278 ///
283279 /// ## Peer scoring
284280 ///
285- /// The block is invalid and the peer is faulty
286- TransactionDataExceedsSizeLimit ,
287- /// The execution payload references an execution block that cannot trigger the merge.
281+ /// The block is invalid and the peer sent us a block that passes gossip propagation conditions,
282+ /// but is invalid upon further verification.
283+ InvalidTerminalPoWBlock { parent_hash : Hash256 } ,
284+ /// The `TERMINAL_BLOCK_HASH` is set, but the block has not reached the
285+ /// `TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH`.
288286 ///
289287 /// ## Peer scoring
290288 ///
291289 /// The block is invalid and the peer sent us a block that passes gossip propagation conditions,
292290 /// but is invalid upon further verification.
293- InvalidTerminalPoWBlock ,
294- /// The execution payload references execution blocks that are unavailable on our execution
295- /// nodes.
291+ InvalidActivationEpoch {
292+ activation_epoch : Epoch ,
293+ epoch : Epoch ,
294+ } ,
295+ /// The `TERMINAL_BLOCK_HASH` is set, but does not match the value specified by the block.
296296 ///
297297 /// ## Peer scoring
298298 ///
299- /// It's not clear if the peer is invalid or if it's on a different execution fork to us.
300- TerminalPoWBlockNotFound ,
299+ /// The block is invalid and the peer sent us a block that passes gossip propagation conditions,
300+ /// but is invalid upon further verification.
301+ InvalidTerminalBlockHash {
302+ terminal_block_hash : Hash256 ,
303+ payload_parent_hash : Hash256 ,
304+ } ,
305+ /// The execution node failed to provide a parent block to a known block. This indicates an
306+ /// issue with the execution node.
307+ ///
308+ /// ## Peer scoring
309+ ///
310+ /// The peer is not necessarily invalid.
311+ PoWParentMissing ( Hash256 ) ,
301312}
302313
303314impl From < execution_layer:: Error > for ExecutionPayloadError {
@@ -768,8 +779,8 @@ impl<T: BeaconChainTypes> GossipVerifiedBlock<T> {
768779 } ) ;
769780 }
770781
771- // validate the block's execution_payload
772- validate_execution_payload ( & parent_block, block. message ( ) , chain) ?;
782+ // Validate the block's execution_payload (if any).
783+ validate_execution_payload_for_gossip ( & parent_block, block. message ( ) , chain) ?;
773784
774785 Ok ( Self {
775786 block,
@@ -1103,83 +1114,16 @@ impl<'a, T: BeaconChainTypes> FullyVerifiedBlock<'a, T> {
11031114 // - Doing the check here means we can keep our fork-choice implementation "pure". I.e., no
11041115 // calls to remote servers.
11051116 if is_merge_block ( & state, block. message ( ) . body ( ) ) {
1106- let execution_layer = chain
1107- . execution_layer
1108- . as_ref ( )
1109- . ok_or ( ExecutionPayloadError :: NoExecutionConnection ) ?;
1110- let execution_payload =
1111- block
1112- . message ( )
1113- . body ( )
1114- . execution_payload ( )
1115- . ok_or_else ( || InconsistentFork {
1116- fork_at_slot : eth2:: types:: ForkName :: Merge ,
1117- object_fork : block. message ( ) . body ( ) . fork_name ( ) ,
1118- } ) ?;
1119-
1120- let is_valid_terminal_pow_block = execution_layer
1121- . block_on ( |execution_layer| {
1122- execution_layer. is_valid_terminal_pow_block_hash (
1123- execution_payload. parent_hash ,
1124- & chain. spec ,
1125- )
1126- } )
1127- . map_err ( ExecutionPayloadError :: from) ?;
1128-
1129- match is_valid_terminal_pow_block {
1130- Some ( true ) => Ok ( ( ) ) ,
1131- Some ( false ) => Err ( ExecutionPayloadError :: InvalidTerminalPoWBlock ) ,
1132- None => {
1133- info ! (
1134- chain. log,
1135- "Optimistically accepting terminal block" ;
1136- "block_hash" => ?execution_payload. parent_hash,
1137- "msg" => "the terminal block/parent was unavailable"
1138- ) ;
1139- Ok ( ( ) )
1140- }
1141- } ?;
1117+ validate_merge_block ( chain, block. message ( ) ) ?
11421118 }
11431119
1144- // This is the soonest we can run these checks as they must be called AFTER per_slot_processing
1120+ // The specification declares that this should be run *inside* `per_block_processing`,
1121+ // however we run it here to keep `per_block_processing` pure (i.e., no calls to external
1122+ // servers).
11451123 //
1146- // TODO(merge): handle the latest_valid_hash of an invalid payload.
1147- let ( _latest_valid_hash, payload_verification_status) =
1148- if is_execution_enabled ( & state, block. message ( ) . body ( ) ) {
1149- let execution_layer = chain
1150- . execution_layer
1151- . as_ref ( )
1152- . ok_or ( ExecutionPayloadError :: NoExecutionConnection ) ?;
1153- let execution_payload =
1154- block
1155- . message ( )
1156- . body ( )
1157- . execution_payload ( )
1158- . ok_or_else ( || InconsistentFork {
1159- fork_at_slot : eth2:: types:: ForkName :: Merge ,
1160- object_fork : block. message ( ) . body ( ) . fork_name ( ) ,
1161- } ) ?;
1162-
1163- let execute_payload_response = execution_layer
1164- . block_on ( |execution_layer| execution_layer. execute_payload ( execution_payload) ) ;
1165-
1166- match execute_payload_response {
1167- Ok ( ( status, latest_valid_hash) ) => match status {
1168- ExecutePayloadResponseStatus :: Valid => {
1169- ( latest_valid_hash, PayloadVerificationStatus :: Verified )
1170- }
1171- ExecutePayloadResponseStatus :: Invalid => {
1172- return Err ( ExecutionPayloadError :: RejectedByExecutionEngine . into ( ) ) ;
1173- }
1174- ExecutePayloadResponseStatus :: Syncing => {
1175- ( latest_valid_hash, PayloadVerificationStatus :: NotVerified )
1176- }
1177- } ,
1178- Err ( _) => ( None , PayloadVerificationStatus :: NotVerified ) ,
1179- }
1180- } else {
1181- ( None , PayloadVerificationStatus :: Irrelevant )
1182- } ;
1124+ // It is important that this function is called *after* `per_slot_processing`, since the
1125+ // `randao` may change.
1126+ let payload_verification_status = execute_payload ( chain, & state, block. message ( ) ) ?;
11831127
11841128 // If the block is sufficiently recent, notify the validator monitor.
11851129 if let Some ( slot) = chain. slot_clock . now ( ) {
@@ -1290,64 +1234,6 @@ impl<'a, T: BeaconChainTypes> FullyVerifiedBlock<'a, T> {
12901234 }
12911235}
12921236
1293- /// Validate the gossip block's execution_payload according to the checks described here:
1294- /// https://github.com/ethereum/consensus-specs/blob/dev/specs/merge/p2p-interface.md#beacon_block
1295- fn validate_execution_payload < T : BeaconChainTypes > (
1296- parent_block : & ProtoBlock ,
1297- block : BeaconBlockRef < ' _ , T :: EthSpec > ,
1298- chain : & BeaconChain < T > ,
1299- ) -> Result < ( ) , BlockError < T :: EthSpec > > {
1300- // Only apply this validation if this is a merge beacon block.
1301- if let Some ( execution_payload) = block. body ( ) . execution_payload ( ) {
1302- // This logic should match `is_execution_enabled`. We use only the execution block hash of
1303- // the parent here in order to avoid loading the parent state during gossip verification.
1304-
1305- let is_merge_complete = match parent_block. execution_status {
1306- // Optimistically declare that an "unknown" status block has completed the merge.
1307- ExecutionStatus :: Valid ( _) | ExecutionStatus :: Unknown ( _) => true ,
1308- // It's impossible for an irrelevant block to have completed the merge. It is pre-merge
1309- // by definition.
1310- ExecutionStatus :: Irrelevant ( _) => false ,
1311- // If the parent has an invalid payload then it's impossible to build a valid block upon
1312- // it. Reject the block.
1313- ExecutionStatus :: Invalid ( _) => {
1314- return Err ( BlockError :: ParentExecutionPayloadInvalid {
1315- parent_root : parent_block. root ,
1316- } )
1317- }
1318- } ;
1319- let is_merge_block =
1320- !is_merge_complete && * execution_payload != <ExecutionPayload < T :: EthSpec > >:: default ( ) ;
1321- if !is_merge_block && !is_merge_complete {
1322- return Ok ( ( ) ) ;
1323- }
1324-
1325- let expected_timestamp = chain
1326- . slot_clock
1327- . compute_timestamp_at_slot ( block. slot ( ) )
1328- . ok_or ( BlockError :: BeaconChainError (
1329- BeaconChainError :: UnableToComputeTimeAtSlot ,
1330- ) ) ?;
1331- // The block's execution payload timestamp is correct with respect to the slot
1332- if execution_payload. timestamp != expected_timestamp {
1333- return Err ( BlockError :: ExecutionPayloadError (
1334- ExecutionPayloadError :: InvalidPayloadTimestamp {
1335- expected : expected_timestamp,
1336- found : execution_payload. timestamp ,
1337- } ,
1338- ) ) ;
1339- }
1340- // The execution payload transaction list data is within expected size limits
1341- if execution_payload. transactions . len ( ) > T :: EthSpec :: max_transactions_per_payload ( ) {
1342- return Err ( BlockError :: ExecutionPayloadError (
1343- ExecutionPayloadError :: TransactionDataExceedsSizeLimit ,
1344- ) ) ;
1345- }
1346- }
1347-
1348- Ok ( ( ) )
1349- }
1350-
13511237/// Check that the count of skip slots between the block and its parent does not exceed our maximum
13521238/// value.
13531239///
0 commit comments