23
23
import tech .pegasys .teku .infrastructure .time .TimeProvider ;
24
24
import tech .pegasys .teku .infrastructure .unsigned .UInt64 ;
25
25
import tech .pegasys .teku .spec .Spec ;
26
- import tech .pegasys .teku .spec .config .SpecConfig ;
27
26
import tech .pegasys .teku .spec .datastructures .execution .ExecutionPayloadContext ;
28
27
import tech .pegasys .teku .spec .executionlayer .ExecutionLayerChannel ;
29
28
import tech .pegasys .teku .spec .executionlayer .ForkChoiceState ;
29
+ import tech .pegasys .teku .spec .executionlayer .PayloadBuildingAttributes ;
30
30
import tech .pegasys .teku .statetransition .forkchoice .ForkChoiceUpdatedResultSubscriber .ForkChoiceUpdatedResultNotification ;
31
- import tech .pegasys .teku .statetransition .forkchoice .ProposersDataManager .ProposersDataManagerSubscriber ;
32
31
import tech .pegasys .teku .storage .client .RecentChainData ;
33
32
34
- public class ForkChoiceNotifierImpl implements ForkChoiceNotifier , ProposersDataManagerSubscriber {
33
+ public class ForkChoiceNotifierImpl implements ForkChoiceNotifier {
35
34
private static final Logger LOG = LogManager .getLogger ();
36
35
37
36
private final EventThread eventThread ;
@@ -64,7 +63,6 @@ public ForkChoiceNotifierImpl(
64
63
this .recentChainData = recentChainData ;
65
64
this .proposersDataManager = proposersDataManager ;
66
65
this .timeProvider = timeProvider ;
67
- proposersDataManager .subscribeToProposersDataChanges (this );
68
66
}
69
67
70
68
@ Override
@@ -107,14 +105,6 @@ public boolean validatorIsConnected(UInt64 validatorIndex, UInt64 currentSlot) {
107
105
return proposersDataManager .validatorIsConnected (validatorIndex , currentSlot );
108
106
}
109
107
110
- @ Override
111
- public void onPreparedProposersUpdated () {
112
- eventThread .execute (this ::internalUpdatePreparableProposers );
113
- }
114
-
115
- @ Override
116
- public void onValidatorRegistrationsUpdated () {}
117
-
118
108
private void internalTerminalBlockReached (Bytes32 executionBlockHash ) {
119
109
eventThread .checkOnEventThread ();
120
110
LOG .debug ("internalTerminalBlockReached executionBlockHash {}" , executionBlockHash );
@@ -198,18 +188,6 @@ private SafeFuture<Optional<ExecutionPayloadContext>> internalGetPayloadId(
198
188
}
199
189
}
200
190
201
- private void internalUpdatePreparableProposers () {
202
- eventThread .checkOnEventThread ();
203
-
204
- LOG .debug ("internalUpdatePreparableProposers" );
205
-
206
- // Default to the genesis slot if we're pre-genesis.
207
- final UInt64 currentSlot = recentChainData .getCurrentSlot ().orElse (SpecConfig .GENESIS_SLOT );
208
-
209
- // Update payload attributes in case we now need to propose the next block
210
- updatePayloadAttributes (currentSlot .plus (1 ));
211
- }
212
-
213
191
private void internalForkChoiceUpdated (
214
192
final ForkChoiceState forkChoiceState , final Optional <UInt64 > proposingSlot ) {
215
193
eventThread .checkOnEventThread ();
@@ -220,14 +198,60 @@ private void internalForkChoiceUpdated(
220
198
221
199
LOG .debug ("internalForkChoiceUpdated forkChoiceUpdateData {}" , forkChoiceUpdateData );
222
200
223
- final Optional <UInt64 > attributesSlot =
224
- proposingSlot .or (() -> recentChainData .getCurrentSlot ().map (UInt64 ::increment ));
225
-
226
- attributesSlot .ifPresent (this ::updatePayloadAttributes );
201
+ calculatePayloadAttributesSlot (forkChoiceState , proposingSlot )
202
+ .ifPresent (this ::updatePayloadAttributes );
227
203
228
204
sendForkChoiceUpdated ();
229
205
}
230
206
207
+ /**
208
+ * Determine for which slot we should calculate payload attributes (block proposal)
209
+ *
210
+ * <pre>
211
+ * this will guarantee that whenever we calculate a payload attributes for a slot, it will remain stable until:
212
+ * 1. next slot attestation due is reached (internalAttestationsDue forcing attributes calculation for next slot)
213
+ * OR
214
+ * 2. we imported the block for current slot and has become the head
215
+ * </pre>
216
+ */
217
+ private Optional <UInt64 > calculatePayloadAttributesSlot (
218
+ final ForkChoiceState forkChoiceState , final Optional <UInt64 > proposingSlot ) {
219
+ if (proposingSlot .isPresent ()) {
220
+ // We are in the context of a block production, so we should use the proposing slot
221
+ return proposingSlot ;
222
+ }
223
+
224
+ final Optional <UInt64 > currentSlot = recentChainData .getCurrentSlot ();
225
+ if (currentSlot .isEmpty ()) {
226
+ // We are pre-genesis, so we don't care about proposing slots
227
+ return Optional .empty ();
228
+ }
229
+
230
+ final Optional <UInt64 > maybeCurrentPayloadAttributesSlot =
231
+ forkChoiceUpdateData
232
+ .getPayloadBuildingAttributes ()
233
+ .map (PayloadBuildingAttributes ::getProposalSlot );
234
+
235
+ if (maybeCurrentPayloadAttributesSlot .isPresent ()
236
+ // we are still in the same slot as the last proposing slot
237
+ && currentSlot .get ().equals (maybeCurrentPayloadAttributesSlot .get ())
238
+ // we have not yet imported our own produced block
239
+ && forkChoiceState .getHeadBlockSlot ().isLessThan (maybeCurrentPayloadAttributesSlot .get ())) {
240
+
241
+ LOG .debug (
242
+ "current payload attributes slot has been chosen for payload attributes calculation: {}" ,
243
+ currentSlot .get ());
244
+
245
+ // in case we propose two blocks in a row and we fail producing the first block,
246
+ // we won't keep using the same first slot because internalAttestationsDue will
247
+ // update the payload attributes for the second block slot
248
+ return currentSlot ;
249
+ }
250
+
251
+ // chain advanced since last proposing slot, we should consider attributes for the next slot
252
+ return currentSlot .map (UInt64 ::increment );
253
+ }
254
+
231
255
private void internalAttestationsDue (final UInt64 slot ) {
232
256
eventThread .checkOnEventThread ();
233
257
0 commit comments