From 764b17237e99774bf17539c046b504dcbabaaec8 Mon Sep 17 00:00:00 2001 From: Kristiyan Selveliev Date: Fri, 30 Aug 2024 18:51:55 +0300 Subject: [PATCH] Refactor ContractCallSystemPrecompileHistoricalTest (#9185) This PR refactors ContractCallSystemPrecompileHistoricalTest to use the web3j plugin test. This PR modifies: ContractCallSystemPrecompileHistoricalTest now uses the web3j plugin. Added prng and exchange rate historical solidity files. The rest of the modifications are via the spotlessApply --------- Signed-off-by: Kristiyan Selveliev --- ...actCallSystemPrecompileHistoricalTest.java | 104 ++++++++---------- .../web3/service/ContractCallTestSetup.java | 26 ----- .../web3/service/OpcodeServiceTest.java | 15 ++- .../web3/utils/ContractCallTestUtil.java | 2 +- .../ExchangeRatePrecompileHistorical.sol | 24 ++++ .../IPrngSystemContractHistorical.sol | 8 ++ .../PrngSystemContractHistorical.sol | 15 +++ 7 files changed, 109 insertions(+), 85 deletions(-) create mode 100644 hedera-mirror-web3/src/test/solidity_historical/ExchangeRatePrecompileHistorical.sol create mode 100644 hedera-mirror-web3/src/test/solidity_historical/IPrngSystemContractHistorical.sol create mode 100644 hedera-mirror-web3/src/test/solidity_historical/PrngSystemContractHistorical.sol diff --git a/hedera-mirror-web3/src/test/java/com/hedera/mirror/web3/service/ContractCallSystemPrecompileHistoricalTest.java b/hedera-mirror-web3/src/test/java/com/hedera/mirror/web3/service/ContractCallSystemPrecompileHistoricalTest.java index 94aa4da4343..a22885a5d6b 100644 --- a/hedera-mirror-web3/src/test/java/com/hedera/mirror/web3/service/ContractCallSystemPrecompileHistoricalTest.java +++ b/hedera-mirror-web3/src/test/java/com/hedera/mirror/web3/service/ContractCallSystemPrecompileHistoricalTest.java @@ -16,74 +16,66 @@ package com.hedera.mirror.web3.service; -import static com.hedera.mirror.web3.service.model.CallServiceParameters.CallType.ETH_CALL; import static org.assertj.core.api.AssertionsForClassTypes.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; -import com.hedera.mirror.web3.utils.ContractFunctionProviderEnum; +import com.google.common.collect.Range; import com.hedera.mirror.web3.viewmodel.BlockType; -import java.util.Arrays; -import java.util.List; -import java.util.stream.Stream; -import lombok.Getter; -import lombok.RequiredArgsConstructor; +import com.hedera.mirror.web3.web3j.generated.ExchangeRatePrecompileHistorical; +import com.hedera.mirror.web3.web3j.generated.PrngSystemContractHistorical; +import java.math.BigInteger; import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; +import org.junit.jupiter.params.provider.CsvSource; -public class ContractCallSystemPrecompileHistoricalTest extends ContractCallTestSetup { - - private static final List BLOCK_NUMBERS_FOR_EVM_VERSION = List.of( - BlockType.of(String.valueOf(EVM_V_46_BLOCK)), - BlockType.of(String.valueOf(EVM_V_38_BLOCK)), - BlockType.of(String.valueOf(EVM_V_34_BLOCK)), - BlockType.of(String.valueOf(EVM_V_34_BLOCK - 1))); - - private static Stream exchangeRateFunctionsProviderHistorical() { - return Arrays.stream(ExchangeRateFunctions.values()) - .flatMap(exchangeRateFunction -> BLOCK_NUMBERS_FOR_EVM_VERSION.stream() - .map(blockNumber -> Arguments.of(exchangeRateFunction, blockNumber))); - } - - private static Stream blockNumberForDifferentEvmVersionsProviderHistorical() { - return BLOCK_NUMBERS_FOR_EVM_VERSION.stream().map(Arguments::of); - } +public class ContractCallSystemPrecompileHistoricalTest extends AbstractContractCallServiceTest { @ParameterizedTest - @MethodSource("exchangeRateFunctionsProviderHistorical") - void exchangeRateFunctionsTestEthCallHistorical(final ExchangeRateFunctions contractFunc, BlockType blockNumber) { - final var functionHash = functionEncodeDecoder.functionHashFor( - contractFunc.name, EXCHANGE_RATE_PRECOMPILE_ABI_PATH, contractFunc.functionParameters); - final var serviceParameters = serviceParametersForExecution( - functionHash, EXCHANGE_RATE_PRECOMPILE_CONTRACT_ADDRESS, ETH_CALL, 0L, blockNumber); - final var successfulResponse = functionEncodeDecoder.encodedResultFor( - contractFunc.name, EXCHANGE_RATE_PRECOMPILE_ABI_PATH, contractFunc.expectedResultFields); - - assertThat(contractCallService.processCall(serviceParameters)).isEqualTo(successfulResponse); + @CsvSource({"150", "100", "50", "49"}) + void exchangeRatePrecompileTinycentsToTinybars(long blockNumber) throws Exception { + // Given + final var recordFile = + domainBuilder.recordFile().customize(f -> f.index(blockNumber)).persist(); + testWeb3jService.setBlockType(BlockType.of(String.valueOf(blockNumber))); + testWeb3jService.setHistoricalRange( + Range.closedOpen(recordFile.getConsensusStart(), recordFile.getConsensusEnd())); + final var contract = testWeb3jService.deploy(ExchangeRatePrecompileHistorical::deploy); + // When + final var result = + contract.call_tinycentsToTinybars(BigInteger.valueOf(100L)).send(); + // Then + assertThat(result).isEqualTo(BigInteger.valueOf(8L)); } @ParameterizedTest - @MethodSource("blockNumberForDifferentEvmVersionsProviderHistorical") - void pseudoRandomGeneratorPrecompileFunctionsTestEthCallHistorical(BlockType blockNumber) { - final var functionName = "getPseudorandomSeed"; - final var functionHash = functionEncodeDecoder.functionHashFor(functionName, PRNG_PRECOMPILE_ABI_PATH); - final var serviceParameters = - serviceParametersForExecution(functionHash, PRNG_CONTRACT_ADDRESS, ETH_CALL, 0L, blockNumber); - - final var result = contractCallService.processCall(serviceParameters); - - // Length of "0x" + 64 hex characters (2 per byte * 32 bytes) - assertEquals(66, result.length(), "The string should represent a 32-byte long array"); + @CsvSource({"150", "100", "50", "49"}) + void exchangeRatePrecompileTinybarsToTinycents(long blockNumber) throws Exception { + // Given + final var recordFile = + domainBuilder.recordFile().customize(f -> f.index(blockNumber)).persist(); + testWeb3jService.setBlockType(BlockType.of(String.valueOf(blockNumber))); + testWeb3jService.setHistoricalRange( + Range.closedOpen(recordFile.getConsensusStart(), recordFile.getConsensusEnd())); + final var contract = testWeb3jService.deploy(ExchangeRatePrecompileHistorical::deploy); + // When + final var result = + contract.call_tinybarsToTinycents(BigInteger.valueOf(100L)).send(); + // Then + assertThat(result).isEqualTo(BigInteger.valueOf(1200L)); } - @Getter - @RequiredArgsConstructor - enum ExchangeRateFunctions implements ContractFunctionProviderEnum { - TINYCENTS_TO_TINYBARS("tinycentsToTinybars", new Object[] {100L}, new Long[] {8L}), - TINYBARS_TO_TINYCENTS("tinybarsToTinycents", new Object[] {100L}, new Object[] {1200L}); - - private final String name; - private final Object[] functionParameters; - private final Object[] expectedResultFields; + @ParameterizedTest + @CsvSource({"150", "100", "50", "49"}) + void pseudoRandomGeneratorPrecompileFunctionsTestEthCallHistorical(long blockNumber) throws Exception { + // Given + final var recordFile = + domainBuilder.recordFile().customize(f -> f.index(blockNumber)).persist(); + testWeb3jService.setBlockType(BlockType.of(String.valueOf(blockNumber))); + testWeb3jService.setHistoricalRange( + Range.closedOpen(recordFile.getConsensusStart(), recordFile.getConsensusEnd())); + final var contract = testWeb3jService.deploy(PrngSystemContractHistorical::deploy); + // When + final var result = contract.call_getPseudorandomSeed().send(); + // Then + assertEquals(32, result.length, "The string should represent a 32-byte long array"); } } diff --git a/hedera-mirror-web3/src/test/java/com/hedera/mirror/web3/service/ContractCallTestSetup.java b/hedera-mirror-web3/src/test/java/com/hedera/mirror/web3/service/ContractCallTestSetup.java index ef7f5920462..896ef1cc5ad 100644 --- a/hedera-mirror-web3/src/test/java/com/hedera/mirror/web3/service/ContractCallTestSetup.java +++ b/hedera-mirror-web3/src/test/java/com/hedera/mirror/web3/service/ContractCallTestSetup.java @@ -1757,32 +1757,6 @@ protected void contractAllowancesPersist( .persist(); } - // Contracts persist - protected void evmCodesContractPersist() { - final var evmCodesContractBytes = functionEncodeDecoder.getContractBytes(EVM_CODES_BYTES_PATH); - final var evmCodesContractEntityId = entityIdFromEvmAddress(EVM_CODES_CONTRACT_ADDRESS); - final var evmCodesContractEvmAddress = toEvmAddress(evmCodesContractEntityId); - - domainBuilder - .entity() - .customize(e -> e.id(evmCodesContractEntityId.getId()) - .num(evmCodesContractEntityId.getNum()) - .evmAddress(evmCodesContractEvmAddress) - .type(CONTRACT) - .balance(1500L)) - .persist(); - - domainBuilder - .contract() - .customize(c -> c.id(evmCodesContractEntityId.getId()).runtimeBytecode(evmCodesContractBytes)) - .persist(); - - domainBuilder - .recordFile() - .customize(f -> f.bytes(evmCodesContractBytes)) - .persist(); - } - protected EntityId dynamicEthCallContractPresist() { final var contractBytes = functionEncodeDecoder.getContractBytes(DYNAMIC_ETH_CALLS_BYTES_PATH); final var contractEntityId = entityIdFromEvmAddress(DYNAMIC_ETH_CALLS_CONTRACT_ADDRESS); diff --git a/hedera-mirror-web3/src/test/java/com/hedera/mirror/web3/service/OpcodeServiceTest.java b/hedera-mirror-web3/src/test/java/com/hedera/mirror/web3/service/OpcodeServiceTest.java index 5c96193dc4e..721b60af80e 100644 --- a/hedera-mirror-web3/src/test/java/com/hedera/mirror/web3/service/OpcodeServiceTest.java +++ b/hedera-mirror-web3/src/test/java/com/hedera/mirror/web3/service/OpcodeServiceTest.java @@ -883,6 +883,17 @@ private enum NestedEthCallContractFunctions implements ContractFunctionProviderE private final Object[] expectedResultFields; } + @Getter + @RequiredArgsConstructor + enum ExchangeRateFunctions implements ContractFunctionProviderEnum { + TINYCENTS_TO_TINYBARS("tinycentsToTinybars", new Object[] {100L}, new Long[] {8L}), + TINYBARS_TO_TINYCENTS("tinybarsToTinycents", new Object[] {100L}, new Object[] {1200L}); + + private final String name; + private final Object[] functionParameters; + private final Object[] expectedResultFields; + } + @Nested @TestInstance(TestInstance.Lifecycle.PER_CLASS) @DisplayName("processOpcodeCall") @@ -1111,7 +1122,7 @@ void callWithContractResultNotFoundExceptionTest() { contractEntityId = systemExchangeRateContractPersist(); final TransactionIdOrHashParameter transactionIdOrHash = setUp( - ContractCallSystemPrecompileHistoricalTest.ExchangeRateFunctions.TINYBARS_TO_TINYCENTS, + ExchangeRateFunctions.TINYBARS_TO_TINYCENTS, TransactionType.CONTRACTCALL, EXCHANGE_RATE_PRECOMPILE_CONTRACT_ADDRESS, EXCHANGE_RATE_PRECOMPILE_ABI_PATH, @@ -1129,7 +1140,7 @@ void callWithTransactionNotFoundExceptionTest() { contractEntityId = systemExchangeRateContractPersist(); final TransactionIdOrHashParameter transactionIdOrHash = setUp( - ContractCallSystemPrecompileHistoricalTest.ExchangeRateFunctions.TINYCENTS_TO_TINYBARS, + ExchangeRateFunctions.TINYCENTS_TO_TINYBARS, TransactionType.CONTRACTCALL, EXCHANGE_RATE_PRECOMPILE_CONTRACT_ADDRESS, EXCHANGE_RATE_PRECOMPILE_ABI_PATH, diff --git a/hedera-mirror-web3/src/test/java/com/hedera/mirror/web3/utils/ContractCallTestUtil.java b/hedera-mirror-web3/src/test/java/com/hedera/mirror/web3/utils/ContractCallTestUtil.java index 18c5fc04e1c..1c3ba784b4b 100644 --- a/hedera-mirror-web3/src/test/java/com/hedera/mirror/web3/utils/ContractCallTestUtil.java +++ b/hedera-mirror-web3/src/test/java/com/hedera/mirror/web3/utils/ContractCallTestUtil.java @@ -79,7 +79,7 @@ public class ContractCallTestUtil { * Checks if the *actual* gas usage is within 5-20% greater than the *expected* gas used from the initial call. * * @param estimatedGas The expected gas used from the initial call. - * @param actualGas The actual gas used. + * @param actualGas The actual gas used. * @return {@code true} if the actual gas usage is within the expected range, otherwise {@code false}. */ public static boolean isWithinExpectedGasRange(final long estimatedGas, final long actualGas) { diff --git a/hedera-mirror-web3/src/test/solidity_historical/ExchangeRatePrecompileHistorical.sol b/hedera-mirror-web3/src/test/solidity_historical/ExchangeRatePrecompileHistorical.sol new file mode 100644 index 00000000000..b16c414f7c4 --- /dev/null +++ b/hedera-mirror-web3/src/test/solidity_historical/ExchangeRatePrecompileHistorical.sol @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: Apache-2.0 +pragma solidity >=0.5.0 <0.9.0; + +contract ExchangeRatePrecompileHistorical { + + uint256 constant TINY_PARTS_PER_WHOLE = 100_000_000; + address constant PRECOMPILE_ADDRESS = address(0x168); + bytes4 constant TINYCENTS_TO_TINYBARS = bytes4(keccak256("tinycentsToTinybars(uint256)")); + bytes4 constant TINYBARS_TO_TINYCENTS = bytes4(keccak256("tinybarsToTinycents(uint256)")); + + function tinycentsToTinybars(uint256 tinycents) external payable returns (uint256 tinybars) { + (bool success, bytes memory result) = PRECOMPILE_ADDRESS.call{value: msg.value}( + abi.encodeWithSelector(TINYCENTS_TO_TINYBARS, tinycents)); + require(success); + tinybars = abi.decode(result, (uint256)); + } + + function tinybarsToTinycents(uint256 tinybars) external payable returns (uint256 tinycents) { + (bool success, bytes memory result) = PRECOMPILE_ADDRESS.call{value: msg.value}( + abi.encodeWithSelector(TINYBARS_TO_TINYCENTS, tinybars)); + require(success); + tinycents = abi.decode(result, (uint256)); + } +} \ No newline at end of file diff --git a/hedera-mirror-web3/src/test/solidity_historical/IPrngSystemContractHistorical.sol b/hedera-mirror-web3/src/test/solidity_historical/IPrngSystemContractHistorical.sol new file mode 100644 index 00000000000..ecc4af55d17 --- /dev/null +++ b/hedera-mirror-web3/src/test/solidity_historical/IPrngSystemContractHistorical.sol @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: Apache-2.0 +pragma solidity >=0.5.0 <0.9.0; + +interface IPrngSystemContractHistorical { + // Generates a 256-bit pseudorandom seed using the first 256-bits of running hash from the latest RecordFile in the database. + // Users can generate a pseudorandom number in a specified range using the seed by (integer value of seed % range) + function getPseudorandomSeed() external returns (bytes32); +} diff --git a/hedera-mirror-web3/src/test/solidity_historical/PrngSystemContractHistorical.sol b/hedera-mirror-web3/src/test/solidity_historical/PrngSystemContractHistorical.sol new file mode 100644 index 00000000000..8619d45a92c --- /dev/null +++ b/hedera-mirror-web3/src/test/solidity_historical/PrngSystemContractHistorical.sol @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: Apache-2.0 +pragma solidity >=0.5.0 <0.9.0; + +import "./IPrngSystemContractHistorical.sol"; + +contract PrngSystemContractHistorical { + address constant PRECOMPILE_ADDRESS = address(0x169); + + function getPseudorandomSeed() external payable returns (bytes32 randomBytes) { + (bool success, bytes memory result) = PRECOMPILE_ADDRESS.call{value: msg.value}( + abi.encodeWithSelector(IPrngSystemContractHistorical.getPseudorandomSeed.selector)); + require(success); + randomBytes = abi.decode(result, (bytes32)); + } +} \ No newline at end of file