diff --git a/vms/proposervm/block.go b/vms/proposervm/block.go index 464acb9fc8cd..d320a80543bc 100644 --- a/vms/proposervm/block.go +++ b/vms/proposervm/block.go @@ -369,7 +369,10 @@ func (p *postForkCommonComponents) verifyPostDurangoBlockDelay( currentSlot = proposer.TimeToSlot(parentTimestamp, blkTimestamp) proposerID = blk.Proposer() ) + // populate the slot for the block. + blk.slot = ¤tSlot + // find the expected proposer expectedProposerID, err := p.vm.Windower.ExpectedProposer( ctx, blkHeight, @@ -452,6 +455,11 @@ func (p *postForkCommonComponents) shouldBuildSignedBlockPostDurango( ) return false, err } + + // report the build slot to the metrics. + p.vm.proposerBuildSlotGauge.Set(float64(proposer.TimeToSlot(parentTimestamp, nextStartTime))) + + // set the scheduler to let us know when the next block need to be built. p.vm.Scheduler.SetBuildBlockTime(nextStartTime) // In case the inner VM only issued one pendingTxs message, we should diff --git a/vms/proposervm/block_test.go b/vms/proposervm/block_test.go index 12b18a75d681..d55a615537d0 100644 --- a/vms/proposervm/block_test.go +++ b/vms/proposervm/block_test.go @@ -396,8 +396,9 @@ func TestPostDurangoBuildChildResetScheduler(t *testing.T) { ValidatorState: vdrState, Log: logging.NoLog{}, }, - Windower: windower, - Scheduler: scheduler, + Windower: windower, + Scheduler: scheduler, + proposerBuildSlotGauge: prometheus.NewGauge(prometheus.GaugeOpts{}), } vm.Clock.Set(now) diff --git a/vms/proposervm/post_fork_block.go b/vms/proposervm/post_fork_block.go index 707b6dc327c7..2c875807eb79 100644 --- a/vms/proposervm/post_fork_block.go +++ b/vms/proposervm/post_fork_block.go @@ -17,6 +17,11 @@ var _ PostForkBlock = (*postForkBlock)(nil) type postForkBlock struct { block.SignedBlock postForkCommonComponents + + // slot of the proposer that produced this block. + // It is populated in verifyPostDurangoBlockDelay. + // It is used to report metrics during Accept. + slot *uint64 } // Accept: @@ -27,7 +32,13 @@ func (b *postForkBlock) Accept(ctx context.Context) error { if err := b.acceptOuterBlk(); err != nil { return err } - return b.acceptInnerBlk(ctx) + if err := b.acceptInnerBlk(ctx); err != nil { + return err + } + if b.slot != nil { + b.vm.acceptedBlocksSlotHistogram.Observe(float64(*b.slot)) + } + return nil } func (b *postForkBlock) acceptOuterBlk() error { diff --git a/vms/proposervm/vm.go b/vms/proposervm/vm.go index 4442aca65a9b..f5916fcf9f42 100644 --- a/vms/proposervm/vm.go +++ b/vms/proposervm/vm.go @@ -9,6 +9,7 @@ import ( "fmt" "time" + "github.com/prometheus/client_golang/prometheus" "go.uber.org/zap" "github.com/ava-labs/avalanchego/cache" @@ -22,6 +23,7 @@ import ( "github.com/ava-labs/avalanchego/snow/consensus/snowman" "github.com/ava-labs/avalanchego/snow/engine/common" "github.com/ava-labs/avalanchego/snow/engine/snowman/block" + "github.com/ava-labs/avalanchego/utils" "github.com/ava-labs/avalanchego/utils/constants" "github.com/ava-labs/avalanchego/utils/math" "github.com/ava-labs/avalanchego/utils/timer/mockable" @@ -97,6 +99,14 @@ type VM struct { // lastAcceptedHeight is set to the last accepted PostForkBlock's height. lastAcceptedHeight uint64 + + // proposerBuildSlotGauge reports the slot index when this node may attempt + // to build a block. + proposerBuildSlotGauge prometheus.Gauge + + // acceptedBlocksSlotHistogram reports the slots that accepted blocks were + // proposed in. + acceptedBlocksSlotHistogram prometheus.Histogram } // New performs best when [minBlkDelay] is whole seconds. This is because block @@ -206,7 +216,28 @@ func (vm *VM) Initialize( default: return err } - return nil + + vm.proposerBuildSlotGauge = prometheus.NewGauge(prometheus.GaugeOpts{ + Name: "block_building_slot", + Help: "the slot that this node may attempt to build a block", + }) + vm.acceptedBlocksSlotHistogram = prometheus.NewHistogram(prometheus.HistogramOpts{ + Name: "accepted_blocks_slot", + Help: "the slot accepted blocks were proposed in", + // define the following ranges: + // (-inf, 0] + // (0, 1] + // (1, 2] + // (2, inf) + // the usage of ".5" before was to ensure we work around the limitation + // of comparing floating point of the same numerical value. + Buckets: []float64{0.5, 1.5, 2.5}, + }) + + return utils.Err( + vm.Config.Registerer.Register(vm.proposerBuildSlotGauge), + vm.Config.Registerer.Register(vm.acceptedBlocksSlotHistogram), + ) } // shutdown ops then propagate shutdown to innerVM @@ -294,13 +325,15 @@ func (vm *VM) SetPreference(ctx context.Context, preferred ids.ID) error { ) if vm.IsDurangoActivated(parentTimestamp) { currentTime := vm.Clock.Time().Truncate(time.Second) - nextStartTime, err = vm.getPostDurangoSlotTime( + if nextStartTime, err = vm.getPostDurangoSlotTime( ctx, childBlockHeight, pChainHeight, proposer.TimeToSlot(parentTimestamp, currentTime), parentTimestamp, - ) + ); err == nil { + vm.proposerBuildSlotGauge.Set(float64(proposer.TimeToSlot(parentTimestamp, nextStartTime))) + } } else { nextStartTime, err = vm.getPreDurangoSlotTime( ctx,