### Question:
VoluntaryExitValidator { public InternalValidationResult validate(SignedVoluntaryExit exit) { if (!isFirstValidExitForValidator(exit)) { LOG.trace("VoluntaryExitValidator: Exit is not the first one for the given validator."); return IGNORE; } if (!passesProcessVoluntaryExitConditions(exit)) { return REJECT; } if (receivedValidExitSet.add(exit.getMessage().getValidator_index())) { return ACCEPT; } else { LOG.trace("VoluntaryExitValidator: Exit is not the first one for the given validator."); return IGNORE; } } VoluntaryExitValidator(
      RecentChainData recentChainData,
      VoluntaryExitStateTransitionValidator stateTransitionValidator,
      VoluntaryExitSignatureVerifier signatureVerifier); InternalValidationResult validate(SignedVoluntaryExit exit);  }### Answer:
@Test public void shouldAcceptValidVoluntaryExit() throws Exception { beaconChainUtil.initializeStorage(); beaconChainUtil.createAndImportBlockAtSlot(6); SignedVoluntaryExit exit = dataStructureUtil.randomSignedVoluntaryExit(); when(stateTransitionValidator.validate(recentChainData.getBestState().orElseThrow(), exit)) .thenReturn(Optional.empty()); when(signatureVerifier.verifySignature( recentChainData.getBestState().orElseThrow(), exit, BLSSignatureVerifier.SIMPLE)) .thenReturn(true); assertThat(voluntaryExitValidator.validate(exit)).isEqualTo(ACCEPT); }
@Test public void shouldIgnoreExitsAfterTheFirstForValidator() throws Exception { beaconChainUtil.initializeStorage(); beaconChainUtil.createAndImportBlockAtSlot(6); SignedVoluntaryExit exit1 = dataStructureUtil.randomSignedVoluntaryExit(); SignedVoluntaryExit exit2 = new SignedVoluntaryExit(exit1.getMessage(), exit1.getSignature()); SignedVoluntaryExit exit3 = new SignedVoluntaryExit(exit2.getMessage(), exit2.getSignature()); when(stateTransitionValidator.validate(eq(recentChainData.getBestState().orElseThrow()), any())) .thenReturn(Optional.empty()); when(signatureVerifier.verifySignature( eq(recentChainData.getBestState().orElseThrow()), any(), eq(BLSSignatureVerifier.SIMPLE))) .thenReturn(true); assertThat(voluntaryExitValidator.validate(exit1)).isEqualTo(ACCEPT); assertThat(voluntaryExitValidator.validate(exit2)).isEqualTo(IGNORE); assertThat(voluntaryExitValidator.validate(exit3)).isEqualTo(IGNORE); }
@Test public void shouldRejectInvalidExit() throws Exception { beaconChainUtil.initializeStorage(); beaconChainUtil.createAndImportBlockAtSlot(6); SignedVoluntaryExit exit = dataStructureUtil.randomSignedVoluntaryExit(); when(stateTransitionValidator.validate(recentChainData.getBestState().orElseThrow(), exit)) .thenReturn( Optional.of(VoluntaryExitStateTransitionValidator.ExitInvalidReason.EXIT_INITIATED)); when(signatureVerifier.verifySignature( recentChainData.getBestState().orElseThrow(), exit, BLSSignatureVerifier.SIMPLE)) .thenReturn(true); assertThat(voluntaryExitValidator.validate(exit)).isEqualTo(REJECT); }
@Test public void shouldRejectExitWithInvalidSignature() throws Exception { beaconChainUtil.initializeStorage(); beaconChainUtil.createAndImportBlockAtSlot(6); SignedVoluntaryExit exit = dataStructureUtil.randomSignedVoluntaryExit(); when(stateTransitionValidator.validate(recentChainData.getBestState().orElseThrow(), exit)) .thenReturn(Optional.empty()); when(signatureVerifier.verifySignature( recentChainData.getBestState().orElseThrow(), exit, BLSSignatureVerifier.SIMPLE)) .thenReturn(false); assertThat(voluntaryExitValidator.validate(exit)).isEqualTo(REJECT); }