### Question:
BlockDutyScheduler extends AbstractDutyScheduler { @Override public void onBlockProductionDue(final UInt64 slot) { notifyDutyQueue(DutyQueue::onBlockProductionDue, slot); } BlockDutyScheduler(
      final MetricsSystem metricsSystem, final DutyLoader epochDutiesScheduler); @Override void onBlockProductionDue(final UInt64 slot);  }### Answer:
@Test public void shouldNotPerformDutiesForSameSlotTwice() { final UInt64 blockProposerSlot = UInt64.valueOf(5); final ValidatorDuties validator1Duties = ValidatorDuties.withDuties( VALIDATOR1_KEY, 5, 3, 6, 0, List.of(blockProposerSlot), UInt64.valueOf(7)); when(validatorApiChannel.getDuties(eq(ZERO), any())) .thenReturn(completedFuture(Optional.of(List.of(validator1Duties)))); final BlockProductionDuty blockCreationDuty = mock(BlockProductionDuty.class); when(blockCreationDuty.performDuty()).thenReturn(new SafeFuture<>()); when(dutyFactory.createBlockProductionDuty(blockProposerSlot, validator1)) .thenReturn(blockCreationDuty); dutyScheduler.onSlot(compute_start_slot_at_epoch(ZERO)); dutyScheduler.onBlockProductionDue(blockProposerSlot); verify(blockCreationDuty).performDuty(); dutyScheduler.onBlockProductionDue(blockProposerSlot); verifyNoMoreInteractions(blockCreationDuty); }
@Test public void shouldScheduleBlockProposalDuty() { final UInt64 blockProposerSlot = UInt64.valueOf(5); final ValidatorDuties validator1Duties = ValidatorDuties.withDuties( VALIDATOR1_KEY, 5, 3, 6, 0, List.of(blockProposerSlot), UInt64.valueOf(7)); when(validatorApiChannel.getDuties(eq(ZERO), any())) .thenReturn(completedFuture(Optional.of(List.of(validator1Duties)))); final BlockProductionDuty blockCreationDuty = mock(BlockProductionDuty.class); when(blockCreationDuty.performDuty()).thenReturn(new SafeFuture<>()); when(dutyFactory.createBlockProductionDuty(blockProposerSlot, validator1)) .thenReturn(blockCreationDuty); dutyScheduler.onSlot(compute_start_slot_at_epoch(ZERO)); dutyScheduler.onBlockProductionDue(blockProposerSlot); verify(blockCreationDuty).performDuty(); }
@Test public void shouldDelayExecutingDutiesUntilSchedulingIsComplete() { final ScheduledDuties scheduledDuties = mock(ScheduledDuties.class); final StubMetricsSystem metricsSystem = new StubMetricsSystem(); final ValidatorTimingChannel dutyScheduler = new BlockDutyScheduler( metricsSystem, new RetryingDutyLoader( asyncRunner, new ValidatorApiDutyLoader( metricsSystem, validatorApiChannel, forkProvider, () -> scheduledDuties, Map.of(VALIDATOR1_KEY, validator1, VALIDATOR2_KEY, validator2)))); final SafeFuture<Optional<List<ValidatorDuties>>> epoch0Duties = new SafeFuture<>(); when(validatorApiChannel.getDuties(eq(ZERO), any())).thenReturn(epoch0Duties); when(validatorApiChannel.getDuties(eq(ONE), any())) .thenReturn(SafeFuture.completedFuture(Optional.of(emptyList()))); dutyScheduler.onSlot(ZERO); dutyScheduler.onBlockProductionDue(ZERO); verify(scheduledDuties, never()).produceBlock(ZERO); epoch0Duties.complete(Optional.of(emptyList())); verify(scheduledDuties).produceBlock(ZERO); }