diff --git a/packages/beacon-node/src/chain/opPools/proposerPreferencesPool.ts b/packages/beacon-node/src/chain/opPools/proposerPreferencesPool.ts index 56eb1d87401b..7ecdaa15853f 100644 --- a/packages/beacon-node/src/chain/opPools/proposerPreferencesPool.ts +++ b/packages/beacon-node/src/chain/opPools/proposerPreferencesPool.ts @@ -17,7 +17,7 @@ import {toRootHex} from "@lodestar/utils"; export class ProposerPreferencesPool { private readonly bySlot = new Map>(); - /** Lookup for bid validation: matches `(bid.slot, get_proposer_dependent_root(parent_state, ...))`. */ + /** Lookup for bid validation: matches `(bid.slot, get_shuffling_dependent_root(store, bid.parent_block_root, epoch))`. */ get(slot: Slot, dependentRootHex: RootHex): gloas.SignedProposerPreferences | null { return this.bySlot.get(slot)?.get(dependentRootHex) ?? null; } diff --git a/packages/beacon-node/src/chain/validation/attestation.ts b/packages/beacon-node/src/chain/validation/attestation.ts index f3b7b8863f57..bb0dae257b80 100644 --- a/packages/beacon-node/src/chain/validation/attestation.ts +++ b/packages/beacon-node/src/chain/validation/attestation.ts @@ -319,10 +319,17 @@ async function validateAttestationNoSignatureCheck( // [REJECT] If `attestation.data.index == 1` (payload present for a past // block), the execution payload for `block` passes validation. // [IGNORE] When `attestation.data.index == 1` (payload present for a past block), - // the corresponding execution payload for `block` has been seen (a client MAY queue - // attestations for processing once the payload is retrieved and SHOULD request the - // payload envelope via `ExecutionPayloadEnvelopesByRoot`). - if (block !== null && attData.index === 1 && !chain.seenPayloadEnvelope(toRootHex(attData.beaconBlockRoot))) { + // the corresponding execution payload for `block` has been fully imported, including its + // data -- i.e. `is_payload_verified(store, beacon_block_root)` returns True (consensus-specs + // #5355). `forkChoice.hasPayloadHexUnsafe` is the equivalent of `root in store.payloads`: + // it is true only once the SignedExecutionPayloadEnvelope has been imported and verified, + // not merely seen on gossip. A client MAY queue attestations until the payload is imported + // and SHOULD request the payload envelope via `ExecutionPayloadEnvelopesByRoot`. + if ( + block !== null && + attData.index === 1 && + !chain.forkChoice.hasPayloadHexUnsafe(toRootHex(attData.beaconBlockRoot)) + ) { throw new AttestationError(GossipAction.IGNORE, { code: AttestationErrorCode.EXECUTION_PAYLOAD_NOT_SEEN, beaconBlockRoot: toRootHex(attData.beaconBlockRoot),