Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 3 additions & 5 deletions packages/beacon-node/src/chain/blocks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,11 +108,9 @@ export async function processBlocks(
throw segmentExecStatus.execAborted.execError;
}

if (opts.skipVerifyBlockSignatures !== true) {
for (const blockInput of relevantBlocks) {
const block = blockInput.getBlock().message;
this.seenBlockProposers.add(block.slot, block.proposerIndex);
}
for (const blockInput of relevantBlocks) {
const block = blockInput.getBlock().message;
this.seenBlockProposers.add(block.slot, block.proposerIndex);
}

const {executionStatuses} = segmentExecStatus;
Expand Down
46 changes: 21 additions & 25 deletions packages/beacon-node/src/chain/blocks/verifyBlock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ import {
computeEpochAtSlot,
signedBlockToSignedHeader,
} from "@lodestar/state-transition";
import {IndexedAttestation, Slot, deneb, ssz} from "@lodestar/types";
import {toRootHex} from "@lodestar/utils";
import {IndexedAttestation, Slot, deneb} from "@lodestar/types";
import {getBlobKzgCommitments} from "../../util/dataColumns.js";
import {callInNextEventLoop} from "../../util/eventLoop.js";
import type {BeaconChain} from "../chain.js";
import {BlockError, BlockErrorCode} from "../errors/index.js";
import {BlockProcessOpts} from "../options.js";
Expand Down Expand Up @@ -193,34 +193,30 @@ export async function verifyBlocksInEpoch(
),

// All signatures at once
opts.skipVerifyBlockSignatures !== true
? verifyBlocksSignatures(
this.config,
this.bls,
this.logger,
this.metrics,
preState0,
blocks,
indexedAttestationsByBlock,
opts
)
: Promise.resolve({verifySignaturesTime: Date.now()}),
verifyBlocksSignatures(
this.config,
this.bls,
this.logger,
this.metrics,
preState0,
blocks,
indexedAttestationsByBlock,
opts
),

// TODO GLOAS: can verify payload signatures in batch too
// maybe chain with the above verifyBlocksSignatures()
]);

