diff --git a/CHANGELOG.md b/CHANGELOG.md index ee2d88d0..6de7dbab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ All notable changes to this project will be documented in this file. - Add blockchain connection health indicator. (#601) - Block some connections and messages when blockchain connection is down. (#604) - Block deal watching mechanisms when communication with the blockchain node is lost. (#606) +- Use `isEligibleToContributeAndFinalize` method from `TaskDescription`. (#619) ### Bug Fixes - Clean call to `iexecHubService#getTaskDescriptionFromChain` in test. (#597) - Reject deal if TEE tag but trust not in {0,1}. (#598) diff --git a/src/main/java/com/iexec/core/detector/task/FinalizedTaskDetector.java b/src/main/java/com/iexec/core/detector/task/FinalizedTaskDetector.java index fdd6456d..5cecd280 100644 --- a/src/main/java/com/iexec/core/detector/task/FinalizedTaskDetector.java +++ b/src/main/java/com/iexec/core/detector/task/FinalizedTaskDetector.java @@ -19,6 +19,7 @@ import com.iexec.common.replicate.ReplicateStatus; import com.iexec.commons.poco.chain.ChainTask; import com.iexec.commons.poco.chain.ChainTaskStatus; +import com.iexec.commons.poco.task.TaskDescription; import com.iexec.core.chain.IexecHubService; import com.iexec.core.detector.Detector; import com.iexec.core.replicate.Replicate; @@ -89,8 +90,8 @@ boolean isChainTaskCompleted(Task task) { } boolean isTaskContributeAndFinalizeDone(Task task) { - // Only TEE tasks can follow ContributeAndFinalize workflow - if (!task.isTeeTask()) { + final TaskDescription taskDescription = iexecHubService.getTaskDescription(task.getChainTaskId()); + if (!taskDescription.isEligibleToContributeAndFinalize()) { return false; } diff --git a/src/main/java/com/iexec/core/task/update/TaskUpdateManager.java b/src/main/java/com/iexec/core/task/update/TaskUpdateManager.java index bdc7a6b9..d3f81660 100644 --- a/src/main/java/com/iexec/core/task/update/TaskUpdateManager.java +++ b/src/main/java/com/iexec/core/task/update/TaskUpdateManager.java @@ -20,6 +20,7 @@ import com.iexec.commons.poco.chain.ChainReceipt; import com.iexec.commons.poco.chain.ChainTask; import com.iexec.commons.poco.chain.ChainTaskStatus; +import com.iexec.commons.poco.task.TaskDescription; import com.iexec.core.chain.IexecHubService; import com.iexec.core.chain.adapter.BlockchainAdapterService; import com.iexec.core.replicate.Replicate; @@ -331,7 +332,8 @@ void running2Finalized2Completed(Task task) { boolean isTaskInRunningStatus = task.getCurrentStatus() == RUNNING; final String chainTaskId = task.getChainTaskId(); - if (!task.isTeeTask()) { + final TaskDescription taskDescription = iexecHubService.getTaskDescription(task.getChainTaskId()); + if (!taskDescription.isEligibleToContributeAndFinalize()) { log.debug("Task not running in a TEE, flow running2Finalized2Completed is not possible" + " [chainTaskId:{}]", chainTaskId); return; diff --git a/src/main/java/com/iexec/core/workflow/ReplicateWorkflow.java b/src/main/java/com/iexec/core/workflow/ReplicateWorkflow.java index 2713aa54..8476b003 100644 --- a/src/main/java/com/iexec/core/workflow/ReplicateWorkflow.java +++ b/src/main/java/com/iexec/core/workflow/ReplicateWorkflow.java @@ -196,7 +196,7 @@ TaskNotificationType getNextActionWhenStatusAndCause(ReplicateStatus whenStatus, return PLEASE_ABORT; } // We must check CallBack is empty because there is an issue in poco (transaction is revert) - if (taskDescription.isTeeTask() && !taskDescription.containsCallback()) { + if (taskDescription.isEligibleToContributeAndFinalize()) { return PLEASE_CONTRIBUTE_AND_FINALIZE; } } diff --git a/src/test/java/com/iexec/core/detector/task/FinalizedTaskDetectorTests.java b/src/test/java/com/iexec/core/detector/task/FinalizedTaskDetectorTests.java index 8b69f54c..e550303e 100644 --- a/src/test/java/com/iexec/core/detector/task/FinalizedTaskDetectorTests.java +++ b/src/test/java/com/iexec/core/detector/task/FinalizedTaskDetectorTests.java @@ -20,6 +20,7 @@ import com.iexec.common.replicate.ReplicateStatusModifier; import com.iexec.commons.poco.chain.ChainTask; import com.iexec.commons.poco.chain.ChainTaskStatus; +import com.iexec.commons.poco.task.TaskDescription; import com.iexec.core.chain.IexecHubService; import com.iexec.core.replicate.Replicate; import com.iexec.core.replicate.ReplicatesService; @@ -32,6 +33,7 @@ import org.junit.jupiter.api.Test; import org.mockito.*; +import java.math.BigInteger; import java.util.List; import java.util.Optional; @@ -68,6 +70,7 @@ void shouldDetectTasks() { final String contributedAndFinalizedChainTaskId = "0x75bc5e94ed1486b940bd6cc0013c418efad58a0a52a3d08cee89faaa21970426"; final Task contributeAndFinalizeTask = getContributeAndFinalizeDoneTask(contributedAndFinalizedChainTaskId).build(); when(taskService.findByCurrentStatus(TaskStatus.RUNNING)).thenReturn(List.of(contributeAndFinalizeTask)); + mockTaskDescriptionFromTask(contributeAndFinalizeTask); detector.detect(); @@ -106,6 +109,7 @@ void shouldDetectContributeAndFinalizeDoneTask() { final Task task = getContributeAndFinalizeDoneTask(CHAIN_TASK_ID).build(); when(taskService.findByCurrentStatus(TaskStatus.RUNNING)).thenReturn(List.of(task)); + mockTaskDescriptionFromTask(task); detector.detectContributeAndFinalizeDoneTasks(); @@ -117,6 +121,7 @@ void shouldDetectNoContributeAndFinalizeDoneTaskAsTaskIsRevealing() { final Task task = getOnchainRevealingTask(CHAIN_DEAL_ID).build(); when(taskService.findByCurrentStatus(TaskStatus.RUNNING)).thenReturn(List.of(task)); + mockTaskDescriptionFromTask(task); detector.detectContributeAndFinalizeDoneTasks(); @@ -162,6 +167,7 @@ void shouldChainTaskNotBeCompletedAsChainTaskNotCompleted() { @Test void shouldTaskBeContributeAndFinalizeDone() { final Task task = getContributeAndFinalizeDoneTask(CHAIN_TASK_ID).build(); + mockTaskDescriptionFromTask(task); final boolean taskContributeAndFinalizeDone = detector.isTaskContributeAndFinalizeDone(task); @@ -175,6 +181,7 @@ void shouldTaskNotBeContributeAndFinalizeDoneAsNotTee() { .currentStatus(TaskStatus.FINALIZING) .tag(NO_TEE_TAG) .build(); + mockTaskDescriptionFromTask(task); final boolean taskContributeAndFinalizeDone = detector.isTaskContributeAndFinalizeDone(task); @@ -197,6 +204,7 @@ void shouldTaskNotBeContributeAndFinalizeDoneAsMultipleReplicates() { when(replicatesService.getReplicates(CHAIN_TASK_ID)).thenReturn(List.of(replicate1, replicate2)); when(iexecHubService.getChainTask(CHAIN_TASK_ID)).thenReturn(Optional.of(chainTask)); + mockTaskDescriptionFromTask(task); final boolean taskContributeAndFinalizeDone = detector.isTaskContributeAndFinalizeDone(task); @@ -214,6 +222,7 @@ void shouldTaskNotBeContributeAndFinalizeDoneAsReplicateNotDone() { replicate.updateStatus(ReplicateStatus.COMPUTING, ReplicateStatusModifier.WORKER); when(replicatesService.getReplicates(CHAIN_TASK_ID)).thenReturn(List.of(replicate)); + mockTaskDescriptionFromTask(task); final boolean taskContributeAndFinalizeDone = detector.isTaskContributeAndFinalizeDone(task); @@ -236,6 +245,7 @@ void shouldTaskNotBeContributeAndFinalizeDoneAsChainTaskNotCompleted() { when(replicatesService.getReplicates(CHAIN_TASK_ID)).thenReturn(List.of(replicate)); when(iexecHubService.getChainTask(CHAIN_TASK_ID)).thenReturn(Optional.of(chainTask)); + mockTaskDescriptionFromTask(task); final boolean taskContributeAndFinalizeDone = detector.isTaskContributeAndFinalizeDone(task); @@ -291,7 +301,18 @@ private Task.TaskBuilder getContributeAndFinalizeDoneTask(String chainTaskId) { when(replicatesService.getReplicates(chainTaskId)).thenReturn(List.of(replicate)); return getOnchainCompletedTask(chainTaskId) - .tag(TEE_TAG); + .tag(TEE_TAG) + .trust(1); + } + + private void mockTaskDescriptionFromTask(Task task) { + final TaskDescription taskDescription = TaskDescription.builder() + .chainTaskId(task.getChainTaskId()) + .isTeeTask(task.isTeeTask()) + .trust(BigInteger.valueOf(task.getTrust())) + .callback("") + .build(); + when(iexecHubService.getTaskDescription(task.getChainTaskId())).thenReturn(taskDescription); } // endregion } diff --git a/src/test/java/com/iexec/core/task/TaskTests.java b/src/test/java/com/iexec/core/task/TaskTests.java index 7c9fb97f..0796a884 100644 --- a/src/test/java/com/iexec/core/task/TaskTests.java +++ b/src/test/java/com/iexec/core/task/TaskTests.java @@ -23,9 +23,9 @@ import java.util.Date; import java.util.List; -import static com.iexec.core.task.TaskStatus.CONSENSUS_REACHED; import static com.iexec.common.utils.DateTimeUtils.addMinutesToDate; import static com.iexec.common.utils.DateTimeUtils.now; +import static com.iexec.core.task.TaskStatus.CONSENSUS_REACHED; import static org.assertj.core.api.Assertions.assertThat; class TaskTests { diff --git a/src/test/java/com/iexec/core/task/TaskTestsUtils.java b/src/test/java/com/iexec/core/task/TaskTestsUtils.java index d66bc03f..657cc7c6 100644 --- a/src/test/java/com/iexec/core/task/TaskTestsUtils.java +++ b/src/test/java/com/iexec/core/task/TaskTestsUtils.java @@ -37,7 +37,7 @@ public class TaskTestsUtils { public final static String RESULT_LINK = "/ipfs/the_result_string"; public static Task getStubTask(long maxExecutionTime) { - Task task = new Task(CHAIN_DEAL_ID, 0, DAPP_NAME, COMMAND_LINE, 0, maxExecutionTime, NO_TEE_TAG); + Task task = new Task(CHAIN_DEAL_ID, 0, DAPP_NAME, COMMAND_LINE, 1, maxExecutionTime, NO_TEE_TAG); task.setFinalDeadline(Date.from(Instant.now().plus(1, ChronoUnit.MINUTES))); return task; } diff --git a/src/test/java/com/iexec/core/task/update/TaskUpdateManagerTest.java b/src/test/java/com/iexec/core/task/update/TaskUpdateManagerTest.java index 6df4977e..5ecaeec3 100644 --- a/src/test/java/com/iexec/core/task/update/TaskUpdateManagerTest.java +++ b/src/test/java/com/iexec/core/task/update/TaskUpdateManagerTest.java @@ -23,6 +23,7 @@ import com.iexec.commons.poco.chain.ChainReceipt; import com.iexec.commons.poco.chain.ChainTask; import com.iexec.commons.poco.chain.ChainTaskStatus; +import com.iexec.commons.poco.task.TaskDescription; import com.iexec.commons.poco.tee.TeeUtils; import com.iexec.commons.poco.utils.BytesUtils; import com.iexec.core.chain.IexecHubService; @@ -48,6 +49,7 @@ import org.mockito.MockitoAnnotations; import org.springframework.context.ApplicationEventPublisher; +import java.math.BigInteger; import java.time.Instant; import java.time.temporal.ChronoUnit; import java.util.ArrayList; @@ -689,6 +691,7 @@ void shouldNotUpdateRunning2Finalized2CompletedWhenTaskNotRunning() { Task task = getStubTask(maxExecutionTime); task.changeStatus(INITIALIZED); task.setTag(TeeUtils.TEE_SCONE_ONLY_TAG); + mockTaskDescriptionFromTask(task); taskUpdateManager.running2Finalized2Completed(task); assertThat(task.getCurrentStatus()).isEqualTo(INITIALIZED); @@ -701,6 +704,7 @@ void shouldNotUpdateRunning2Finalized2CompletedWhenNoReplicates() { task.setTag(TeeUtils.TEE_SCONE_ONLY_TAG); when(replicatesService.getReplicatesList(CHAIN_TASK_ID)).thenReturn(Optional.empty()); + mockTaskDescriptionFromTask(task); taskUpdateManager.running2Finalized2Completed(task); assertThat(task.getCurrentStatus()).isEqualTo(RUNNING); @@ -714,6 +718,7 @@ void shouldNotUpdateRunning2Finalized2CompletedWhenTaskIsNotTee() { final ReplicatesList replicatesList = Mockito.spy(new ReplicatesList(CHAIN_TASK_ID)); when(replicatesService.getReplicatesList(CHAIN_TASK_ID)).thenReturn(Optional.of(replicatesList)); + mockTaskDescriptionFromTask(task); taskUpdateManager.running2Finalized2Completed(task); assertThat(task.getCurrentStatus()).isEqualTo(RUNNING); } @@ -728,6 +733,7 @@ void shouldNotUpdateRunning2Finalized2CompletedWhenNoReplicatesOnContributeAndFi when(replicatesService.getReplicatesList(CHAIN_TASK_ID)).thenReturn(Optional.of(replicatesList)); when(replicatesList.getNbReplicatesWithCurrentStatus(ReplicateStatus.CONTRIBUTE_AND_FINALIZE_DONE)).thenReturn(0); + mockTaskDescriptionFromTask(task); taskUpdateManager.running2Finalized2Completed(task); assertThat(task.getCurrentStatus()).isEqualTo(RUNNING); @@ -744,6 +750,7 @@ void shouldNotUpdateRunning2Finalized2CompletedWhenMoreThanOneReplicatesOnContri when(replicatesService.getReplicatesList(CHAIN_TASK_ID)).thenReturn(Optional.of(replicatesList)); when(replicatesList.getNbReplicatesWithCurrentStatus(ReplicateStatus.CONTRIBUTE_AND_FINALIZE_DONE)).thenReturn(2); doNothing().when(applicationEventPublisher).publishEvent(any()); + mockTaskDescriptionFromTask(task); taskUpdateManager.running2Finalized2Completed(task); assertThat(task.getCurrentStatus()).isEqualTo(FAILED); @@ -770,6 +777,7 @@ void shouldUpdateRunning2ConsensusReached() { when(iexecHubService.getConsensusBlock(anyString(), anyLong())).thenReturn(ChainReceipt.builder().blockNumber(1L).build()); doNothing().when(applicationEventPublisher).publishEvent(any()); when(replicatesList.getNbValidContributedWinners(any())).thenReturn(2); + mockTaskDescriptionFromTask(task); taskUpdateManager.updateTask(task.getChainTaskId()); assertThat(task.getCurrentStatus()).isEqualTo(CONSENSUS_REACHED); @@ -857,6 +865,7 @@ void shouldUpdateRunning2RunningFailedOn1Worker() { when(replicatesService.getReplicatesList(task.getChainTaskId())).thenReturn(Optional.of(replicatesList)); when(workerService.getAliveWorkers()).thenReturn(workersList); doNothing().when(applicationEventPublisher).publishEvent(any()); + mockTaskDescriptionFromTask(task); taskUpdateManager.updateTask(task.getChainTaskId()); assertThat(task.getDateOfStatus(RUNNING_FAILED)).isPresent(); @@ -893,6 +902,7 @@ void shouldUpdateRunning2RunningFailedOn2Workers() { when(replicatesService.getReplicatesList(task.getChainTaskId())).thenReturn(Optional.of(replicatesList)); when(workerService.getAliveWorkers()).thenReturn(workersList); doNothing().when(applicationEventPublisher).publishEvent(any()); + mockTaskDescriptionFromTask(task); taskUpdateManager.updateTask(task.getChainTaskId()); assertThat(task.getDateOfStatus(RUNNING_FAILED)).isPresent(); @@ -924,6 +934,7 @@ void shouldNotUpdateRunning2RunningFailedOn1WorkerAsNonTeeTask() { when(replicatesService.getReplicatesList(task.getChainTaskId())).thenReturn(Optional.of(replicatesList)); when(workerService.getAliveWorkers()).thenReturn(workersList); doNothing().when(applicationEventPublisher).publishEvent(any()); + mockTaskDescriptionFromTask(task); taskUpdateManager.updateTask(task.getChainTaskId()); assertThat(task.getDateOfStatus(RUNNING)).isPresent(); @@ -959,6 +970,7 @@ void shouldNotUpdateRunning2RunningFailedOn2WorkersAsNonTeeTask() { when(replicatesService.getReplicatesList(task.getChainTaskId())).thenReturn(Optional.of(replicatesList)); when(workerService.getAliveWorkers()).thenReturn(workersList); doNothing().when(applicationEventPublisher).publishEvent(any()); + mockTaskDescriptionFromTask(task); taskUpdateManager.updateTask(task.getChainTaskId()); assertThat(task.getDateOfStatus(RUNNING)).isPresent(); @@ -994,6 +1006,7 @@ void shouldNotUpdateRunning2AllWorkersFailedSinceOneStillComputing() { when(replicatesService.getReplicatesList(task.getChainTaskId())).thenReturn(Optional.of(replicatesList)); when(workerService.getAliveWorkers()).thenReturn(workersList); doNothing().when(applicationEventPublisher).publishEvent(any()); + mockTaskDescriptionFromTask(task); taskUpdateManager.updateTask(task.getChainTaskId()); assertThat(task.getDateOfStatus(RUNNING_FAILED)).isEmpty(); @@ -1028,6 +1041,7 @@ void shouldNotUpdateRunning2AllWorkersFailedSinceOneHasReachedComputed() { when(replicatesService.getReplicatesList(task.getChainTaskId())).thenReturn(Optional.of(replicatesList)); when(workerService.getAliveWorkers()).thenReturn(workersList); doNothing().when(applicationEventPublisher).publishEvent(any()); + mockTaskDescriptionFromTask(task); taskUpdateManager.updateTask(task.getChainTaskId()); assertThat(task.getDateOfStatus(RUNNING_FAILED)).isEmpty(); @@ -1058,6 +1072,7 @@ void shouldNotUpdateRunning2AllWorkersFailedSinceOneStillHasToBeLaunched() { when(replicatesService.getReplicatesList(task.getChainTaskId())).thenReturn(Optional.of(replicatesList)); when(workerService.getAliveWorkers()).thenReturn(workersList); doNothing().when(applicationEventPublisher).publishEvent(any()); + mockTaskDescriptionFromTask(task); taskUpdateManager.updateTask(task.getChainTaskId()); assertThat(task.getDateOfStatus(RUNNING_FAILED)).isEmpty(); @@ -1709,6 +1724,7 @@ void shouldUpdateTaskRunning2Finalized2Completed() { doNothing().when(applicationEventPublisher).publishEvent(any()); when(taskService.getTaskByChainTaskId(CHAIN_TASK_ID)).thenReturn(Optional.of(task)); + mockTaskDescriptionFromTask(task); taskUpdateManager.updateTask(CHAIN_TASK_ID); assertThat(task.getCurrentStatus()).isEqualTo(COMPLETED); @@ -1875,4 +1891,16 @@ void shouldTriggerUpdateTaskAsynchronously() { taskUpdateRequestManager.publishRequest(CHAIN_TASK_ID); verify(taskUpdateRequestManager).publishRequest(CHAIN_TASK_ID); } + + // region utils + private void mockTaskDescriptionFromTask(Task task) { + final TaskDescription taskDescription = TaskDescription.builder() + .chainTaskId(task.getChainTaskId()) + .isTeeTask(task.isTeeTask()) + .trust(BigInteger.valueOf(task.getTrust())) + .callback("") + .build(); + when(iexecHubService.getTaskDescription(task.getChainTaskId())).thenReturn(taskDescription); + } + // endregion } diff --git a/src/test/java/com/iexec/core/workflow/ReplicateWorkflowTests.java b/src/test/java/com/iexec/core/workflow/ReplicateWorkflowTests.java index 33628034..776f101e 100644 --- a/src/test/java/com/iexec/core/workflow/ReplicateWorkflowTests.java +++ b/src/test/java/com/iexec/core/workflow/ReplicateWorkflowTests.java @@ -32,6 +32,7 @@ import java.io.File; import java.io.IOException; +import java.math.BigInteger; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -166,7 +167,7 @@ void shouldGetNextActionOnComputedWithTeeTaskShouldBePleaseContributeAndFinalize assertThat(replicateWorkflow .getNextAction(COMPUTED, null, - TaskDescription.builder().isTeeTask(true).callback(BytesUtils.EMPTY_ADDRESS).build())) + TaskDescription.builder().isTeeTask(true).trust(BigInteger.ONE).callback(BytesUtils.EMPTY_ADDRESS).build())) .isEqualTo(PLEASE_CONTRIBUTE_AND_FINALIZE); }