mirror of
https://github.com/ChainSafe/lodestar.git
synced 2026-01-09 15:48:08 -05:00
fix: untrusted slot in network processor (#8466)
**Motivation** - we see different slots for the same root in `BlockInputSync` logs, this causes confusion - this was added last week in #8416 **Description** - the [root, slot] is not trusted in network processor because messages could be originated from an out-of-sync node - we actually don't need the slot in BlockInputSync, it's just a nice to have but caused confusion. So I reverted that part: do not emit slot to `BlockInputSync` from network processor - log the full root hex Closes #8465 --------- Co-authored-by: Tuyen Nguyen <twoeths@users.noreply.github.com>
This commit is contained in:
@@ -3,7 +3,7 @@ import {StrictEventEmitter} from "strict-event-emitter-types";
|
||||
import {routes} from "@lodestar/api";
|
||||
import {CheckpointWithHex} from "@lodestar/fork-choice";
|
||||
import {CachedBeaconStateAllForks} from "@lodestar/state-transition";
|
||||
import {RootOptionalSlot, deneb, fulu, phase0} from "@lodestar/types";
|
||||
import {RootHex, deneb, fulu, phase0} from "@lodestar/types";
|
||||
import {PeerIdStr} from "../util/peerId.js";
|
||||
import {BlockInputSource, IBlockInput} from "./blocks/blockInput/types.js";
|
||||
|
||||
@@ -76,7 +76,7 @@ type ApiEvents = {[K in routes.events.EventType]: (data: routes.events.EventData
|
||||
|
||||
export type ChainEventData = {
|
||||
[ChainEvent.unknownParent]: {blockInput: IBlockInput; peer: PeerIdStr; source: BlockInputSource};
|
||||
[ChainEvent.unknownBlockRoot]: {rootSlot: RootOptionalSlot; peer?: PeerIdStr; source: BlockInputSource};
|
||||
[ChainEvent.unknownBlockRoot]: {rootHex: RootHex; peer?: PeerIdStr; source: BlockInputSource};
|
||||
[ChainEvent.incompleteBlockInput]: {blockInput: IBlockInput; peer: PeerIdStr; source: BlockInputSource};
|
||||
};
|
||||
|
||||
|
||||
@@ -230,14 +230,13 @@ export class NetworkProcessor {
|
||||
return queue.getAll();
|
||||
}
|
||||
|
||||
searchUnknownSlotRoot(slotRoot: SlotRootHex, source: BlockInputSource, peer?: PeerIdStr): void {
|
||||
const {slot, root} = slotRoot;
|
||||
searchUnknownSlotRoot({slot, root}: SlotRootHex, source: BlockInputSource, peer?: PeerIdStr): void {
|
||||
if (this.chain.seenBlock(root) || this.unknownRootsBySlot.getOrDefault(slot).has(root)) {
|
||||
return;
|
||||
}
|
||||
// Search for the unknown block
|
||||
this.unknownRootsBySlot.getOrDefault(slot).add(root);
|
||||
this.chain.emitter.emit(ChainEvent.unknownBlockRoot, {rootSlot: slotRoot, peer, source});
|
||||
this.chain.emitter.emit(ChainEvent.unknownBlockRoot, {rootHex: root, peer, source});
|
||||
}
|
||||
|
||||
private onPendingGossipsubMessage(message: PendingGossipsubMessage): void {
|
||||
|
||||
@@ -37,8 +37,6 @@ export type PendingBlockInput = {
|
||||
export type PendingRootHex = {
|
||||
status: PendingBlockInputStatus.pending | PendingBlockInputStatus.fetching;
|
||||
rootHex: RootHex;
|
||||
// optional because we may not know the slot of parent_unknown event
|
||||
slot?: Slot;
|
||||
timeAddedSec: number;
|
||||
timeSyncedSec?: number;
|
||||
peerIdStrings: Set<string>;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import {ChainForkConfig} from "@lodestar/config";
|
||||
import {ForkSeq, INTERVALS_PER_SLOT} from "@lodestar/params";
|
||||
import {RequestError, RequestErrorCode} from "@lodestar/reqresp";
|
||||
import {RootHex, Slot} from "@lodestar/types";
|
||||
import {Logger, prettyBytes, prettyPrintIndices, pruneSetToMax, sleep} from "@lodestar/utils";
|
||||
import {RootHex} from "@lodestar/types";
|
||||
import {Logger, prettyPrintIndices, pruneSetToMax, sleep} from "@lodestar/utils";
|
||||
import {isBlockInputBlobs, isBlockInputColumns} from "../chain/blocks/blockInput/blockInput.js";
|
||||
import {BlockInputSource, IBlockInput} from "../chain/blocks/blockInput/types.js";
|
||||
import {BlockError, BlockErrorCode} from "../chain/errors/index.js";
|
||||
@@ -146,8 +146,7 @@ export class BlockInputSync {
|
||||
*/
|
||||
private onUnknownBlockRoot = (data: ChainEventData[ChainEvent.unknownBlockRoot]): void => {
|
||||
try {
|
||||
const {root, slot} = data.rootSlot;
|
||||
this.addByRootHex(root, slot, data.peer);
|
||||
this.addByRootHex(data.rootHex, data.peer);
|
||||
this.triggerUnknownBlockSearch();
|
||||
this.metrics?.blockInputSync.requests.inc({type: PendingBlockType.UNKNOWN_BLOCK_ROOT});
|
||||
this.metrics?.blockInputSync.source.inc({source: data.source});
|
||||
@@ -175,8 +174,7 @@ export class BlockInputSync {
|
||||
*/
|
||||
private onUnknownParent = (data: ChainEventData[ChainEvent.unknownParent]): void => {
|
||||
try {
|
||||
// we don't know the slot of parent, hence make it undefined
|
||||
this.addByRootHex(data.blockInput.parentRootHex, undefined, data.peer);
|
||||
this.addByRootHex(data.blockInput.parentRootHex, data.peer);
|
||||
this.addByBlockInput(data.blockInput, data.peer);
|
||||
this.triggerUnknownBlockSearch();
|
||||
this.metrics?.blockInputSync.requests.inc({type: PendingBlockType.UNKNOWN_PARENT});
|
||||
@@ -186,12 +184,11 @@ export class BlockInputSync {
|
||||
}
|
||||
};
|
||||
|
||||
private addByRootHex = (rootHex: RootHex, slot?: Slot, peerIdStr?: PeerIdStr): void => {
|
||||
private addByRootHex = (rootHex: RootHex, peerIdStr?: PeerIdStr): void => {
|
||||
let pendingBlock = this.pendingBlocks.get(rootHex);
|
||||
if (!pendingBlock) {
|
||||
pendingBlock = {
|
||||
status: PendingBlockInputStatus.pending,
|
||||
slot,
|
||||
rootHex: rootHex,
|
||||
peerIdStrings: new Set(),
|
||||
timeAddedSec: Date.now() / 1000,
|
||||
@@ -199,7 +196,7 @@ export class BlockInputSync {
|
||||
this.pendingBlocks.set(rootHex, pendingBlock);
|
||||
|
||||
this.logger.verbose("Added new rootHex to BlockInputSync.pendingBlocks", {
|
||||
rootHex: prettyBytes(pendingBlock.rootHex),
|
||||
root: pendingBlock.rootHex,
|
||||
peerIdStr: peerIdStr ?? "unknown peer",
|
||||
});
|
||||
}
|
||||
@@ -318,7 +315,7 @@ export class BlockInputSync {
|
||||
const rootHex = getBlockInputSyncCacheItemRootHex(block);
|
||||
const logCtx = {
|
||||
slot: getBlockInputSyncCacheItemSlot(block),
|
||||
blockRoot: prettyBytes(rootHex),
|
||||
root: rootHex,
|
||||
pendingBlocks: this.pendingBlocks.size,
|
||||
};
|
||||
|
||||
@@ -362,7 +359,7 @@ export class BlockInputSync {
|
||||
});
|
||||
this.removeAndDownScoreAllDescendants(block);
|
||||
} else {
|
||||
this.onUnknownBlockRoot({rootSlot: {root: pending.blockInput.parentRootHex}, source: BlockInputSource.byRoot});
|
||||
this.onUnknownBlockRoot({rootHex: pending.blockInput.parentRootHex, source: BlockInputSource.byRoot});
|
||||
}
|
||||
} else {
|
||||
this.metrics?.blockInputSync.downloadedBlocksError.inc();
|
||||
@@ -407,7 +404,7 @@ export class BlockInputSync {
|
||||
// eligible for proposer boost to prevent unbundling attack
|
||||
this.logger.verbose("Avoid proposer boost for this block of known proposer", {
|
||||
slot: blockSlot,
|
||||
blockRoot: prettyBytes(pendingBlock.blockInput.blockRootHex),
|
||||
root: pendingBlock.blockInput.blockRootHex,
|
||||
proposerIndex,
|
||||
});
|
||||
await sleep(this.proposerBoostSecWindow * 1000);
|
||||
@@ -500,7 +497,7 @@ export class BlockInputSync {
|
||||
: null;
|
||||
|
||||
const fetchStartSec = Date.now() / 1000;
|
||||
let slot = isPendingBlockInput(cacheItem) ? cacheItem.blockInput.slot : cacheItem.slot;
|
||||
let slot = isPendingBlockInput(cacheItem) ? cacheItem.blockInput.slot : undefined;
|
||||
if (slot !== undefined) {
|
||||
this.metrics?.blockInputSync.fetchBegin.observe(this.chain.clock.secFromSlot(slot, fetchStartSec));
|
||||
}
|
||||
@@ -515,7 +512,7 @@ export class BlockInputSync {
|
||||
const peerMeta = this.peerBalancer.bestPeerForPendingColumns(pendingColumns, excludedPeers);
|
||||
if (peerMeta === null) {
|
||||
// no more peer with needed columns to try, throw error
|
||||
let message = `Error fetching UnknownBlockRoot slot=${slot} blockRoot=${prettyBytes(rootHex)} after ${i}: cannot find peer`;
|
||||
let message = `Error fetching UnknownBlockRoot slot=${slot} root=${rootHex} after ${i}: cannot find peer`;
|
||||
if (pendingColumns) {
|
||||
message += ` with needed columns=${prettyPrintIndices(Array.from(pendingColumns))}`;
|
||||
}
|
||||
@@ -605,7 +602,7 @@ export class BlockInputSync {
|
||||
}
|
||||
} // end while loop over peers
|
||||
|
||||
const message = `Error fetching BlockInput with slot=${slot} blockRoot=${prettyBytes(rootHex)} after ${i - 1} attempts.`;
|
||||
const message = `Error fetching BlockInput with slot=${slot} root=${rootHex} after ${i - 1} attempts.`;
|
||||
|
||||
if (!isPendingBlockInput(cacheItem)) {
|
||||
throw Error(`${message} No block and no data was found.`);
|
||||
|
||||
@@ -176,7 +176,7 @@ describe("sync / unknown block sync for fulu", () => {
|
||||
break;
|
||||
case ChainEvent.unknownBlockRoot:
|
||||
bn2.chain.emitter.emit(ChainEvent.unknownBlockRoot, {
|
||||
rootSlot: {root: headSummary.blockRoot},
|
||||
rootHex: headSummary.blockRoot,
|
||||
peer: bn2.network.peerId.toString(),
|
||||
source: BlockInputSource.gossip,
|
||||
});
|
||||
|
||||
@@ -215,7 +215,7 @@ describe.skip(
|
||||
});
|
||||
} else {
|
||||
chain.emitter?.emit(ChainEvent.unknownBlockRoot, {
|
||||
rootSlot: {root: blockRootHexC},
|
||||
rootHex: blockRootHexC,
|
||||
peer,
|
||||
source: BlockInputSource.gossip,
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user