Skip to content

Commit 9e91aa1

Browse files
authored
feat: support assertDatasetDealCompatibility new PoCo method (#152)
1 parent 0073c06 commit 9e91aa1

File tree

10 files changed

+281
-91
lines changed

10 files changed

+281
-91
lines changed

docker-compose.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
services:
22
poco-chain:
3-
image: docker-regis.iex.ec/poco-chain:1.0.0-poco-v5.5.0-voucher-v1.0.0-nethermind
3+
image: docker-regis.iex.ec/poco-chain:1.1.0-poco-v6.1.0-contracts-voucher-v1.0.0-nethermind
44
expose:
55
- "8545"

src/main/java/com/iexec/commons/poco/chain/AbstractAssetDeploymentService.java

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
import java.math.BigInteger;
2525
import java.util.Objects;
2626

27+
import static com.iexec.commons.poco.chain.Web3jAbstractService.toEthereumAddress;
28+
2729
@Slf4j
2830
public abstract class AbstractAssetDeploymentService {
2931
private static final String ASSET_REGISTRY_ADDRESS_INITIALIZATION_NEEDED =
@@ -60,9 +62,4 @@ public String submitAssetTxData(BigInteger nonce, BigInteger gasPrice, String as
6062
Objects.requireNonNull(assetRegistryAddress, ASSET_REGISTRY_ADDRESS_INITIALIZATION_NEEDED);
6163
return signerService.signAndSendTransaction(nonce, gasPrice, assetRegistryAddress, assetTxData);
6264
}
63-
64-
private String toEthereumAddress(String hexaString) {
65-
return Numeric.toHexStringWithPrefixZeroPadded(
66-
Numeric.toBigInt(hexaString), 40);
67-
}
6865
}

src/main/java/com/iexec/commons/poco/chain/IexecHubAbstractService.java

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818

1919
import com.iexec.commons.poco.contract.generated.IexecHubContract;
2020
import com.iexec.commons.poco.eip712.EIP712Domain;
21+
import com.iexec.commons.poco.encoding.MatchOrdersDataEncoder;
22+
import com.iexec.commons.poco.order.DatasetOrder;
2123
import com.iexec.commons.poco.task.TaskDescription;
2224
import com.iexec.commons.poco.utils.BytesUtils;
2325
import com.iexec.commons.poco.utils.MultiAddressHelper;
@@ -28,7 +30,6 @@
2830
import org.web3j.abi.FunctionReturnDecoder;
2931
import org.web3j.crypto.Credentials;
3032
import org.web3j.ens.EnsResolutionException;
31-
import org.web3j.protocol.core.DefaultBlockParameterName;
3233
import org.web3j.tuples.generated.Tuple3;
3334
import org.web3j.tx.RawTransactionManager;
3435
import org.web3j.tx.gas.ContractGasProvider;
@@ -41,6 +42,8 @@
4142
import java.util.Map;
4243
import java.util.Optional;
4344

45+
import static com.iexec.commons.poco.chain.Web3jAbstractService.toBigInt;
46+
import static com.iexec.commons.poco.chain.Web3jAbstractService.toEthereumAddress;
4447
import static com.iexec.commons.poco.encoding.AccessorsEncoder.*;
4548
import static com.iexec.commons.poco.tee.TeeEnclaveConfiguration.buildEnclaveConfigurationFromJsonString;
4649
import static com.iexec.commons.poco.utils.BytesUtils.isNonZeroedBytes32;
@@ -433,7 +436,7 @@ private String sendCallAndDecodeDynamicBytes(final String address, final String
433436
* @throws IOException on communication error
434437
*/
435438
private String sendCallAndGetRawResult(final String address, final String selector) throws IOException {
436-
return txManager.sendCall(address, selector, DefaultBlockParameterName.LATEST);
439+
return web3jAbstractService.sendCall(address, selector);
437440
}
438441

439442
public Optional<Integer> getWorkerScore(String address) {
@@ -537,6 +540,11 @@ public boolean isTeeTask(String chainTaskId) {
537540

538541
// region accessors
539542

543+
public void assertDatasetDealCompatibility(final DatasetOrder datasetOrder, final String dealId) throws IOException {
544+
final String txData = MatchOrdersDataEncoder.encodeAssertDatasetDealCompatibility(datasetOrder, dealId);
545+
web3jAbstractService.sendCall(iexecHubAddress, txData);
546+
}
547+
540548
/**
541549
* Send call to callbackgas() PoCo method.
542550
*
@@ -568,14 +576,12 @@ public BigInteger getFinalDeadlineRatio() throws IOException {
568576
}
569577

570578
private BigInteger sendCallWithFunctionSelector(final String functionSelector) throws IOException {
571-
return Numeric.toBigInt(
572-
txManager.sendCall(iexecHubAddress, functionSelector, DefaultBlockParameterName.LATEST));
579+
return toBigInt(web3jAbstractService.sendCall(iexecHubAddress, functionSelector));
573580
}
574581

575582
public String getOwner(final String address) {
576583
try {
577-
return Numeric.toHexStringWithPrefixZeroPadded(
578-
Numeric.toBigInt(txManager.sendCall(address, OWNER_SELECTOR, DefaultBlockParameterName.LATEST)), 40);
584+
return toEthereumAddress(web3jAbstractService.sendCall(address, OWNER_SELECTOR));
579585
} catch (Exception e) {
580586
log.error("Failed to get owner [address:{}]", address, e);
581587
}
@@ -591,8 +597,8 @@ public String getOwner(final String address) {
591597
* @throws IOException on communication error with the blockchain network
592598
*/
593599
public BigInteger viewConsumed(final String typedHash) throws IOException {
594-
return Numeric.toBigInt(
595-
txManager.sendCall(iexecHubAddress, VIEW_CONSUMED_SELECTOR + Numeric.cleanHexPrefix(typedHash), DefaultBlockParameterName.LATEST));
600+
final String payload = VIEW_CONSUMED_SELECTOR + Numeric.cleanHexPrefix(typedHash);
601+
return toBigInt(web3jAbstractService.sendCall(iexecHubAddress, payload));
596602
}
597603

598604
// endregion

src/main/java/com/iexec/commons/poco/chain/SignerService.java

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import org.web3j.protocol.core.DefaultBlockParameter;
3434
import org.web3j.protocol.core.DefaultBlockParameterName;
3535
import org.web3j.protocol.core.Response;
36+
import org.web3j.protocol.core.methods.response.EthCall;
3637
import org.web3j.protocol.core.methods.response.EthEstimateGas;
3738
import org.web3j.protocol.core.methods.response.EthSendTransaction;
3839
import org.web3j.protocol.core.methods.response.Transaction;
@@ -45,6 +46,11 @@
4546
import java.security.InvalidAlgorithmParameterException;
4647
import java.security.NoSuchAlgorithmException;
4748
import java.security.NoSuchProviderException;
49+
import java.util.regex.Matcher;
50+
import java.util.regex.Pattern;
51+
52+
import static com.iexec.commons.poco.chain.Web3jAbstractService.GENERIC_EVM_ERROR_MESSAGE;
53+
import static org.web3j.protocol.core.methods.request.Transaction.createEthCallTransaction;
4854

4955
@Slf4j
5056
public class SignerService {
@@ -163,12 +169,23 @@ public String signEIP712EntityAndBuildToken(EIP712Entity<?> eip712Entity) {
163169
return signedMessage == null ? null : String.join("_", hash, signedMessage, credentials.getAddress());
164170
}
165171

172+
// TODO keep single instance with the one in Web3jAbstractService
173+
private void decodeAndThrowEvmRpcError(final Response.Error error, final String label) {
174+
log.error("{}} failed [message:{}, code:{}, data:{}]",
175+
label, error.getMessage(), error.getCode(), error.getData());
176+
final String revertMessage = GENERIC_EVM_ERROR_MESSAGE.equals(error.getMessage()) ? error.getData() : error.getMessage();
177+
final Pattern p = Pattern.compile("^\"?Reverted (0x[0-9A-Fa-f]+)\"?$");
178+
final Matcher m = p.matcher(revertMessage);
179+
final String message = m.matches() ? BytesUtils.hexStringToAscii(m.group(1)) : revertMessage;
180+
throw new JsonRpcError(error.getCode(), message, null);
181+
}
182+
166183
/**
167184
* Sends an {@code eth_call} to an Ethereum address.
168185
* <p>
169186
* The call is synchronous and does not modify the blockchain state.
170187
* <p>
171-
* The {@code sendCall} method can throw runtime exceptions, specifically {@code ContractCallException}.
188+
* The {@code sendCall} method can throw runtime exceptions, specifically {@code JsonRpcError}.
172189
* Those exceptions must be caught and handled properly in the business code.
173190
*
174191
* @param to Contract address to send the call to
@@ -182,9 +199,13 @@ public String sendCall(String to, String data) throws IOException {
182199
}
183200

184201
public String sendCall(String to, String data, DefaultBlockParameter defaultBlockParameter) throws IOException {
185-
final String value = txManager.sendCall(to, data, defaultBlockParameter);
186-
log.debug("value {}", value);
187-
return value;
202+
final EthCall ethCall = web3j.ethCall(
203+
createEthCallTransaction(credentials.getAddress(), to, data), defaultBlockParameter).send();
204+
if (ethCall.hasError()) {
205+
decodeAndThrowEvmRpcError(ethCall.getError(), "ethCall");
206+
}
207+
log.debug("ethCall [value:{}]", ethCall.getValue());
208+
return ethCall.getValue();
188209
}
189210

190211
/**
@@ -197,13 +218,10 @@ public String sendCall(String to, String data, DefaultBlockParameter defaultBloc
197218
* @see <a href="https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_estimategas">eth_estimateGas JSON RPC-API</a>
198219
*/
199220
public BigInteger estimateGas(String to, String data) throws IOException {
200-
final EthEstimateGas estimateGas = this.web3j.ethEstimateGas(org.web3j.protocol.core.methods.request.Transaction.createEthCallTransaction(
201-
credentials.getAddress(), to, data)).send();
221+
final EthEstimateGas estimateGas = web3j.ethEstimateGas(
222+
createEthCallTransaction(credentials.getAddress(), to, data)).send();
202223
if (estimateGas.hasError()) {
203-
final Response.Error responseError = estimateGas.getError();
204-
log.error("estimateGas failed [message:{}, code:{}, data:{}]",
205-
responseError.getMessage(), responseError.getCode(), responseError.getData());
206-
throw new JsonRpcError(responseError);
224+
decodeAndThrowEvmRpcError(estimateGas.getError(), "estimateGas");
207225
}
208226
log.debug("estimateGas [amountUsed:{}]", estimateGas.getAmountUsed());
209227
return estimateGas.getAmountUsed();

src/main/java/com/iexec/commons/poco/chain/Web3jAbstractService.java

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,19 +16,25 @@
1616

1717
package com.iexec.commons.poco.chain;
1818

19+
import com.iexec.commons.poco.utils.BytesUtils;
1920
import com.iexec.commons.poco.utils.WaitUtils;
2021
import jakarta.annotation.PostConstruct;
2122
import lombok.Getter;
2223
import lombok.extern.slf4j.Slf4j;
2324
import org.web3j.protocol.Web3j;
25+
import org.web3j.protocol.core.DefaultBlockParameter;
2426
import org.web3j.protocol.core.DefaultBlockParameterName;
27+
import org.web3j.protocol.core.Response;
28+
import org.web3j.protocol.core.methods.response.EthCall;
2529
import org.web3j.protocol.core.methods.response.Transaction;
2630
import org.web3j.protocol.core.methods.response.TransactionReceipt;
31+
import org.web3j.protocol.exceptions.JsonRpcError;
2732
import org.web3j.protocol.http.HttpService;
2833
import org.web3j.tx.gas.ContractGasProvider;
2934
import org.web3j.tx.gas.DynamicGasProvider;
3035
import org.web3j.tx.gas.PriorityGasProvider;
3136
import org.web3j.utils.Async;
37+
import org.web3j.utils.Numeric;
3238

3339
import java.io.IOException;
3440
import java.math.BigDecimal;
@@ -37,13 +43,18 @@
3743
import java.util.NoSuchElementException;
3844
import java.util.Optional;
3945
import java.util.function.Predicate;
46+
import java.util.regex.Matcher;
47+
import java.util.regex.Pattern;
4048

4149
import static com.iexec.commons.poco.chain.ChainUtils.weiToEth;
4250
import static com.iexec.commons.poco.encoding.PoCoDataEncoder.GAS_LIMIT_CAP;
51+
import static org.web3j.protocol.core.methods.request.Transaction.createEthCallTransaction;
4352

4453
@Slf4j
4554
public abstract class Web3jAbstractService {
4655

56+
public static final String GENERIC_EVM_ERROR_MESSAGE = "VM execution error.";
57+
4758
@Getter
4859
private final int chainId;
4960
private final String chainNodeAddress;
@@ -190,6 +201,44 @@ public boolean isBlockAvailable(long blockNumber) {
190201
return false;
191202
}
192203

204+
/**
205+
* Sends an {@code eth_call} to an Ethereum address.
206+
* <p>
207+
* The call is synchronous and does not modify the blockchain state.
208+
* <p>
209+
* The {@code sendCall} method can throw runtime exceptions, specifically {@code JsonRpcError}.
210+
* Those exceptions must be caught and handled properly in the business code.
211+
*
212+
* @param to Contract address to send the call to
213+
* @param data Encoded data representing the method to call with its parameters
214+
* @return A single value returned by the called method.
215+
* @throws IOException in case of communication failure with the blockchain network.
216+
* @see <a href="https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_call">eth_call JSON-RPC API</a>
217+
*/
218+
public String sendCall(final String to, final String data) throws IOException {
219+
return sendCall(to, data, DefaultBlockParameterName.LATEST);
220+
}
221+
222+
public String sendCall(final String to, final String data, final DefaultBlockParameter defaultBlockParameter) throws IOException {
223+
final EthCall ethCall = web3j.ethCall(
224+
createEthCallTransaction("", to, data), defaultBlockParameter).send();
225+
if (ethCall.hasError()) {
226+
decodeAndThrowEvmRpcError(ethCall.getError());
227+
}
228+
log.debug("ethCall [value:{}]", ethCall.getValue());
229+
return ethCall.getValue();
230+
}
231+
232+
private void decodeAndThrowEvmRpcError(final Response.Error error) {
233+
log.error("ethCall failed [message:{}, code:{}, data:{}]",
234+
error.getMessage(), error.getCode(), error.getData());
235+
final String revertMessage = GENERIC_EVM_ERROR_MESSAGE.equals(error.getMessage()) ? error.getData() : error.getMessage();
236+
final Pattern p = Pattern.compile("^\"?Reverted (0x[0-9A-Fa-f]+)\"?$");
237+
final Matcher m = p.matcher(revertMessage);
238+
final String message = m.matches() ? BytesUtils.hexStringToAscii(m.group(1)) : revertMessage;
239+
throw new JsonRpcError(error.getCode(), message, null);
240+
}
241+
193242
public boolean hasEnoughGas(String address) {
194243
// if a sidechain is used, there is no need to check if the wallet has enough gas.
195244
// if mainnet is used, the check should be done.
@@ -309,4 +358,12 @@ public boolean repeatCheck(int nbBlocksToWaitPerTry, int maxTry, String logTag,
309358
logTag, functionArgs, maxTry, msToWait, timePerBlock);
310359
return false;
311360
}
361+
362+
public static BigInteger toBigInt(final String hexString) {
363+
return Numeric.toBigInt(hexString);
364+
}
365+
366+
public static String toEthereumAddress(final String hexString) {
367+
return Numeric.toHexStringWithPrefixZeroPadded(Numeric.toBigInt(hexString), 40);
368+
}
312369
}

src/main/java/com/iexec/commons/poco/encoding/MatchOrdersDataEncoder.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,22 @@
3636
@NoArgsConstructor(access = AccessLevel.PRIVATE)
3737
public class MatchOrdersDataEncoder {
3838

39+
private static final String ASSERT_DATASET_DEAL_COMPATIBILITY_SELECTOR = "0x80f03425";
3940
private static final String MATCH_ORDERS_SELECTOR = "0x156194d4";
4041

42+
public static String encodeAssertDatasetDealCompatibility(final DatasetOrder datasetOrder, final String dealId) {
43+
final StringBuilder sb = new StringBuilder(ASSERT_DATASET_DEAL_COMPATIBILITY_SELECTOR);
44+
long offset = 2;
45+
String datasetOrderContribOffset = toHexString(BigInteger.valueOf(offset * 32));
46+
String datasetOrderContrib = createDatasetOrderTxData(datasetOrder);
47+
48+
sb.append(datasetOrderContribOffset);
49+
sb.append(toHexString(dealId));
50+
sb.append(datasetOrderContrib);
51+
52+
return sb.toString();
53+
}
54+
4155
/**
4256
* Encodes a {@code BrokerOrder} to a hexadecimal string. This string is the payload representing
4357
* a {@code matchOrders} call. This call is submitted to the blockchain network by providing the payload

src/test/java/com/iexec/commons/poco/itest/AssetRegistriesTests.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
import org.web3j.crypto.Credentials;
3131
import org.web3j.crypto.WalletUtils;
3232
import org.web3j.crypto.exception.CipherException;
33-
import org.web3j.tx.exceptions.ContractCallException;
33+
import org.web3j.protocol.exceptions.JsonRpcError;
3434

3535
import java.io.File;
3636
import java.io.IOException;
@@ -122,17 +122,17 @@ void shouldCreateCallRevertWhenAssetDeployed() throws IOException {
122122
);
123123

124124
// call on create assets should revert
125-
final String errorMessage = "Contract Call has been reverted by the EVM with the reason: 'VM execution error.'.";
125+
final String errorMessage = "Create2: Failed on deploy";
126126

127127
assertAll(
128128
() -> assertThatThrownBy(() -> iexecHubService.callCreateApp(appName), "Should have failed to call createApp")
129-
.isInstanceOf(ContractCallException.class)
129+
.isInstanceOf(JsonRpcError.class)
130130
.hasMessage(errorMessage),
131131
() -> assertThatThrownBy(() -> iexecHubService.callCreateDataset(datasetName), "Should have failed to call createDataset")
132-
.isInstanceOf(ContractCallException.class)
132+
.isInstanceOf(JsonRpcError.class)
133133
.hasMessage(errorMessage),
134134
() -> assertThatThrownBy(() -> iexecHubService.callCreateWorkerpool(workerpoolName), "Should have failed to call createWorkerpool")
135-
.isInstanceOf(ContractCallException.class)
135+
.isInstanceOf(JsonRpcError.class)
136136
.hasMessage(errorMessage)
137137
);
138138

src/test/java/com/iexec/commons/poco/itest/ChainTests.java

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -77,14 +77,14 @@ void init() throws CipherException, IOException {
7777
void shouldGetAccount() {
7878
final ChainAccount chainAccount = iexecHubService.getChainAccount(credentials.getAddress()).orElse(null);
7979
assertThat(chainAccount).isNotNull();
80-
assertThat(chainAccount.getDeposit()).isEqualTo(40_178L);
80+
assertThat(chainAccount.getDeposit()).isEqualTo(1000000000000L);
8181
assertThat(chainAccount.getLocked()).isZero();
8282
}
8383

8484
@Test
8585
void shouldGetBalance() {
8686
final BigInteger balance = web3jService.getBalance(credentials.getAddress()).orElse(null);
87-
assertThat(balance).isEqualTo(new BigInteger("3188369135434504514964210500676909925639291603846501657344"));
87+
assertThat(balance).isEqualTo(new BigInteger("1000000000000000000000"));
8888
}
8989

9090
@Test
@@ -144,11 +144,11 @@ void shouldGetCategory(long id, ChainCategory expectedCategory) {
144144

145145
private static Stream<Arguments> categoryProvider() {
146146
return Stream.of(
147-
Arguments.of(0, ChainCategory.builder().id(0).name("XS").description("{}").maxExecutionTime(300_000L).build()),
148-
Arguments.of(1, ChainCategory.builder().id(1).name("S").description("{}").maxExecutionTime(1_200_000L).build()),
149-
Arguments.of(2, ChainCategory.builder().id(2).name("M").description("{}").maxExecutionTime(3_600_000L).build()),
150-
Arguments.of(3, ChainCategory.builder().id(3).name("L").description("{}").maxExecutionTime(10_800_000L).build()),
151-
Arguments.of(4, ChainCategory.builder().id(4).name("XL").description("{}").maxExecutionTime(36_000_000L).build())
147+
Arguments.of(0, ChainCategory.builder().id(0).name("XS").description("\"\"").maxExecutionTime(300_000L).build()),
148+
Arguments.of(1, ChainCategory.builder().id(1).name("S").description("\"\"").maxExecutionTime(1_200_000L).build()),
149+
Arguments.of(2, ChainCategory.builder().id(2).name("M").description("\"\"").maxExecutionTime(3_600_000L).build()),
150+
Arguments.of(3, ChainCategory.builder().id(3).name("L").description("\"\"").maxExecutionTime(10_800_000L).build()),
151+
Arguments.of(4, ChainCategory.builder().id(4).name("XL").description("\"\"").maxExecutionTime(36_000_000L).build())
152152
);
153153
}
154154

src/test/java/com/iexec/commons/poco/itest/IexecHubTestService.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
public class IexecHubTestService extends IexecHubAbstractService {
4141
static final BigInteger GAS_PRICE = BigInteger.valueOf(22_000_000_000L);
4242
static final BigInteger GAS_LIMIT = BigInteger.valueOf(1_000_000L);
43-
static final String IEXEC_HUB_ADDRESS = "0xc4b11f41746D3Ad8504da5B383E1aB9aa969AbC7";
43+
static final String IEXEC_HUB_ADDRESS = "0xeB196D71Bf359bfDB7Ee54429236A09DBF3966B3";
4444

4545
static final String ASSET_MULTI_ADDRESS = "multiAddress";
4646
static final String ASSET_CHECKSUM = Numeric.toHexStringNoPrefix(new byte[32]);

0 commit comments

Comments
 (0)