diff --git a/packages/beacon-node/src/chain/blocks/verifyBlocksStateTransitionOnly.ts b/packages/beacon-node/src/chain/blocks/verifyBlocksStateTransitionOnly.ts index 2afc9543f847..709ad0c02b27 100644 --- a/packages/beacon-node/src/chain/blocks/verifyBlocksStateTransitionOnly.ts +++ b/packages/beacon-node/src/chain/blocks/verifyBlocksStateTransitionOnly.ts @@ -57,7 +57,7 @@ export async function verifyBlocksStateTransitionOnly( metrics ); - const hashTreeRootTimer = metrics?.stateHashTreeRootTime.startTimer(); + const hashTreeRootTimer = metrics?.stateHashTreeRootTime.startTimer({source: "block_transition"}); const stateRoot = postState.hashTreeRoot(); hashTreeRootTimer?.(); diff --git a/packages/beacon-node/src/chain/prepareNextSlot.ts b/packages/beacon-node/src/chain/prepareNextSlot.ts index 43fac1d1b120..ce8e720cd766 100644 --- a/packages/beacon-node/src/chain/prepareNextSlot.ts +++ b/packages/beacon-node/src/chain/prepareNextSlot.ts @@ -104,6 +104,12 @@ export class PrepareNextSlotScheduler { RegenCaller.precomputeEpoch ); + // cache HashObjects for faster hashTreeRoot() later, especially for computeNewStateRoot() if we need to produce a block at slot 0 of epoch + // see https://github.com/ChainSafe/lodestar/issues/6194 + const hashTreeRootTimer = this.metrics?.stateHashTreeRootTime.startTimer({source: "prepare_next_slot"}); + prepareState.hashTreeRoot(); + hashTreeRootTimer?.(); + // assuming there is no reorg, it caches the checkpoint state & helps avoid doing a full state transition in the next slot // + when gossip block comes, we need to validate and run state transition // + if next slot is a skipped slot, it'd help getting target checkpoint state faster to validate attestations diff --git a/packages/beacon-node/src/chain/produceBlock/computeNewStateRoot.ts b/packages/beacon-node/src/chain/produceBlock/computeNewStateRoot.ts index fcc2a97b42b1..f5d02dbf9b6f 100644 --- a/packages/beacon-node/src/chain/produceBlock/computeNewStateRoot.ts +++ b/packages/beacon-node/src/chain/produceBlock/computeNewStateRoot.ts @@ -44,5 +44,9 @@ export function computeNewStateRoot( const {attestations, syncAggregate, slashing} = postState.proposerRewards; const proposerReward = BigInt(attestations + syncAggregate + slashing); - return {newStateRoot: postState.hashTreeRoot(), proposerReward}; + const hashTreeRootTimer = metrics?.stateHashTreeRootTime.startTimer({source: "compute_new_state_root"}); + const newStateRoot = postState.hashTreeRoot(); + hashTreeRootTimer?.(); + + return {newStateRoot, proposerReward}; } diff --git a/packages/beacon-node/src/metrics/metrics/lodestar.ts b/packages/beacon-node/src/metrics/metrics/lodestar.ts index 64d43af9001d..8a22fe8f0a9b 100644 --- a/packages/beacon-node/src/metrics/metrics/lodestar.ts +++ b/packages/beacon-node/src/metrics/metrics/lodestar.ts @@ -304,10 +304,11 @@ export function createLodestarMetrics( help: "Time to call commit after process a single block in seconds", buckets: [0.005, 0.01, 0.02, 0.05, 0.1, 1], }), - stateHashTreeRootTime: register.histogram({ + stateHashTreeRootTime: register.histogram<"source">({ name: "lodestar_stfn_hash_tree_root_seconds", help: "Time to compute the hash tree root of a post state in seconds", - buckets: [0.005, 0.01, 0.02, 0.05, 0.1, 1], + buckets: [0.05, 0.1, 0.2, 0.5, 1, 1.5], + labelNames: ["source"], }), preStateBalancesNodesPopulatedMiss: register.gauge<"source">({ name: "lodestar_stfn_balances_nodes_populated_miss_total",