@@ -47,7 +47,15 @@ import {
47
47
getValidatorStatus ,
48
48
} from "@lodestar/types" ;
49
49
import { ExecutionStatus , DataAvailabilityStatus } from "@lodestar/fork-choice" ;
50
- import { fromHex , toHex , resolveOrRacePromises , prettyWeiToEth , toRootHex } from "@lodestar/utils" ;
50
+ import {
51
+ fromHex ,
52
+ toHex ,
53
+ resolveOrRacePromises ,
54
+ prettyWeiToEth ,
55
+ toRootHex ,
56
+ TimeoutError ,
57
+ formatWeiToEth ,
58
+ } from "@lodestar/utils" ;
51
59
import {
52
60
AttestationError ,
53
61
AttestationErrorCode ,
@@ -115,6 +123,41 @@ type ProduceFullOrBlindedBlockOrContentsRes = {executionPayloadSource: ProducedB
115
123
| ( ProduceBlindedBlockRes & { executionPayloadBlinded : true } )
116
124
) ;
117
125
126
+ /**
127
+ * Engine block selection reasons tracked in metrics
128
+ */
129
+ export enum EngineBlockSelectionReason {
130
+ BuilderDisabled = "builder_disabled" ,
131
+ BuilderError = "builder_error" ,
132
+ BuilderTimeout = "builder_timeout" ,
133
+ BuilderPending = "builder_pending" ,
134
+ BuilderNoBid = "builder_no_bid" ,
135
+ BuilderCensorship = "builder_censorship" ,
136
+ BlockValue = "block_value" ,
137
+ EnginePreferred = "engine_preferred" ,
138
+ }
139
+
140
+ /**
141
+ * Builder block selection reasons tracked in metrics
142
+ */
143
+ export enum BuilderBlockSelectionReason {
144
+ EngineDisabled = "engine_disabled" ,
145
+ EngineError = "engine_error" ,
146
+ EnginePending = "engine_pending" ,
147
+ BlockValue = "block_value" ,
148
+ BuilderPreferred = "builder_preferred" ,
149
+ }
150
+
151
+ export type BlockSelectionResult =
152
+ | {
153
+ source : ProducedBlockSource . engine ;
154
+ reason : EngineBlockSelectionReason ;
155
+ }
156
+ | {
157
+ source : ProducedBlockSource . builder ;
158
+ reason : BuilderBlockSelectionReason ;
159
+ } ;
160
+
118
161
/**
119
162
* Server implementation for handling validator duties.
120
163
* See `@lodestar/validator/src/api` for the client implementation).
@@ -417,6 +460,7 @@ export function getValidatorApi(
417
460
418
461
metrics ?. blockProductionSuccess . inc ( { source} ) ;
419
462
metrics ?. blockProductionNumAggregated . observe ( { source} , block . body . attestations . length ) ;
463
+ metrics ?. blockProductionExecutionPayloadValue . observe ( { source} , Number ( formatWeiToEth ( executionPayloadValue ) ) ) ;
420
464
logger . verbose ( "Produced blinded block" , {
421
465
slot,
422
466
executionPayloadValue,
@@ -491,6 +535,7 @@ export function getValidatorApi(
491
535
492
536
metrics ?. blockProductionSuccess . inc ( { source} ) ;
493
537
metrics ?. blockProductionNumAggregated . observe ( { source} , block . body . attestations . length ) ;
538
+ metrics ?. blockProductionExecutionPayloadValue . observe ( { source} , Number ( formatWeiToEth ( executionPayloadValue ) ) ) ;
494
539
logger . verbose ( "Produced execution block" , {
495
540
slot,
496
541
executionPayloadValue,
@@ -694,6 +739,11 @@ export function getValidatorApi(
694
739
...getBlockValueLogInfo ( engine . value ) ,
695
740
} ) ;
696
741
742
+ metrics ?. blockProductionSelectionResults . inc ( {
743
+ source : ProducedBlockSource . engine ,
744
+ reason : EngineBlockSelectionReason . BuilderCensorship ,
745
+ } ) ;
746
+
697
747
return { ...engine . value , executionPayloadBlinded : false , executionPayloadSource : ProducedBlockSource . engine } ;
698
748
}
699
749
@@ -704,6 +754,16 @@ export function getValidatorApi(
704
754
...getBlockValueLogInfo ( builder . value ) ,
705
755
} ) ;
706
756
757
+ metrics ?. blockProductionSelectionResults . inc ( {
758
+ source : ProducedBlockSource . builder ,
759
+ reason :
760
+ isEngineEnabled === false
761
+ ? BuilderBlockSelectionReason . EngineDisabled
762
+ : engine . status === "pending"
763
+ ? BuilderBlockSelectionReason . EnginePending
764
+ : BuilderBlockSelectionReason . EngineError ,
765
+ } ) ;
766
+
707
767
return { ...builder . value , executionPayloadBlinded : true , executionPayloadSource : ProducedBlockSource . builder } ;
708
768
}
709
769
@@ -714,16 +774,33 @@ export function getValidatorApi(
714
774
...getBlockValueLogInfo ( engine . value ) ,
715
775
} ) ;
716
776
777
+ metrics ?. blockProductionSelectionResults . inc ( {
778
+ source : ProducedBlockSource . engine ,
779
+ reason :
780
+ isBuilderEnabled === false
781
+ ? EngineBlockSelectionReason . BuilderDisabled
782
+ : builder . status === "pending"
783
+ ? EngineBlockSelectionReason . BuilderPending
784
+ : builder . reason instanceof NoBidReceived
785
+ ? EngineBlockSelectionReason . BuilderNoBid
786
+ : builder . reason instanceof TimeoutError
787
+ ? EngineBlockSelectionReason . BuilderTimeout
788
+ : EngineBlockSelectionReason . BuilderError ,
789
+ } ) ;
790
+
717
791
return { ...engine . value , executionPayloadBlinded : false , executionPayloadSource : ProducedBlockSource . engine } ;
718
792
}
719
793
720
794
if ( engine . status === "fulfilled" && builder . status === "fulfilled" ) {
721
- const executionPayloadSource = selectBlockProductionSource ( {
795
+ const result = selectBlockProductionSource ( {
722
796
builderBlockValue : builder . value . executionPayloadValue + builder . value . consensusBlockValue ,
723
797
engineBlockValue : engine . value . executionPayloadValue + engine . value . consensusBlockValue ,
724
798
builderBoostFactor,
725
799
builderSelection,
726
800
} ) ;
801
+ const executionPayloadSource = result . source ;
802
+
803
+ metrics ?. blockProductionSelectionResults . inc ( result ) ;
727
804
728
805
logger . info ( `Selected ${ executionPayloadSource } block` , {
729
806
...loggerContext ,
0 commit comments