Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 11 additions & 9 deletions src/main/java/com/iexec/commons/poco/chain/ChainAccount.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2020-2023 IEXEC BLOCKCHAIN TECH
* Copyright 2020-2025 IEXEC BLOCKCHAIN TECH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -16,27 +16,29 @@

package com.iexec.commons.poco.chain;

import com.iexec.commons.poco.encoding.PoCoDataDecoder;
import lombok.Builder;
import lombok.Value;
import org.web3j.tuples.generated.Tuple2;
import lombok.extern.slf4j.Slf4j;

import java.math.BigInteger;
import static com.iexec.commons.poco.chain.Web3jAbstractService.toBigInt;

@Slf4j
@Value
@Builder
public class ChainAccount {

long deposit;
long locked;

public static ChainAccount tuple2Account(Tuple2<BigInteger, BigInteger> account) {
if (account != null) {
public static ChainAccount fromRawData(final String rawData) {
log.debug("ChainAccount.fromRawData");
final String[] parts = PoCoDataDecoder.toParts(rawData);
if (parts.length == 2) {
return ChainAccount.builder()
.deposit(account.component1().longValue())
.locked(account.component2().longValue())
.deposit(toBigInt(parts[0]).longValue())
.locked(toBigInt(parts[1]).longValue())
.build();
}
return null;
}

}
21 changes: 14 additions & 7 deletions src/main/java/com/iexec/commons/poco/chain/ChainCategory.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2020-2023 IEXEC BLOCKCHAIN TECH
* Copyright 2020-2025 IEXEC BLOCKCHAIN TECH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -16,26 +16,33 @@

package com.iexec.commons.poco.chain;

import com.iexec.commons.poco.encoding.PoCoDataDecoder;
import lombok.Builder;
import lombok.Value;
import lombok.extern.slf4j.Slf4j;

import java.math.BigInteger;
import static com.iexec.commons.poco.chain.Web3jAbstractService.toBigInt;

@Slf4j
@Value
@Builder
public class ChainCategory {

long id;
String name;
String description;
long maxExecutionTime;

public static ChainCategory tuple2ChainCategory(long id, String name, String description, BigInteger maxTime) {
public static ChainCategory fromRawData(final long id, final String rawData) {
log.debug("ChainCategory.fromRawData");
final String[] parts = PoCoDataDecoder.toParts(rawData);
final int offset = toBigInt(parts[0]).intValue() / 32;
final int nameContribOffset = toBigInt(parts[offset]).intValue() / 32;
final int descriptionContribOffset = toBigInt(parts[offset + 1]).intValue() / 32;
return ChainCategory.builder()
.id(id)
.name(name)
.description(description)
.maxExecutionTime(maxTime.longValue() * 1000)
.name(PoCoDataDecoder.decodeToAsciiString(parts, offset + nameContribOffset))
.description(PoCoDataDecoder.decodeToAsciiString(parts, offset + descriptionContribOffset))
.maxExecutionTime(toBigInt(parts[offset + 2]).longValue() * 1000)
.build();
}
}
27 changes: 16 additions & 11 deletions src/main/java/com/iexec/commons/poco/chain/ChainContribution.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2020-2023 IEXEC BLOCKCHAIN TECH
* Copyright 2020-2025 IEXEC BLOCKCHAIN TECH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -16,32 +16,37 @@

package com.iexec.commons.poco.chain;

import com.iexec.commons.poco.utils.BytesUtils;
import com.iexec.commons.poco.encoding.PoCoDataDecoder;
import lombok.Builder;
import lombok.Value;
import org.web3j.tuples.generated.Tuple4;
import lombok.extern.slf4j.Slf4j;

import java.math.BigInteger;

import static com.iexec.commons.poco.chain.Web3jAbstractService.toBigInt;

@Slf4j
@Value
@Builder
public class ChainContribution {

ChainContributionStatus status;
String resultHash;
String resultSeal;
String enclaveChallenge;
BigInteger weight;

public static ChainContribution tuple2Contribution(Tuple4<BigInteger, byte[], byte[], String> contribution) {
if (contribution != null) {
public static ChainContribution fromRawData(final String rawData) {
log.debug("ChainContribution.fromRawData");
final String[] parts = PoCoDataDecoder.toParts(rawData);
if (parts.length == 5) {
return ChainContribution.builder()
.status(ChainContributionStatus.getValue(contribution.component1()))
.resultHash(BytesUtils.bytesToString(contribution.component2()))
.resultSeal(BytesUtils.bytesToString(contribution.component3()))
.enclaveChallenge(contribution.component4())
.status(ChainContributionStatus.values()[toBigInt(parts[0]).intValue()])
.resultHash("0x" + parts[1])
.resultSeal("0x" + parts[2])
.enclaveChallenge("0x" + parts[3])
.weight(toBigInt(parts[4]))
.build();
}
return null;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
import lombok.extern.slf4j.Slf4j;
import org.web3j.crypto.Credentials;
import org.web3j.ens.EnsResolutionException;
import org.web3j.tuples.generated.Tuple3;
import org.web3j.tx.RawTransactionManager;
import org.web3j.tx.gas.ContractGasProvider;
import org.web3j.tx.response.PollingTransactionReceiptProcessor;
Expand Down Expand Up @@ -286,25 +285,29 @@ public Optional<ChainTask> getChainTask(String chainTaskId) {
return Optional.empty();
}

public Optional<ChainAccount> getChainAccount(String walletAddress) {
public Optional<ChainAccount> getChainAccount(final String walletAddress) {
try {
return Optional.of(ChainAccount.tuple2Account(
iexecHubContract.viewAccountABILegacy(walletAddress).send()));
final String txData = VIEW_ACCOUNT_SELECTOR +
Numeric.toHexStringNoPrefixZeroPadded(Numeric.toBigInt(walletAddress), 64);
return Optional.ofNullable(ChainAccount.fromRawData(
web3jAbstractService.sendCall(credentials.getAddress(), iexecHubAddress, txData)));
} catch (Exception e) {
log.error("Failed to get ChainAccount [walletAddress:{}]", walletAddress, e);
}
return Optional.empty();
}

public Optional<ChainContribution> getChainContribution(String chainTaskId,
String workerAddress) {
public Optional<ChainContribution> getChainContribution(final String chainTaskId,
final String workerAddress) {
try {
return Optional.of(ChainContribution.tuple2Contribution(
iexecHubContract.viewContributionABILegacy(
BytesUtils.stringToBytes(chainTaskId), workerAddress).send()));
final String txData = VIEW_CONTRIBUTION_SELECTOR +
Numeric.toHexStringNoPrefixZeroPadded(Numeric.toBigInt(chainTaskId), 64) +
Numeric.toHexStringNoPrefixZeroPadded(Numeric.toBigInt(workerAddress), 64);
final String rawData = web3jAbstractService.sendCall(credentials.getAddress(), iexecHubAddress, txData);
return Optional.ofNullable(ChainContribution.fromRawData(rawData));
} catch (Exception e) {
log.error("Failed to get ChainContribution [chainTaskId:{}" +
", workerAddress:{}]", chainTaskId, workerAddress, e);
log.error("Failed to get ChainContribution [chainTaskId:{}, workerAddress:{}]",
chainTaskId, workerAddress, e);
}
return Optional.empty();
}
Expand Down Expand Up @@ -337,13 +340,9 @@ public Optional<ChainCategory> getChainCategory(final long id) {
*/
private void retrieveCategory(final long id) {
try {
Tuple3<String, String, BigInteger> category = iexecHubContract
.viewCategoryABILegacy(BigInteger.valueOf(id)).send();
ChainCategory chainCategory = ChainCategory.tuple2ChainCategory(id,
category.component1(),
category.component2(),
category.component3()
);
final String txData = VIEW_CATEGORY_SELECTOR + Numeric.toHexStringNoPrefixZeroPadded(BigInteger.valueOf(id), 64);
final ChainCategory chainCategory = ChainCategory.fromRawData(
id, web3jAbstractService.sendCall(credentials.getAddress(), iexecHubAddress, txData));
if (chainCategory.getMaxExecutionTime() <= 0) {
log.error("Category max execution time should be greater than zero " +
"(likely a blockchain issue) [categoryId:{}, maxExecutionTime:{}]",
Expand Down Expand Up @@ -386,10 +385,21 @@ public Optional<ChainDataset> getChainDataset(final String datasetAddress) {
return Optional.empty();
}

public Optional<Integer> getWorkerScore(String address) {
/**
* Read worker score.
* <p>
* The score only changes in replicated deals when an actual replication occurs.
*
* @param address Worker address
* @return The worker score
* @see <a href="https://github.com/iExecBlockchainComputing/PoCo/blob/v6.1.0-contracts/contracts/facets/IexecPoco2Facet.sol#L462">distributeRewards</a>
*/
public Optional<Integer> getWorkerScore(final String address) {
if (address != null && !address.isEmpty()) {
try {
BigInteger workerScore = iexecHubContract.viewScore(address).send();
final String txData = VIEW_SCORE_SELECTOR +
Numeric.toHexStringNoPrefixZeroPadded(Numeric.toBigInt(address), 64);
final BigInteger workerScore = toBigInt(web3jAbstractService.sendCall(credentials.getAddress(), iexecHubAddress, txData));
return Optional.of(workerScore.intValue());
} catch (Exception e) {
log.error("Failed to getWorkerScore [address:{}]", address, e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,11 @@ public class AccessorsEncoder {
*/
public static final String OWNER_SELECTOR = "0x8da5cb5b";

public static final String VIEW_ACCOUNT_SELECTOR = "0x6b55f4a5";
public static final String VIEW_CATEGORY_SELECTOR = "0x4f5f44ec";
public static final String VIEW_CONSUMED_SELECTOR = "0x4b2bec8c";
public static final String VIEW_CONTRIBUTION_SELECTOR = "0xe741363b";
public static final String VIEW_SCORE_SELECTOR = "0xdb230b52";

// app
/**
Expand Down
43 changes: 15 additions & 28 deletions src/main/java/com/iexec/commons/poco/encoding/LogTopic.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,34 +39,21 @@ public class LogTopic {


public static String decode(String topic) {
switch (topic) {
case TRANSFER_EVENT:
return "Transfer";
case REWARD_EVENT:
return "Reward";
case SEIZE_EVENT:
return "Seize";
case LOCK_EVENT:
return "Lock";
case UNLOCK_EVENT:
return "Unlock";
case ORDERS_MATCHED_EVENT:
return "OrdersMatched";
case SCHEDULER_NOTICE_EVENT:
return "SchedulerNotice";
case TASK_INITIALIZE_EVENT:
return "TaskInitialize";
case TASK_CONTRIBUTE_EVENT:
return "TaskContribute";
case TASK_CONSENSUS_EVENT:
return "TaskConsensus";
case TASK_REVEAL_EVENT:
return "TaskReveal";
case TASK_FINALIZE_EVENT:
return "TaskFinalize";
default:
return topic;
}
return switch (topic) {
case TRANSFER_EVENT -> "Transfer";
case REWARD_EVENT -> "Reward";
case SEIZE_EVENT -> "Seize";
case LOCK_EVENT -> "Lock";
case UNLOCK_EVENT -> "Unlock";
case ORDERS_MATCHED_EVENT -> "OrdersMatched";
case SCHEDULER_NOTICE_EVENT -> "SchedulerNotice";
case TASK_INITIALIZE_EVENT -> "TaskInitialize";
case TASK_CONTRIBUTE_EVENT -> "TaskContribute";
case TASK_CONSENSUS_EVENT -> "TaskConsensus";
case TASK_REVEAL_EVENT -> "TaskReveal";
case TASK_FINALIZE_EVENT -> "TaskFinalize";
default -> topic;
};
}

}
20 changes: 20 additions & 0 deletions src/main/java/com/iexec/commons/poco/encoding/PoCoDataDecoder.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,24 @@
@Slf4j
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class PoCoDataDecoder {
/**
* Extracts 32 bytes hex strings from a raw data and converts them back to ASCII characters.
*
* @param parts Arrays of 32 bytes hex strings
* @param offset Where to find the first data which is the string length
* @return The decoded string
*/
public static String decodeToAsciiString(final String[] parts, final int offset) {
return BytesUtils.hexStringToAscii(decodeToHexString(parts, offset));
}

/**
* Extracts 32 bytes hex strings from a raw data.
*
* @param parts Arrays of 32 bytes hex strings
* @param offset Where to find the first data which is the string length
* @return The extracted hex string
*/
public static String decodeToHexString(final String[] parts, final int offset) {
final int size = toBigInt(parts[offset]).intValue();
log.debug("Size {}", size);
Expand All @@ -50,6 +64,12 @@ public static String decodeToHexString(final String[] parts, final int offset) {
return sb.toString();
}

/**
* Remove hex prefix and split every 32 bytes, i.e. every 64 hex characters.
*
* @param rawData Raw data to parse
* @return array containing 32 bytes length hex strings
*/
public static String[] toParts(final String rawData) {
final String[] parts = Numeric.cleanHexPrefix(rawData).split("(?<=\\G.{64})");
if (log.isTraceEnabled()) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* Copyright 2025 IEXEC BLOCKCHAIN TECH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.iexec.commons.poco.encoding;

import org.junit.jupiter.api.Test;
import org.web3j.crypto.Hash;

import static com.iexec.commons.poco.encoding.AccessorsEncoder.*;
import static org.assertj.core.api.Assertions.assertThat;

class AccessorsEncoderTests {
private String getSelector(final String methodSignature) {
return Hash.sha3String(methodSignature).substring(0, 10);
}

@Test
void checkSelectorValues() {
assertThat(getSelector("callbackgas()")).isEqualTo(CALLBACKGAS_SELECTOR);
assertThat(getSelector("contribution_deadline_ratio()")).isEqualTo(CONTRIBUTION_DEADLINE_RATIO_SELECTOR);
assertThat(getSelector("final_deadline_ratio()")).isEqualTo(FINAL_DEADLINE_RATIO_SELECTOR);
assertThat(getSelector("owner()")).isEqualTo(OWNER_SELECTOR);
assertThat(getSelector("viewAccount(address)")).isEqualTo(VIEW_ACCOUNT_SELECTOR);
assertThat(getSelector("viewCategory(uint256)")).isEqualTo(VIEW_CATEGORY_SELECTOR);
assertThat(getSelector("viewConsumed(bytes32)")).isEqualTo(VIEW_CONSUMED_SELECTOR);
assertThat(getSelector("viewContribution(bytes32,address)")).isEqualTo(VIEW_CONTRIBUTION_SELECTOR);
assertThat(getSelector("viewScore(address)")).isEqualTo(VIEW_SCORE_SELECTOR);
assertThat(getSelector("viewApp(address)")).isEqualTo(VIEW_APP_SELECTOR);
assertThat(getSelector("viewDataset(address)")).isEqualTo(VIEW_DATASET_SELECTOR);
}
}
Loading