Skip to content

Commit 2935a0c

Browse files
authored
Merge pull request #688 from iExecBlockchainComputing/release/8.4.1
Release/8.4.1
2 parents 7c93c40 + 3dce7c7 commit 2935a0c

File tree

50 files changed

+2311
-2214
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+2311
-2214
lines changed

CHANGELOG.md

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,36 @@
22

33
All notable changes to this project will be documented in this file.
44

5+
## [[8.4.1]](https://github.com/iExecBlockchainComputing/iexec-core/releases/tag/v8.4.1) 2024-04-03
6+
7+
### New Features
8+
9+
- Add `ConsensusReachedTaskDetector` to detect missed `TaskConsensus` on-chain events. (#683 #684)
10+
- Generate enclave challenge with `Authorization` header after on-chain task has been initialized. (#686)
11+
12+
### Bug Fixes
13+
14+
- Keep a single `updateReplicateStatus` method in `ReplicatesService`. (#670)
15+
- Check result has been uploaded for TEE tasks. (#672)
16+
- Check for consensus early if a worker has already `CONTRIBUTED` when the task is updated to `RUNNING`. (#673)
17+
- Always provide a `WorkerpoolAuthorization` to a worker during its recovery. (#674)
18+
- Move task metrics from `TaskUpdateManager` to `TaskService`. (#676)
19+
- Fail fast when tasks are detected past their contribution or final deadline. (#677)
20+
- Mitigate potential race conditions by enforcing `currentStatus` value when updating a task. (#681)
21+
- Use semaphores in `TaskUpdateRequestManager` to avoid blocking task update threads. (#685)
22+
23+
### Quality
24+
25+
- Prepare migration to `java.time` package by building `Date` objects from `Instant` objects. (#671)
26+
- Add logs for better traceability. (#675)
27+
- Remove code only used in tests from `TaskService` and `Task`. (#678 #679)
28+
- Implement each task status transition in a single method. (#680)
29+
- Execute `TaskUpdateManager` tests on a running MongoDB container. (#682)
30+
31+
### Dependency Upgrades
32+
33+
- Upgrade to `iexec-sms-library` 8.5.1. (#687)
34+
535
## [[8.4.0]](https://github.com/iExecBlockchainComputing/iexec-core/releases/tag/v8.4.0) 2024-02-29
636

737
### New Features
@@ -21,9 +51,9 @@ All notable changes to this project will be documented in this file.
2151
### Dependency Upgrades
2252

2353
- Upgrade to `iexec-common` 8.4.0. (#666)
24-
- Upgrade to `iexec-blockchain-adapter` 8.4.0. (#667)
25-
- Upgrade to `iexec-result-proxy` 8.4.0. (#667)
26-
- Upgrade to `iexec-sms` 8.5.0. (#667)
54+
- Upgrade to `iexec-blockchain-adapter-library` 8.4.0. (#667)
55+
- Upgrade to `iexec-result-proxy-library` 8.4.0. (#667)
56+
- Upgrade to `iexec-sms-library` 8.5.0. (#667)
2757

2858
## [[8.3.0]](https://github.com/iExecBlockchainComputing/iexec-core/releases/tag/v8.3.0) 2024-01-11
2959

gradle.properties

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
version=8.4.0
1+
version=8.4.1
22
iexecCommonVersion=8.4.0
33
iexecCommonsPocoVersion=3.2.0
44
iexecBlockchainAdapterVersion=8.4.0
55
iexecResultVersion=8.4.0
6-
iexecSmsVersion=8.5.0
6+
iexecSmsVersion=8.5.1
77

88
nexusUser
99
nexusPassword

src/main/java/com/iexec/core/chain/IexecHubService.java

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2020-2023 IEXEC BLOCKCHAIN TECH
2+
* Copyright 2020-2024 IEXEC BLOCKCHAIN TECH
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -30,6 +30,7 @@
3030
import org.web3j.protocol.core.methods.response.TransactionReceipt;
3131

3232
import java.math.BigInteger;
33+
import java.time.Instant;
3334
import java.util.Date;
3435
import java.util.List;
3536
import java.util.Optional;
@@ -38,7 +39,6 @@
3839
import java.util.concurrent.Executors;
3940
import java.util.concurrent.ThreadPoolExecutor;
4041

41-
import static com.iexec.common.utils.DateTimeUtils.now;
4242
import static com.iexec.commons.poco.chain.ChainContributionStatus.CONTRIBUTED;
4343
import static com.iexec.commons.poco.chain.ChainContributionStatus.REVEALED;
4444
import static com.iexec.commons.poco.contract.generated.IexecHubContract.*;
@@ -160,18 +160,17 @@ public Date getChainDealFinalDeadline(ChainDeal chainDeal) {
160160
}
161161

162162
public boolean canFinalize(String chainTaskId) {
163-
Optional<ChainTask> optional = getChainTask(chainTaskId);
164-
if (optional.isEmpty()) {
163+
final ChainTask chainTask = getChainTask(chainTaskId).orElse(null);
164+
if (chainTask == null) {
165165
return false;
166166
}
167-
ChainTask chainTask = optional.get();
168167

169-
boolean isChainTaskStatusRevealing = chainTask.getStatus().equals(ChainTaskStatus.REVEALING);
170-
boolean isFinalDeadlineInFuture = now() < chainTask.getFinalDeadline();
171-
boolean hasEnoughRevealors = (chainTask.getRevealCounter() == chainTask.getWinnerCounter())
172-
|| (chainTask.getRevealCounter() > 0 && chainTask.getRevealDeadline() <= now());
168+
final boolean isChainTaskStatusRevealing = chainTask.getStatus() == ChainTaskStatus.REVEALING;
169+
final boolean isFinalDeadlineInFuture = Instant.now().toEpochMilli() < chainTask.getFinalDeadline();
170+
final boolean hasEnoughRevealors = chainTask.getRevealCounter() == chainTask.getWinnerCounter()
171+
|| (chainTask.getRevealCounter() > 0 && chainTask.getRevealDeadline() <= Instant.now().toEpochMilli());
172+
final boolean ret = isChainTaskStatusRevealing && isFinalDeadlineInFuture && hasEnoughRevealors;
173173

174-
boolean ret = isChainTaskStatusRevealing && isFinalDeadlineInFuture && hasEnoughRevealors;
175174
if (ret) {
176175
log.info("Finalizable onchain [chainTaskId:{}]", chainTaskId);
177176
} else {
@@ -183,15 +182,14 @@ public boolean canFinalize(String chainTaskId) {
183182
}
184183

185184
public boolean canReopen(String chainTaskId) {
186-
Optional<ChainTask> optional = getChainTask(chainTaskId);
187-
if (optional.isEmpty()) {
185+
final ChainTask chainTask = getChainTask(chainTaskId).orElse(null);
186+
if (chainTask == null) {
188187
return false;
189188
}
190-
ChainTask chainTask = optional.get();
191189

192-
boolean isChainTaskStatusRevealing = chainTask.getStatus().equals(ChainTaskStatus.REVEALING);
193-
boolean isBeforeFinalDeadline = now() < chainTask.getFinalDeadline();
194-
boolean isAfterRevealDeadline = chainTask.getRevealDeadline() <= now();
190+
boolean isChainTaskStatusRevealing = chainTask.getStatus() == ChainTaskStatus.REVEALING;
191+
boolean isBeforeFinalDeadline = Instant.now().toEpochMilli() < chainTask.getFinalDeadline();
192+
boolean isAfterRevealDeadline = chainTask.getRevealDeadline() <= Instant.now().toEpochMilli();
195193
boolean revealCounterEqualsZero = chainTask.getRevealCounter() == 0;
196194

197195
boolean check = isChainTaskStatusRevealing && isBeforeFinalDeadline && isAfterRevealDeadline
@@ -247,7 +245,9 @@ Flowable<IexecHubContract.SchedulerNoticeEventResponse> getDealEventObservable(E
247245
}
248246

249247
public boolean hasEnoughGas() {
250-
return hasEnoughGas(credentialsService.getCredentials().getAddress());
248+
final boolean hasEnoughGas = hasEnoughGas(credentialsService.getCredentials().getAddress());
249+
log.debug("Gas status [hasEnoughGas:{}]", hasEnoughGas);
250+
return hasEnoughGas;
251251
}
252252

253253
private ChainReceipt buildChainReceipt(TransactionReceipt receipt) {

src/main/java/com/iexec/core/configuration/CronConfiguration.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ public class CronConfiguration {
2323
@Value("${cron.detector.chain.contribute}")
2424
private int contribute;
2525

26+
@Value("${cron.detector.chain.consensus-reached}")
27+
private int consensusReached;
28+
2629
@Value("${cron.detector.chain.reveal}")
2730
private int reveal;
2831

@@ -42,5 +45,5 @@ public class CronConfiguration {
4245
private int revealTimeout;
4346

4447
@Value("${cron.detector.timeout.result-upload}")
45-
private int resultUploadTimeout;
48+
private int resultUploadTimeout;
4649
}

src/main/java/com/iexec/core/detector/WorkerLostDetector.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2020 IEXEC BLOCKCHAIN TECH
2+
* Copyright 2020-2024 IEXEC BLOCKCHAIN TECH
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -18,6 +18,7 @@
1818

1919
import com.google.common.collect.ImmutableSet;
2020
import com.iexec.common.replicate.ReplicateStatus;
21+
import com.iexec.common.replicate.ReplicateStatusUpdate;
2122
import com.iexec.core.replicate.ReplicatesService;
2223
import com.iexec.core.task.TaskService;
2324
import com.iexec.core.worker.Worker;
@@ -69,7 +70,7 @@ public void detect() {
6970
replicatesService.updateReplicateStatus(
7071
chainTaskId,
7172
workerWallet,
72-
WORKER_LOST
73+
ReplicateStatusUpdate.poolManagerRequest(WORKER_LOST)
7374
);
7475
}
7576
});

src/main/java/com/iexec/core/detector/replicate/ReplicateResultUploadTimeoutDetector.java

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2020 IEXEC BLOCKCHAIN TECH
2+
* Copyright 2020-2024 IEXEC BLOCKCHAIN TECH
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,6 +16,7 @@
1616

1717
package com.iexec.core.detector.replicate;
1818

19+
import com.iexec.common.replicate.ReplicateStatusUpdate;
1920
import com.iexec.core.detector.Detector;
2021
import com.iexec.core.replicate.Replicate;
2122
import com.iexec.core.replicate.ReplicatesService;
@@ -27,11 +28,10 @@
2728
import org.springframework.scheduling.annotation.Scheduled;
2829
import org.springframework.stereotype.Service;
2930

30-
import java.util.Date;
31-
import java.util.Optional;
31+
import java.time.Instant;
32+
import java.time.temporal.ChronoUnit;
3233

3334
import static com.iexec.common.replicate.ReplicateStatus.RESULT_UPLOAD_FAILED;
34-
import static com.iexec.common.utils.DateTimeUtils.addMinutesToDate;
3535

3636
@Slf4j
3737
@Service
@@ -62,14 +62,13 @@ public void detect() {
6262
String chainTaskId = task.getChainTaskId();
6363
String uploadingWallet = task.getUploadingWorkerWalletAddress();
6464

65-
Optional<Replicate> oUploadingReplicate = replicatesService.getReplicate(chainTaskId, uploadingWallet);
66-
if (oUploadingReplicate.isEmpty()) {
65+
final Replicate uploadingReplicate = replicatesService.getReplicate(chainTaskId, uploadingWallet).orElse(null);
66+
if (uploadingReplicate == null) {
6767
return;
6868
}
6969

70-
Replicate uploadingReplicate = oUploadingReplicate.get();
71-
72-
boolean startedUploadLongAgo = new Date().after(addMinutesToDate(task.getLatestStatusChange().getDate(), 2));
70+
boolean startedUploadLongAgo = Instant.now().isAfter(
71+
Instant.ofEpochMilli(task.getLatestStatusChange().getDate().getTime()).plus(2L, ChronoUnit.MINUTES));
7372
boolean hasReplicateAlreadyFailedToUpload = uploadingReplicate.containsStatus(RESULT_UPLOAD_FAILED);
7473

7574
if (!startedUploadLongAgo) {
@@ -84,8 +83,8 @@ public void detect() {
8483
log.info("detected replicate with resultUploadTimeout [chainTaskId:{}, replicate:{}, currentStatus:{}]",
8584
chainTaskId, uploadingReplicate.getWalletAddress(), uploadingReplicate.getCurrentStatus());
8685

87-
replicatesService.updateReplicateStatus(chainTaskId, uploadingReplicate.getWalletAddress(),
88-
RESULT_UPLOAD_FAILED);
86+
replicatesService.updateReplicateStatus(
87+
chainTaskId, uploadingReplicate.getWalletAddress(), ReplicateStatusUpdate.poolManagerRequest(RESULT_UPLOAD_FAILED));
8988
taskUpdateRequestManager.publishRequest(task.getChainTaskId());
9089
}
9190
}

src/main/java/com/iexec/core/detector/replicate/UnnotifiedAbstractDetector.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
import com.iexec.common.replicate.ReplicateStatus;
2020
import com.iexec.common.replicate.ReplicateStatusDetails;
21+
import com.iexec.common.replicate.ReplicateStatusUpdate;
2122
import com.iexec.commons.poco.chain.ChainContributionStatus;
2223
import com.iexec.commons.poco.chain.ChainReceipt;
2324
import com.iexec.core.chain.IexecHubService;
@@ -185,7 +186,8 @@ private void updateReplicateStatuses(Task task, Replicate replicate) {
185186
// by default, no need to retrieve anything
186187
break;
187188
}
188-
replicatesService.updateReplicateStatus(chainTaskId, wallet, statusToUpdate, details);
189+
final ReplicateStatusUpdate statusUpdate = ReplicateStatusUpdate.poolManagerRequest(statusToUpdate, details);
190+
replicatesService.updateReplicateStatus(chainTaskId, wallet, statusUpdate);
189191
}
190192
}
191193
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
/*
2+
* Copyright 2024 IEXEC BLOCKCHAIN TECH
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.iexec.core.detector.task;
18+
19+
import com.iexec.core.chain.IexecHubService;
20+
import com.iexec.core.detector.Detector;
21+
import com.iexec.core.task.Task;
22+
import com.iexec.core.task.TaskService;
23+
import com.iexec.core.task.TaskStatus;
24+
import com.iexec.core.task.update.TaskUpdateRequestManager;
25+
import lombok.extern.slf4j.Slf4j;
26+
import org.springframework.scheduling.annotation.Scheduled;
27+
import org.springframework.stereotype.Service;
28+
29+
import static com.iexec.commons.poco.chain.ChainTaskStatus.REVEALING;
30+
import static com.iexec.core.task.TaskStatus.RUNNING;
31+
32+
@Slf4j
33+
@Service
34+
public class ConsensusReachedTaskDetector implements Detector {
35+
36+
private final IexecHubService iexecHubService;
37+
private final TaskService taskService;
38+
private final TaskUpdateRequestManager taskUpdateRequestManager;
39+
40+
public ConsensusReachedTaskDetector(IexecHubService iexecHubService,
41+
TaskService taskService,
42+
TaskUpdateRequestManager taskUpdateRequestManager) {
43+
this.iexecHubService = iexecHubService;
44+
this.taskService = taskService;
45+
this.taskUpdateRequestManager = taskUpdateRequestManager;
46+
}
47+
48+
@Scheduled(fixedRateString = "#{@cronConfiguration.getConsensusReached()}")
49+
@Override
50+
public void detect() {
51+
log.debug("Trying to detect running tasks with on-chain consensus");
52+
taskService.findByCurrentStatus(RUNNING).stream()
53+
.filter(this::isConsensusReached)
54+
.forEach(this::publishTaskUpdateRequest);
55+
}
56+
57+
private boolean isConsensusReached(Task task) {
58+
return iexecHubService.getChainTask(task.getChainTaskId()).stream()
59+
.allMatch(chainTask -> chainTask.getStatus() == REVEALING);
60+
}
61+
62+
private void publishTaskUpdateRequest(Task task) {
63+
log.info("Detected confirmed missing update (task) [is:{}, should:{}, taskId:{}]",
64+
task.getCurrentStatus(), TaskStatus.CONSENSUS_REACHED, task.getChainTaskId());
65+
taskUpdateRequestManager.publishRequest(task.getChainTaskId());
66+
}
67+
}
Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2020 IEXEC BLOCKCHAIN TECH
2+
* Copyright 2020-2024 IEXEC BLOCKCHAIN TECH
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -17,40 +17,45 @@
1717
package com.iexec.core.detector.task;
1818

1919
import com.iexec.core.detector.Detector;
20-
import com.iexec.core.task.Task;
2120
import com.iexec.core.task.TaskService;
2221
import com.iexec.core.task.TaskStatus;
23-
import com.iexec.core.task.update.TaskUpdateRequestManager;
22+
import com.iexec.core.task.TaskStatusChange;
23+
import com.iexec.core.task.event.ContributionTimeoutEvent;
2424
import lombok.extern.slf4j.Slf4j;
25+
import org.springframework.context.ApplicationEventPublisher;
26+
import org.springframework.data.mongodb.core.query.Criteria;
27+
import org.springframework.data.mongodb.core.query.Query;
28+
import org.springframework.data.mongodb.core.query.Update;
2529
import org.springframework.scheduling.annotation.Scheduled;
2630
import org.springframework.stereotype.Service;
2731

28-
import java.util.Arrays;
29-
import java.util.Date;
32+
import java.time.Instant;
3033

3134
@Slf4j
3235
@Service
3336
public class ContributionTimeoutTaskDetector implements Detector {
3437

3538
private final TaskService taskService;
36-
private final TaskUpdateRequestManager taskUpdateRequestManager;
39+
private final ApplicationEventPublisher applicationEventPublisher;
3740

38-
public ContributionTimeoutTaskDetector(TaskService taskService,
39-
TaskUpdateRequestManager taskUpdateRequestManager) {
41+
public ContributionTimeoutTaskDetector(TaskService taskService, ApplicationEventPublisher applicationEventPublisher) {
4042
this.taskService = taskService;
41-
this.taskUpdateRequestManager = taskUpdateRequestManager;
43+
this.applicationEventPublisher = applicationEventPublisher;
4244
}
4345

4446
@Scheduled(fixedRateString = "#{@cronConfiguration.getContribute()}")
4547
@Override
4648
public void detect() {
47-
log.debug("Trying to detect contribution timeout");
48-
for (Task task : taskService.findByCurrentStatus(Arrays.asList(TaskStatus.INITIALIZED, TaskStatus.RUNNING))) {
49-
Date now = new Date();
50-
if (now.after(task.getContributionDeadline())) {
51-
log.info("Task with contribution timeout found [chainTaskId:{}]", task.getChainTaskId());
52-
taskUpdateRequestManager.publishRequest(task.getChainTaskId());
53-
}
54-
}
49+
log.debug("Trying to detect tasks after contribution deadline");
50+
final Instant now = Instant.now();
51+
final Query query = Query.query(Criteria.where("currentStatus").in(TaskStatus.INITIALIZED, TaskStatus.RUNNING)
52+
.and("contributionDeadline").lte(now)
53+
.and("finalDeadline").gt(now));
54+
final Update update = Update.update("currentStatus", TaskStatus.FAILED)
55+
.push("dateStatusList").each(
56+
TaskStatusChange.builder().status(TaskStatus.CONTRIBUTION_TIMEOUT).build(),
57+
TaskStatusChange.builder().status(TaskStatus.FAILED).build());
58+
taskService.updateMultipleTasksByQuery(query, update)
59+
.forEach(id -> applicationEventPublisher.publishEvent(new ContributionTimeoutEvent(id)));
5560
}
5661
}

0 commit comments

Comments
 (0)