From 923447f4b3161efce91d0aff17f19fb8d0e21e2f Mon Sep 17 00:00:00 2001 From: Juraj Piar Date: Thu, 6 Jun 2024 23:53:51 +0100 Subject: [PATCH 1/2] feat(smgp): adds context fetching callback to providers --- .../src/main/java/co/rsk/RskContext.java | 4 +- .../OnChainMinGasPriceSystemConfig.java | 18 +++- .../provider/MinGasPriceProviderFactory.java | 6 +- .../provider/StableMinGasPriceProvider.java | 13 ++- .../onchain/OnChainMinGasPriceProvider.java | 54 ++++++++++-- .../OnChainMinGasPriceProviderFactory.java | 4 +- .../provider/web/WebMinGasPriceProvider.java | 4 +- .../WebStableMinGasPriceProviderFactory.java | 4 +- .../MinGasPriceProviderFactoryTest.java | 8 +- .../StableMinGasPriceProviderTest.java | 4 +- .../OnChainMinGasPriceProviderTest.java | 84 +++++++++++++++++++ 11 files changed, 175 insertions(+), 28 deletions(-) create mode 100644 rskj-core/src/test/java/co/rsk/mine/gas/provider/onchain/OnChainMinGasPriceProviderTest.java diff --git a/rskj-core/src/main/java/co/rsk/RskContext.java b/rskj-core/src/main/java/co/rsk/RskContext.java index 3c4d27e8313..2848ec7c4d8 100644 --- a/rskj-core/src/main/java/co/rsk/RskContext.java +++ b/rskj-core/src/main/java/co/rsk/RskContext.java @@ -1860,7 +1860,7 @@ private MinGasPriceProvider getMinGasPriceProvider() { if (minGasPriceProvider == null) { long minGasPrice = getRskSystemProperties().minerMinGasPrice(); StableMinGasPriceSystemConfig stableGasPriceSystemConfig = getRskSystemProperties().getStableGasPriceSystemConfig(); - minGasPriceProvider = MinGasPriceProviderFactory.create(minGasPrice, stableGasPriceSystemConfig); + minGasPriceProvider = MinGasPriceProviderFactory.create(minGasPrice, stableGasPriceSystemConfig, this::getEthModule); } logger.debug("MinGasPriceProvider type: {}", minGasPriceProvider.getType().name()); return minGasPriceProvider; @@ -2222,4 +2222,4 @@ private void checkIfNotClosed() { throw new IllegalStateException("RSK Context is closed and cannot be in use anymore"); } } -} \ No newline at end of file +} diff --git a/rskj-core/src/main/java/co/rsk/config/mining/OnChainMinGasPriceSystemConfig.java b/rskj-core/src/main/java/co/rsk/config/mining/OnChainMinGasPriceSystemConfig.java index 30788f74277..018ca648bce 100644 --- a/rskj-core/src/main/java/co/rsk/config/mining/OnChainMinGasPriceSystemConfig.java +++ b/rskj-core/src/main/java/co/rsk/config/mining/OnChainMinGasPriceSystemConfig.java @@ -6,13 +6,27 @@ public class OnChainMinGasPriceSystemConfig { public static final String ONCHAIN_STABLE_GAS_PRICE_CONFIG_PATH = "onChain"; //TODO property example private static final String ADDRESS_PROPERTY = "address"; + private static final String FROM_PROPERTY = "from"; + private static final String DATA_PROPERTY = "data"; private final String address; + private final String from; + private final String data; public OnChainMinGasPriceSystemConfig(Config config) { - this.address = config.getString(ADDRESS_PROPERTY); + address = config.getString(ADDRESS_PROPERTY); + from = config.getString(FROM_PROPERTY); + data = config.getString(DATA_PROPERTY); } - public String getAddress() { + public String address() { return address; } + + public String from() { + return from; + } + + public String data() { + return data; + } } diff --git a/rskj-core/src/main/java/co/rsk/mine/gas/provider/MinGasPriceProviderFactory.java b/rskj-core/src/main/java/co/rsk/mine/gas/provider/MinGasPriceProviderFactory.java index 2db4047e4c7..d9481c1c44e 100644 --- a/rskj-core/src/main/java/co/rsk/mine/gas/provider/MinGasPriceProviderFactory.java +++ b/rskj-core/src/main/java/co/rsk/mine/gas/provider/MinGasPriceProviderFactory.java @@ -14,7 +14,7 @@ public class MinGasPriceProviderFactory { private MinGasPriceProviderFactory() { } - public static MinGasPriceProvider create(long fixedMinGasPrice, StableMinGasPriceSystemConfig stableMinGasPriceSystemConfig) { + public static MinGasPriceProvider create(long fixedMinGasPrice, StableMinGasPriceSystemConfig stableMinGasPriceSystemConfig, StableMinGasPriceProvider.GetContextCallback getContextCallback) { FixedMinGasPriceProvider fixedMinGasPriceProvider = new FixedMinGasPriceProvider(fixedMinGasPrice); if (stableMinGasPriceSystemConfig == null) { logger.warn("Could not find stable min gas price system config, using {} provider", fixedMinGasPriceProvider.getType().name()); @@ -32,9 +32,9 @@ public static MinGasPriceProvider create(long fixedMinGasPrice, StableMinGasPric switch (method) { case WEB: - return WebStableMinGasPriceProviderFactory.create(stableMinGasPriceSystemConfig, fixedMinGasPriceProvider); + return WebStableMinGasPriceProviderFactory.create(stableMinGasPriceSystemConfig, fixedMinGasPriceProvider, getContextCallback); case ON_CHAIN: - return OnChainMinGasPriceProviderFactory.create(stableMinGasPriceSystemConfig, fixedMinGasPriceProvider); + return OnChainMinGasPriceProviderFactory.create(stableMinGasPriceSystemConfig, fixedMinGasPriceProvider, getContextCallback); default: logger.debug("Could not find a valid implementation for the method {}. Returning fallback provider {}", method, fixedMinGasPriceProvider.getType().name()); return fixedMinGasPriceProvider; diff --git a/rskj-core/src/main/java/co/rsk/mine/gas/provider/StableMinGasPriceProvider.java b/rskj-core/src/main/java/co/rsk/mine/gas/provider/StableMinGasPriceProvider.java index 5b0f1883c88..a2345ec29b1 100644 --- a/rskj-core/src/main/java/co/rsk/mine/gas/provider/StableMinGasPriceProvider.java +++ b/rskj-core/src/main/java/co/rsk/mine/gas/provider/StableMinGasPriceProvider.java @@ -1,15 +1,24 @@ package co.rsk.mine.gas.provider; import co.rsk.core.Coin; +import co.rsk.rpc.modules.eth.EthModule; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public abstract class StableMinGasPriceProvider implements MinGasPriceProvider { private static final Logger logger = LoggerFactory.getLogger("StableMinGasPrice"); - private final MinGasPriceProvider fallBackProvider; + protected final MinGasPriceProvider fallBackProvider; + protected final GetContextCallback getContextCallback; - protected StableMinGasPriceProvider(MinGasPriceProvider fallBackProvider) { + protected StableMinGasPriceProvider(MinGasPriceProvider fallBackProvider, GetContextCallback getContextCallback) { this.fallBackProvider = fallBackProvider; + this.getContextCallback = getContextCallback; + } + + + @FunctionalInterface + public interface GetContextCallback { + EthModule getEthModule(); } public abstract Long getStableMinGasPrice(); diff --git a/rskj-core/src/main/java/co/rsk/mine/gas/provider/onchain/OnChainMinGasPriceProvider.java b/rskj-core/src/main/java/co/rsk/mine/gas/provider/onchain/OnChainMinGasPriceProvider.java index cc278ef105b..27fe25bb275 100644 --- a/rskj-core/src/main/java/co/rsk/mine/gas/provider/onchain/OnChainMinGasPriceProvider.java +++ b/rskj-core/src/main/java/co/rsk/mine/gas/provider/onchain/OnChainMinGasPriceProvider.java @@ -4,13 +4,28 @@ import co.rsk.mine.gas.provider.MinGasPriceProvider; import co.rsk.mine.gas.provider.MinGasPriceProviderType; import co.rsk.mine.gas.provider.StableMinGasPriceProvider; +import co.rsk.rpc.modules.eth.EthModule; +import co.rsk.util.HexUtils; +import org.ethereum.rpc.parameters.BlockIdentifierParam; +import org.ethereum.rpc.parameters.CallArgumentsParam; +import org.ethereum.rpc.parameters.HexAddressParam; +import org.ethereum.rpc.parameters.HexDataParam; +import org.ethereum.rpc.parameters.HexNumberParam; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class OnChainMinGasPriceProvider extends StableMinGasPriceProvider { - private final String address; + private final String toAddress; + private final String fromAddress; + private final String data; - protected OnChainMinGasPriceProvider(MinGasPriceProvider fallBackProvider, OnChainMinGasPriceSystemConfig config) { - super(fallBackProvider); - this.address = config.getAddress(); + Logger logger = LoggerFactory.getLogger(OnChainMinGasPriceProvider.class); + + protected OnChainMinGasPriceProvider(MinGasPriceProvider fallBackProvider, OnChainMinGasPriceSystemConfig config, GetContextCallback getContextCallback) { + super(fallBackProvider, getContextCallback); + this.toAddress = config.address(); + this.fromAddress = config.from(); + this.data = config.data(); } @Override @@ -20,10 +35,35 @@ public MinGasPriceProviderType getType() { @Override public Long getStableMinGasPrice() { - return null; + EthModule ethModule = this.getContextCallback.getEthModule(); + CallArgumentsParam callArguments = new CallArgumentsParam( + new HexAddressParam(fromAddress), + new HexAddressParam(toAddress), + null, + null, + null, + null, + new HexNumberParam(ethModule.chainId()), + null, + new HexDataParam(data), + null + ); + try { + String callOutput = ethModule.call(callArguments, new BlockIdentifierParam("latest")); + + // TODO: how should we handle the output based on the return types of the function signature? + // TODO: This will only support uint256 but bytes32 is possible + return HexUtils.jsonHexToLong( + callOutput + ); + } catch (Exception e) { + logger.error("Error calling eth module", e); + + return fallBackProvider.getMinGasPrice(); + } } - public String getAddress() { - return address; + public String getToAddress() { + return toAddress; } } diff --git a/rskj-core/src/main/java/co/rsk/mine/gas/provider/onchain/OnChainMinGasPriceProviderFactory.java b/rskj-core/src/main/java/co/rsk/mine/gas/provider/onchain/OnChainMinGasPriceProviderFactory.java index ee022684e2a..794c8375cbe 100644 --- a/rskj-core/src/main/java/co/rsk/mine/gas/provider/onchain/OnChainMinGasPriceProviderFactory.java +++ b/rskj-core/src/main/java/co/rsk/mine/gas/provider/onchain/OnChainMinGasPriceProviderFactory.java @@ -8,7 +8,7 @@ public class OnChainMinGasPriceProviderFactory { private OnChainMinGasPriceProviderFactory() { } - public static OnChainMinGasPriceProvider create(StableMinGasPriceSystemConfig config, MinGasPriceProvider fallbackProvider) { - return new OnChainMinGasPriceProvider(fallbackProvider, config.getOnChainConfig()); + public static OnChainMinGasPriceProvider create(StableMinGasPriceSystemConfig config, MinGasPriceProvider fallbackProvider, OnChainMinGasPriceProvider.GetContextCallback getContextCallback) { + return new OnChainMinGasPriceProvider(fallbackProvider, config.getOnChainConfig(), getContextCallback); } } diff --git a/rskj-core/src/main/java/co/rsk/mine/gas/provider/web/WebMinGasPriceProvider.java b/rskj-core/src/main/java/co/rsk/mine/gas/provider/web/WebMinGasPriceProvider.java index 532f1d774ce..635b17ecdab 100644 --- a/rskj-core/src/main/java/co/rsk/mine/gas/provider/web/WebMinGasPriceProvider.java +++ b/rskj-core/src/main/java/co/rsk/mine/gas/provider/web/WebMinGasPriceProvider.java @@ -11,8 +11,8 @@ public class WebMinGasPriceProvider extends StableMinGasPriceProvider { private final int timeout; private final int refreshRate; - WebMinGasPriceProvider(MinGasPriceProvider fallBackProvider, WebStableMinGasPriceConfig config) { - super(fallBackProvider); + WebMinGasPriceProvider(MinGasPriceProvider fallBackProvider, WebStableMinGasPriceConfig config, StableMinGasPriceProvider.GetContextCallback getContextCallback) { + super(fallBackProvider, getContextCallback); url = config.getUrl(); jsonPath = config.getJsonPath(); apiKey = config.getApiKey(); diff --git a/rskj-core/src/main/java/co/rsk/mine/gas/provider/web/WebStableMinGasPriceProviderFactory.java b/rskj-core/src/main/java/co/rsk/mine/gas/provider/web/WebStableMinGasPriceProviderFactory.java index 8036e0bde74..4bc78cc3abd 100644 --- a/rskj-core/src/main/java/co/rsk/mine/gas/provider/web/WebStableMinGasPriceProviderFactory.java +++ b/rskj-core/src/main/java/co/rsk/mine/gas/provider/web/WebStableMinGasPriceProviderFactory.java @@ -10,7 +10,7 @@ public class WebStableMinGasPriceProviderFactory { private WebStableMinGasPriceProviderFactory() { } - public static StableMinGasPriceProvider create(StableMinGasPriceSystemConfig config, MinGasPriceProvider fallbackProvider) { + public static StableMinGasPriceProvider create(StableMinGasPriceSystemConfig config, MinGasPriceProvider fallbackProvider, StableMinGasPriceProvider.GetContextCallback getContextCallback) { WebStableMinGasSystemConfig httpGetSystemConfig = config.getWebConfig(); WebStableMinGasPriceConfig httpGetStableMinGasPriceConfig = WebStableMinGasPriceConfig.builder().setUrl(httpGetSystemConfig.getUrl()) .setJsonPath(httpGetSystemConfig.getRequestPath()) @@ -19,7 +19,7 @@ public static StableMinGasPriceProvider create(StableMinGasPriceSystemConfig con .setMinStableGasPrice(config.getMinStableGasPrice()) .setRefreshRate(config.getRefreshRate()) .build(); - return new WebMinGasPriceProvider(fallbackProvider, httpGetStableMinGasPriceConfig); + return new WebMinGasPriceProvider(fallbackProvider, httpGetStableMinGasPriceConfig, getContextCallback); } } diff --git a/rskj-core/src/test/java/co/rsk/mine/gas/provider/MinGasPriceProviderFactoryTest.java b/rskj-core/src/test/java/co/rsk/mine/gas/provider/MinGasPriceProviderFactoryTest.java index 6e8fd4b3895..61f5b376e24 100644 --- a/rskj-core/src/test/java/co/rsk/mine/gas/provider/MinGasPriceProviderFactoryTest.java +++ b/rskj-core/src/test/java/co/rsk/mine/gas/provider/MinGasPriceProviderFactoryTest.java @@ -22,7 +22,7 @@ void createFixedMinGasPriceProvider() { ); StableMinGasPriceSystemConfig config = new StableMinGasPriceSystemConfig(testConfig); - MinGasPriceProvider provider = MinGasPriceProviderFactory.create(100L, config); + MinGasPriceProvider provider = MinGasPriceProviderFactory.create(100L, config, () -> null); assertTrue(provider instanceof FixedMinGasPriceProvider); assertEquals(100, provider.getMinGasPrice()); @@ -31,7 +31,7 @@ void createFixedMinGasPriceProvider() { @Test void createWithNullConfig() { - MinGasPriceProvider provider = MinGasPriceProviderFactory.create(100L, null); + MinGasPriceProvider provider = MinGasPriceProviderFactory.create(100L, null, () -> null); assertTrue(provider instanceof FixedMinGasPriceProvider); assertEquals(100, provider.getMinGasPrice()); assertEquals(MinGasPriceProviderType.FIXED, provider.getType()); @@ -52,7 +52,7 @@ void createWebProviderMethod() { StableMinGasPriceSystemConfig disabledConfig = new StableMinGasPriceSystemConfig(testConfig); - MinGasPriceProvider provider = MinGasPriceProviderFactory.create(100L, disabledConfig); + MinGasPriceProvider provider = MinGasPriceProviderFactory.create(100L, disabledConfig, () -> null); assertTrue(provider instanceof WebMinGasPriceProvider); assertEquals(100, provider.getMinGasPrice()); @@ -74,7 +74,7 @@ void createWithDisabledConfigReturnFixed() { StableMinGasPriceSystemConfig disabledConfig = new StableMinGasPriceSystemConfig(testConfig); - MinGasPriceProvider provider = MinGasPriceProviderFactory.create(100L, disabledConfig); + MinGasPriceProvider provider = MinGasPriceProviderFactory.create(100L, disabledConfig, () -> null); assertTrue(provider instanceof FixedMinGasPriceProvider); assertEquals(100, provider.getMinGasPrice()); diff --git a/rskj-core/src/test/java/co/rsk/mine/gas/provider/StableMinGasPriceProviderTest.java b/rskj-core/src/test/java/co/rsk/mine/gas/provider/StableMinGasPriceProviderTest.java index 2f84a91177a..2ff37441f09 100644 --- a/rskj-core/src/test/java/co/rsk/mine/gas/provider/StableMinGasPriceProviderTest.java +++ b/rskj-core/src/test/java/co/rsk/mine/gas/provider/StableMinGasPriceProviderTest.java @@ -51,7 +51,7 @@ void testGetMinGasPriceAsCoin() { public static class TestStableMingGasPriceProvider extends StableMinGasPriceProvider { protected TestStableMingGasPriceProvider(MinGasPriceProvider fallBackProvider) { - super(fallBackProvider); + super(fallBackProvider, () -> null); } @Override @@ -64,4 +64,4 @@ public Long getStableMinGasPrice() { return 1L; } } -} \ No newline at end of file +} diff --git a/rskj-core/src/test/java/co/rsk/mine/gas/provider/onchain/OnChainMinGasPriceProviderTest.java b/rskj-core/src/test/java/co/rsk/mine/gas/provider/onchain/OnChainMinGasPriceProviderTest.java new file mode 100644 index 00000000000..a914bea242a --- /dev/null +++ b/rskj-core/src/test/java/co/rsk/mine/gas/provider/onchain/OnChainMinGasPriceProviderTest.java @@ -0,0 +1,84 @@ +package co.rsk.mine.gas.provider.onchain; + +import co.rsk.config.mining.OnChainMinGasPriceSystemConfig; +import co.rsk.mine.gas.provider.MinGasPriceProvider; +import co.rsk.mine.gas.provider.MinGasPriceProviderType; +import co.rsk.util.HexUtils; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import co.rsk.rpc.modules.eth.EthModule; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.NullSource; +import org.junit.jupiter.params.provider.ValueSource; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class OnChainMinGasPriceProviderTest { + private final String oracle_address = "0xbffBD993FF1d229B0FfE55668F2009d20d4F7C5f"; + private final String from_address = "0xbffBD993FF1d229B0FfE55668F2009d20d4F7C5f"; + private final String data = "0x"; + private final long fallback_minGasPrice_fake = 1234567890L; + + private EthModule ethModule_mock; + private MinGasPriceProvider fallback_mock; + private OnChainMinGasPriceSystemConfig onChainMinGasPriceSystemConfig_mock; + + private OnChainMinGasPriceProvider onChainMinGasPriceProvider; + + @BeforeEach + public void beforeEach() { + ethModule_mock = mock(EthModule.class); + when(ethModule_mock.chainId()).thenReturn("0x21"); + + fallback_mock = mock(MinGasPriceProvider.class); + when(fallback_mock.getType()).thenReturn(MinGasPriceProviderType.FIXED); + when(fallback_mock.getMinGasPrice()).thenReturn(fallback_minGasPrice_fake); + + onChainMinGasPriceSystemConfig_mock = mock(OnChainMinGasPriceSystemConfig.class); + when(onChainMinGasPriceSystemConfig_mock.address()).thenReturn(oracle_address); + when(onChainMinGasPriceSystemConfig_mock.from()).thenReturn(from_address); + when(onChainMinGasPriceSystemConfig_mock.data()).thenReturn(data); + + + onChainMinGasPriceProvider = new OnChainMinGasPriceProvider( + fallback_mock, + onChainMinGasPriceSystemConfig_mock, + () -> ethModule_mock + ); + } + + @AfterEach + public void afterEach() { + ethModule_mock = null; + fallback_mock = null; + } + + @Test + public void getStableMinGasPrice_callsEthModulesCallMethod() { + String expectedPrice = "0x21"; + when(ethModule_mock.call(any(), any())).thenReturn(expectedPrice); + + Assertions.assertEquals( + HexUtils.jsonHexToLong(expectedPrice), + onChainMinGasPriceProvider.getStableMinGasPrice() + ); + } + + @ParameterizedTest + @NullSource + @ValueSource(strings = {"", "0x"}) + public void getStableMinGasPrice_callsFallback_whenNoData(String data_input) { + when(onChainMinGasPriceSystemConfig_mock.data()).thenReturn(data_input); + + Assertions.assertEquals( + fallback_minGasPrice_fake, + onChainMinGasPriceProvider.getStableMinGasPrice(), + "For " + data_input + ": " + ); + } + +} From 3dab0533507c1dc815d323f0359b8487be1a029e Mon Sep 17 00:00:00 2001 From: Juraj Piar Date: Fri, 7 Jun 2024 12:20:27 +0100 Subject: [PATCH 2/2] feat(stableMinGasPrice): makes only ethCall use context --- .../provider/MinGasPriceProviderFactory.java | 5 +- .../provider/StableMinGasPriceProvider.java | 11 +--- .../onchain/OnChainMinGasPriceProvider.java | 27 ++++++++-- .../provider/web/WebMinGasPriceProvider.java | 4 +- .../WebStableMinGasPriceProviderFactory.java | 4 +- .../OnChainMinGasPriceSystemConfigTest.java | 40 ++++++++++++++ .../StableMinGasPriceProviderTest.java | 2 +- .../OnChainMinGasPriceProviderTest.java | 54 +++++++++++++++++-- 8 files changed, 123 insertions(+), 24 deletions(-) create mode 100644 rskj-core/src/test/java/co/rsk/config/mining/OnChainMinGasPriceSystemConfigTest.java diff --git a/rskj-core/src/main/java/co/rsk/mine/gas/provider/MinGasPriceProviderFactory.java b/rskj-core/src/main/java/co/rsk/mine/gas/provider/MinGasPriceProviderFactory.java index d9481c1c44e..a2ce007f83b 100644 --- a/rskj-core/src/main/java/co/rsk/mine/gas/provider/MinGasPriceProviderFactory.java +++ b/rskj-core/src/main/java/co/rsk/mine/gas/provider/MinGasPriceProviderFactory.java @@ -1,6 +1,7 @@ package co.rsk.mine.gas.provider; import co.rsk.config.mining.StableMinGasPriceSystemConfig; +import co.rsk.mine.gas.provider.onchain.OnChainMinGasPriceProvider; import co.rsk.mine.gas.provider.onchain.OnChainMinGasPriceProviderFactory; import co.rsk.mine.gas.provider.web.WebStableMinGasPriceProviderFactory; import org.slf4j.Logger; @@ -14,7 +15,7 @@ public class MinGasPriceProviderFactory { private MinGasPriceProviderFactory() { } - public static MinGasPriceProvider create(long fixedMinGasPrice, StableMinGasPriceSystemConfig stableMinGasPriceSystemConfig, StableMinGasPriceProvider.GetContextCallback getContextCallback) { + public static MinGasPriceProvider create(long fixedMinGasPrice, StableMinGasPriceSystemConfig stableMinGasPriceSystemConfig, OnChainMinGasPriceProvider.GetContextCallback getContextCallback) { FixedMinGasPriceProvider fixedMinGasPriceProvider = new FixedMinGasPriceProvider(fixedMinGasPrice); if (stableMinGasPriceSystemConfig == null) { logger.warn("Could not find stable min gas price system config, using {} provider", fixedMinGasPriceProvider.getType().name()); @@ -32,7 +33,7 @@ public static MinGasPriceProvider create(long fixedMinGasPrice, StableMinGasPric switch (method) { case WEB: - return WebStableMinGasPriceProviderFactory.create(stableMinGasPriceSystemConfig, fixedMinGasPriceProvider, getContextCallback); + return WebStableMinGasPriceProviderFactory.create(stableMinGasPriceSystemConfig, fixedMinGasPriceProvider); case ON_CHAIN: return OnChainMinGasPriceProviderFactory.create(stableMinGasPriceSystemConfig, fixedMinGasPriceProvider, getContextCallback); default: diff --git a/rskj-core/src/main/java/co/rsk/mine/gas/provider/StableMinGasPriceProvider.java b/rskj-core/src/main/java/co/rsk/mine/gas/provider/StableMinGasPriceProvider.java index a2345ec29b1..fd03cf6ae66 100644 --- a/rskj-core/src/main/java/co/rsk/mine/gas/provider/StableMinGasPriceProvider.java +++ b/rskj-core/src/main/java/co/rsk/mine/gas/provider/StableMinGasPriceProvider.java @@ -1,24 +1,15 @@ package co.rsk.mine.gas.provider; import co.rsk.core.Coin; -import co.rsk.rpc.modules.eth.EthModule; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public abstract class StableMinGasPriceProvider implements MinGasPriceProvider { private static final Logger logger = LoggerFactory.getLogger("StableMinGasPrice"); protected final MinGasPriceProvider fallBackProvider; - protected final GetContextCallback getContextCallback; - protected StableMinGasPriceProvider(MinGasPriceProvider fallBackProvider, GetContextCallback getContextCallback) { + protected StableMinGasPriceProvider(MinGasPriceProvider fallBackProvider) { this.fallBackProvider = fallBackProvider; - this.getContextCallback = getContextCallback; - } - - - @FunctionalInterface - public interface GetContextCallback { - EthModule getEthModule(); } public abstract Long getStableMinGasPrice(); diff --git a/rskj-core/src/main/java/co/rsk/mine/gas/provider/onchain/OnChainMinGasPriceProvider.java b/rskj-core/src/main/java/co/rsk/mine/gas/provider/onchain/OnChainMinGasPriceProvider.java index 27fe25bb275..fb582590449 100644 --- a/rskj-core/src/main/java/co/rsk/mine/gas/provider/onchain/OnChainMinGasPriceProvider.java +++ b/rskj-core/src/main/java/co/rsk/mine/gas/provider/onchain/OnChainMinGasPriceProvider.java @@ -15,14 +15,21 @@ import org.slf4j.LoggerFactory; public class OnChainMinGasPriceProvider extends StableMinGasPriceProvider { + private static final Logger logger = LoggerFactory.getLogger(OnChainMinGasPriceProvider.class); + private final String toAddress; private final String fromAddress; private final String data; - Logger logger = LoggerFactory.getLogger(OnChainMinGasPriceProvider.class); + @FunctionalInterface + public interface GetContextCallback { + EthModule getEthModule(); + } + private final GetContextCallback getContextCallback; protected OnChainMinGasPriceProvider(MinGasPriceProvider fallBackProvider, OnChainMinGasPriceSystemConfig config, GetContextCallback getContextCallback) { - super(fallBackProvider, getContextCallback); + super(fallBackProvider); + this.getContextCallback = getContextCallback; this.toAddress = config.address(); this.fromAddress = config.from(); this.data = config.data(); @@ -36,6 +43,11 @@ public MinGasPriceProviderType getType() { @Override public Long getStableMinGasPrice() { EthModule ethModule = this.getContextCallback.getEthModule(); + if (ethModule == null) { + logger.error("Could not get eth module"); + return fallBackProvider.getMinGasPrice(); + } + CallArgumentsParam callArguments = new CallArgumentsParam( new HexAddressParam(fromAddress), new HexAddressParam(toAddress), @@ -51,8 +63,7 @@ public Long getStableMinGasPrice() { try { String callOutput = ethModule.call(callArguments, new BlockIdentifierParam("latest")); - // TODO: how should we handle the output based on the return types of the function signature? - // TODO: This will only support uint256 but bytes32 is possible + // Parse the output of the call to get the exchange rate. Will not work with bytes32 values! return HexUtils.jsonHexToLong( callOutput ); @@ -66,4 +77,12 @@ public Long getStableMinGasPrice() { public String getToAddress() { return toAddress; } + + public String getFromAddress() { + return fromAddress; + } + + public String getData() { + return data; + } } diff --git a/rskj-core/src/main/java/co/rsk/mine/gas/provider/web/WebMinGasPriceProvider.java b/rskj-core/src/main/java/co/rsk/mine/gas/provider/web/WebMinGasPriceProvider.java index 635b17ecdab..532f1d774ce 100644 --- a/rskj-core/src/main/java/co/rsk/mine/gas/provider/web/WebMinGasPriceProvider.java +++ b/rskj-core/src/main/java/co/rsk/mine/gas/provider/web/WebMinGasPriceProvider.java @@ -11,8 +11,8 @@ public class WebMinGasPriceProvider extends StableMinGasPriceProvider { private final int timeout; private final int refreshRate; - WebMinGasPriceProvider(MinGasPriceProvider fallBackProvider, WebStableMinGasPriceConfig config, StableMinGasPriceProvider.GetContextCallback getContextCallback) { - super(fallBackProvider, getContextCallback); + WebMinGasPriceProvider(MinGasPriceProvider fallBackProvider, WebStableMinGasPriceConfig config) { + super(fallBackProvider); url = config.getUrl(); jsonPath = config.getJsonPath(); apiKey = config.getApiKey(); diff --git a/rskj-core/src/main/java/co/rsk/mine/gas/provider/web/WebStableMinGasPriceProviderFactory.java b/rskj-core/src/main/java/co/rsk/mine/gas/provider/web/WebStableMinGasPriceProviderFactory.java index 4bc78cc3abd..8036e0bde74 100644 --- a/rskj-core/src/main/java/co/rsk/mine/gas/provider/web/WebStableMinGasPriceProviderFactory.java +++ b/rskj-core/src/main/java/co/rsk/mine/gas/provider/web/WebStableMinGasPriceProviderFactory.java @@ -10,7 +10,7 @@ public class WebStableMinGasPriceProviderFactory { private WebStableMinGasPriceProviderFactory() { } - public static StableMinGasPriceProvider create(StableMinGasPriceSystemConfig config, MinGasPriceProvider fallbackProvider, StableMinGasPriceProvider.GetContextCallback getContextCallback) { + public static StableMinGasPriceProvider create(StableMinGasPriceSystemConfig config, MinGasPriceProvider fallbackProvider) { WebStableMinGasSystemConfig httpGetSystemConfig = config.getWebConfig(); WebStableMinGasPriceConfig httpGetStableMinGasPriceConfig = WebStableMinGasPriceConfig.builder().setUrl(httpGetSystemConfig.getUrl()) .setJsonPath(httpGetSystemConfig.getRequestPath()) @@ -19,7 +19,7 @@ public static StableMinGasPriceProvider create(StableMinGasPriceSystemConfig con .setMinStableGasPrice(config.getMinStableGasPrice()) .setRefreshRate(config.getRefreshRate()) .build(); - return new WebMinGasPriceProvider(fallbackProvider, httpGetStableMinGasPriceConfig, getContextCallback); + return new WebMinGasPriceProvider(fallbackProvider, httpGetStableMinGasPriceConfig); } } diff --git a/rskj-core/src/test/java/co/rsk/config/mining/OnChainMinGasPriceSystemConfigTest.java b/rskj-core/src/test/java/co/rsk/config/mining/OnChainMinGasPriceSystemConfigTest.java new file mode 100644 index 00000000000..2458b275c83 --- /dev/null +++ b/rskj-core/src/test/java/co/rsk/config/mining/OnChainMinGasPriceSystemConfigTest.java @@ -0,0 +1,40 @@ +package co.rsk.config.mining; + +import com.typesafe.config.Config; +import com.typesafe.config.ConfigFactory; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class OnChainMinGasPriceSystemConfigTest { + private OnChainMinGasPriceSystemConfig config; + private String address = "0x77045E71a7A2c50903d88e564cD72fab11e82051"; + private String from = "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826"; + private String data = "0x98d5fdca"; + + @BeforeEach + void setUp() { + Config testConfig = ConfigFactory.parseString( + "address=\"" + address + "\"\n" + + "from=\"" + from + "\"\n" + + "data=\"" + data + "\"" + ); + config = new OnChainMinGasPriceSystemConfig(testConfig); + } + + @Test + void testAddress() { + assertEquals(address, config.address()); + } + + @Test + void testFrom() { + assertEquals(from, config.from()); + } + + @Test + void testData() { + assertEquals(data, config.data()); + } +} diff --git a/rskj-core/src/test/java/co/rsk/mine/gas/provider/StableMinGasPriceProviderTest.java b/rskj-core/src/test/java/co/rsk/mine/gas/provider/StableMinGasPriceProviderTest.java index 2ff37441f09..3a012c730cf 100644 --- a/rskj-core/src/test/java/co/rsk/mine/gas/provider/StableMinGasPriceProviderTest.java +++ b/rskj-core/src/test/java/co/rsk/mine/gas/provider/StableMinGasPriceProviderTest.java @@ -51,7 +51,7 @@ void testGetMinGasPriceAsCoin() { public static class TestStableMingGasPriceProvider extends StableMinGasPriceProvider { protected TestStableMingGasPriceProvider(MinGasPriceProvider fallBackProvider) { - super(fallBackProvider, () -> null); + super(fallBackProvider); } @Override diff --git a/rskj-core/src/test/java/co/rsk/mine/gas/provider/onchain/OnChainMinGasPriceProviderTest.java b/rskj-core/src/test/java/co/rsk/mine/gas/provider/onchain/OnChainMinGasPriceProviderTest.java index a914bea242a..4568c18cc96 100644 --- a/rskj-core/src/test/java/co/rsk/mine/gas/provider/onchain/OnChainMinGasPriceProviderTest.java +++ b/rskj-core/src/test/java/co/rsk/mine/gas/provider/onchain/OnChainMinGasPriceProviderTest.java @@ -17,7 +17,7 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -public class OnChainMinGasPriceProviderTest { +class OnChainMinGasPriceProviderTest { private final String oracle_address = "0xbffBD993FF1d229B0FfE55668F2009d20d4F7C5f"; private final String from_address = "0xbffBD993FF1d229B0FfE55668F2009d20d4F7C5f"; private final String data = "0x"; @@ -57,8 +57,42 @@ public void afterEach() { fallback_mock = null; } + + + @ParameterizedTest + @NullSource + @ValueSource(strings = {"0x123", "0xabc"}) + void constructorSetsFieldsCorrectly(String data_input) { + MinGasPriceProvider fallbackProvider = mock(MinGasPriceProvider.class); + OnChainMinGasPriceSystemConfig config = mock(OnChainMinGasPriceSystemConfig.class); + + when(config.address()).thenReturn("0xaddress"); + when(config.from()).thenReturn("0xfrom"); + when(config.data()).thenReturn(data_input); + + OnChainMinGasPriceProvider provider = new OnChainMinGasPriceProvider(fallbackProvider, config, () -> ethModule_mock); + + Assertions.assertEquals("0xaddress", provider.getToAddress()); + } + + @Test + void constructorSetsFieldsToNullWhenConfigReturnsNull() { + MinGasPriceProvider fallbackProvider = mock(MinGasPriceProvider.class); + OnChainMinGasPriceSystemConfig config = mock(OnChainMinGasPriceSystemConfig.class); + + when(config.address()).thenReturn(null); + when(config.from()).thenReturn(null); + when(config.data()).thenReturn(null); + + OnChainMinGasPriceProvider provider = new OnChainMinGasPriceProvider(fallbackProvider, config, () -> ethModule_mock); + + Assertions.assertNull(provider.getToAddress()); + Assertions.assertNull(provider.getFromAddress()); + Assertions.assertNull(provider.getData()); + } + @Test - public void getStableMinGasPrice_callsEthModulesCallMethod() { + void getStableMinGasPrice_callsEthModulesCallMethod() { String expectedPrice = "0x21"; when(ethModule_mock.call(any(), any())).thenReturn(expectedPrice); @@ -71,7 +105,7 @@ public void getStableMinGasPrice_callsEthModulesCallMethod() { @ParameterizedTest @NullSource @ValueSource(strings = {"", "0x"}) - public void getStableMinGasPrice_callsFallback_whenNoData(String data_input) { + void getStableMinGasPrice_callsFallback_whenNoData(String data_input) { when(onChainMinGasPriceSystemConfig_mock.data()).thenReturn(data_input); Assertions.assertEquals( @@ -81,4 +115,18 @@ public void getStableMinGasPrice_callsFallback_whenNoData(String data_input) { ); } + + @Test + void getStableMinGasPrice_callsFallback_whenEthModuleIsNull() { + Assertions.assertEquals( + fallback_minGasPrice_fake, + onChainMinGasPriceProvider.getStableMinGasPrice() + ); + } + + @Test + void getType_returnsOnChain() { + Assertions.assertEquals(MinGasPriceProviderType.ON_CHAIN, onChainMinGasPriceProvider.getType()); + } + }