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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ All notable changes to this project will be documented in this file.
- Add `getAssetAddressFromReceipt` method to `AssetDataEncoder`. (#78)
- Use `eth_call` Ethereum JSON-RPC API to predict assets on-chain address. (#79)
- Add `PoCoDataEncoder` with `initialize`, `contribute`, `reveal`, `finalize` and `contributeAndFinalize` support. (#80 #81)
- Add `eth_estimateGas` Ethereum JSON-RPC API support. (#82)

### Quality

Expand Down
17 changes: 17 additions & 0 deletions src/main/java/com/iexec/commons/poco/chain/SignerService.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import org.web3j.protocol.core.DefaultBlockParameter;
import org.web3j.protocol.core.DefaultBlockParameterName;
import org.web3j.protocol.core.Response;
import org.web3j.protocol.core.methods.response.EthEstimateGas;
import org.web3j.protocol.core.methods.response.EthSendTransaction;
import org.web3j.protocol.core.methods.response.Transaction;
import org.web3j.protocol.exceptions.JsonRpcError;
Expand Down Expand Up @@ -152,6 +153,22 @@ public String sendCall(String to, String data, DefaultBlockParameter defaultBloc
return value;
}

/**
* Estimates Gas amount to be used to mine the transaction described by the given payload.
*
* @param to Contract address to send the call to
* @param data Encoded data representing the method to estimate with its parameters
* @return The estimated Gas amount needed to mine the transaction
* @throws IOException in case of communication failure with the blockchain network
* @see <a href="https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_estimategas">eth_estimateGas JSON RPC-API</a>
*/
public BigInteger estimateGas(String to, String data) throws IOException {
final EthEstimateGas estimateGas = this.web3j.ethEstimateGas(org.web3j.protocol.core.methods.request.Transaction.createEthCallTransaction(
credentials.getAddress(), to, data)).send();
log.debug("estimateGas [amountUsed:{}]", estimateGas.getAmountUsed());
return estimateGas.getAmountUsed();
}

/**
* Sign and send transaction for signer
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
import java.util.concurrent.TimeUnit;

import static com.iexec.commons.poco.itest.IexecHubTestService.*;
import static com.iexec.commons.poco.itest.OrdersService.*;
import static com.iexec.commons.poco.itest.Web3jTestService.BLOCK_TIME;
import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat;
import static org.awaitility.Awaitility.await;
Expand Down Expand Up @@ -70,15 +71,18 @@ void init() throws CipherException, IOException {

@Test
void shouldContributeAndFinalize() throws Exception {
final String predictedAppAddress = iexecHubService.callCreateApp("my-app");
final String predictedDatasetAddress = iexecHubService.callCreateDataset("my-dataset");
final String predictedWorkerpoolAddress = iexecHubService.callCreateWorkerpool("my-workerpool");
final String predictedAppAddress = iexecHubService.callCreateApp(APP_NAME);
final String predictedDatasetAddress = iexecHubService.callCreateDataset(DATASET_NAME);
final String predictedWorkerpoolAddress = iexecHubService.callCreateWorkerpool(WORKERPOOL_NAME);
final BigInteger estimatedCreateAppGas = iexecHubService.estimateCreateApp(APP_NAME);
final BigInteger estimatedCreateDatasetGas = iexecHubService.estimateCreateDataset(DATASET_NAME);
final BigInteger estimatedCreateWorkerpoolGas = iexecHubService.estimateCreateWorkerpool(WORKERPOOL_NAME);
BigInteger nonce = web3jService.getNonce(signerService.getAddress());
final String appTxHash = iexecHubService.submitCreateAppTx(nonce, "my-app");
final String appTxHash = iexecHubService.submitCreateAppTx(nonce, estimatedCreateAppGas, APP_NAME);
nonce = nonce.add(BigInteger.ONE);
final String datasetTxHash = iexecHubService.submitCreateDatasetTx(nonce, "my-dataset");
final String datasetTxHash = iexecHubService.submitCreateDatasetTx(nonce, estimatedCreateDatasetGas, DATASET_NAME);
nonce = nonce.add(BigInteger.ONE);
final String workerpoolTxHash = iexecHubService.submitCreateWorkerpoolTx(nonce, "my-workerpool");
final String workerpoolTxHash = iexecHubService.submitCreateWorkerpoolTx(nonce, estimatedCreateWorkerpoolGas, WORKERPOOL_NAME);

// Wait for assets deployment to be able to call MatchOrders
await().atMost(BLOCK_TIME, TimeUnit.SECONDS)
Expand All @@ -89,6 +93,8 @@ void shouldContributeAndFinalize() throws Exception {
nonce = nonce.add(BigInteger.ONE);
final String matchOrdersTxHash = ordersService.submitMatchOrders(
predictedAppAddress, predictedDatasetAddress, predictedWorkerpoolAddress, nonce);
final BigInteger estimatedMatchOrdersGas = ordersService.estimateMatchOrders(
predictedAppAddress, predictedDatasetAddress, predictedWorkerpoolAddress);

// init
final String initializeTxData = PoCoDataEncoder.encodeInitialize(predictedDealId, 0);
Expand Down Expand Up @@ -124,6 +130,12 @@ void shouldContributeAndFinalize() throws Exception {
.containsExactly(predictedAppAddress, predictedDatasetAddress, predictedWorkerpoolAddress);
assertThat(iexecHubService.getChainDeal(predictedDealId)).isPresent();
assertThat(iexecHubService.getChainTask(predictedChainTaskId)).isPresent();

// Gas
web3jService.displayGas("createApp", estimatedCreateAppGas, appTxHash);
web3jService.displayGas("createDataset", estimatedCreateDatasetGas, datasetTxHash);
web3jService.displayGas("createWorkerpool", estimatedCreateWorkerpoolGas, workerpoolTxHash);
web3jService.displayGas("matchOrders", estimatedMatchOrdersGas, matchOrdersTxHash);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
import java.util.concurrent.TimeUnit;

import static com.iexec.commons.poco.itest.IexecHubTestService.*;
import static com.iexec.commons.poco.itest.OrdersService.*;
import static com.iexec.commons.poco.itest.Web3jTestService.BLOCK_TIME;
import static org.assertj.core.api.Assertions.assertThat;
import static org.awaitility.Awaitility.await;
Expand Down Expand Up @@ -70,15 +71,18 @@ void init() throws CipherException, IOException {

@Test
void shouldContributeRevealFinalize() throws Exception {
final String predictedAppAddress = iexecHubService.callCreateApp("my-app");
final String predictedDatasetAddress = iexecHubService.callCreateDataset("my-dataset");
final String predictedWorkerpoolAddress = iexecHubService.callCreateWorkerpool("my-workerpool");
final String predictedAppAddress = iexecHubService.callCreateApp(APP_NAME);
final String predictedDatasetAddress = iexecHubService.callCreateDataset(DATASET_NAME);
final String predictedWorkerpoolAddress = iexecHubService.callCreateWorkerpool(WORKERPOOL_NAME);
final BigInteger estimatedCreateAppGas = iexecHubService.estimateCreateApp(APP_NAME);
final BigInteger estimatedCreateDatasetGas = iexecHubService.estimateCreateDataset(DATASET_NAME);
final BigInteger estimatedCreateWorkerpoolGas = iexecHubService.estimateCreateWorkerpool(WORKERPOOL_NAME);
BigInteger nonce = web3jService.getNonce(signerService.getAddress());
final String appTxHash = iexecHubService.submitCreateAppTx(nonce, "my-app");
final String appTxHash = iexecHubService.submitCreateAppTx(nonce, estimatedCreateAppGas, APP_NAME);
nonce = nonce.add(BigInteger.ONE);
final String datasetTxHash = iexecHubService.submitCreateDatasetTx(nonce, "my-dataset");
final String datasetTxHash = iexecHubService.submitCreateDatasetTx(nonce, estimatedCreateDatasetGas, DATASET_NAME);
nonce = nonce.add(BigInteger.ONE);
final String workerpoolTxHash = iexecHubService.submitCreateWorkerpoolTx(nonce, "my-workerpool");
final String workerpoolTxHash = iexecHubService.submitCreateWorkerpoolTx(nonce, estimatedCreateWorkerpoolGas, WORKERPOOL_NAME);

// Wait for assets deployment to be able to call MatchOrders
await().atMost(BLOCK_TIME, TimeUnit.SECONDS)
Expand All @@ -87,6 +91,8 @@ void shouldContributeRevealFinalize() throws Exception {
final String predictedDealId = ordersService.callMatchOrders(
predictedAppAddress, predictedDatasetAddress, predictedWorkerpoolAddress);
final String predictedChainTaskId = ChainUtils.generateChainTaskId(predictedDealId, 0);
final BigInteger estimatedMatchOrdersGas = ordersService.estimateMatchOrders(
predictedAppAddress, predictedDatasetAddress, predictedWorkerpoolAddress);

// deal id
nonce = nonce.add(BigInteger.ONE);
Expand Down Expand Up @@ -139,6 +145,12 @@ void shouldContributeRevealFinalize() throws Exception {
.containsExactly(predictedAppAddress, predictedDatasetAddress, predictedWorkerpoolAddress);
assertThat(iexecHubService.getChainDeal(predictedDealId)).isPresent();
assertThat(iexecHubService.getChainTask(predictedChainTaskId)).isPresent();

// Gas
web3jService.displayGas("createApp", estimatedCreateAppGas, appTxHash);
web3jService.displayGas("createDataset", estimatedCreateDatasetGas, datasetTxHash);
web3jService.displayGas("createWorkerpool", estimatedCreateWorkerpoolGas, workerpoolTxHash);
web3jService.displayGas("matchOrders", estimatedMatchOrdersGas, matchOrdersTxHash);
}

}
103 changes: 65 additions & 38 deletions src/test/java/com/iexec/commons/poco/itest/IexecHubTestService.java
Original file line number Diff line number Diff line change
Expand Up @@ -45,99 +45,126 @@ public IexecHubTestService(Credentials credentials, Web3jAbstractService web3jAb
web3jAbstractService.getWeb3j(), web3jAbstractService.getChainId(), credentials);
}

// region createApp
public String callCreateApp(String name) throws IOException {
log.info("callCreateApp");
final String appRegistryAddress = toEthereumAddress(
signerService.sendCall(IEXEC_HUB_ADDRESS, APP_REGISTRY_SELECTOR));
final String appTxData = AssetDataEncoder.encodeApp(
signerService.getAddress(),
name,
"DOCKER",
"multiAddress",
Numeric.toHexStringNoPrefixZeroPadded(BigInteger.ZERO, 64),
"{}"
);
final String appTxData = createAppTxData(name);
return toEthereumAddress(signerService.sendCall(appRegistryAddress, appTxData));
}

public String submitCreateAppTx(BigInteger nonce, String name) throws IOException {
public BigInteger estimateCreateApp(String name) throws IOException {
log.info("estimateCreateApp");
final String appRegistryAddress = toEthereumAddress(
signerService.sendCall(IEXEC_HUB_ADDRESS, APP_REGISTRY_SELECTOR));
final String appTxData = createAppTxData(name);
return signerService.estimateGas(appRegistryAddress, appTxData);
}

public String submitCreateAppTx(BigInteger nonce, BigInteger gasLimit, String name) throws IOException {
log.info("submitCreateAppTx");
final String appRegistryAddress = toEthereumAddress(
signerService.sendCall(IEXEC_HUB_ADDRESS, APP_REGISTRY_SELECTOR));
log.info("app registry address {}", appRegistryAddress);
final String appTxData = AssetDataEncoder.encodeApp(
final String appTxData = createAppTxData(name);
final String appTxHash = signerService.signAndSendTransaction(
nonce, GAS_PRICE, gasLimit, appRegistryAddress, appTxData
);
log.info("app tx hash {}", appTxHash);
return appTxHash;
}

private String createAppTxData(String name) {
return AssetDataEncoder.encodeApp(
signerService.getAddress(),
name,
"DOCKER",
"multiAddress",
Numeric.toHexStringNoPrefixZeroPadded(BigInteger.ZERO, 64),
"{}"
);
final String appTxHash = signerService.signAndSendTransaction(
nonce, GAS_PRICE, GAS_LIMIT, appRegistryAddress, appTxData
);
log.info("app tx hash {}", appTxHash);
return appTxHash;
}
// endregion

// region createDataset
public String callCreateDataset(String name) throws IOException {
log.info("callCreateDataset");
final String datasetRegistryAddress = toEthereumAddress(
signerService.sendCall(IEXEC_HUB_ADDRESS, DATASET_REGISTRY_SELECTOR));
final String datasetTxData = AssetDataEncoder.encodeDataset(
signerService.getAddress(),
name,
"multiAddress",
Numeric.toHexStringNoPrefixZeroPadded(BigInteger.ZERO, 64)
);
final String datasetTxData = createDatasetTxData(name);
return toEthereumAddress(signerService.sendCall(datasetRegistryAddress, datasetTxData));
}

public String submitCreateDatasetTx(BigInteger nonce, String name) throws IOException {
public BigInteger estimateCreateDataset(String name) throws IOException {
log.info("callCreateDataset");
final String datasetRegistryAddress = toEthereumAddress(
signerService.sendCall(IEXEC_HUB_ADDRESS, DATASET_REGISTRY_SELECTOR));
final String datasetTxData = createDatasetTxData(name);
return signerService.estimateGas(datasetRegistryAddress, datasetTxData);
}

public String submitCreateDatasetTx(BigInteger nonce, BigInteger gasLimit, String name) throws IOException {
log.info("submitCreateDatasetTx");
final String datasetRegistryAddress = toEthereumAddress(
signerService.sendCall(IEXEC_HUB_ADDRESS, DATASET_REGISTRY_SELECTOR));
log.info("dataset registry address {}", datasetRegistryAddress);
final String datasetTxData = AssetDataEncoder.encodeDataset(
final String datasetTxData = createDatasetTxData(name);
final String datasetTxHash = signerService.signAndSendTransaction(
nonce, GAS_PRICE, gasLimit, datasetRegistryAddress, datasetTxData
);
log.info("dataset tx hash {}", datasetTxHash);
return datasetTxHash;
}

private String createDatasetTxData(String name) {
return AssetDataEncoder.encodeDataset(
signerService.getAddress(),
name,
"multiAddress",
Numeric.toHexStringNoPrefixZeroPadded(BigInteger.ZERO, 64)
);
final String datasetTxHash = signerService.signAndSendTransaction(
nonce, GAS_PRICE, GAS_LIMIT, datasetRegistryAddress, datasetTxData
);
log.info("dataset tx hash {}", datasetTxHash);
return datasetTxHash;
}
// enderegion

// region createWorkerpool
public String callCreateWorkerpool(String name) throws Exception {
log.info("callCreateWorkerpool");
final String workerpoolRegistryAddress = toEthereumAddress(
signerService.sendCall(IEXEC_HUB_ADDRESS, WORKERPOOL_REGISTRY_SELECTOR));
final String workerpoolTxData = AssetDataEncoder.encodeWorkerpool(
signerService.getAddress(),
name
);
final String workerpoolTxData = createWorkerpoolTxData(name);
return toEthereumAddress(signerService.sendCall(workerpoolRegistryAddress, workerpoolTxData));
}

public String submitCreateWorkerpoolTx(BigInteger nonce, String name) throws IOException {
public BigInteger estimateCreateWorkerpool(String name) throws Exception {
log.info("callCreateWorkerpool");
final String workerpoolRegistryAddress = toEthereumAddress(
signerService.sendCall(IEXEC_HUB_ADDRESS, WORKERPOOL_REGISTRY_SELECTOR));
final String workerpoolTxData = createWorkerpoolTxData(name);
return signerService.estimateGas(workerpoolRegistryAddress, workerpoolTxData);
}

public String submitCreateWorkerpoolTx(BigInteger nonce, BigInteger gasLimit, String name) throws IOException {
log.info("submitCreateWorkerpoolTx");
final String workerpoolRegistryAddress = toEthereumAddress(
signerService.sendCall(IEXEC_HUB_ADDRESS, WORKERPOOL_REGISTRY_SELECTOR));
log.info("workerpool registry address {}", workerpoolRegistryAddress);
final String workerpoolTxData = AssetDataEncoder.encodeWorkerpool(
signerService.getAddress(),
name
);
final String workerpoolTxData = createWorkerpoolTxData(name);
final String workerpoolTxHash = signerService.signAndSendTransaction(
nonce, GAS_PRICE, GAS_LIMIT, workerpoolRegistryAddress, workerpoolTxData
nonce, GAS_PRICE, gasLimit, workerpoolRegistryAddress, workerpoolTxData
);
log.info("workerpool tx hash {}", workerpoolTxHash);
return workerpoolTxHash;
}

private String createWorkerpoolTxData(String name) {
return AssetDataEncoder.encodeWorkerpool(
signerService.getAddress(),
name
);
}
// endregion

private String toEthereumAddress(String hexaString) {
return Numeric.toHexStringWithPrefixZeroPadded(
Numeric.toBigInt(hexaString), 40);
Expand Down
Loading