if (opts.skipVerifyBlockSignatures !== true) {
for (const block of blocks) {
const {slot, proposerIndex} = block.message;
const signedBlockHeader = signedBlockToSignedHeader(this.config, block);
const blockRoot = toRootHex(ssz.phase0.BeaconBlockHeader.hashTreeRoot(signedBlockHeader.message));
this.seenBlockProposers.observeBlockRoot(slot, proposerIndex, blockRoot, signedBlockHeader);
// Only produce a slashing while importing the block. A block that is verified before it is published
// must not be treated as equivocation evidence since it may never be seen by the network
if (opts.verifyOnly !== true && this.seenBlockProposers.isEquivocating(slot, proposerIndex)) {
this.processProposerEquivocation(slot, proposerIndex);
}
for (const blockInput of blockInputs) {
const block = blockInput.getBlock();
const {slot, proposerIndex} = block.message;
const signedBlockHeader = signedBlockToSignedHeader(this.config, block);
this.seenBlockProposers.observeBlockRoot(slot, proposerIndex, blockInput.blockRootHex, signedBlockHeader);
// Only produce a slashing while importing the block. A block that is verified before it is published
// must not be treated as equivocation evidence since it may never be seen by the network
if (opts.verifyOnly !== true && this.seenBlockProposers.isEquivocating(slot, proposerIndex)) {
callInNextEventLoop(() => this.processProposerEquivocation(slot, proposerIndex));
}
}

Expand Down
7 changes: 6 additions & 1 deletion packages/beacon-node/src/chain/chain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1217,7 +1217,12 @@ export class BeaconChain implements IBeaconChain {
this.emitter.emit(routes.events.EventType.proposerSlashing, proposerSlashing);
this.emitter.emit(ChainEvent.publishProposerSlashing, proposerSlashing);
this.metrics?.opPool.proposerSlashingsProduced.inc();
this.logger.info("Produced proposer slashing from observed equivocation", {slot: blockSlot, proposerIndex});
this.logger.info("Produced proposer slashing from observed equivocation", {
slot: blockSlot,
proposerIndex,
header1Root: toRootHex(ssz.phase0.BeaconBlockHeader.hashTreeRoot(header1.message)),
header2Root: toRootHex(ssz.phase0.BeaconBlockHeader.hashTreeRoot(header2.message)),
});
} finally {
this.producingProposerSlashing.delete(proposerIndex);
}
Expand Down
2 changes: 0 additions & 2 deletions packages/beacon-node/src/chain/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,6 @@ export type BlockProcessOpts = {
verifyOnly?: boolean;
/** Used to specify to skip execution payload validation */
skipVerifyExecutionPayload?: boolean;
/** Used to specify to skip block signatures validation */
skipVerifyBlockSignatures?: boolean;

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

per #9757 (comment), we should just remove it

};

export type PoolOpts = {
Expand Down
15 changes: 11 additions & 4 deletions packages/beacon-node/src/chain/seenCache/seenBlockProposers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import {Epoch, RootHex, Slot, ValidatorIndex, phase0} from "@lodestar/types";
import {MapDef} from "@lodestar/utils";

/** Two distinct block roots signed by the same proposer for the same slot are sufficient to establish an equivocation */
const MAX_BLOCK_ROOTS_PER_PROPOSAL = 2;
const MIN_EQUIVOCATION_BLOCK_ROOTS_PER_PROPOSAL = 2;

/**
* Keeps a cache to filter block proposals from the same validator in the same slot.
Expand Down Expand Up @@ -36,7 +36,8 @@ export class SeenBlockProposers {

isEquivocating(blockSlot: Slot, proposerIndex: ValidatorIndex): boolean {
return (
(this.signedBlockHeadersBySlot.get(blockSlot)?.get(proposerIndex)?.size ?? 0) >= MAX_BLOCK_ROOTS_PER_PROPOSAL
(this.signedBlockHeadersBySlot.get(blockSlot)?.get(proposerIndex)?.size ?? 0) >=
MIN_EQUIVOCATION_BLOCK_ROOTS_PER_PROPOSAL
);
}

Expand All @@ -53,7 +54,10 @@ export class SeenBlockProposers {
proposerIndex: ValidatorIndex
): [phase0.SignedBeaconBlockHeader, phase0.SignedBeaconBlockHeader] | null {
const signedBlockHeaderByRoot = this.signedBlockHeadersBySlot.get(blockSlot)?.get(proposerIndex);
if (signedBlockHeaderByRoot === undefined || signedBlockHeaderByRoot.size < MAX_BLOCK_ROOTS_PER_PROPOSAL) {
if (
signedBlockHeaderByRoot === undefined ||
signedBlockHeaderByRoot.size < MIN_EQUIVOCATION_BLOCK_ROOTS_PER_PROPOSAL
) {
return null;
}
const [signedHeader1, signedHeader2] = signedBlockHeaderByRoot.values();
Expand All @@ -72,7 +76,10 @@ export class SeenBlockProposers {
}

const signedBlockHeaderByRoot = this.signedBlockHeadersBySlot.getOrDefault(blockSlot).getOrDefault(proposerIndex);
if (signedBlockHeaderByRoot.size < MAX_BLOCK_ROOTS_PER_PROPOSAL && !signedBlockHeaderByRoot.has(blockRoot)) {
if (
signedBlockHeaderByRoot.size < MIN_EQUIVOCATION_BLOCK_ROOTS_PER_PROPOSAL &&
!signedBlockHeaderByRoot.has(blockRoot)
) {
signedBlockHeaderByRoot.set(blockRoot, signedBlockHeader);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,8 +129,6 @@ describe("api - beacon - publishBlockV2", () => {
await api.publishBlockV2({signedBlockContents: {signedBlock}, broadcastValidation});

expect(verifyBlocksInEpoch).toHaveBeenCalledOnce();
const verifyOpts = vi.mocked(verifyBlocksInEpoch).mock.calls[0][3];
expect(verifyOpts.skipVerifyBlockSignatures).not.toBe(true);
expect(modules.network.publishBeaconBlock).toHaveBeenCalledWith(signedBlock);
}
);
Expand Down
Loading