diff --git a/examples/src/main/java/com/hedera/hashgraph/sdk/examples/MirrorNodeContractQueriesExample.java b/examples/src/main/java/com/hedera/hashgraph/sdk/examples/MirrorNodeContractQueriesExample.java new file mode 100644 index 000000000..0180cc224 --- /dev/null +++ b/examples/src/main/java/com/hedera/hashgraph/sdk/examples/MirrorNodeContractQueriesExample.java @@ -0,0 +1,176 @@ +/*- + * + * Hedera Java SDK + * + * Copyright (C) 2023 - 2024 Hedera Hashgraph, LLC + * + * 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.hedera.hashgraph.sdk.examples; + +import com.hedera.hashgraph.sdk.AccountId; +import com.hedera.hashgraph.sdk.Client; +import com.hedera.hashgraph.sdk.ContractCallQuery; +import com.hedera.hashgraph.sdk.ContractCreateTransaction; +import com.hedera.hashgraph.sdk.ContractFunctionParameters; +import com.hedera.hashgraph.sdk.FileCreateTransaction; +import com.hedera.hashgraph.sdk.FileId; +import com.hedera.hashgraph.sdk.Hbar; +import com.hedera.hashgraph.sdk.MirrorNodeContractCallQuery; +import com.hedera.hashgraph.sdk.MirrorNodeContractEstimateGasQuery; +import com.hedera.hashgraph.sdk.MirrorNodeContractQuery; +import com.hedera.hashgraph.sdk.PrivateKey; +import com.hedera.hashgraph.sdk.PublicKey; +import com.hedera.hashgraph.sdk.TransactionReceipt; +import com.hedera.hashgraph.sdk.TransactionResponse; +import com.hedera.hashgraph.sdk.logger.LogLevel; +import com.hedera.hashgraph.sdk.logger.Logger; +import io.github.cdimascio.dotenv.Dotenv; +import java.nio.charset.StandardCharsets; +import java.util.Objects; + +public class MirrorNodeContractQueriesExample { + /* + * See .env.sample in the examples folder root for how to specify values below + * or set environment variables with the same names. + */ + + /** + * Operator's account ID. + * Used to sign and pay for operations on Hedera. + */ + private static final AccountId OPERATOR_ID = AccountId.fromString(Objects.requireNonNull(Dotenv.load().get("OPERATOR_ID"))); + + /** + * Operator's private key. + */ + private static final PrivateKey OPERATOR_KEY = PrivateKey.fromString(Objects.requireNonNull(Dotenv.load().get("OPERATOR_KEY"))); + + /** + * HEDERA_NETWORK defaults to testnet if not specified in dotenv file. + * Network can be: localhost, testnet, previewnet or mainnet. + */ + private static final String HEDERA_NETWORK = Dotenv.load().get("HEDERA_NETWORK", "testnet"); + + /** + * SDK_LOG_LEVEL defaults to SILENT if not specified in dotenv file. + * Log levels can be: TRACE, DEBUG, INFO, WARN, ERROR, SILENT. + *

+ * Important pre-requisite: set simple logger log level to same level as the SDK_LOG_LEVEL, + * for example via VM options: -Dorg.slf4j.simpleLogger.log.com.hedera.hashgraph=trace + */ + private static final String SDK_LOG_LEVEL = Dotenv.load().get("SDK_LOG_LEVEL", "SILENT"); + + private static final String SMART_CONTRACT_BYTECODE = "608060405234801561001057600080fd5b506040516104d73803806104d78339818101604052602081101561003357600080fd5b810190808051604051939291908464010000000082111561005357600080fd5b90830190602082018581111561006857600080fd5b825164010000000081118282018810171561008257600080fd5b82525081516020918201929091019080838360005b838110156100af578181015183820152602001610097565b50505050905090810190601f1680156100dc5780820380516001836020036101000a031916815260200191505b506040525050600080546001600160a01b0319163317905550805161010890600190602084019061010f565b50506101aa565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061015057805160ff191683800117855561017d565b8280016001018555821561017d579182015b8281111561017d578251825591602001919060010190610162565b5061018992915061018d565b5090565b6101a791905b808211156101895760008155600101610193565b90565b61031e806101b96000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c8063368b87721461004657806341c0e1b5146100ee578063ce6d41de146100f6575b600080fd5b6100ec6004803603602081101561005c57600080fd5b81019060208101813564010000000081111561007757600080fd5b82018360208201111561008957600080fd5b803590602001918460018302840111640100000000831117156100ab57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550610173945050505050565b005b6100ec6101a2565b6100fe6101ba565b6040805160208082528351818301528351919283929083019185019080838360005b83811015610138578181015183820152602001610120565b50505050905090810190601f1680156101655780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6000546001600160a01b0316331461018a5761019f565b805161019d906001906020840190610250565b505b50565b6000546001600160a01b03163314156101b85733ff5b565b60018054604080516020601f600260001961010087891615020190951694909404938401819004810282018101909252828152606093909290918301828280156102455780601f1061021a57610100808354040283529160200191610245565b820191906000526020600020905b81548152906001019060200180831161022857829003601f168201915b505050505090505b90565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061029157805160ff19168380011785556102be565b828001600101855582156102be579182015b828111156102be5782518255916020019190600101906102a3565b506102ca9291506102ce565b5090565b61024d91905b808211156102ca57600081556001016102d456fea264697066735822122084964d4c3f6bc912a9d20e14e449721012d625aa3c8a12de41ae5519752fc89064736f6c63430006000033"; + + public static void main(String[] args) throws Exception { + System.out.println("Mirror node contract query Example Start!"); + + /* + * Step 0: + * Create and configure the SDK Client. + */ + Client client = ClientHelper.forName(HEDERA_NETWORK); + // All generated transactions will be paid by this account and signed by this key. + client.setOperator(OPERATOR_ID, OPERATOR_KEY); + // Attach logger to the SDK Client. + client.setLogger(new Logger(LogLevel.valueOf(SDK_LOG_LEVEL))); + + var operatorPublicKey = OPERATOR_KEY.getPublicKey(); + + /* + * Step 1: + * Create the contract + */ + System.out.println("Creating new file..."); + TransactionResponse fileCreateTxResponse = new FileCreateTransaction() + // Use the same key as the operator to "own" this file. + .setKeys(operatorPublicKey) + .setContents(SMART_CONTRACT_BYTECODE) + // The default max fee of 1 Hbar is not enough to create a file (starts around ~1.1 Hbar). + .setMaxTransactionFee(Hbar.from(2)) + .execute(client); + + TransactionReceipt fileCreateTxReceipt = fileCreateTxResponse.getReceipt(client); + FileId newFileId = fileCreateTxReceipt.fileId; + + Objects.requireNonNull(newFileId); + System.out.println("Created new file with ID: " + newFileId); + + var response = new ContractCreateTransaction() + .setAdminKey(client.getOperatorPublicKey()) + .setGas(200000) + .setConstructorParameters(new ContractFunctionParameters().addString("Hello from Hedera.")) + .setBytecodeFileId(newFileId) + .setContractMemo("Simple contract with string field") + .execute(client); + + var contractId = Objects.requireNonNull(response.getReceipt(client).contractId); + + /* + * Step 3: + * Wait for mirror node to import data + */ + Thread.sleep(4000); + + /* + * Step 4: + * Estimate the gas needed + */ + var gas = new MirrorNodeContractEstimateGasQuery() + .setContractId(contractId) + .setFunction("getMessage") + .execute(client); + + System.out.println("Gas needed for this query: " + gas); + + /* + * Step 5: + * Do the query against the consensus node using the estimated gas + */ + var callQuery = new ContractCallQuery() + .setContractId(contractId) + .setGas(gas) + .setFunction("getMessage") + .setQueryPayment(new Hbar(1)); + + var result = callQuery + .execute(client); + + /* + * Step 5: + * Simulate the transaction for free, using the mirror node + */ + var simulationResult = new MirrorNodeContractCallQuery() + .setContractId(contractId) + .setFunction("getMessage") + .execute(client); + + System.out.println("Simulation result: " + decodeABIHex(simulationResult.substring(2))); + System.out.println("Contract call result: " + result.getString(0)); + } + private static String decodeABIHex(String hex) { + int length = Integer.parseInt(hex.substring(64, 128), 16); + + String hexStringData = hex.substring(128, 128 + length * 2); + + byte[] bytes = new byte[length]; + for (int i = 0; i < length; i++) { + bytes[i] = (byte) Integer.parseInt(hexStringData.substring(i * 2, i * 2 + 2), 16); + } + + return new String(bytes, StandardCharsets.UTF_8); + } +} diff --git a/sdk/src/main/java/com/hedera/hashgraph/sdk/MirrorNodeContractCallQuery.java b/sdk/src/main/java/com/hedera/hashgraph/sdk/MirrorNodeContractCallQuery.java new file mode 100644 index 000000000..7601f683c --- /dev/null +++ b/sdk/src/main/java/com/hedera/hashgraph/sdk/MirrorNodeContractCallQuery.java @@ -0,0 +1,42 @@ +/*- + * + * Hedera Java SDK + * + * Copyright (C) 2020 - 2024 Hedera Hashgraph, LLC + * + * 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.hedera.hashgraph.sdk; + +import java.util.concurrent.ExecutionException; + +public class MirrorNodeContractCallQuery extends MirrorNodeContractQuery { + /** + * Does transient simulation of read-write operations and returns the result in hexadecimal string format. + * + * @param client The Client instance to perform the operation with + * @return The result of the contract call + * @throws ExecutionException + * @throws InterruptedException + */ + public String execute(Client client) throws ExecutionException, InterruptedException { + return call(client); + } + + @Override + public String toString() { + return "MirrorNodeContractCallQuery" + super.toString(); + } +} diff --git a/sdk/src/main/java/com/hedera/hashgraph/sdk/MirrorNodeContractEstimateGasQuery.java b/sdk/src/main/java/com/hedera/hashgraph/sdk/MirrorNodeContractEstimateGasQuery.java new file mode 100644 index 000000000..2c9562c95 --- /dev/null +++ b/sdk/src/main/java/com/hedera/hashgraph/sdk/MirrorNodeContractEstimateGasQuery.java @@ -0,0 +1,43 @@ +/*- + * + * Hedera Java SDK + * + * Copyright (C) 2020 - 2024 Hedera Hashgraph, LLC + * + * 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.hedera.hashgraph.sdk; + +import java.util.concurrent.ExecutionException; + +public class MirrorNodeContractEstimateGasQuery extends MirrorNodeContractQuery { + + /** + * Returns gas estimation for the EVM execution. + * + * @param client The Client instance to perform the operation with + * @return The estimated gas cost + * @throws ExecutionException + * @throws InterruptedException + */ + public long execute(Client client) throws ExecutionException, InterruptedException { + return estimate(client); + } + + @Override + public String toString() { + return "MirrorNodeContractEstimateGasQuery" + super.toString(); + } +} diff --git a/sdk/src/main/java/com/hedera/hashgraph/sdk/MirrorNodeContractQuery.java b/sdk/src/main/java/com/hedera/hashgraph/sdk/MirrorNodeContractQuery.java index c49032c38..6047ea64c 100644 --- a/sdk/src/main/java/com/hedera/hashgraph/sdk/MirrorNodeContractQuery.java +++ b/sdk/src/main/java/com/hedera/hashgraph/sdk/MirrorNodeContractQuery.java @@ -38,7 +38,7 @@ * MirrorNodeContractQuery returns a result from EVM execution such as cost-free execution of read-only smart contract * queries, gas estimation, and transient simulation of read-write operations. */ -public class MirrorNodeContractQuery { +public abstract class MirrorNodeContractQuery> { // The contract we are sending the transaction to private ContractId contractId = null; private String contractEvmAddress = null; @@ -56,6 +56,11 @@ public class MirrorNodeContractQuery { // The block number for the simulation private long blockNumber; + @SuppressWarnings("unchecked") + protected T self() { + return (T) this; + } + public ContractId getContractId() { return this.contractId; } @@ -66,10 +71,10 @@ public ContractId getContractId() { * @param contractId The ContractId to be set * @return {@code this} */ - public MirrorNodeContractQuery setContractId(ContractId contractId) { + public T setContractId(ContractId contractId) { Objects.requireNonNull(contractId); this.contractId = contractId; - return this; + return self(); } public String getContractEvmAddress() { @@ -82,11 +87,11 @@ public String getContractEvmAddress() { * @param contractEvmAddress * @return {@code this} */ - public MirrorNodeContractQuery setContractEvmAddress(String contractEvmAddress) { + public T setContractEvmAddress(String contractEvmAddress) { Objects.requireNonNull(contractEvmAddress); this.contractEvmAddress = contractEvmAddress; this.contractId = null; - return this; + return self(); } public AccountId getSender() { @@ -99,10 +104,10 @@ public AccountId getSender() { * @param sender The AccountId to be set * @return {@code this} */ - public MirrorNodeContractQuery setSender(AccountId sender) { + public T setSender(AccountId sender) { Objects.requireNonNull(sender); this.sender = sender; - return this; + return self(); } public String getSenderEvmAddress() { @@ -115,11 +120,11 @@ public String getSenderEvmAddress() { * @param senderEvmAddress * @return {@code this} */ - public MirrorNodeContractQuery setSenderEvmAddress(String senderEvmAddress) { + public T setSenderEvmAddress(String senderEvmAddress) { Objects.requireNonNull(senderEvmAddress); this.senderEvmAddress = senderEvmAddress; this.sender = null; - return this; + return self(); } public byte[] getCallData() { @@ -133,7 +138,7 @@ public byte[] getCallData() { * @param params The function parameters to be set * @return {@code this} */ - public MirrorNodeContractQuery setFunction(String name, ContractFunctionParameters params) { + public T setFunction(String name, ContractFunctionParameters params) { Objects.requireNonNull(params); return setFunctionParameters(params.toBytes(name)); } @@ -147,7 +152,7 @@ public MirrorNodeContractQuery setFunction(String name, ContractFunctionParamete * @param name The String to be set as the function name * @return {@code this} */ - public MirrorNodeContractQuery setFunction(String name) { + public T setFunction(String name) { return setFunction(name, new ContractFunctionParameters()); } @@ -160,10 +165,10 @@ public MirrorNodeContractQuery setFunction(String name) { * @param functionParameters The function parameters to be set * @return {@code this} */ - public MirrorNodeContractQuery setFunctionParameters(ByteString functionParameters) { + public T setFunctionParameters(ByteString functionParameters) { Objects.requireNonNull(functionParameters); this.callData = functionParameters.toByteArray(); - return this; + return self(); } public long getValue() { @@ -178,9 +183,9 @@ public long getValue() { * @param value the amount of value to send, in tinybars or wei * @return {@code this} */ - public MirrorNodeContractQuery setValue(long value) { + public T setValue(long value) { this.value = value; - return this; + return self(); } public long getGasLimit() { @@ -195,9 +200,9 @@ public long getGasLimit() { * @param gasLimit the maximum gas allowed for the transaction * @return {@code this} */ - public MirrorNodeContractQuery setGasLimit(long gasLimit) { + public T setGasLimit(long gasLimit) { this.gasLimit = gasLimit; - return this; + return self(); } public long getGasPrice() { @@ -212,9 +217,9 @@ public long getGasPrice() { * @param gasPrice the gas price, in tinybars or wei, for each unit of gas * @return {@code this} */ - public MirrorNodeContractQuery setGasPrice(long gasPrice) { + public T setGasPrice(long gasPrice) { this.gasPrice = gasPrice; - return this; + return self(); } public long getBlockNumber() { @@ -229,9 +234,9 @@ public long getBlockNumber() { * @param blockNumber the block number at which to simulate the contract call * @return {@code this} */ - public MirrorNodeContractQuery setBlockNumber(long blockNumber) { + public T setBlockNumber(long blockNumber) { this.blockNumber = blockNumber; - return this; + return self(); } /** @@ -241,7 +246,7 @@ public MirrorNodeContractQuery setBlockNumber(long blockNumber) { * @throws ExecutionException * @throws InterruptedException */ - public long estimate(Client client) throws ExecutionException, InterruptedException { + protected long estimate(Client client) throws ExecutionException, InterruptedException { fillEvmAddresses(client); return getEstimateGasFromMirrorNodeAsync(client).get(); } @@ -254,7 +259,7 @@ public long estimate(Client client) throws ExecutionException, InterruptedExcept * @throws ExecutionException * @throws InterruptedException */ - public String call(Client client) throws ExecutionException, InterruptedException { + protected String call(Client client) throws ExecutionException, InterruptedException { fillEvmAddresses(client); var blockNum = this.blockNumber == 0 ? "latest" : String.valueOf(this.blockNumber); return getContractCallResultFromMirrorNodeAsync(client, blockNum).get(); @@ -276,7 +281,7 @@ private CompletableFuture getContractCallResultFromMirrorNodeAsync(Clien .thenApply(MirrorNodeContractQuery::parseContractCallResult); } - public CompletableFuture getEstimateGasFromMirrorNodeAsync(Client client) { + private CompletableFuture getEstimateGasFromMirrorNodeAsync(Client client) { return executeMirrorNodeRequest(client, "latest", true) .thenApply(MirrorNodeContractQuery::parseHexEstimateToLong); } @@ -331,7 +336,7 @@ static long parseHexEstimateToLong(String responseBody) { @Override public String toString() { - return "MirrorNodeContractQuery{" + + return "{" + "contractId=" + contractId + ", contractEvmAddress='" + contractEvmAddress + '\'' + ", sender=" + sender + diff --git a/sdk/src/test/java/com/hedera/hashgraph/sdk/MirrorNodeContractQueryTest.java b/sdk/src/test/java/com/hedera/hashgraph/sdk/MirrorNodeContractQueryTest.java index 1f612aa8c..888672bd1 100644 --- a/sdk/src/test/java/com/hedera/hashgraph/sdk/MirrorNodeContractQueryTest.java +++ b/sdk/src/test/java/com/hedera/hashgraph/sdk/MirrorNodeContractQueryTest.java @@ -36,7 +36,8 @@ class MirrorNodeContractQueryTest { - private MirrorNodeContractQuery query; + private MirrorNodeContractEstimateGasQuery mirrorNodeContractEstimateGasQuery; + private MirrorNodeContractCallQuery mirrorNodeContractCallQuery; private ContractId mockContractId; @BeforeAll @@ -51,81 +52,108 @@ public static void afterAll() { @BeforeEach void setUp() { - query = new MirrorNodeContractQuery(); + mirrorNodeContractEstimateGasQuery = new MirrorNodeContractEstimateGasQuery(); + mirrorNodeContractCallQuery = new MirrorNodeContractCallQuery(); mockContractId = Mockito.mock(ContractId.class); } @Test void testSetAndGetContractId() { - query.setContractId(mockContractId); - assertEquals(mockContractId, query.getContractId()); + mirrorNodeContractEstimateGasQuery.setContractId(mockContractId); + assertEquals(mockContractId, mirrorNodeContractEstimateGasQuery.getContractId()); + + mirrorNodeContractCallQuery.setContractId(mockContractId); + assertEquals(mockContractId, mirrorNodeContractCallQuery.getContractId()); } @Test void testSetContractIdWithNullThrowsException() { - assertThrows(NullPointerException.class, () -> query.setContractId(null)); + assertThrows(NullPointerException.class, () -> mirrorNodeContractEstimateGasQuery.setContractId(null)); + assertThrows(NullPointerException.class, () -> mirrorNodeContractCallQuery.setContractId(null)); } @Test void testSetAndGetContractEvmAddress() { String evmAddress = "0x1234567890abcdef1234567890abcdef12345678"; - query.setContractEvmAddress(evmAddress); - assertEquals(evmAddress, query.getContractEvmAddress()); - assertNull(query.getContractId()); + mirrorNodeContractEstimateGasQuery.setContractEvmAddress(evmAddress); + assertEquals(evmAddress, mirrorNodeContractEstimateGasQuery.getContractEvmAddress()); + assertNull(mirrorNodeContractEstimateGasQuery.getContractId()); + + mirrorNodeContractCallQuery.setContractEvmAddress(evmAddress); + assertEquals(evmAddress, mirrorNodeContractCallQuery.getContractEvmAddress()); + assertNull(mirrorNodeContractCallQuery.getContractId()); } @Test void testSetContractEvmAddressWithNullThrowsException() { - assertThrows(NullPointerException.class, () -> query.setContractEvmAddress(null)); + assertThrows(NullPointerException.class, () -> mirrorNodeContractEstimateGasQuery.setContractEvmAddress(null)); + assertThrows(NullPointerException.class, () -> mirrorNodeContractCallQuery.setContractEvmAddress(null)); } @Test void testSetAndGetcallData() { ByteString params = ByteString.copyFromUtf8("test"); - query.setFunctionParameters(params); - assertArrayEquals(params.toByteArray(), query.getCallData()); + mirrorNodeContractEstimateGasQuery.setFunctionParameters(params); + assertArrayEquals(params.toByteArray(), mirrorNodeContractEstimateGasQuery.getCallData()); + + mirrorNodeContractCallQuery.setFunctionParameters(params); + assertArrayEquals(params.toByteArray(), mirrorNodeContractCallQuery.getCallData()); } @Test void testSetFunctionWithoutParameters() { - query.setFunction("myFunction"); - assertNotNull(query.getCallData()); + mirrorNodeContractEstimateGasQuery.setFunction("myFunction"); + assertNotNull(mirrorNodeContractEstimateGasQuery.getCallData()); } @Test void testSetAndGetBlockNumber() { long blockNumber = 123456; - query.setBlockNumber(blockNumber); - assertEquals(blockNumber, query.getBlockNumber()); + mirrorNodeContractEstimateGasQuery.setBlockNumber(blockNumber); + assertEquals(blockNumber, mirrorNodeContractEstimateGasQuery.getBlockNumber()); + + mirrorNodeContractCallQuery.setBlockNumber(blockNumber); + assertEquals(blockNumber, mirrorNodeContractCallQuery.getBlockNumber()); } @Test void testSetAndGetValue() { long value = 1000; - query.setValue(value); - assertEquals(value, query.getValue()); + mirrorNodeContractEstimateGasQuery.setValue(value); + assertEquals(value, mirrorNodeContractEstimateGasQuery.getValue()); + + mirrorNodeContractCallQuery.setValue(value); + assertEquals(value, mirrorNodeContractCallQuery.getValue()); } @Test void testSetAndGetGas() { long gas = 50000; - query.setGasLimit(gas); - assertEquals(gas, query.getGasLimit()); + mirrorNodeContractEstimateGasQuery.setGasLimit(gas); + assertEquals(gas, mirrorNodeContractEstimateGasQuery.getGasLimit()); + + mirrorNodeContractCallQuery.setGasLimit(gas); + assertEquals(gas, mirrorNodeContractCallQuery.getGasLimit()); } @Test void testSetAndGetGasPrice() { long gasPrice = 200; - query.setGasPrice(gasPrice); - assertEquals(gasPrice, query.getGasPrice()); + mirrorNodeContractEstimateGasQuery.setGasPrice(gasPrice); + assertEquals(gasPrice, mirrorNodeContractEstimateGasQuery.getGasPrice()); + + mirrorNodeContractCallQuery.setGasPrice(gasPrice); + assertEquals(gasPrice, mirrorNodeContractCallQuery.getGasPrice()); } @Test void testEstimateGasWithMissingContractIdOrEvmAddressThrowsException() { ByteString params = ByteString.copyFromUtf8("gasParams"); - query.setFunctionParameters(params); + mirrorNodeContractEstimateGasQuery.setFunctionParameters(params); + assertThrows(NullPointerException.class, () -> mirrorNodeContractEstimateGasQuery.estimate(null)); - assertThrows(NullPointerException.class, () -> query.estimate(null)); + mirrorNodeContractCallQuery.setFunctionParameters(params); + assertThrows(NullPointerException.class, () -> mirrorNodeContractCallQuery.estimate(null)); } @Test @@ -256,7 +284,7 @@ void shouldSerialize() { long testGasPrice = 20L; long testBlockNumber = 123456L; - var query = new MirrorNodeContractQuery() + var mirrorNodeContractEstimateGasQuery = new MirrorNodeContractEstimateGasQuery() .setContractId(testContractId) .setContractEvmAddress(testEvmAddress) .setSender(testSenderId) @@ -268,7 +296,20 @@ void shouldSerialize() { .setGasPrice(testGasPrice) .setBlockNumber(testBlockNumber); - SnapshotMatcher.expect(query.toString() + var mirrorNodeContractCallQuery = new MirrorNodeContractCallQuery() + .setContractId(testContractId) + .setContractEvmAddress(testEvmAddress) + .setSender(testSenderId) + .setSenderEvmAddress(testSenderEvmAddress) + .setFunction(testFunctionName, testParams) + .setFunctionParameters(testCallData) + .setValue(testValue) + .setGasLimit(testGasLimit) + .setGasPrice(testGasPrice) + .setBlockNumber(testBlockNumber); + + + SnapshotMatcher.expect(mirrorNodeContractEstimateGasQuery.toString() + mirrorNodeContractCallQuery.toString() ).toMatchSnapshot(); } } diff --git a/sdk/src/test/java/com/hedera/hashgraph/sdk/MirrorNodeContractQueryTest.snap b/sdk/src/test/java/com/hedera/hashgraph/sdk/MirrorNodeContractQueryTest.snap index 6f22e4bfe..2394e7ccf 100644 --- a/sdk/src/test/java/com/hedera/hashgraph/sdk/MirrorNodeContractQueryTest.snap +++ b/sdk/src/test/java/com/hedera/hashgraph/sdk/MirrorNodeContractQueryTest.snap @@ -1,3 +1,3 @@ com.hedera.hashgraph.sdk.MirrorNodeContractQueryTest.shouldSerialize=[ - "MirrorNodeContractQuery{contractId=null, contractEvmAddress='0x1234567890abcdef1234567890abcdef12345678', sender=null, senderEvmAddress='0xabcdefabcdefabcdefabcdefabcdefabcdef', callData=[116, 101, 115, 116, 68, 97, 116, 97], value=1000, gasLimit=500000, gasPrice=20, blockNumber=123456}" + "MirrorNodeContractEstimateGasQuery{contractId=null, contractEvmAddress='0x1234567890abcdef1234567890abcdef12345678', sender=null, senderEvmAddress='0xabcdefabcdefabcdefabcdefabcdefabcdef', callData=[116, 101, 115, 116, 68, 97, 116, 97], value=1000, gasLimit=500000, gasPrice=20, blockNumber=123456}MirrorNodeContractCallQuery{contractId=null, contractEvmAddress='0x1234567890abcdef1234567890abcdef12345678', sender=null, senderEvmAddress='0xabcdefabcdefabcdefabcdefabcdefabcdef', callData=[116, 101, 115, 116, 68, 97, 116, 97], value=1000, gasLimit=500000, gasPrice=20, blockNumber=123456}" ] \ No newline at end of file diff --git a/sdk/src/testIntegration/java/com/hedera/hashgraph/sdk/test/integration/ContractCallIntegrationTest.java b/sdk/src/testIntegration/java/com/hedera/hashgraph/sdk/test/integration/ContractCallIntegrationTest.java index 192fcb17b..141bf9467 100644 --- a/sdk/src/testIntegration/java/com/hedera/hashgraph/sdk/test/integration/ContractCallIntegrationTest.java +++ b/sdk/src/testIntegration/java/com/hedera/hashgraph/sdk/test/integration/ContractCallIntegrationTest.java @@ -27,6 +27,7 @@ import com.hedera.hashgraph.sdk.FileDeleteTransaction; import com.hedera.hashgraph.sdk.Hbar; import com.hedera.hashgraph.sdk.MaxQueryPaymentExceededException; +import com.hedera.hashgraph.sdk.MirrorNodeContractEstimateGasQuery; import com.hedera.hashgraph.sdk.MirrorNodeContractQuery; import com.hedera.hashgraph.sdk.PrecheckStatusException; import com.hedera.hashgraph.sdk.Status; @@ -66,10 +67,10 @@ void canCallContractFunction() throws Exception { // Wait for mirror node to import data Thread.sleep(2000); - var gas = new MirrorNodeContractQuery() + var gas = new MirrorNodeContractEstimateGasQuery() .setContractId(contractId) .setFunction("getMessage") - .estimate(testEnv.client); + .execute(testEnv.client); var callQuery = new ContractCallQuery() .setContractId(contractId) @@ -256,10 +257,10 @@ void getCostBigMaxContractCallFunction() throws Exception { // Wait for mirror node to import data Thread.sleep(2000); - var gas = new MirrorNodeContractQuery() + long gas = new MirrorNodeContractEstimateGasQuery() .setContractId(contractId) .setFunction("getMessage") - .estimate(testEnv.client); + .execute(testEnv.client); var callQuery = new ContractCallQuery() .setContractId(contractId) @@ -311,10 +312,10 @@ void getCostSmallMaxContractCallFunction() throws Exception { // Wait for mirror node to import data Thread.sleep(2000); - var gas = new MirrorNodeContractQuery() + var gas = new MirrorNodeContractEstimateGasQuery() .setContractId(contractId) .setFunction("getMessage") - .estimate(testEnv.client); + .execute(testEnv.client); var callQuery = new ContractCallQuery() .setContractId(contractId) @@ -365,10 +366,10 @@ void getCostInsufficientTxFeeContractCallFunction() throws Exception { // Wait for mirror node to import data Thread.sleep(2000); - var gas = new MirrorNodeContractQuery() + var gas = new MirrorNodeContractEstimateGasQuery() .setContractId(contractId) .setFunction("getMessage") - .estimate(testEnv.client); + .execute(testEnv.client); var callQuery = new ContractCallQuery() .setContractId(contractId) diff --git a/sdk/src/testIntegration/java/com/hedera/hashgraph/sdk/test/integration/ContractExecuteIntegrationTest.java b/sdk/src/testIntegration/java/com/hedera/hashgraph/sdk/test/integration/ContractExecuteIntegrationTest.java index 8ab6bc419..9f2b099bd 100644 --- a/sdk/src/testIntegration/java/com/hedera/hashgraph/sdk/test/integration/ContractExecuteIntegrationTest.java +++ b/sdk/src/testIntegration/java/com/hedera/hashgraph/sdk/test/integration/ContractExecuteIntegrationTest.java @@ -28,6 +28,7 @@ import com.hedera.hashgraph.sdk.ContractFunctionParameters; import com.hedera.hashgraph.sdk.FileCreateTransaction; import com.hedera.hashgraph.sdk.FileDeleteTransaction; +import com.hedera.hashgraph.sdk.MirrorNodeContractEstimateGasQuery; import com.hedera.hashgraph.sdk.MirrorNodeContractQuery; import com.hedera.hashgraph.sdk.PrecheckStatusException; import com.hedera.hashgraph.sdk.ReceiptStatusException; @@ -64,10 +65,10 @@ void canExecuteContractMethods() throws Exception { // Wait for mirror node to import data Thread.sleep(2000); - var gas = new MirrorNodeContractQuery() + var gas = new MirrorNodeContractEstimateGasQuery() .setContractId(contractId) .setFunction("setMessage", new ContractFunctionParameters().addString("new message")) - .estimate(testEnv.client); + .execute(testEnv.client); var receipt = new ContractExecuteTransaction() .setContractId(contractId) .setGas(gas + 10000) diff --git a/sdk/src/testIntegration/java/com/hedera/hashgraph/sdk/test/integration/ContractFunctionParametersIntegrationTest.java b/sdk/src/testIntegration/java/com/hedera/hashgraph/sdk/test/integration/ContractFunctionParametersIntegrationTest.java index e51b82c4d..3ef94829b 100644 --- a/sdk/src/testIntegration/java/com/hedera/hashgraph/sdk/test/integration/ContractFunctionParametersIntegrationTest.java +++ b/sdk/src/testIntegration/java/com/hedera/hashgraph/sdk/test/integration/ContractFunctionParametersIntegrationTest.java @@ -32,6 +32,7 @@ import com.hedera.hashgraph.sdk.FileDeleteTransaction; import com.hedera.hashgraph.sdk.FileId; import com.hedera.hashgraph.sdk.Hbar; +import com.hedera.hashgraph.sdk.MirrorNodeContractEstimateGasQuery; import com.hedera.hashgraph.sdk.MirrorNodeContractQuery; import java.math.BigInteger; import java.util.Arrays; @@ -85,9 +86,9 @@ public void afterEach() throws InterruptedException { @Test @DisplayName("Can receive uint8 min value from contract call") void canCallContractFunctionUint8Min() throws Exception { - var gas = new MirrorNodeContractQuery().setContractId(contractId) + var gas = new MirrorNodeContractEstimateGasQuery().setContractId(contractId) .setFunction("returnUint8", new ContractFunctionParameters().addUint8((byte) 0x0)) - .estimate(testEnv.client); + .execute(testEnv.client); var response = new ContractCallQuery().setContractId(contractId).setGas(gas) .setFunction("returnUint8", new ContractFunctionParameters().addUint8((byte) 0x0)) @@ -102,9 +103,9 @@ void canCallContractFunctionUint8Max() throws Exception { int uint8Max = 255; byte uint8MaxByte = (byte) uint8Max; - var gas = new MirrorNodeContractQuery().setContractId(contractId) + var gas = new MirrorNodeContractEstimateGasQuery().setContractId(contractId) .setFunction("returnUint8", new ContractFunctionParameters().addUint8(uint8MaxByte)) - .estimate(testEnv.client); + .execute(testEnv.client); var response = new ContractCallQuery().setContractId(contractId).setGas(gas) .setFunction("returnUint8", new ContractFunctionParameters().addUint8(uint8MaxByte)) @@ -123,9 +124,9 @@ void canCallContractFunctionUint8Array() throws Exception { byte uint8MaxByte = (byte) uint8Max; byte[] uint8Array = {uint8MinByte, uint8MaxByte}; - var gas = new MirrorNodeContractQuery().setContractId(contractId) + var gas = new MirrorNodeContractEstimateGasQuery().setContractId(contractId) .setFunction("returnUint8Arr", new ContractFunctionParameters().addUint8Array(uint8Array)) - .estimate(testEnv.client); + .execute(testEnv.client); var response = new ContractCallQuery().setContractId(contractId).setGas(gas) .setFunction("returnUint8Arr", new ContractFunctionParameters().addUint8Array(uint8Array)) @@ -153,9 +154,9 @@ void canCallContractFunctionUint16Max() throws Exception { var uint16Max = "65535"; int uint16MaxInt = Integer.parseUnsignedInt(uint16Max); - var gas = new MirrorNodeContractQuery().setContractId(contractId) + var gas = new MirrorNodeContractEstimateGasQuery().setContractId(contractId) .setFunction("returnUint16", new ContractFunctionParameters().addUint16(uint16MaxInt)) - .estimate(testEnv.client); + .execute(testEnv.client); var response = new ContractCallQuery().setContractId(contractId).setGas(gas) .setFunction("returnUint16", new ContractFunctionParameters().addUint16(uint16MaxInt)) @@ -174,9 +175,9 @@ void canCallContractFunctionUint16Array() throws Exception { int uint16MaxInt = Integer.parseUnsignedInt(uint16Max); int[] uint16Array = {uint16MinInt, uint16MaxInt}; - var gas = new MirrorNodeContractQuery().setContractId(contractId) + var gas = new MirrorNodeContractEstimateGasQuery().setContractId(contractId) .setFunction("returnUint16Arr", new ContractFunctionParameters().addUint16Array(uint16Array)) - .estimate(testEnv.client); + .execute(testEnv.client); var response = new ContractCallQuery().setContractId(contractId).setGas(gas) .setFunction("returnUint16Arr", new ContractFunctionParameters().addUint16Array(uint16Array)) @@ -190,9 +191,9 @@ void canCallContractFunctionUint16Array() throws Exception { @Test @DisplayName("Can receive uint24 min value from contract call") void canCallContractFunctionUint24Min() throws Exception { - var gas = new MirrorNodeContractQuery().setContractId(contractId) + var gas = new MirrorNodeContractEstimateGasQuery().setContractId(contractId) .setFunction("returnUint24", new ContractFunctionParameters().addUint24(0)) - .estimate(testEnv.client); + .execute(testEnv.client); var response = new ContractCallQuery().setContractId(contractId).setGas(gas) .setFunction("returnUint24", new ContractFunctionParameters().addUint24(0)).setQueryPayment(new Hbar(10)) @@ -207,9 +208,9 @@ void canCallContractFunctionUint24Max() throws Exception { var uint24Max = "16777215"; int uint24MaxInt = Integer.parseUnsignedInt(uint24Max); - var gas = new MirrorNodeContractQuery().setContractId(contractId) + var gas = new MirrorNodeContractEstimateGasQuery().setContractId(contractId) .setFunction("returnUint24", new ContractFunctionParameters().addUint24(uint24MaxInt)) - .estimate(testEnv.client); + .execute(testEnv.client); var response = new ContractCallQuery().setContractId(contractId).setGas(gas) .setFunction("returnUint24", new ContractFunctionParameters().addUint24(uint24MaxInt)) @@ -228,9 +229,9 @@ void canCallContractFunctionUint24Array() throws Exception { int uint24MaxInt = Integer.parseUnsignedInt(uint24Max); int[] uint24Array = {uint24MinInt, uint24MaxInt}; - var gas = new MirrorNodeContractQuery().setContractId(contractId) + var gas = new MirrorNodeContractEstimateGasQuery().setContractId(contractId) .setFunction("returnUint24Arr", new ContractFunctionParameters().addUint24Array(uint24Array)) - .estimate(testEnv.client); + .execute(testEnv.client); var response = new ContractCallQuery().setContractId(contractId).setGas(gas) .setFunction("returnUint24Arr", new ContractFunctionParameters().addUint24Array(uint24Array)) diff --git a/sdk/src/testIntegration/java/com/hedera/hashgraph/sdk/test/integration/MirrorNodeContractQueryIntegrationTest.java b/sdk/src/testIntegration/java/com/hedera/hashgraph/sdk/test/integration/MirrorNodeContractQueryIntegrationTest.java index a161d802e..d542df7e4 100644 --- a/sdk/src/testIntegration/java/com/hedera/hashgraph/sdk/test/integration/MirrorNodeContractQueryIntegrationTest.java +++ b/sdk/src/testIntegration/java/com/hedera/hashgraph/sdk/test/integration/MirrorNodeContractQueryIntegrationTest.java @@ -34,6 +34,8 @@ import com.hedera.hashgraph.sdk.FileCreateTransaction; import com.hedera.hashgraph.sdk.FileDeleteTransaction; import com.hedera.hashgraph.sdk.Hbar; +import com.hedera.hashgraph.sdk.MirrorNodeContractCallQuery; +import com.hedera.hashgraph.sdk.MirrorNodeContractEstimateGasQuery; import com.hedera.hashgraph.sdk.MirrorNodeContractQuery; import com.hedera.hashgraph.sdk.PrivateKey; import java.util.Objects; @@ -67,10 +69,10 @@ void canSimulateTransaction() throws Exception { // Wait for mirror node to import data Thread.sleep(2000); - var gas = new MirrorNodeContractQuery() + var gas = new MirrorNodeContractEstimateGasQuery() .setContractId(contractId) .setFunction("getOwner") - .estimate(testEnv.client); + .execute(testEnv.client); var result = new ContractCallQuery() .setContractId(contractId) @@ -79,17 +81,18 @@ void canSimulateTransaction() throws Exception { .setQueryPayment(new Hbar(1)) .execute(testEnv.client); - var simulationResult = new MirrorNodeContractQuery() + var simulationResult = new MirrorNodeContractCallQuery() + .setContractEvmAddress("asdf") .setContractId(contractId) .setFunction("getOwner") - .call(testEnv.client); + .execute(testEnv.client); assertThat(result.getAddress(0)).isEqualTo(simulationResult.substring(26)); - gas = new MirrorNodeContractQuery() + gas = new MirrorNodeContractEstimateGasQuery() .setContractId(contractId) .setFunction("addOwner", new ContractFunctionParameters().addAddress(ADDRESS)) - .estimate(testEnv.client); + .execute(testEnv.client); new ContractExecuteTransaction() .setContractId(contractId) @@ -98,10 +101,10 @@ void canSimulateTransaction() throws Exception { .execute(testEnv.client) .getReceipt(testEnv.client); - new MirrorNodeContractQuery() + new MirrorNodeContractCallQuery() .setContractId(contractId) .setFunction("addOwner", new ContractFunctionParameters().addAddress(ADDRESS)) - .call(testEnv.client); + .execute(testEnv.client); new ContractDeleteTransaction() .setTransferAccountId(testEnv.operatorId) @@ -123,17 +126,17 @@ void failsWhenContractIsNotDeployed() throws Exception { var contractId = new ContractId(1231456); assertThatExceptionOfType(ExecutionException.class).isThrownBy(() -> { - new MirrorNodeContractQuery() + new MirrorNodeContractEstimateGasQuery() .setContractId(contractId) .setFunction("getOwner") - .estimate(testEnv.client); + .execute(testEnv.client); }).withMessageContaining("Received non-200 response from Mirror Node"); assertThatExceptionOfType(ExecutionException.class).isThrownBy(() -> { - new MirrorNodeContractQuery() + new MirrorNodeContractCallQuery() .setContractId(contractId) .setFunction("getOwner") - .call(testEnv.client); + .execute(testEnv.client); }).withMessageContaining("Received non-200 response from Mirror Node"); } } @@ -161,21 +164,20 @@ void failsWhenGasLimitIsLow() throws Exception { Thread.sleep(2000); assertThatExceptionOfType(ExecutionException.class).isThrownBy(() -> { - new MirrorNodeContractQuery() + new MirrorNodeContractEstimateGasQuery() .setContractId(contractId) .setGasLimit(100) .setFunction("addOwnerAndTransfer", new ContractFunctionParameters().addAddress(ADDRESS)) - .estimate(testEnv.client); + .execute(testEnv.client); }).withMessageContaining("Received non-200 response from Mirror Node"); assertThatExceptionOfType(ExecutionException.class).isThrownBy(() -> { - new MirrorNodeContractQuery() + new MirrorNodeContractCallQuery() .setContractId(contractId) .setGasLimit(100) .setFunction("addOwnerAndTransfer", new ContractFunctionParameters().addAddress(ADDRESS)) - .call(testEnv.client); + .execute(testEnv.client); }).withMessageContaining("Received non-200 response from Mirror Node"); - } } @@ -202,17 +204,17 @@ void failsWhenSenderIsNotSet() throws Exception { Thread.sleep(2000); assertThatExceptionOfType(ExecutionException.class).isThrownBy(() -> { - new MirrorNodeContractQuery() + new MirrorNodeContractEstimateGasQuery() .setContractId(contractId) .setFunction("addOwnerAndTransfer", new ContractFunctionParameters().addAddress(ADDRESS)) - .estimate(testEnv.client); + .execute(testEnv.client); }).withMessageContaining("Received non-200 response from Mirror Node"); assertThatExceptionOfType(ExecutionException.class).isThrownBy(() -> { - new MirrorNodeContractQuery() + new MirrorNodeContractCallQuery() .setContractId(contractId) .setFunction("addOwnerAndTransfer", new ContractFunctionParameters().addAddress(ADDRESS)) - .call(testEnv.client); + .execute(testEnv.client); }).withMessageContaining("Received non-200 response from Mirror Node"); } @@ -249,19 +251,19 @@ void canSimulateWithSenderSet() throws Exception { var receiverEvmAddress = getEvmAddressFromMirrorNodeAsync(testEnv.client, receiverAccountId.num).get() .toString(); - var owner = new MirrorNodeContractQuery() + var owner = new MirrorNodeContractCallQuery() .setContractId(contractId) .setFunction("getOwner") - .call(testEnv.client) + .execute(testEnv.client) .substring(26); - var gas = new MirrorNodeContractQuery() + var gas = new MirrorNodeContractEstimateGasQuery() .setContractId(contractId) .setGasLimit(1_000_000) .setFunction("addOwnerAndTransfer", new ContractFunctionParameters().addAddress(receiverEvmAddress)) .setSenderEvmAddress(owner) .setValue(123) - .estimate(testEnv.client); + .execute(testEnv.client); new ContractExecuteTransaction() .setContractId(contractId) @@ -271,13 +273,13 @@ void canSimulateWithSenderSet() throws Exception { .execute(testEnv.client) .getReceipt(testEnv.client); - new MirrorNodeContractQuery() + new MirrorNodeContractCallQuery() .setContractId(contractId) .setGasLimit(1_000_000) .setFunction("addOwnerAndTransfer", new ContractFunctionParameters().addAddress(receiverEvmAddress)) .setSenderEvmAddress(owner) .setValue(123) - .call(testEnv.client); + .execute(testEnv.client); } } }