Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New metric filtering missed blocks #3927

Merged
merged 10 commits into from
May 10, 2022
12 changes: 12 additions & 0 deletions dashboards/lodestar_general.json
Original file line number Diff line number Diff line change
Expand Up @@ -8632,6 +8632,18 @@
"interval": "",
"legendFormat": "till processed",
"refId": "B"
},
{
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"exemplar": false,
"expr": "delta(lodestar_gossip_block_elapsed_time_till_become_head_sum[$__rate_interval])\n/\ndelta(lodestar_gossip_block_elapsed_time_till_become_head_count[$__rate_interval])",
"hide": false,
"interval": "",
"legendFormat": "till become head",
"refId": "C"
}
],
"title": "Gossip Block Received Delay",
Expand Down
4 changes: 4 additions & 0 deletions packages/lodestar/src/chain/clock/LocalClock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,10 @@ export class LocalClock implements IBeaconClock {
});
}

secFromSlot(slot: Slot, toSec = Date.now() / 1000): number {
return toSec - (this.genesisTime + slot * this.config.SECONDS_PER_SLOT);
}

private onNextSlot = (slot?: Slot): void => {
const clockSlot = slot ?? getCurrentSlot(this.config, this.genesisTime);
// process multiple clock slots in the case the main thread has been saturated for > SECONDS_PER_SLOT
Expand Down
4 changes: 4 additions & 0 deletions packages/lodestar/src/chain/clock/interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,8 @@ export interface IBeaconClock {
* Rejects if the clock is aborted
*/
waitForSlot(slot: Slot): Promise<void>;
/**
* Return second from a slot to either toSec or now.
*/
secFromSlot(slot: Slot, toSec?: number): number;
}
13 changes: 12 additions & 1 deletion packages/lodestar/src/chain/eventHandlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -149,13 +149,23 @@ export async function onForkChoiceFinalized(this: BeaconChain, cp: CheckpointWit
}

export function onForkChoiceHead(this: BeaconChain, head: IProtoBlock): void {
const delaySec = this.clock.secFromSlot(head.slot);
this.logger.verbose("New chain head", {
headSlot: head.slot,
headRoot: head.blockRoot,
delaySec,
});
this.syncContributionAndProofPool.prune(head.slot);
this.seenContributionAndProof.prune(head.slot);
this.metrics?.headSlot.set(head.slot);

if (this.metrics) {
this.metrics.headSlot.set(head.slot);
// Only track "recent" blocks. Otherwise sync can distort this metrics heavily.
// We want to track recent blocks coming from gossip, unknown block sync, and API.
if (delaySec < 64 * this.config.SECONDS_PER_SLOT) {
this.metrics.elapsedTimeTillBecomeHead.observe(delaySec);
}
}
}

export function onForkChoiceReorg(this: BeaconChain, head: IProtoBlock, oldHead: IProtoBlock, depth: number): void {
Expand Down Expand Up @@ -184,6 +194,7 @@ export async function onBlock(
this.logger.verbose("Block processed", {
slot: block.message.slot,
root: blockRoot,
delaySec: this.clock.secFromSlot(block.message.slot),
});
}

Expand Down
13 changes: 9 additions & 4 deletions packages/lodestar/src/metrics/metrics/lodestar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -514,17 +514,22 @@ export function createLodestarMetrics(

// Gossip block
gossipBlock: {
elappsedTimeTillReceived: register.histogram({
elapsedTimeTillReceived: register.histogram({
name: "lodestar_gossip_block_elappsed_time_till_received",
help: "Time elappsed between block slot time and the time block received via gossip",
buckets: [0.1, 1, 10],
buckets: [0.5, 1, 2, 4, 6, 12],
}),
elappsedTimeTillProcessed: register.histogram({
elapsedTimeTillProcessed: register.histogram({
name: "lodestar_gossip_block_elappsed_time_till_processed",
help: "Time elappsed between block slot time and the time block processed",
buckets: [0.1, 1, 10],
buckets: [0.5, 1, 2, 4, 6, 12],
}),
},
elapsedTimeTillBecomeHead: register.histogram({
name: "lodestar_gossip_block_elapsed_time_till_become_head",
help: "Time elappsed between block slot time and the time block becomes head",
buckets: [0.5, 1, 2, 4, 6, 12],
}),

backfillSync: {
backfilledTillSlot: register.gauge({
Expand Down
2 changes: 1 addition & 1 deletion packages/lodestar/src/metrics/validatorMonitor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,7 @@ export function createValidatorMonitor(
const validator = validators.get(index);
// Returns the delay between the start of `block.slot` and `seenTimestamp`.
const delaySec = seenTimestampSec - (genesisTime + block.slot * config.SECONDS_PER_SLOT);
metrics.gossipBlock.elappsedTimeTillReceived.observe(delaySec);
metrics.gossipBlock.elapsedTimeTillReceived.observe(delaySec);
if (validator) {
metrics.validatorMonitor.beaconBlockTotal.inc({src, index});
metrics.validatorMonitor.beaconBlockDelaySeconds.observe({src, index}, delaySec);
Expand Down
6 changes: 4 additions & 2 deletions packages/lodestar/src/network/gossip/handlers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,11 +76,13 @@ export function getGossipHandlers(modules: ValidatorFnsModules, options: GossipH
[GossipType.beacon_block]: async (signedBlock, topic, peerIdStr, seenTimestampSec) => {
const slot = signedBlock.message.slot;
const blockHex = prettyBytes(config.getForkTypes(slot).BeaconBlock.hashTreeRoot(signedBlock.message));
const delaySec = chain.clock.secFromSlot(slot, seenTimestampSec);
logger.verbose("Received gossip block", {
slot: slot,
root: blockHex,
curentSlot: chain.clock.currentSlot,
peerId: peerIdStr,
delaySec,
});

try {
Expand Down Expand Up @@ -120,8 +122,8 @@ export function getGossipHandlers(modules: ValidatorFnsModules, options: GossipH
.processBlock(signedBlock, {validProposerSignature: true, blsVerifyOnMainThread: true})
.then(() => {
// Returns the delay between the start of `block.slot` and `current time`
const delaySec = Date.now() / 1000 - (chain.genesisTime + slot * config.SECONDS_PER_SLOT);
metrics?.gossipBlock.elappsedTimeTillProcessed.observe(delaySec);
const delaySec = chain.clock.secFromSlot(slot);
metrics?.gossipBlock.elapsedTimeTillProcessed.observe(delaySec);
})
.catch((e) => {
if (e instanceof BlockError) {
Expand Down
5 changes: 5 additions & 0 deletions packages/lodestar/test/utils/clock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,9 @@ export class ClockStatic implements IBeaconClock {
async waitForSlot(): Promise<void> {
//
}

secFromSlot(slot: number, toSec?: number): number {
// SECONDS_PER_SLOT = 6 in minimal config
return (toSec ?? Date.now() / 1000) - slot * 6;
}
}