From 2031de797420f0d4063c3e87a00fbd98ef7548f7 Mon Sep 17 00:00:00 2001 From: Angel Soto Date: Fri, 3 May 2024 20:49:41 +0200 Subject: [PATCH 01/17] Adding Default Min Gas Price provider --- .../src/main/java/co/rsk/RskContext.java | 18 +++++++++-- .../main/java/co/rsk/config/MiningConfig.java | 17 +++++----- .../rsk/mine/MinimumGasPriceCalculator.java | 9 ++++-- .../mine/gas/DefaultMinGasPriceProvider.java | 28 +++++++++++++++++ .../co/rsk/mine/gas/GasPriceProviderType.java | 6 ++++ .../co/rsk/mine/gas/MinGasPriceProvider.java | 12 +++++++ .../rsk/blockchain/utils/BlockGenerator.java | 3 +- .../test/java/co/rsk/config/ConfigUtils.java | 5 +-- .../java/co/rsk/mine/MainNetMinerTest.java | 3 +- .../java/co/rsk/mine/MinerManagerTest.java | 3 +- .../java/co/rsk/mine/MinerServerTest.java | 3 +- .../mine/MinimumGasPriceCalculatorTest.java | 29 ++++++++++++----- .../co/rsk/mine/TransactionModuleTest.java | 2 +- .../gas/DefaultMinGasPriceProviderTest.java | 31 +++++++++++++++++++ .../modules/trace/TraceModuleImplTest.java | 15 +++++---- .../ethereum/rpc/Web3ImplSnapshotTest.java | 3 +- 16 files changed, 149 insertions(+), 38 deletions(-) create mode 100644 rskj-core/src/main/java/co/rsk/mine/gas/DefaultMinGasPriceProvider.java create mode 100644 rskj-core/src/main/java/co/rsk/mine/gas/GasPriceProviderType.java create mode 100644 rskj-core/src/main/java/co/rsk/mine/gas/MinGasPriceProvider.java create mode 100644 rskj-core/src/test/java/co/rsk/mine/gas/DefaultMinGasPriceProviderTest.java diff --git a/rskj-core/src/main/java/co/rsk/RskContext.java b/rskj-core/src/main/java/co/rsk/RskContext.java index d8d2aa84fc5..bdb8ab4a1d9 100644 --- a/rskj-core/src/main/java/co/rsk/RskContext.java +++ b/rskj-core/src/main/java/co/rsk/RskContext.java @@ -40,6 +40,8 @@ import co.rsk.metrics.HashRateCalculatorMining; import co.rsk.metrics.HashRateCalculatorNonMining; import co.rsk.mine.*; +import co.rsk.mine.gas.DefaultMinGasPriceProvider; +import co.rsk.mine.gas.MinGasPriceProvider; import co.rsk.net.*; import co.rsk.net.discovery.KnownPeersHandler; import co.rsk.net.discovery.PeerExplorer; @@ -255,6 +257,8 @@ public class RskContext implements NodeContext, NodeBootstrapper { private BlockChainFlusher blockChainFlusher; private final Map dbPathToDbKindMap = new HashMap<>(); + private MinGasPriceProvider minGasPriceProvider; + private volatile boolean closed; /***** Constructors ***********************************************************************************************/ @@ -1842,7 +1846,7 @@ private BlockToMineBuilder getBlockToMineBuilder() { getMinerClock(), getBlockFactory(), getBlockExecutor(), - new MinimumGasPriceCalculator(Coin.valueOf(getMiningConfig().getMinGasPriceTarget())), + new MinimumGasPriceCalculator(getMinGasPriceProvider()), new MinerUtils(), getBlockTxSignatureCache() ); @@ -1851,6 +1855,14 @@ private BlockToMineBuilder getBlockToMineBuilder() { return blockToMineBuilder; } + private MinGasPriceProvider getMinGasPriceProvider() { + long minGasPrice = getRskSystemProperties().minerMinGasPrice(); + if (minGasPriceProvider == null) { + minGasPriceProvider = new DefaultMinGasPriceProvider(minGasPrice); + } + return minGasPriceProvider; + } + private BlockNodeInformation getBlockNodeInformation() { if (blockNodeInformation == null) { blockNodeInformation = new BlockNodeInformation(); @@ -2142,7 +2154,6 @@ private MiningConfig getMiningConfig() { rskSystemProperties.coinbaseAddress(), rskSystemProperties.minerMinFeesNotifyInDollars(), rskSystemProperties.minerGasUnitInDollars(), - rskSystemProperties.minerMinGasPrice(), rskSystemProperties.getNetworkConstants().getUncleListLimit(), rskSystemProperties.getNetworkConstants().getUncleGenerationLimit(), new GasLimitConfig( @@ -2151,7 +2162,8 @@ private MiningConfig getMiningConfig() { rskSystemProperties.getForceTargetGasLimit() ), rskSystemProperties.isMinerServerFixedClock(), - rskSystemProperties.workSubmissionRateLimitInMills() + rskSystemProperties.workSubmissionRateLimitInMills(), + getMinGasPriceProvider() ); } diff --git a/rskj-core/src/main/java/co/rsk/config/MiningConfig.java b/rskj-core/src/main/java/co/rsk/config/MiningConfig.java index cc536c880b3..bb94279d481 100644 --- a/rskj-core/src/main/java/co/rsk/config/MiningConfig.java +++ b/rskj-core/src/main/java/co/rsk/config/MiningConfig.java @@ -19,6 +19,7 @@ package co.rsk.config; import co.rsk.core.RskAddress; +import co.rsk.mine.gas.MinGasPriceProvider; /** * Wraps configuration for Mining, which is usually derived from configuration files. @@ -29,25 +30,25 @@ public class MiningConfig { private final RskAddress coinbaseAddress; private final double minFeesNotifyInDollars; private final double minerGasUnitInDollars; - private final long minGasPriceTarget; private final int uncleListLimit; private final int uncleGenerationLimit; private final GasLimitConfig gasLimit; private final boolean isFixedClock; private final long workSubmissionRateLimitInMills; + private final MinGasPriceProvider minGasPriceProvider; public MiningConfig(RskAddress coinbaseAddress, double minFeesNotifyInDollars, double minerGasUnitInDollars, - long minGasPriceTarget, int uncleListLimit, int uncleGenerationLimit, GasLimitConfig gasLimit, - boolean isFixedClock, long workSubmissionRateLimitInMills) { + int uncleListLimit, int uncleGenerationLimit, GasLimitConfig gasLimit, + boolean isFixedClock, long workSubmissionRateLimitInMills, MinGasPriceProvider minGasPriceProvider) { this.coinbaseAddress = coinbaseAddress; this.minFeesNotifyInDollars = minFeesNotifyInDollars; this.minerGasUnitInDollars = minerGasUnitInDollars; - this.minGasPriceTarget= minGasPriceTarget; this.uncleListLimit = uncleListLimit; this.uncleGenerationLimit = uncleGenerationLimit; this.gasLimit = gasLimit; this.isFixedClock = isFixedClock; this.workSubmissionRateLimitInMills = workSubmissionRateLimitInMills; + this.minGasPriceProvider = minGasPriceProvider; } public RskAddress getCoinbaseAddress() { @@ -62,10 +63,6 @@ public double getGasUnitInDollars() { return minerGasUnitInDollars; } - public long getMinGasPriceTarget() { - return minGasPriceTarget; - } - public int getUncleListLimit() { return uncleListLimit; } @@ -85,4 +82,8 @@ public boolean isFixedClock() { public long getWorkSubmissionRateLimitInMills() { return workSubmissionRateLimitInMills; } + + public MinGasPriceProvider getMinGasPriceProvider() { + return minGasPriceProvider; + } } diff --git a/rskj-core/src/main/java/co/rsk/mine/MinimumGasPriceCalculator.java b/rskj-core/src/main/java/co/rsk/mine/MinimumGasPriceCalculator.java index d550e14db21..636fb3425f3 100644 --- a/rskj-core/src/main/java/co/rsk/mine/MinimumGasPriceCalculator.java +++ b/rskj-core/src/main/java/co/rsk/mine/MinimumGasPriceCalculator.java @@ -19,6 +19,7 @@ package co.rsk.mine; import co.rsk.core.Coin; +import co.rsk.mine.gas.MinGasPriceProvider; /** * This is the implementation of RSKIP-09 @@ -26,14 +27,15 @@ */ public class MinimumGasPriceCalculator { - private final Coin targetMGP; + private MinGasPriceProvider minGasPriceProvider; - public MinimumGasPriceCalculator(Coin targetMGP) { - this.targetMGP = targetMGP; + public MinimumGasPriceCalculator(MinGasPriceProvider minGasPriceProvider) { + this.minGasPriceProvider = minGasPriceProvider; } public Coin calculate(Coin previousMGP) { BlockGasPriceRange priceRange = new BlockGasPriceRange(previousMGP); + Coin targetMGP = minGasPriceProvider.getMinGasPriceAsCoin(); if (priceRange.inRange(targetMGP)) { return targetMGP; } @@ -44,4 +46,5 @@ public Coin calculate(Coin previousMGP) { return priceRange.getLowerLimit(); } + } diff --git a/rskj-core/src/main/java/co/rsk/mine/gas/DefaultMinGasPriceProvider.java b/rskj-core/src/main/java/co/rsk/mine/gas/DefaultMinGasPriceProvider.java new file mode 100644 index 00000000000..492376217a6 --- /dev/null +++ b/rskj-core/src/main/java/co/rsk/mine/gas/DefaultMinGasPriceProvider.java @@ -0,0 +1,28 @@ +package co.rsk.mine.gas; + +import co.rsk.core.Coin; + +public class DefaultMinGasPriceProvider implements MinGasPriceProvider { + + + private final long minGasPrice; + + public DefaultMinGasPriceProvider(long minGasPrice) { + this.minGasPrice = minGasPrice; + } + + @Override + public long getMinGasPrice() { + return minGasPrice; + } + + @Override + public GasPriceProviderType getType() { + return GasPriceProviderType.DEFAULT; + } + + @Override + public Coin getMinGasPriceAsCoin() { + return Coin.valueOf(minGasPrice); + } +} diff --git a/rskj-core/src/main/java/co/rsk/mine/gas/GasPriceProviderType.java b/rskj-core/src/main/java/co/rsk/mine/gas/GasPriceProviderType.java new file mode 100644 index 00000000000..d37b5cb4342 --- /dev/null +++ b/rskj-core/src/main/java/co/rsk/mine/gas/GasPriceProviderType.java @@ -0,0 +1,6 @@ +package co.rsk.mine.gas; + +public enum GasPriceProviderType { + DEFAULT, + STABLE +} diff --git a/rskj-core/src/main/java/co/rsk/mine/gas/MinGasPriceProvider.java b/rskj-core/src/main/java/co/rsk/mine/gas/MinGasPriceProvider.java new file mode 100644 index 00000000000..ec133aa4b82 --- /dev/null +++ b/rskj-core/src/main/java/co/rsk/mine/gas/MinGasPriceProvider.java @@ -0,0 +1,12 @@ +package co.rsk.mine.gas; + +import co.rsk.core.Coin; + +public interface MinGasPriceProvider { + + long getMinGasPrice(); + + GasPriceProviderType getType(); + + Coin getMinGasPriceAsCoin(); +} diff --git a/rskj-core/src/test/java/co/rsk/blockchain/utils/BlockGenerator.java b/rskj-core/src/test/java/co/rsk/blockchain/utils/BlockGenerator.java index 03360b9cfeb..bfc90ef0fb2 100644 --- a/rskj-core/src/test/java/co/rsk/blockchain/utils/BlockGenerator.java +++ b/rskj-core/src/test/java/co/rsk/blockchain/utils/BlockGenerator.java @@ -26,6 +26,7 @@ import co.rsk.core.bc.BlockHashesHelper; import co.rsk.crypto.Keccak256; import co.rsk.mine.MinimumGasPriceCalculator; +import co.rsk.mine.gas.DefaultMinGasPriceProvider; import co.rsk.peg.PegTestUtils; import co.rsk.peg.simples.SimpleRskTransaction; import org.bouncycastle.pqc.math.linearalgebra.ByteUtils; @@ -313,7 +314,7 @@ public Block createBlock(long number, int ntxs, Long gasLimit){ } Coin previousMGP = parent.getMinimumGasPrice() != null ? parent.getMinimumGasPrice() : Coin.valueOf(10L); - Coin minimumGasPrice = new MinimumGasPriceCalculator(Coin.valueOf(100L)).calculate(previousMGP); + Coin minimumGasPrice = new MinimumGasPriceCalculator(new DefaultMinGasPriceProvider(100L)).calculate(previousMGP); boolean isRskip126Enabled = activationConfig.isActive(ConsensusRule.RSKIP126, 0); diff --git a/rskj-core/src/test/java/co/rsk/config/ConfigUtils.java b/rskj-core/src/test/java/co/rsk/config/ConfigUtils.java index 5020b165d82..203e0ea49a2 100644 --- a/rskj-core/src/test/java/co/rsk/config/ConfigUtils.java +++ b/rskj-core/src/test/java/co/rsk/config/ConfigUtils.java @@ -18,6 +18,7 @@ package co.rsk.config; import co.rsk.core.RskAddress; +import co.rsk.mine.gas.DefaultMinGasPriceProvider; public class ConfigUtils { public static MiningConfig getDefaultMiningConfig() { @@ -26,12 +27,12 @@ public static MiningConfig getDefaultMiningConfig() { new RskAddress(coinbaseAddress), 0.0, 1.0, - 0, 10, 7, new GasLimitConfig(3000000, 500000, true), true, - 0L + 0L, + new DefaultMinGasPriceProvider(0) ); } } diff --git a/rskj-core/src/test/java/co/rsk/mine/MainNetMinerTest.java b/rskj-core/src/test/java/co/rsk/mine/MainNetMinerTest.java index 63a427680c5..1c70d23f547 100644 --- a/rskj-core/src/test/java/co/rsk/mine/MainNetMinerTest.java +++ b/rskj-core/src/test/java/co/rsk/mine/MainNetMinerTest.java @@ -22,7 +22,6 @@ import co.rsk.config.MiningConfig; import co.rsk.config.TestSystemProperties; import co.rsk.core.BlockDifficulty; -import co.rsk.core.Coin; import co.rsk.core.DifficultyCalculator; import co.rsk.core.bc.BlockChainImpl; import co.rsk.core.bc.BlockChainImplTest; @@ -239,7 +238,7 @@ private BlockToMineBuilder blockToMineBuilder() { clock, blockFactory, blockExecutor, - new MinimumGasPriceCalculator(Coin.valueOf(miningConfig.getMinGasPriceTarget())), + new MinimumGasPriceCalculator(miningConfig.getMinGasPriceProvider()), new MinerUtils(), new BlockTxSignatureCache(new ReceivedTxSignatureCache()) ); diff --git a/rskj-core/src/test/java/co/rsk/mine/MinerManagerTest.java b/rskj-core/src/test/java/co/rsk/mine/MinerManagerTest.java index 787e6a39fa7..7c62508dc90 100644 --- a/rskj-core/src/test/java/co/rsk/mine/MinerManagerTest.java +++ b/rskj-core/src/test/java/co/rsk/mine/MinerManagerTest.java @@ -20,7 +20,6 @@ import co.rsk.config.ConfigUtils; import co.rsk.config.MiningConfig; import co.rsk.config.TestSystemProperties; -import co.rsk.core.Coin; import co.rsk.core.DifficultyCalculator; import co.rsk.core.SnapshotManager; import co.rsk.core.bc.BlockExecutor; @@ -291,7 +290,7 @@ private MinerServerImpl getMinerServer() { clock, blockFactory, blockExecutor, - new MinimumGasPriceCalculator(Coin.valueOf(miningConfig.getMinGasPriceTarget())), + new MinimumGasPriceCalculator(miningConfig.getMinGasPriceProvider()), new MinerUtils(), new BlockTxSignatureCache(new ReceivedTxSignatureCache()) // TODO -> should it be ReceivedTxSignatureCache? See Miner Server Test for reference ), diff --git a/rskj-core/src/test/java/co/rsk/mine/MinerServerTest.java b/rskj-core/src/test/java/co/rsk/mine/MinerServerTest.java index cdca5ceea1b..fc6a1719b55 100644 --- a/rskj-core/src/test/java/co/rsk/mine/MinerServerTest.java +++ b/rskj-core/src/test/java/co/rsk/mine/MinerServerTest.java @@ -29,6 +29,7 @@ import co.rsk.core.bc.*; import co.rsk.crypto.Keccak256; import co.rsk.db.RepositoryLocator; +import co.rsk.mine.gas.DefaultMinGasPriceProvider; import co.rsk.net.BlockProcessor; import co.rsk.net.NodeBlockProcessor; import co.rsk.net.handler.quota.TxQuotaChecker; @@ -130,7 +131,7 @@ protected RepositoryLocator buildRepositoryLocator() { blockFactory = rskTestContext.getBlockFactory(); blockExecutor = rskTestContext.getBlockExecutor(); - minimumGasPriceCalculator = new MinimumGasPriceCalculator(Coin.ZERO); + minimumGasPriceCalculator = new MinimumGasPriceCalculator(new DefaultMinGasPriceProvider(0L)); minerUtils = new MinerUtils(); } diff --git a/rskj-core/src/test/java/co/rsk/mine/MinimumGasPriceCalculatorTest.java b/rskj-core/src/test/java/co/rsk/mine/MinimumGasPriceCalculatorTest.java index 50c83b5e329..a14dc01938e 100644 --- a/rskj-core/src/test/java/co/rsk/mine/MinimumGasPriceCalculatorTest.java +++ b/rskj-core/src/test/java/co/rsk/mine/MinimumGasPriceCalculatorTest.java @@ -19,19 +19,33 @@ package co.rsk.mine; import co.rsk.core.Coin; +import co.rsk.mine.gas.MinGasPriceProvider; import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +import static org.mockito.Mockito.when; /** * Created by mario on 22/12/16. */ class MinimumGasPriceCalculatorTest { + private MinGasPriceProvider minGasPriceProvider; + private MinimumGasPriceCalculator mgpCalculator; + + @BeforeEach + void init() { + minGasPriceProvider = Mockito.mock(MinGasPriceProvider.class); + mgpCalculator = new MinimumGasPriceCalculator(minGasPriceProvider); + } + @Test void increaseMgp() { Coin target = Coin.valueOf(2000L); Coin prev = Coin.valueOf(1000L); - MinimumGasPriceCalculator mgpCalculator = new MinimumGasPriceCalculator(target); + when(minGasPriceProvider.getMinGasPriceAsCoin()).thenReturn(target); Coin mgp = mgpCalculator.calculate(prev); Assertions.assertEquals(Coin.valueOf(1010), mgp); } @@ -40,7 +54,7 @@ void increaseMgp() { void decreaseMGP() { Coin prev = Coin.valueOf(1000L); Coin target = Coin.valueOf(900L); - MinimumGasPriceCalculator mgpCalculator = new MinimumGasPriceCalculator(target); + when(minGasPriceProvider.getMinGasPriceAsCoin()).thenReturn(target); Coin mgp = mgpCalculator.calculate(prev); Assertions.assertEquals(Coin.valueOf(990), mgp); } @@ -49,7 +63,7 @@ void decreaseMGP() { void mgpOnRage() { Coin prev = Coin.valueOf(1000L); Coin target = Coin.valueOf(995L); - MinimumGasPriceCalculator mgpCalculator = new MinimumGasPriceCalculator(target); + when(minGasPriceProvider.getMinGasPriceAsCoin()).thenReturn(target); Coin mgp = mgpCalculator.calculate(prev); Assertions.assertEquals(target, mgp); } @@ -58,7 +72,7 @@ void mgpOnRage() { void previousMgpEqualsTarget() { Coin prev = Coin.valueOf(1000L); Coin target = Coin.valueOf(1000L); - MinimumGasPriceCalculator mgpCalculator = new MinimumGasPriceCalculator(target); + when(minGasPriceProvider.getMinGasPriceAsCoin()).thenReturn(target); Coin mgp = mgpCalculator.calculate(prev); Assertions.assertEquals(target, mgp); } @@ -66,7 +80,7 @@ void previousMgpEqualsTarget() { @Test void previousValueIsZero() { Coin target = Coin.valueOf(1000L); - MinimumGasPriceCalculator mgpCalculator = new MinimumGasPriceCalculator(target); + when(minGasPriceProvider.getMinGasPriceAsCoin()).thenReturn(target); Coin mgp = mgpCalculator.calculate(Coin.ZERO); Assertions.assertEquals(Coin.valueOf(1L), mgp); } @@ -74,7 +88,7 @@ void previousValueIsZero() { @Test void previousValueIsSmallTargetIsZero() { Coin target = Coin.ZERO; - MinimumGasPriceCalculator mgpCalculator = new MinimumGasPriceCalculator(target); + when(minGasPriceProvider.getMinGasPriceAsCoin()).thenReturn(target); Coin mgp = mgpCalculator.calculate(Coin.valueOf(1L)); Assertions.assertEquals(Coin.ZERO, mgp); } @@ -83,8 +97,9 @@ void previousValueIsSmallTargetIsZero() { void cantGetMGPtoBeNegative() { Coin previous = Coin.ZERO; Coin target = Coin.valueOf(-100L); - MinimumGasPriceCalculator mgpCalculator = new MinimumGasPriceCalculator(target); + when(minGasPriceProvider.getMinGasPriceAsCoin()).thenReturn(target); previous = mgpCalculator.calculate(previous); Assertions.assertTrue(previous.compareTo(Coin.valueOf(-1)) > 0); } + } diff --git a/rskj-core/src/test/java/co/rsk/mine/TransactionModuleTest.java b/rskj-core/src/test/java/co/rsk/mine/TransactionModuleTest.java index 1d2f6641773..05be6bcf0c2 100644 --- a/rskj-core/src/test/java/co/rsk/mine/TransactionModuleTest.java +++ b/rskj-core/src/test/java/co/rsk/mine/TransactionModuleTest.java @@ -612,7 +612,7 @@ private Web3Impl internalCreateEnvironment(Blockchain blockchain, minerClock, blockFactory, blockExecutor, - new MinimumGasPriceCalculator(Coin.valueOf(miningConfig.getMinGasPriceTarget())), + new MinimumGasPriceCalculator(miningConfig.getMinGasPriceProvider()), new MinerUtils(), new BlockTxSignatureCache(new ReceivedTxSignatureCache()) ), diff --git a/rskj-core/src/test/java/co/rsk/mine/gas/DefaultMinGasPriceProviderTest.java b/rskj-core/src/test/java/co/rsk/mine/gas/DefaultMinGasPriceProviderTest.java new file mode 100644 index 00000000000..8189909d666 --- /dev/null +++ b/rskj-core/src/test/java/co/rsk/mine/gas/DefaultMinGasPriceProviderTest.java @@ -0,0 +1,31 @@ +package co.rsk.mine.gas; + +import co.rsk.core.Coin; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +class DefaultMinGasPriceProviderTest { + + + @Test + void testConstructorAndGetMinGasPrice() { + long minGasPrice = 100L; + DefaultMinGasPriceProvider provider = new DefaultMinGasPriceProvider(minGasPrice); + assertEquals(minGasPrice, provider.getMinGasPrice()); + } + + @Test + void testGetType() { + long minGasPrice = 100L; + DefaultMinGasPriceProvider provider = new DefaultMinGasPriceProvider(minGasPrice); + assertEquals(GasPriceProviderType.DEFAULT, provider.getType()); + } + + @Test + void testGetMinGasPriceAsCoin() { + long minGasPrice = 50; + DefaultMinGasPriceProvider provider = new DefaultMinGasPriceProvider(minGasPrice); + assertEquals(Coin.valueOf(minGasPrice), provider.getMinGasPriceAsCoin()); + } +} \ No newline at end of file diff --git a/rskj-core/src/test/java/co/rsk/rpc/modules/trace/TraceModuleImplTest.java b/rskj-core/src/test/java/co/rsk/rpc/modules/trace/TraceModuleImplTest.java index a5d440c97e9..3907ec7e29a 100644 --- a/rskj-core/src/test/java/co/rsk/rpc/modules/trace/TraceModuleImplTest.java +++ b/rskj-core/src/test/java/co/rsk/rpc/modules/trace/TraceModuleImplTest.java @@ -20,9 +20,9 @@ import co.rsk.config.GasLimitConfig; import co.rsk.config.MiningConfig; import co.rsk.config.RskSystemProperties; -import co.rsk.core.Coin; import co.rsk.core.DifficultyCalculator; import co.rsk.mine.*; +import co.rsk.mine.gas.DefaultMinGasPriceProvider; import co.rsk.rpc.ExecutionBlockRetriever; import co.rsk.test.World; import co.rsk.test.builders.AccountBuilder; @@ -34,7 +34,10 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.ObjectNode; -import org.ethereum.core.*; +import org.ethereum.core.Account; +import org.ethereum.core.Block; +import org.ethereum.core.BlockFactory; +import org.ethereum.core.Transaction; import org.ethereum.datasource.HashMapDB; import org.ethereum.db.ReceiptStore; import org.ethereum.db.ReceiptStoreImpl; @@ -425,8 +428,7 @@ private static ExecutionBlockRetriever createExecutionBlockRetriever(World world rskSystemProperties.coinbaseAddress(), rskSystemProperties.minerMinFeesNotifyInDollars(), rskSystemProperties.minerGasUnitInDollars(), - rskSystemProperties.minerMinGasPrice(), - rskSystemProperties.getNetworkConstants().getUncleListLimit(), + rskSystemProperties.getNetworkConstants().getUncleListLimit(), rskSystemProperties.getNetworkConstants().getUncleGenerationLimit(), new GasLimitConfig( rskSystemProperties.getNetworkConstants().getMinGasLimit(), @@ -434,7 +436,8 @@ private static ExecutionBlockRetriever createExecutionBlockRetriever(World world rskSystemProperties.getForceTargetGasLimit() ), rskSystemProperties.isMinerServerFixedClock(), - rskSystemProperties.workSubmissionRateLimitInMills() + rskSystemProperties.workSubmissionRateLimitInMills(), + new DefaultMinGasPriceProvider(rskSystemProperties.minerMinGasPrice()) ); BlockToMineBuilder builder = new BlockToMineBuilder( rskSystemProperties.getActivationConfig(), @@ -452,7 +455,7 @@ private static ExecutionBlockRetriever createExecutionBlockRetriever(World world new MinerClock(miningConfig.isFixedClock(), Clock.systemUTC()), new BlockFactory(rskSystemProperties.getActivationConfig()), world.getBlockExecutor(), - new MinimumGasPriceCalculator(Coin.valueOf(miningConfig.getMinGasPriceTarget())), + new MinimumGasPriceCalculator(miningConfig.getMinGasPriceProvider()), new MinerUtils(), world.getBlockTxSignatureCache() ); diff --git a/rskj-core/src/test/java/org/ethereum/rpc/Web3ImplSnapshotTest.java b/rskj-core/src/test/java/org/ethereum/rpc/Web3ImplSnapshotTest.java index 129731b242f..000b37ec4b5 100644 --- a/rskj-core/src/test/java/org/ethereum/rpc/Web3ImplSnapshotTest.java +++ b/rskj-core/src/test/java/org/ethereum/rpc/Web3ImplSnapshotTest.java @@ -21,7 +21,6 @@ import co.rsk.config.ConfigUtils; import co.rsk.config.MiningConfig; import co.rsk.config.TestSystemProperties; -import co.rsk.core.Coin; import co.rsk.core.DifficultyCalculator; import co.rsk.core.SnapshotManager; import co.rsk.core.bc.BlockChainStatus; @@ -234,7 +233,7 @@ private MinerServer getMinerServerForTest(SimpleEthereum ethereum, MinerClock cl clock, blockFactory, factory.getBlockExecutor(), - new MinimumGasPriceCalculator(Coin.valueOf(miningConfig.getMinGasPriceTarget())), + new MinimumGasPriceCalculator(miningConfig.getMinGasPriceProvider()), new MinerUtils(), new BlockTxSignatureCache(new ReceivedTxSignatureCache()) ), From 760908ab7cf271f5262d7eee6a23918eca668ba3 Mon Sep 17 00:00:00 2001 From: Angel Soto Date: Fri, 10 May 2024 11:48:17 +0200 Subject: [PATCH 02/17] Adding StableMinGasPrice related class structure for a future implementation --- .../src/main/java/co/rsk/RskContext.java | 11 ++- .../HttpGetStableMinGasSystemConfig.java | 39 ++++++++ .../mining/StableMinGasPriceSystemConfig.java | 50 ++++++++++ .../mine/gas/DefaultMinGasPriceProvider.java | 4 +- .../co/rsk/mine/gas/GasPriceProviderType.java | 6 -- .../gas/HttpGetStableMinGasPriceConfig.java | 92 +++++++++++++++++++ .../gas/HttpGetStableMinGasPriceProvider.java | 29 ++++++ .../co/rsk/mine/gas/MinGasPriceProvider.java | 2 +- .../rsk/mine/gas/MinGasPriceProviderType.java | 7 ++ .../mine/gas/StableMinGasPriceProvider.java | 32 +++++++ .../gas/StableMinGasPriceProviderFactory.java | 43 +++++++++ .../org/ethereum/config/SystemProperties.java | 30 +++--- rskj-core/src/main/resources/expected.conf | 6 ++ rskj-core/src/main/resources/reference.conf | 6 ++ .../gas/DefaultMinGasPriceProviderTest.java | 2 +- 15 files changed, 335 insertions(+), 24 deletions(-) create mode 100644 rskj-core/src/main/java/co/rsk/config/mining/HttpGetStableMinGasSystemConfig.java create mode 100644 rskj-core/src/main/java/co/rsk/config/mining/StableMinGasPriceSystemConfig.java delete mode 100644 rskj-core/src/main/java/co/rsk/mine/gas/GasPriceProviderType.java create mode 100644 rskj-core/src/main/java/co/rsk/mine/gas/HttpGetStableMinGasPriceConfig.java create mode 100644 rskj-core/src/main/java/co/rsk/mine/gas/HttpGetStableMinGasPriceProvider.java create mode 100644 rskj-core/src/main/java/co/rsk/mine/gas/MinGasPriceProviderType.java create mode 100644 rskj-core/src/main/java/co/rsk/mine/gas/StableMinGasPriceProvider.java create mode 100644 rskj-core/src/main/java/co/rsk/mine/gas/StableMinGasPriceProviderFactory.java diff --git a/rskj-core/src/main/java/co/rsk/RskContext.java b/rskj-core/src/main/java/co/rsk/RskContext.java index bdb8ab4a1d9..db574ff53fe 100644 --- a/rskj-core/src/main/java/co/rsk/RskContext.java +++ b/rskj-core/src/main/java/co/rsk/RskContext.java @@ -21,6 +21,7 @@ import co.rsk.cli.CliArgs; import co.rsk.cli.RskCli; import co.rsk.config.*; +import co.rsk.config.mining.StableMinGasPriceSystemConfig; import co.rsk.core.*; import co.rsk.core.bc.*; import co.rsk.crypto.Keccak256; @@ -42,6 +43,7 @@ import co.rsk.mine.*; import co.rsk.mine.gas.DefaultMinGasPriceProvider; import co.rsk.mine.gas.MinGasPriceProvider; +import co.rsk.mine.gas.StableMinGasPriceProviderFactory; import co.rsk.net.*; import co.rsk.net.discovery.KnownPeersHandler; import co.rsk.net.discovery.PeerExplorer; @@ -1633,7 +1635,7 @@ List getInitialBootNodes(KnownPeersHandler knownPeersHandler) { if (rskSystemProperties.usePeersFromLastSession()) { List peerLastSession = knownPeersHandler.readPeers(); - logger.debug("Loading peers from previous session: {}",peerLastSession); + logger.debug("Loading peers from previous session: {}", peerLastSession); initialBootNodes.addAll(peerLastSession); } return new ArrayList<>(initialBootNodes); @@ -1856,10 +1858,13 @@ private BlockToMineBuilder getBlockToMineBuilder() { } private MinGasPriceProvider getMinGasPriceProvider() { - long minGasPrice = getRskSystemProperties().minerMinGasPrice(); if (minGasPriceProvider == null) { - minGasPriceProvider = new DefaultMinGasPriceProvider(minGasPrice); + long minGasPrice = getRskSystemProperties().minerMinGasPrice(); + DefaultMinGasPriceProvider defaultMinGasPriceProvider = new DefaultMinGasPriceProvider(minGasPrice); + StableMinGasPriceSystemConfig stableGasPriceSystemConfig = getRskSystemProperties().getStableGasPriceSystemConfig(); + minGasPriceProvider = stableGasPriceSystemConfig.isEnabled() ? StableMinGasPriceProviderFactory.create(stableGasPriceSystemConfig, defaultMinGasPriceProvider) : defaultMinGasPriceProvider; } + logger.debug("MinGasPriceProvider type: {}", minGasPriceProvider.getType().name()); return minGasPriceProvider; } diff --git a/rskj-core/src/main/java/co/rsk/config/mining/HttpGetStableMinGasSystemConfig.java b/rskj-core/src/main/java/co/rsk/config/mining/HttpGetStableMinGasSystemConfig.java new file mode 100644 index 00000000000..378b06fa2d0 --- /dev/null +++ b/rskj-core/src/main/java/co/rsk/config/mining/HttpGetStableMinGasSystemConfig.java @@ -0,0 +1,39 @@ +package co.rsk.config.mining; + +import com.typesafe.config.Config; + +public class HttpGetStableMinGasSystemConfig { + public static final String HTTP_GET_STABLE_GAS_PRICE_CONFIG_PATH = "miner.httpGet"; + private static final String URL_PROPERTY = "url"; + private static final String JSON_PATH_PROPERTY = "jsonPath"; + private static final String TIMEOUT_PROPERTY = "timeout"; + private static final String API_KEY_PROPERTY = "apiKey"; + + private final String url; + private final String jsonPath; + private final int timeout; + private final String apiKey; + + public HttpGetStableMinGasSystemConfig(Config config) { + this.url = config.getString(URL_PROPERTY); + this.jsonPath = config.getString(JSON_PATH_PROPERTY); + this.timeout = config.getInt(TIMEOUT_PROPERTY); + this.apiKey = config.getString(API_KEY_PROPERTY); + } + + public String getUrl() { + return url; + } + + public String getJsonPath() { + return jsonPath; + } + + public int getTimeout() { + return timeout; + } + + public String getApiKey() { + return apiKey; + } +} diff --git a/rskj-core/src/main/java/co/rsk/config/mining/StableMinGasPriceSystemConfig.java b/rskj-core/src/main/java/co/rsk/config/mining/StableMinGasPriceSystemConfig.java new file mode 100644 index 00000000000..9200cb69653 --- /dev/null +++ b/rskj-core/src/main/java/co/rsk/config/mining/StableMinGasPriceSystemConfig.java @@ -0,0 +1,50 @@ +package co.rsk.config.mining; + +import co.rsk.mine.gas.MinGasPriceProviderType; +import com.typesafe.config.Config; + +public class StableMinGasPriceSystemConfig { + public static final String STABLE_GAS_PRICE_CONFIG_PATH_PROPERTY = "miner.stableGasPrice"; + private static final String ENABLED_PROPERTY = "enabled"; + private static final String REFRESH_RATE_PROPERTY = "refreshRate"; + private static final String MIN_STABLE_GAS_PRICE_PROPERTY = "minStableGasPrice"; + private static final String METHOD_PROPERTY = "method"; + + private final Integer refreshRate; + private final Integer minStableGasPrice; + private final boolean enabled; + private final MinGasPriceProviderType method; + private final Config config; + + public StableMinGasPriceSystemConfig(Config config) { + enabled = config.getBoolean(ENABLED_PROPERTY); + refreshRate = config.getInt(REFRESH_RATE_PROPERTY); + minStableGasPrice = config.getInt(MIN_STABLE_GAS_PRICE_PROPERTY); + method = config.getEnum(MinGasPriceProviderType.class, METHOD_PROPERTY); + this.config = config; + } + + public boolean isValid() { + return true; + } + + public int getRefreshRate() { + return refreshRate; + } + + public int getMinStableGasPrice() { + return minStableGasPrice; + } + + public boolean isEnabled() { + return enabled; + } + + public HttpGetStableMinGasSystemConfig getHttpGetConfig() { + return new HttpGetStableMinGasSystemConfig(config.getConfig(HttpGetStableMinGasSystemConfig.HTTP_GET_STABLE_GAS_PRICE_CONFIG_PATH)); + } + + public MinGasPriceProviderType getMethod() { + return method; + } +} diff --git a/rskj-core/src/main/java/co/rsk/mine/gas/DefaultMinGasPriceProvider.java b/rskj-core/src/main/java/co/rsk/mine/gas/DefaultMinGasPriceProvider.java index 492376217a6..b0b0b9fd21b 100644 --- a/rskj-core/src/main/java/co/rsk/mine/gas/DefaultMinGasPriceProvider.java +++ b/rskj-core/src/main/java/co/rsk/mine/gas/DefaultMinGasPriceProvider.java @@ -17,8 +17,8 @@ public long getMinGasPrice() { } @Override - public GasPriceProviderType getType() { - return GasPriceProviderType.DEFAULT; + public MinGasPriceProviderType getType() { + return MinGasPriceProviderType.DEFAULT; } @Override diff --git a/rskj-core/src/main/java/co/rsk/mine/gas/GasPriceProviderType.java b/rskj-core/src/main/java/co/rsk/mine/gas/GasPriceProviderType.java deleted file mode 100644 index d37b5cb4342..00000000000 --- a/rskj-core/src/main/java/co/rsk/mine/gas/GasPriceProviderType.java +++ /dev/null @@ -1,6 +0,0 @@ -package co.rsk.mine.gas; - -public enum GasPriceProviderType { - DEFAULT, - STABLE -} diff --git a/rskj-core/src/main/java/co/rsk/mine/gas/HttpGetStableMinGasPriceConfig.java b/rskj-core/src/main/java/co/rsk/mine/gas/HttpGetStableMinGasPriceConfig.java new file mode 100644 index 00000000000..47e8ab6eb69 --- /dev/null +++ b/rskj-core/src/main/java/co/rsk/mine/gas/HttpGetStableMinGasPriceConfig.java @@ -0,0 +1,92 @@ +package co.rsk.mine.gas; + +public class HttpGetStableMinGasPriceConfig { + private final String url; + private final String jsonPath; + private final int timeout; + private final String apiKey; + private final long minStableGasPrice; + private final int refreshRate; + + public HttpGetStableMinGasPriceConfig(String url, String jsonPath, int timeout, String apiKey, long minStableGasPrice, int refreshRate) { + this.url = url; + this.jsonPath = jsonPath; + this.timeout = timeout; + this.apiKey = apiKey; + this.minStableGasPrice = minStableGasPrice; + this.refreshRate = refreshRate; + } + + public String getUrl() { + return url; + } + + public String getJsonPath() { + return jsonPath; + } + + public int getTimeout() { + return timeout; + } + + public String getApiKey() { + return apiKey; + } + + public long getMinStableGasPrice() { + return minStableGasPrice; + } + + public int getRefreshRate() { + return refreshRate; + } + + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + private String url; + private String jsonPath; + private int timeout; + private String apiKey; + private long minStableGasPrice; + private int refreshRate; + + public Builder setUrl(String url) { + this.url = url; + return this; + } + + public Builder setJsonPath(String jsonPath) { + this.jsonPath = jsonPath; + return this; + } + + public Builder setTimeout(int timeout) { + this.timeout = timeout; + return this; + } + + public Builder setApiKey(String apiKey) { + this.apiKey = apiKey; + return this; + } + + public Builder setMinStableGasPrice(long minStableGasPrice) { + this.minStableGasPrice = minStableGasPrice; + return this; + } + + public Builder setRefreshRate(int refreshRate) { + this.refreshRate = refreshRate; + return this; + } + + public HttpGetStableMinGasPriceConfig build() { + return new HttpGetStableMinGasPriceConfig(url, jsonPath, timeout, apiKey, minStableGasPrice, refreshRate); + } + } + + +} diff --git a/rskj-core/src/main/java/co/rsk/mine/gas/HttpGetStableMinGasPriceProvider.java b/rskj-core/src/main/java/co/rsk/mine/gas/HttpGetStableMinGasPriceProvider.java new file mode 100644 index 00000000000..e4b22e1282d --- /dev/null +++ b/rskj-core/src/main/java/co/rsk/mine/gas/HttpGetStableMinGasPriceProvider.java @@ -0,0 +1,29 @@ +package co.rsk.mine.gas; + +public class HttpGetStableMinGasPriceProvider extends StableMinGasPriceProvider { + private final String url; + private final String jsonPath; + private final String apiKey; + private final int timeout; + private final int refreshRate; + + HttpGetStableMinGasPriceProvider(DefaultMinGasPriceProvider fallBackProvider, HttpGetStableMinGasPriceConfig config) { + super(fallBackProvider); + url = config.getUrl(); + jsonPath = config.getJsonPath(); + apiKey = config.getApiKey(); + timeout = config.getTimeout(); + refreshRate = config.getRefreshRate(); + } + + @Override + public Long getStableMinGasPrice() { + return null; + } + + @Override + public MinGasPriceProviderType getType() { + return MinGasPriceProviderType.HTTP_GET; + } +} + diff --git a/rskj-core/src/main/java/co/rsk/mine/gas/MinGasPriceProvider.java b/rskj-core/src/main/java/co/rsk/mine/gas/MinGasPriceProvider.java index ec133aa4b82..6b76c5d2a66 100644 --- a/rskj-core/src/main/java/co/rsk/mine/gas/MinGasPriceProvider.java +++ b/rskj-core/src/main/java/co/rsk/mine/gas/MinGasPriceProvider.java @@ -6,7 +6,7 @@ public interface MinGasPriceProvider { long getMinGasPrice(); - GasPriceProviderType getType(); + MinGasPriceProviderType getType(); Coin getMinGasPriceAsCoin(); } diff --git a/rskj-core/src/main/java/co/rsk/mine/gas/MinGasPriceProviderType.java b/rskj-core/src/main/java/co/rsk/mine/gas/MinGasPriceProviderType.java new file mode 100644 index 00000000000..b04bd460cb7 --- /dev/null +++ b/rskj-core/src/main/java/co/rsk/mine/gas/MinGasPriceProviderType.java @@ -0,0 +1,7 @@ +package co.rsk.mine.gas; + +public enum MinGasPriceProviderType { + DEFAULT, + HTTP_GET, + ETH_CALL +} diff --git a/rskj-core/src/main/java/co/rsk/mine/gas/StableMinGasPriceProvider.java b/rskj-core/src/main/java/co/rsk/mine/gas/StableMinGasPriceProvider.java new file mode 100644 index 00000000000..72a0c38be18 --- /dev/null +++ b/rskj-core/src/main/java/co/rsk/mine/gas/StableMinGasPriceProvider.java @@ -0,0 +1,32 @@ +package co.rsk.mine.gas; + +import co.rsk.core.Coin; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public abstract class StableMinGasPriceProvider implements MinGasPriceProvider { + private static final Logger logger = LoggerFactory.getLogger("StableMinGasPrice"); + private final DefaultMinGasPriceProvider fallBackProvider; + + + StableMinGasPriceProvider(DefaultMinGasPriceProvider fallBackProvider) { + this.fallBackProvider = fallBackProvider; + } + + public abstract Long getStableMinGasPrice(); + + @Override + public long getMinGasPrice() { + Long stableMinGasPrice = getStableMinGasPrice(); + if (stableMinGasPrice == null) { + logger.error("Could not get stable min gas price from method {}, using fallback provider: {}", this.getType().name(), fallBackProvider.getType().name()); + return fallBackProvider.getMinGasPrice(); + } + return stableMinGasPrice; + } + + @Override + public Coin getMinGasPriceAsCoin() { + return Coin.valueOf(getMinGasPrice()); + } +} diff --git a/rskj-core/src/main/java/co/rsk/mine/gas/StableMinGasPriceProviderFactory.java b/rskj-core/src/main/java/co/rsk/mine/gas/StableMinGasPriceProviderFactory.java new file mode 100644 index 00000000000..a7fc7d1a919 --- /dev/null +++ b/rskj-core/src/main/java/co/rsk/mine/gas/StableMinGasPriceProviderFactory.java @@ -0,0 +1,43 @@ +package co.rsk.mine.gas; + +import co.rsk.config.mining.HttpGetStableMinGasSystemConfig; +import co.rsk.config.mining.StableMinGasPriceSystemConfig; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +public class StableMinGasPriceProviderFactory { + + private static final Logger logger = LoggerFactory.getLogger("StableMinGasPrice"); + + private StableMinGasPriceProviderFactory() {} + + public static MinGasPriceProvider create(StableMinGasPriceSystemConfig config, DefaultMinGasPriceProvider fallBackProvider) { + MinGasPriceProviderType method = config.getMethod(); + if (method == null) { + logger.error("Could not finde valid mehtod in config, using fallback provider: {}", fallBackProvider.getType().name()); + return fallBackProvider; + } + switch (method) { + case HTTP_GET: + return createHttpGetStableGasPriceProvider(config, fallBackProvider); + case ETH_CALL: + throw new UnsupportedOperationException("ETH_CALL method is not supported yet"); + default: + logger.debug("Could not find a valid implementation for the method {}. Returning fallback provider {}", method, fallBackProvider.getType().name()); + return fallBackProvider; + } + } + + private static HttpGetStableMinGasPriceProvider createHttpGetStableGasPriceProvider(StableMinGasPriceSystemConfig config, DefaultMinGasPriceProvider fallBackProvider) { + HttpGetStableMinGasSystemConfig httpGetSystemConfig = config.getHttpGetConfig(); + HttpGetStableMinGasPriceConfig httpGetStableMinGasPriceConfig = HttpGetStableMinGasPriceConfig.builder().setUrl(httpGetSystemConfig.getUrl()) + .setJsonPath(httpGetSystemConfig.getJsonPath()) + .setTimeout(httpGetSystemConfig.getTimeout()) + .setApiKey(httpGetSystemConfig.getApiKey()) + .setMinStableGasPrice(config.getMinStableGasPrice()) + .setRefreshRate(config.getRefreshRate()) + .build(); + return new HttpGetStableMinGasPriceProvider(fallBackProvider, httpGetStableMinGasPriceConfig); + } +} diff --git a/rskj-core/src/main/java/org/ethereum/config/SystemProperties.java b/rskj-core/src/main/java/org/ethereum/config/SystemProperties.java index cf1e49c79d6..322fb49a5a6 100644 --- a/rskj-core/src/main/java/org/ethereum/config/SystemProperties.java +++ b/rskj-core/src/main/java/org/ethereum/config/SystemProperties.java @@ -23,6 +23,7 @@ import co.rsk.peg.constants.BridgeDevNetConstants; import co.rsk.peg.constants.BridgeRegTestConstants; import co.rsk.config.ConfigLoader; +import co.rsk.config.mining.StableMinGasPriceSystemConfig; import com.typesafe.config.Config; import com.typesafe.config.ConfigObject; import com.typesafe.config.ConfigRenderOptions; @@ -128,10 +129,12 @@ public abstract class SystemProperties { protected SystemProperties(ConfigLoader loader) { try { this.configFromFiles = loader.getConfig(); - logger.trace( - "Config trace: {}", - configFromFiles.root().render(ConfigRenderOptions.defaults().setComments(false).setJson(false)) - ); + if(logger.isTraceEnabled()){ + logger.trace( + "Config trace: {}", + configFromFiles.root().render(ConfigRenderOptions.defaults().setComments(false).setJson(false)) + ); + } Properties props = new Properties(); try (InputStream is = getClass().getResourceAsStream("/version.properties")) { @@ -152,11 +155,11 @@ private static String getProjectVersion(Properties props) { return "-.-.-"; } - return versionNumber.replaceAll("'", ""); + return versionNumber.replace("'", ""); } private static String getProjectVersionModifier(Properties props) { - return props.getProperty("modifier").replaceAll("\"", ""); + return props.getProperty("modifier").replace("\"", ""); } public Config getConfig() { @@ -406,7 +409,9 @@ private String getGeneratedNodePrivateKey() { file.getParentFile().mkdirs(); try (FileWriter writer = new FileWriter(file)) { props.store(writer, "Generated NodeID. To use your own nodeId please refer to 'peer.privateKey' config option."); - logger.info("New nodeID generated: {}", props.getProperty("nodeId")); + if(logger.isInfoEnabled()) { + logger.info("New nodeID generated: {}", props.getProperty("nodeId")); + } logger.info("Generated nodeID and its private key stored in {}", file); } } @@ -505,10 +510,8 @@ private InetAddress getMyPublicIpFromRemoteService() { InetAddress resolvedIp = tryParseIpOrThrow(ipFromService); logger.info("Identified public IP: {}", resolvedIp); return resolvedIp; - } catch (IOException e) { - logger.error("Can't get public IP", e); - } catch (IllegalArgumentException e) { - logger.error("Can't get public IP", e); + } catch (IOException | IllegalArgumentException exception) { + logger.error("Can't get public IP", exception); } InetAddress bindAddress = getBindAddress(); @@ -769,4 +772,9 @@ public int getRpcMaxResponseSize() { return configFromFiles.getInt(PROPERTY_RPC_MAX_RESPONSE_SIZE); } + + public StableMinGasPriceSystemConfig getStableGasPriceSystemConfig() { + Config config = configFromFiles.getConfig(StableMinGasPriceSystemConfig.STABLE_GAS_PRICE_CONFIG_PATH_PROPERTY); + return new StableMinGasPriceSystemConfig(config); + } } diff --git a/rskj-core/src/main/resources/expected.conf b/rskj-core/src/main/resources/expected.conf index fbb975405ac..085fcfadcfc 100644 --- a/rskj-core/src/main/resources/expected.conf +++ b/rskj-core/src/main/resources/expected.conf @@ -186,6 +186,12 @@ miner = { delayBetweenBlocks = delayBetweenRefreshes = } + stableGasPrice { + enabled = + minStableGasPrice = + refreshRate = + method = + } coinbase.secret = reward.address =
gasUnitInDollars = diff --git a/rskj-core/src/main/resources/reference.conf b/rskj-core/src/main/resources/reference.conf index ced28172cfe..6a59fcdb03a 100644 --- a/rskj-core/src/main/resources/reference.conf +++ b/rskj-core/src/main/resources/reference.conf @@ -199,6 +199,12 @@ miner { # The time the miner client will wait to refresh the current work from the miner server delayBetweenRefreshes = 1 second } + stableGasPrice { + enabled = false + minStableGasPrice = 0 + refreshRate = 0 + method = DEFAULT + } } database { diff --git a/rskj-core/src/test/java/co/rsk/mine/gas/DefaultMinGasPriceProviderTest.java b/rskj-core/src/test/java/co/rsk/mine/gas/DefaultMinGasPriceProviderTest.java index 8189909d666..6764f230127 100644 --- a/rskj-core/src/test/java/co/rsk/mine/gas/DefaultMinGasPriceProviderTest.java +++ b/rskj-core/src/test/java/co/rsk/mine/gas/DefaultMinGasPriceProviderTest.java @@ -19,7 +19,7 @@ void testConstructorAndGetMinGasPrice() { void testGetType() { long minGasPrice = 100L; DefaultMinGasPriceProvider provider = new DefaultMinGasPriceProvider(minGasPrice); - assertEquals(GasPriceProviderType.DEFAULT, provider.getType()); + assertEquals(MinGasPriceProviderType.DEFAULT, provider.getType()); } @Test From db7750c1b44e98602ce91639c2a225b37ce065fb Mon Sep 17 00:00:00 2001 From: Angel Soto Date: Wed, 15 May 2024 17:58:53 +0200 Subject: [PATCH 03/17] Updated structure --- .../src/main/java/co/rsk/RskContext.java | 8 ++- .../main/java/co/rsk/config/MiningConfig.java | 2 +- .../OnChainMinGasPriceSystemConfig.java | 18 +++++++ .../mining/StableMinGasPriceSystemConfig.java | 12 +++-- ....java => WebStableMinGasSystemConfig.java} | 6 +-- .../rsk/mine/MinimumGasPriceCalculator.java | 2 +- .../gas/HttpGetStableMinGasPriceProvider.java | 29 ---------- .../rsk/mine/gas/MinGasPriceProviderType.java | 7 --- .../gas/StableMinGasPriceProviderFactory.java | 43 --------------- .../FixedMinGasPriceProvider.java} | 8 +-- .../{ => provider}/MinGasPriceProvider.java | 2 +- .../provider/MinGasPriceProviderFactory.java | 44 +++++++++++++++ .../gas/provider/MinGasPriceProviderType.java | 7 +++ .../StableMinGasPriceProvider.java | 7 ++- .../StableMinGasPriceProviderFactory.java | 15 ++++++ .../onchain/OnChainMinGasPriceProvider.java | 23 ++++++++ .../OnChainMinGasPriceProviderFactory.java | 14 +++++ .../provider/web/WebMinGasPriceProvider.java | 53 +++++++++++++++++++ .../web/WebStableMinGasPriceConfig.java} | 10 ++-- .../WebStableMinGasPriceProviderFactory.java | 25 +++++++++ .../org/ethereum/config/SystemProperties.java | 2 +- .../rsk/blockchain/utils/BlockGenerator.java | 4 +- .../test/java/co/rsk/config/ConfigUtils.java | 4 +- .../java/co/rsk/mine/MinerServerTest.java | 4 +- .../mine/MinimumGasPriceCalculatorTest.java | 2 +- ...java => FixedMinGasPriceProviderTest.java} | 12 +++-- .../modules/trace/TraceModuleImplTest.java | 4 +- 27 files changed, 246 insertions(+), 121 deletions(-) create mode 100644 rskj-core/src/main/java/co/rsk/config/mining/OnChainMinGasPriceSystemConfig.java rename rskj-core/src/main/java/co/rsk/config/mining/{HttpGetStableMinGasSystemConfig.java => WebStableMinGasSystemConfig.java} (82%) delete mode 100644 rskj-core/src/main/java/co/rsk/mine/gas/HttpGetStableMinGasPriceProvider.java delete mode 100644 rskj-core/src/main/java/co/rsk/mine/gas/MinGasPriceProviderType.java delete mode 100644 rskj-core/src/main/java/co/rsk/mine/gas/StableMinGasPriceProviderFactory.java rename rskj-core/src/main/java/co/rsk/mine/gas/{DefaultMinGasPriceProvider.java => provider/FixedMinGasPriceProvider.java} (64%) rename rskj-core/src/main/java/co/rsk/mine/gas/{ => provider}/MinGasPriceProvider.java (83%) create mode 100644 rskj-core/src/main/java/co/rsk/mine/gas/provider/MinGasPriceProviderFactory.java create mode 100644 rskj-core/src/main/java/co/rsk/mine/gas/provider/MinGasPriceProviderType.java rename rskj-core/src/main/java/co/rsk/mine/gas/{ => provider}/StableMinGasPriceProvider.java (83%) create mode 100644 rskj-core/src/main/java/co/rsk/mine/gas/provider/StableMinGasPriceProviderFactory.java create mode 100644 rskj-core/src/main/java/co/rsk/mine/gas/provider/onchain/OnChainMinGasPriceProvider.java create mode 100644 rskj-core/src/main/java/co/rsk/mine/gas/provider/onchain/OnChainMinGasPriceProviderFactory.java create mode 100644 rskj-core/src/main/java/co/rsk/mine/gas/provider/web/WebMinGasPriceProvider.java rename rskj-core/src/main/java/co/rsk/mine/gas/{HttpGetStableMinGasPriceConfig.java => provider/web/WebStableMinGasPriceConfig.java} (83%) create mode 100644 rskj-core/src/main/java/co/rsk/mine/gas/provider/web/WebStableMinGasPriceProviderFactory.java rename rskj-core/src/test/java/co/rsk/mine/gas/{DefaultMinGasPriceProviderTest.java => FixedMinGasPriceProviderTest.java} (52%) diff --git a/rskj-core/src/main/java/co/rsk/RskContext.java b/rskj-core/src/main/java/co/rsk/RskContext.java index db574ff53fe..3c4d27e8313 100644 --- a/rskj-core/src/main/java/co/rsk/RskContext.java +++ b/rskj-core/src/main/java/co/rsk/RskContext.java @@ -41,9 +41,8 @@ import co.rsk.metrics.HashRateCalculatorMining; import co.rsk.metrics.HashRateCalculatorNonMining; import co.rsk.mine.*; -import co.rsk.mine.gas.DefaultMinGasPriceProvider; -import co.rsk.mine.gas.MinGasPriceProvider; -import co.rsk.mine.gas.StableMinGasPriceProviderFactory; +import co.rsk.mine.gas.provider.MinGasPriceProvider; +import co.rsk.mine.gas.provider.MinGasPriceProviderFactory; import co.rsk.net.*; import co.rsk.net.discovery.KnownPeersHandler; import co.rsk.net.discovery.PeerExplorer; @@ -1860,9 +1859,8 @@ private BlockToMineBuilder getBlockToMineBuilder() { private MinGasPriceProvider getMinGasPriceProvider() { if (minGasPriceProvider == null) { long minGasPrice = getRskSystemProperties().minerMinGasPrice(); - DefaultMinGasPriceProvider defaultMinGasPriceProvider = new DefaultMinGasPriceProvider(minGasPrice); StableMinGasPriceSystemConfig stableGasPriceSystemConfig = getRskSystemProperties().getStableGasPriceSystemConfig(); - minGasPriceProvider = stableGasPriceSystemConfig.isEnabled() ? StableMinGasPriceProviderFactory.create(stableGasPriceSystemConfig, defaultMinGasPriceProvider) : defaultMinGasPriceProvider; + minGasPriceProvider = MinGasPriceProviderFactory.create(minGasPrice, stableGasPriceSystemConfig); } logger.debug("MinGasPriceProvider type: {}", minGasPriceProvider.getType().name()); return minGasPriceProvider; diff --git a/rskj-core/src/main/java/co/rsk/config/MiningConfig.java b/rskj-core/src/main/java/co/rsk/config/MiningConfig.java index bb94279d481..5746b203349 100644 --- a/rskj-core/src/main/java/co/rsk/config/MiningConfig.java +++ b/rskj-core/src/main/java/co/rsk/config/MiningConfig.java @@ -19,7 +19,7 @@ package co.rsk.config; import co.rsk.core.RskAddress; -import co.rsk.mine.gas.MinGasPriceProvider; +import co.rsk.mine.gas.provider.MinGasPriceProvider; /** * Wraps configuration for Mining, which is usually derived from configuration files. 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 new file mode 100644 index 00000000000..30788f74277 --- /dev/null +++ b/rskj-core/src/main/java/co/rsk/config/mining/OnChainMinGasPriceSystemConfig.java @@ -0,0 +1,18 @@ +package co.rsk.config.mining; + +import com.typesafe.config.Config; + +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 final String address; + + public OnChainMinGasPriceSystemConfig(Config config) { + this.address = config.getString(ADDRESS_PROPERTY); + } + + public String getAddress() { + return address; + } +} diff --git a/rskj-core/src/main/java/co/rsk/config/mining/StableMinGasPriceSystemConfig.java b/rskj-core/src/main/java/co/rsk/config/mining/StableMinGasPriceSystemConfig.java index 9200cb69653..3944d0ce7ba 100644 --- a/rskj-core/src/main/java/co/rsk/config/mining/StableMinGasPriceSystemConfig.java +++ b/rskj-core/src/main/java/co/rsk/config/mining/StableMinGasPriceSystemConfig.java @@ -1,6 +1,6 @@ package co.rsk.config.mining; -import co.rsk.mine.gas.MinGasPriceProviderType; +import co.rsk.mine.gas.provider.MinGasPriceProviderType; import com.typesafe.config.Config; public class StableMinGasPriceSystemConfig { @@ -40,10 +40,16 @@ public boolean isEnabled() { return enabled; } - public HttpGetStableMinGasSystemConfig getHttpGetConfig() { - return new HttpGetStableMinGasSystemConfig(config.getConfig(HttpGetStableMinGasSystemConfig.HTTP_GET_STABLE_GAS_PRICE_CONFIG_PATH)); + public WebStableMinGasSystemConfig getHttpGetConfig() { + return new WebStableMinGasSystemConfig(config.getConfig(WebStableMinGasSystemConfig.WEB_STABLE_GAS_PRICE_CONFIG_PATH)); } + public OnChainMinGasPriceSystemConfig getOnChainConfig() { + return new OnChainMinGasPriceSystemConfig(config.getConfig(OnChainMinGasPriceSystemConfig.ONCHAIN_STABLE_GAS_PRICE_CONFIG_PATH)); + } + + + public MinGasPriceProviderType getMethod() { return method; } diff --git a/rskj-core/src/main/java/co/rsk/config/mining/HttpGetStableMinGasSystemConfig.java b/rskj-core/src/main/java/co/rsk/config/mining/WebStableMinGasSystemConfig.java similarity index 82% rename from rskj-core/src/main/java/co/rsk/config/mining/HttpGetStableMinGasSystemConfig.java rename to rskj-core/src/main/java/co/rsk/config/mining/WebStableMinGasSystemConfig.java index 378b06fa2d0..8c3f557a14d 100644 --- a/rskj-core/src/main/java/co/rsk/config/mining/HttpGetStableMinGasSystemConfig.java +++ b/rskj-core/src/main/java/co/rsk/config/mining/WebStableMinGasSystemConfig.java @@ -2,8 +2,8 @@ import com.typesafe.config.Config; -public class HttpGetStableMinGasSystemConfig { - public static final String HTTP_GET_STABLE_GAS_PRICE_CONFIG_PATH = "miner.httpGet"; +public class WebStableMinGasSystemConfig { + public static final String WEB_STABLE_GAS_PRICE_CONFIG_PATH = "web"; private static final String URL_PROPERTY = "url"; private static final String JSON_PATH_PROPERTY = "jsonPath"; private static final String TIMEOUT_PROPERTY = "timeout"; @@ -14,7 +14,7 @@ public class HttpGetStableMinGasSystemConfig { private final int timeout; private final String apiKey; - public HttpGetStableMinGasSystemConfig(Config config) { + public WebStableMinGasSystemConfig(Config config) { this.url = config.getString(URL_PROPERTY); this.jsonPath = config.getString(JSON_PATH_PROPERTY); this.timeout = config.getInt(TIMEOUT_PROPERTY); diff --git a/rskj-core/src/main/java/co/rsk/mine/MinimumGasPriceCalculator.java b/rskj-core/src/main/java/co/rsk/mine/MinimumGasPriceCalculator.java index 636fb3425f3..38c16a6c3e8 100644 --- a/rskj-core/src/main/java/co/rsk/mine/MinimumGasPriceCalculator.java +++ b/rskj-core/src/main/java/co/rsk/mine/MinimumGasPriceCalculator.java @@ -19,7 +19,7 @@ package co.rsk.mine; import co.rsk.core.Coin; -import co.rsk.mine.gas.MinGasPriceProvider; +import co.rsk.mine.gas.provider.MinGasPriceProvider; /** * This is the implementation of RSKIP-09 diff --git a/rskj-core/src/main/java/co/rsk/mine/gas/HttpGetStableMinGasPriceProvider.java b/rskj-core/src/main/java/co/rsk/mine/gas/HttpGetStableMinGasPriceProvider.java deleted file mode 100644 index e4b22e1282d..00000000000 --- a/rskj-core/src/main/java/co/rsk/mine/gas/HttpGetStableMinGasPriceProvider.java +++ /dev/null @@ -1,29 +0,0 @@ -package co.rsk.mine.gas; - -public class HttpGetStableMinGasPriceProvider extends StableMinGasPriceProvider { - private final String url; - private final String jsonPath; - private final String apiKey; - private final int timeout; - private final int refreshRate; - - HttpGetStableMinGasPriceProvider(DefaultMinGasPriceProvider fallBackProvider, HttpGetStableMinGasPriceConfig config) { - super(fallBackProvider); - url = config.getUrl(); - jsonPath = config.getJsonPath(); - apiKey = config.getApiKey(); - timeout = config.getTimeout(); - refreshRate = config.getRefreshRate(); - } - - @Override - public Long getStableMinGasPrice() { - return null; - } - - @Override - public MinGasPriceProviderType getType() { - return MinGasPriceProviderType.HTTP_GET; - } -} - diff --git a/rskj-core/src/main/java/co/rsk/mine/gas/MinGasPriceProviderType.java b/rskj-core/src/main/java/co/rsk/mine/gas/MinGasPriceProviderType.java deleted file mode 100644 index b04bd460cb7..00000000000 --- a/rskj-core/src/main/java/co/rsk/mine/gas/MinGasPriceProviderType.java +++ /dev/null @@ -1,7 +0,0 @@ -package co.rsk.mine.gas; - -public enum MinGasPriceProviderType { - DEFAULT, - HTTP_GET, - ETH_CALL -} diff --git a/rskj-core/src/main/java/co/rsk/mine/gas/StableMinGasPriceProviderFactory.java b/rskj-core/src/main/java/co/rsk/mine/gas/StableMinGasPriceProviderFactory.java deleted file mode 100644 index a7fc7d1a919..00000000000 --- a/rskj-core/src/main/java/co/rsk/mine/gas/StableMinGasPriceProviderFactory.java +++ /dev/null @@ -1,43 +0,0 @@ -package co.rsk.mine.gas; - -import co.rsk.config.mining.HttpGetStableMinGasSystemConfig; -import co.rsk.config.mining.StableMinGasPriceSystemConfig; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - - -public class StableMinGasPriceProviderFactory { - - private static final Logger logger = LoggerFactory.getLogger("StableMinGasPrice"); - - private StableMinGasPriceProviderFactory() {} - - public static MinGasPriceProvider create(StableMinGasPriceSystemConfig config, DefaultMinGasPriceProvider fallBackProvider) { - MinGasPriceProviderType method = config.getMethod(); - if (method == null) { - logger.error("Could not finde valid mehtod in config, using fallback provider: {}", fallBackProvider.getType().name()); - return fallBackProvider; - } - switch (method) { - case HTTP_GET: - return createHttpGetStableGasPriceProvider(config, fallBackProvider); - case ETH_CALL: - throw new UnsupportedOperationException("ETH_CALL method is not supported yet"); - default: - logger.debug("Could not find a valid implementation for the method {}. Returning fallback provider {}", method, fallBackProvider.getType().name()); - return fallBackProvider; - } - } - - private static HttpGetStableMinGasPriceProvider createHttpGetStableGasPriceProvider(StableMinGasPriceSystemConfig config, DefaultMinGasPriceProvider fallBackProvider) { - HttpGetStableMinGasSystemConfig httpGetSystemConfig = config.getHttpGetConfig(); - HttpGetStableMinGasPriceConfig httpGetStableMinGasPriceConfig = HttpGetStableMinGasPriceConfig.builder().setUrl(httpGetSystemConfig.getUrl()) - .setJsonPath(httpGetSystemConfig.getJsonPath()) - .setTimeout(httpGetSystemConfig.getTimeout()) - .setApiKey(httpGetSystemConfig.getApiKey()) - .setMinStableGasPrice(config.getMinStableGasPrice()) - .setRefreshRate(config.getRefreshRate()) - .build(); - return new HttpGetStableMinGasPriceProvider(fallBackProvider, httpGetStableMinGasPriceConfig); - } -} diff --git a/rskj-core/src/main/java/co/rsk/mine/gas/DefaultMinGasPriceProvider.java b/rskj-core/src/main/java/co/rsk/mine/gas/provider/FixedMinGasPriceProvider.java similarity index 64% rename from rskj-core/src/main/java/co/rsk/mine/gas/DefaultMinGasPriceProvider.java rename to rskj-core/src/main/java/co/rsk/mine/gas/provider/FixedMinGasPriceProvider.java index b0b0b9fd21b..847887a4a3e 100644 --- a/rskj-core/src/main/java/co/rsk/mine/gas/DefaultMinGasPriceProvider.java +++ b/rskj-core/src/main/java/co/rsk/mine/gas/provider/FixedMinGasPriceProvider.java @@ -1,13 +1,13 @@ -package co.rsk.mine.gas; +package co.rsk.mine.gas.provider; import co.rsk.core.Coin; -public class DefaultMinGasPriceProvider implements MinGasPriceProvider { +public class FixedMinGasPriceProvider implements MinGasPriceProvider { private final long minGasPrice; - public DefaultMinGasPriceProvider(long minGasPrice) { + public FixedMinGasPriceProvider(long minGasPrice) { this.minGasPrice = minGasPrice; } @@ -18,7 +18,7 @@ public long getMinGasPrice() { @Override public MinGasPriceProviderType getType() { - return MinGasPriceProviderType.DEFAULT; + return MinGasPriceProviderType.FIXED; } @Override diff --git a/rskj-core/src/main/java/co/rsk/mine/gas/MinGasPriceProvider.java b/rskj-core/src/main/java/co/rsk/mine/gas/provider/MinGasPriceProvider.java similarity index 83% rename from rskj-core/src/main/java/co/rsk/mine/gas/MinGasPriceProvider.java rename to rskj-core/src/main/java/co/rsk/mine/gas/provider/MinGasPriceProvider.java index 6b76c5d2a66..f5f0369a7c7 100644 --- a/rskj-core/src/main/java/co/rsk/mine/gas/MinGasPriceProvider.java +++ b/rskj-core/src/main/java/co/rsk/mine/gas/provider/MinGasPriceProvider.java @@ -1,4 +1,4 @@ -package co.rsk.mine.gas; +package co.rsk.mine.gas.provider; import co.rsk.core.Coin; 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 new file mode 100644 index 00000000000..2db4047e4c7 --- /dev/null +++ b/rskj-core/src/main/java/co/rsk/mine/gas/provider/MinGasPriceProviderFactory.java @@ -0,0 +1,44 @@ +package co.rsk.mine.gas.provider; + +import co.rsk.config.mining.StableMinGasPriceSystemConfig; +import co.rsk.mine.gas.provider.onchain.OnChainMinGasPriceProviderFactory; +import co.rsk.mine.gas.provider.web.WebStableMinGasPriceProviderFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +public class MinGasPriceProviderFactory { + + private static final Logger logger = LoggerFactory.getLogger("StableMinGasPrice"); + + private MinGasPriceProviderFactory() { + } + + public static MinGasPriceProvider create(long fixedMinGasPrice, StableMinGasPriceSystemConfig stableMinGasPriceSystemConfig) { + FixedMinGasPriceProvider fixedMinGasPriceProvider = new FixedMinGasPriceProvider(fixedMinGasPrice); + if (stableMinGasPriceSystemConfig == null) { + logger.warn("Could not find stable min gas price system config, using {} provider", fixedMinGasPriceProvider.getType().name()); + return fixedMinGasPriceProvider; + } + if (!stableMinGasPriceSystemConfig.isEnabled()) { + return fixedMinGasPriceProvider; + } + MinGasPriceProviderType method = stableMinGasPriceSystemConfig.getMethod(); + if (method == null) { + logger.error("Could not find valid method in config, using fallback provider: {}", fixedMinGasPriceProvider.getType().name()); + return fixedMinGasPriceProvider; + } + + + switch (method) { + case WEB: + return WebStableMinGasPriceProviderFactory.create(stableMinGasPriceSystemConfig, fixedMinGasPriceProvider); + case ON_CHAIN: + return OnChainMinGasPriceProviderFactory.create(stableMinGasPriceSystemConfig, fixedMinGasPriceProvider); + 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/MinGasPriceProviderType.java b/rskj-core/src/main/java/co/rsk/mine/gas/provider/MinGasPriceProviderType.java new file mode 100644 index 00000000000..4de2f99777c --- /dev/null +++ b/rskj-core/src/main/java/co/rsk/mine/gas/provider/MinGasPriceProviderType.java @@ -0,0 +1,7 @@ +package co.rsk.mine.gas.provider; + +public enum MinGasPriceProviderType { + FIXED, + WEB, + ON_CHAIN +} diff --git a/rskj-core/src/main/java/co/rsk/mine/gas/StableMinGasPriceProvider.java b/rskj-core/src/main/java/co/rsk/mine/gas/provider/StableMinGasPriceProvider.java similarity index 83% rename from rskj-core/src/main/java/co/rsk/mine/gas/StableMinGasPriceProvider.java rename to rskj-core/src/main/java/co/rsk/mine/gas/provider/StableMinGasPriceProvider.java index 72a0c38be18..5b0f1883c88 100644 --- a/rskj-core/src/main/java/co/rsk/mine/gas/StableMinGasPriceProvider.java +++ b/rskj-core/src/main/java/co/rsk/mine/gas/provider/StableMinGasPriceProvider.java @@ -1,4 +1,4 @@ -package co.rsk.mine.gas; +package co.rsk.mine.gas.provider; import co.rsk.core.Coin; import org.slf4j.Logger; @@ -6,10 +6,9 @@ public abstract class StableMinGasPriceProvider implements MinGasPriceProvider { private static final Logger logger = LoggerFactory.getLogger("StableMinGasPrice"); - private final DefaultMinGasPriceProvider fallBackProvider; + private final MinGasPriceProvider fallBackProvider; - - StableMinGasPriceProvider(DefaultMinGasPriceProvider fallBackProvider) { + protected StableMinGasPriceProvider(MinGasPriceProvider fallBackProvider) { this.fallBackProvider = fallBackProvider; } diff --git a/rskj-core/src/main/java/co/rsk/mine/gas/provider/StableMinGasPriceProviderFactory.java b/rskj-core/src/main/java/co/rsk/mine/gas/provider/StableMinGasPriceProviderFactory.java new file mode 100644 index 00000000000..24ead01e416 --- /dev/null +++ b/rskj-core/src/main/java/co/rsk/mine/gas/provider/StableMinGasPriceProviderFactory.java @@ -0,0 +1,15 @@ +package co.rsk.mine.gas.provider; + +import co.rsk.config.mining.StableMinGasPriceSystemConfig; + +public abstract class StableMinGasPriceProviderFactory { + private final StableMinGasPriceSystemConfig config; + private final MinGasPriceProvider fallbackProvider; + + public StableMinGasPriceProviderFactory(StableMinGasPriceSystemConfig config, MinGasPriceProvider fallbackProvider) { + this.config = config; + this.fallbackProvider = fallbackProvider; + } + + protected abstract StableMinGasPriceProvider create(); +} 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 new file mode 100644 index 00000000000..ba35804c848 --- /dev/null +++ b/rskj-core/src/main/java/co/rsk/mine/gas/provider/onchain/OnChainMinGasPriceProvider.java @@ -0,0 +1,23 @@ +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.mine.gas.provider.StableMinGasPriceProvider; + +public class OnChainMinGasPriceProvider extends StableMinGasPriceProvider { + + OnChainMinGasPriceProvider(MinGasPriceProvider fallBackProvider, OnChainMinGasPriceSystemConfig config) { + super(fallBackProvider); + } + + @Override + public MinGasPriceProviderType getType() { + return MinGasPriceProviderType.ON_CHAIN; + } + + @Override + public Long getStableMinGasPrice() { + return null; + } +} 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 new file mode 100644 index 00000000000..ee022684e2a --- /dev/null +++ b/rskj-core/src/main/java/co/rsk/mine/gas/provider/onchain/OnChainMinGasPriceProviderFactory.java @@ -0,0 +1,14 @@ +package co.rsk.mine.gas.provider.onchain; + +import co.rsk.config.mining.StableMinGasPriceSystemConfig; +import co.rsk.mine.gas.provider.MinGasPriceProvider; + +public class OnChainMinGasPriceProviderFactory { + + private OnChainMinGasPriceProviderFactory() { + } + + public static OnChainMinGasPriceProvider create(StableMinGasPriceSystemConfig config, MinGasPriceProvider fallbackProvider) { + return new OnChainMinGasPriceProvider(fallbackProvider, config.getOnChainConfig()); + } +} 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 new file mode 100644 index 00000000000..532f1d774ce --- /dev/null +++ b/rskj-core/src/main/java/co/rsk/mine/gas/provider/web/WebMinGasPriceProvider.java @@ -0,0 +1,53 @@ +package co.rsk.mine.gas.provider.web; + +import co.rsk.mine.gas.provider.MinGasPriceProvider; +import co.rsk.mine.gas.provider.MinGasPriceProviderType; +import co.rsk.mine.gas.provider.StableMinGasPriceProvider; + +public class WebMinGasPriceProvider extends StableMinGasPriceProvider { + private final String url; + private final String jsonPath; + private final String apiKey; + private final int timeout; + private final int refreshRate; + + WebMinGasPriceProvider(MinGasPriceProvider fallBackProvider, WebStableMinGasPriceConfig config) { + super(fallBackProvider); + url = config.getUrl(); + jsonPath = config.getJsonPath(); + apiKey = config.getApiKey(); + timeout = config.getTimeout(); + refreshRate = config.getRefreshRate(); + } + + @Override + public Long getStableMinGasPrice() { + return null; + } + + @Override + public MinGasPriceProviderType getType() { + return MinGasPriceProviderType.WEB; + } + + public String getUrl() { + return url; + } + + public String getJsonPath() { + return jsonPath; + } + + public String getApiKey() { + return apiKey; + } + + public int getTimeout() { + return timeout; + } + + public int getRefreshRate() { + return refreshRate; + } +} + diff --git a/rskj-core/src/main/java/co/rsk/mine/gas/HttpGetStableMinGasPriceConfig.java b/rskj-core/src/main/java/co/rsk/mine/gas/provider/web/WebStableMinGasPriceConfig.java similarity index 83% rename from rskj-core/src/main/java/co/rsk/mine/gas/HttpGetStableMinGasPriceConfig.java rename to rskj-core/src/main/java/co/rsk/mine/gas/provider/web/WebStableMinGasPriceConfig.java index 47e8ab6eb69..9d232ecd88e 100644 --- a/rskj-core/src/main/java/co/rsk/mine/gas/HttpGetStableMinGasPriceConfig.java +++ b/rskj-core/src/main/java/co/rsk/mine/gas/provider/web/WebStableMinGasPriceConfig.java @@ -1,6 +1,6 @@ -package co.rsk.mine.gas; +package co.rsk.mine.gas.provider.web; -public class HttpGetStableMinGasPriceConfig { +public class WebStableMinGasPriceConfig { private final String url; private final String jsonPath; private final int timeout; @@ -8,7 +8,7 @@ public class HttpGetStableMinGasPriceConfig { private final long minStableGasPrice; private final int refreshRate; - public HttpGetStableMinGasPriceConfig(String url, String jsonPath, int timeout, String apiKey, long minStableGasPrice, int refreshRate) { + public WebStableMinGasPriceConfig(String url, String jsonPath, int timeout, String apiKey, long minStableGasPrice, int refreshRate) { this.url = url; this.jsonPath = jsonPath; this.timeout = timeout; @@ -83,8 +83,8 @@ public Builder setRefreshRate(int refreshRate) { return this; } - public HttpGetStableMinGasPriceConfig build() { - return new HttpGetStableMinGasPriceConfig(url, jsonPath, timeout, apiKey, minStableGasPrice, refreshRate); + public WebStableMinGasPriceConfig build() { + return new WebStableMinGasPriceConfig(url, jsonPath, timeout, apiKey, minStableGasPrice, refreshRate); } } 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 new file mode 100644 index 00000000000..fa7eeb61f5d --- /dev/null +++ b/rskj-core/src/main/java/co/rsk/mine/gas/provider/web/WebStableMinGasPriceProviderFactory.java @@ -0,0 +1,25 @@ +package co.rsk.mine.gas.provider.web; + +import co.rsk.config.mining.WebStableMinGasSystemConfig; +import co.rsk.config.mining.StableMinGasPriceSystemConfig; +import co.rsk.mine.gas.provider.MinGasPriceProvider; +import co.rsk.mine.gas.provider.StableMinGasPriceProvider; + +public class WebStableMinGasPriceProviderFactory { + + private WebStableMinGasPriceProviderFactory() { + } + + public static StableMinGasPriceProvider create(StableMinGasPriceSystemConfig config, MinGasPriceProvider fallbackProvider) { + WebStableMinGasSystemConfig httpGetSystemConfig = config.getHttpGetConfig(); + WebStableMinGasPriceConfig httpGetStableMinGasPriceConfig = WebStableMinGasPriceConfig.builder().setUrl(httpGetSystemConfig.getUrl()) + .setJsonPath(httpGetSystemConfig.getJsonPath()) + .setTimeout(httpGetSystemConfig.getTimeout()) + .setApiKey(httpGetSystemConfig.getApiKey()) + .setMinStableGasPrice(config.getMinStableGasPrice()) + .setRefreshRate(config.getRefreshRate()) + .build(); + return new WebMinGasPriceProvider(fallbackProvider, httpGetStableMinGasPriceConfig); + } +} + diff --git a/rskj-core/src/main/java/org/ethereum/config/SystemProperties.java b/rskj-core/src/main/java/org/ethereum/config/SystemProperties.java index 322fb49a5a6..0edd706e9ec 100644 --- a/rskj-core/src/main/java/org/ethereum/config/SystemProperties.java +++ b/rskj-core/src/main/java/org/ethereum/config/SystemProperties.java @@ -411,8 +411,8 @@ private String getGeneratedNodePrivateKey() { props.store(writer, "Generated NodeID. To use your own nodeId please refer to 'peer.privateKey' config option."); if(logger.isInfoEnabled()) { logger.info("New nodeID generated: {}", props.getProperty("nodeId")); + logger.info("Generated nodeID and its private key stored in {}", file); } - logger.info("Generated nodeID and its private key stored in {}", file); } } return props.getProperty("nodeIdPrivateKey"); diff --git a/rskj-core/src/test/java/co/rsk/blockchain/utils/BlockGenerator.java b/rskj-core/src/test/java/co/rsk/blockchain/utils/BlockGenerator.java index bfc90ef0fb2..038ee120217 100644 --- a/rskj-core/src/test/java/co/rsk/blockchain/utils/BlockGenerator.java +++ b/rskj-core/src/test/java/co/rsk/blockchain/utils/BlockGenerator.java @@ -26,7 +26,7 @@ import co.rsk.core.bc.BlockHashesHelper; import co.rsk.crypto.Keccak256; import co.rsk.mine.MinimumGasPriceCalculator; -import co.rsk.mine.gas.DefaultMinGasPriceProvider; +import co.rsk.mine.gas.provider.FixedMinGasPriceProvider; import co.rsk.peg.PegTestUtils; import co.rsk.peg.simples.SimpleRskTransaction; import org.bouncycastle.pqc.math.linearalgebra.ByteUtils; @@ -314,7 +314,7 @@ public Block createBlock(long number, int ntxs, Long gasLimit){ } Coin previousMGP = parent.getMinimumGasPrice() != null ? parent.getMinimumGasPrice() : Coin.valueOf(10L); - Coin minimumGasPrice = new MinimumGasPriceCalculator(new DefaultMinGasPriceProvider(100L)).calculate(previousMGP); + Coin minimumGasPrice = new MinimumGasPriceCalculator(new FixedMinGasPriceProvider(100L)).calculate(previousMGP); boolean isRskip126Enabled = activationConfig.isActive(ConsensusRule.RSKIP126, 0); diff --git a/rskj-core/src/test/java/co/rsk/config/ConfigUtils.java b/rskj-core/src/test/java/co/rsk/config/ConfigUtils.java index 203e0ea49a2..3ca7ef199e4 100644 --- a/rskj-core/src/test/java/co/rsk/config/ConfigUtils.java +++ b/rskj-core/src/test/java/co/rsk/config/ConfigUtils.java @@ -18,7 +18,7 @@ package co.rsk.config; import co.rsk.core.RskAddress; -import co.rsk.mine.gas.DefaultMinGasPriceProvider; +import co.rsk.mine.gas.provider.FixedMinGasPriceProvider; public class ConfigUtils { public static MiningConfig getDefaultMiningConfig() { @@ -32,7 +32,7 @@ public static MiningConfig getDefaultMiningConfig() { new GasLimitConfig(3000000, 500000, true), true, 0L, - new DefaultMinGasPriceProvider(0) + new FixedMinGasPriceProvider(0) ); } } diff --git a/rskj-core/src/test/java/co/rsk/mine/MinerServerTest.java b/rskj-core/src/test/java/co/rsk/mine/MinerServerTest.java index fc6a1719b55..8eac7ab4bec 100644 --- a/rskj-core/src/test/java/co/rsk/mine/MinerServerTest.java +++ b/rskj-core/src/test/java/co/rsk/mine/MinerServerTest.java @@ -29,7 +29,7 @@ import co.rsk.core.bc.*; import co.rsk.crypto.Keccak256; import co.rsk.db.RepositoryLocator; -import co.rsk.mine.gas.DefaultMinGasPriceProvider; +import co.rsk.mine.gas.provider.FixedMinGasPriceProvider; import co.rsk.net.BlockProcessor; import co.rsk.net.NodeBlockProcessor; import co.rsk.net.handler.quota.TxQuotaChecker; @@ -131,7 +131,7 @@ protected RepositoryLocator buildRepositoryLocator() { blockFactory = rskTestContext.getBlockFactory(); blockExecutor = rskTestContext.getBlockExecutor(); - minimumGasPriceCalculator = new MinimumGasPriceCalculator(new DefaultMinGasPriceProvider(0L)); + minimumGasPriceCalculator = new MinimumGasPriceCalculator(new FixedMinGasPriceProvider(0L)); minerUtils = new MinerUtils(); } diff --git a/rskj-core/src/test/java/co/rsk/mine/MinimumGasPriceCalculatorTest.java b/rskj-core/src/test/java/co/rsk/mine/MinimumGasPriceCalculatorTest.java index a14dc01938e..054656b6743 100644 --- a/rskj-core/src/test/java/co/rsk/mine/MinimumGasPriceCalculatorTest.java +++ b/rskj-core/src/test/java/co/rsk/mine/MinimumGasPriceCalculatorTest.java @@ -19,7 +19,7 @@ package co.rsk.mine; import co.rsk.core.Coin; -import co.rsk.mine.gas.MinGasPriceProvider; +import co.rsk.mine.gas.provider.MinGasPriceProvider; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; diff --git a/rskj-core/src/test/java/co/rsk/mine/gas/DefaultMinGasPriceProviderTest.java b/rskj-core/src/test/java/co/rsk/mine/gas/FixedMinGasPriceProviderTest.java similarity index 52% rename from rskj-core/src/test/java/co/rsk/mine/gas/DefaultMinGasPriceProviderTest.java rename to rskj-core/src/test/java/co/rsk/mine/gas/FixedMinGasPriceProviderTest.java index 6764f230127..e6f547de530 100644 --- a/rskj-core/src/test/java/co/rsk/mine/gas/DefaultMinGasPriceProviderTest.java +++ b/rskj-core/src/test/java/co/rsk/mine/gas/FixedMinGasPriceProviderTest.java @@ -1,31 +1,33 @@ package co.rsk.mine.gas; import co.rsk.core.Coin; +import co.rsk.mine.gas.provider.FixedMinGasPriceProvider; +import co.rsk.mine.gas.provider.MinGasPriceProviderType; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.*; -class DefaultMinGasPriceProviderTest { +class FixedMinGasPriceProviderTest { @Test void testConstructorAndGetMinGasPrice() { long minGasPrice = 100L; - DefaultMinGasPriceProvider provider = new DefaultMinGasPriceProvider(minGasPrice); + FixedMinGasPriceProvider provider = new FixedMinGasPriceProvider(minGasPrice); assertEquals(minGasPrice, provider.getMinGasPrice()); } @Test void testGetType() { long minGasPrice = 100L; - DefaultMinGasPriceProvider provider = new DefaultMinGasPriceProvider(minGasPrice); - assertEquals(MinGasPriceProviderType.DEFAULT, provider.getType()); + FixedMinGasPriceProvider provider = new FixedMinGasPriceProvider(minGasPrice); + assertEquals(MinGasPriceProviderType.FIXED, provider.getType()); } @Test void testGetMinGasPriceAsCoin() { long minGasPrice = 50; - DefaultMinGasPriceProvider provider = new DefaultMinGasPriceProvider(minGasPrice); + FixedMinGasPriceProvider provider = new FixedMinGasPriceProvider(minGasPrice); assertEquals(Coin.valueOf(minGasPrice), provider.getMinGasPriceAsCoin()); } } \ No newline at end of file diff --git a/rskj-core/src/test/java/co/rsk/rpc/modules/trace/TraceModuleImplTest.java b/rskj-core/src/test/java/co/rsk/rpc/modules/trace/TraceModuleImplTest.java index 3907ec7e29a..435cbf276c6 100644 --- a/rskj-core/src/test/java/co/rsk/rpc/modules/trace/TraceModuleImplTest.java +++ b/rskj-core/src/test/java/co/rsk/rpc/modules/trace/TraceModuleImplTest.java @@ -22,7 +22,7 @@ import co.rsk.config.RskSystemProperties; import co.rsk.core.DifficultyCalculator; import co.rsk.mine.*; -import co.rsk.mine.gas.DefaultMinGasPriceProvider; +import co.rsk.mine.gas.provider.FixedMinGasPriceProvider; import co.rsk.rpc.ExecutionBlockRetriever; import co.rsk.test.World; import co.rsk.test.builders.AccountBuilder; @@ -437,7 +437,7 @@ private static ExecutionBlockRetriever createExecutionBlockRetriever(World world ), rskSystemProperties.isMinerServerFixedClock(), rskSystemProperties.workSubmissionRateLimitInMills(), - new DefaultMinGasPriceProvider(rskSystemProperties.minerMinGasPrice()) + new FixedMinGasPriceProvider(rskSystemProperties.minerMinGasPrice()) ); BlockToMineBuilder builder = new BlockToMineBuilder( rskSystemProperties.getActivationConfig(), From 3bc0a57aac3fe8cbd85932078a605bb435418da8 Mon Sep 17 00:00:00 2001 From: Angel Soto Date: Fri, 17 May 2024 10:23:45 +0200 Subject: [PATCH 04/17] Adding tests --- .../mining/StableMinGasPriceSystemConfig.java | 2 +- .../mining/WebStableMinGasSystemConfig.java | 10 +-- .../WebStableMinGasPriceProviderFactory.java | 4 +- rskj-core/src/main/resources/reference.conf | 2 +- .../StableMinGasPriceSystemConfigTest.java | 83 ++++++++++++++++++ .../WebStableMinGasSystemConfigTest.java | 43 ++++++++++ .../MinGasPriceProviderFactoryTest.java | 85 +++++++++++++++++++ .../StableMinGasPriceProviderTest.java | 67 +++++++++++++++ 8 files changed, 287 insertions(+), 9 deletions(-) create mode 100644 rskj-core/src/test/java/co/rsk/config/mining/StableMinGasPriceSystemConfigTest.java create mode 100644 rskj-core/src/test/java/co/rsk/config/mining/WebStableMinGasSystemConfigTest.java create mode 100644 rskj-core/src/test/java/co/rsk/mine/gas/provider/MinGasPriceProviderFactoryTest.java create mode 100644 rskj-core/src/test/java/co/rsk/mine/gas/provider/StableMinGasPriceProviderTest.java diff --git a/rskj-core/src/main/java/co/rsk/config/mining/StableMinGasPriceSystemConfig.java b/rskj-core/src/main/java/co/rsk/config/mining/StableMinGasPriceSystemConfig.java index 3944d0ce7ba..8513327647f 100644 --- a/rskj-core/src/main/java/co/rsk/config/mining/StableMinGasPriceSystemConfig.java +++ b/rskj-core/src/main/java/co/rsk/config/mining/StableMinGasPriceSystemConfig.java @@ -40,7 +40,7 @@ public boolean isEnabled() { return enabled; } - public WebStableMinGasSystemConfig getHttpGetConfig() { + public WebStableMinGasSystemConfig getWebConfig() { return new WebStableMinGasSystemConfig(config.getConfig(WebStableMinGasSystemConfig.WEB_STABLE_GAS_PRICE_CONFIG_PATH)); } diff --git a/rskj-core/src/main/java/co/rsk/config/mining/WebStableMinGasSystemConfig.java b/rskj-core/src/main/java/co/rsk/config/mining/WebStableMinGasSystemConfig.java index 8c3f557a14d..b8ef3aa792a 100644 --- a/rskj-core/src/main/java/co/rsk/config/mining/WebStableMinGasSystemConfig.java +++ b/rskj-core/src/main/java/co/rsk/config/mining/WebStableMinGasSystemConfig.java @@ -5,18 +5,18 @@ public class WebStableMinGasSystemConfig { public static final String WEB_STABLE_GAS_PRICE_CONFIG_PATH = "web"; private static final String URL_PROPERTY = "url"; - private static final String JSON_PATH_PROPERTY = "jsonPath"; + private static final String REQUEST_PATH = "requestPath"; private static final String TIMEOUT_PROPERTY = "timeout"; private static final String API_KEY_PROPERTY = "apiKey"; private final String url; - private final String jsonPath; + private final String requestPath; private final int timeout; private final String apiKey; public WebStableMinGasSystemConfig(Config config) { this.url = config.getString(URL_PROPERTY); - this.jsonPath = config.getString(JSON_PATH_PROPERTY); + this.requestPath = config.getString(REQUEST_PATH); this.timeout = config.getInt(TIMEOUT_PROPERTY); this.apiKey = config.getString(API_KEY_PROPERTY); } @@ -25,8 +25,8 @@ public String getUrl() { return url; } - public String getJsonPath() { - return jsonPath; + public String getRequestPath() { + return requestPath; } public int getTimeout() { 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 fa7eeb61f5d..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 @@ -11,9 +11,9 @@ private WebStableMinGasPriceProviderFactory() { } public static StableMinGasPriceProvider create(StableMinGasPriceSystemConfig config, MinGasPriceProvider fallbackProvider) { - WebStableMinGasSystemConfig httpGetSystemConfig = config.getHttpGetConfig(); + WebStableMinGasSystemConfig httpGetSystemConfig = config.getWebConfig(); WebStableMinGasPriceConfig httpGetStableMinGasPriceConfig = WebStableMinGasPriceConfig.builder().setUrl(httpGetSystemConfig.getUrl()) - .setJsonPath(httpGetSystemConfig.getJsonPath()) + .setJsonPath(httpGetSystemConfig.getRequestPath()) .setTimeout(httpGetSystemConfig.getTimeout()) .setApiKey(httpGetSystemConfig.getApiKey()) .setMinStableGasPrice(config.getMinStableGasPrice()) diff --git a/rskj-core/src/main/resources/reference.conf b/rskj-core/src/main/resources/reference.conf index 6a59fcdb03a..9e40187354e 100644 --- a/rskj-core/src/main/resources/reference.conf +++ b/rskj-core/src/main/resources/reference.conf @@ -203,7 +203,7 @@ miner { enabled = false minStableGasPrice = 0 refreshRate = 0 - method = DEFAULT + method = FIXED } } diff --git a/rskj-core/src/test/java/co/rsk/config/mining/StableMinGasPriceSystemConfigTest.java b/rskj-core/src/test/java/co/rsk/config/mining/StableMinGasPriceSystemConfigTest.java new file mode 100644 index 00000000000..c128d9966d2 --- /dev/null +++ b/rskj-core/src/test/java/co/rsk/config/mining/StableMinGasPriceSystemConfigTest.java @@ -0,0 +1,83 @@ +package co.rsk.config.mining; + +import co.rsk.mine.gas.provider.MinGasPriceProviderType; +import com.typesafe.config.Config; +import com.typesafe.config.ConfigException; +import com.typesafe.config.ConfigFactory; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +class StableMinGasPriceSystemConfigTest { + + private StableMinGasPriceSystemConfig config; + + @BeforeEach + void setUp() { + Config testConfig = ConfigFactory.parseString( + "enabled=true\n" + + "refreshRate=10\n" + + "minStableGasPrice=100\n" + + "method=FIXED" + ); + config = new StableMinGasPriceSystemConfig(testConfig); + } + + @Test + void testIsValid() { + assertTrue(config.isValid()); + } + + @Test + void testGetRefreshRate() { + assertEquals(10, config.getRefreshRate()); + } + + @Test + void testGetMinStableGasPrice() { + assertEquals(100, config.getMinStableGasPrice()); + } + + @Test + void testIsEnabled() { + assertTrue(config.isEnabled()); + } + + @Test + void testGetMethod() { + assertEquals(MinGasPriceProviderType.FIXED, config.getMethod()); + } + + @Test + void wrongMethodShouldThrowException() { + Config testConfig = ConfigFactory.parseString( + "enabled=true\n" + + "refreshRate=10\n" + + "minStableGasPrice=100\n" + + "method=INVALID" + ); + assertThrows( + ConfigException.BadValue.class, + () -> new StableMinGasPriceSystemConfig(testConfig), + "Expected to throw Config exception, but it didn't" + ); + + } + + @Test + void missingPropertyShouldThrowException() { + Config testConfig = ConfigFactory.parseString( + "enabled=true\n" + + "minStableGasPrice=100\n" + + "method=FIXED" + ); + assertThrows( + ConfigException.Missing.class, + () -> new StableMinGasPriceSystemConfig(testConfig), + "Expected to throw Config exception, but it didn't" + ); + } + + +} \ No newline at end of file diff --git a/rskj-core/src/test/java/co/rsk/config/mining/WebStableMinGasSystemConfigTest.java b/rskj-core/src/test/java/co/rsk/config/mining/WebStableMinGasSystemConfigTest.java new file mode 100644 index 00000000000..29d3be68745 --- /dev/null +++ b/rskj-core/src/test/java/co/rsk/config/mining/WebStableMinGasSystemConfigTest.java @@ -0,0 +1,43 @@ +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.*; + +class WebStableMinGasSystemConfigTest { + private WebStableMinGasSystemConfig config; + + @BeforeEach + void setUp() { + Config testConfig = ConfigFactory.parseString( + "url=\"http://test.url\"\n" + + "requestPath=testPath\n" + + "timeout=1000\n" + + "apiKey=testApiKey" + ); + config = new WebStableMinGasSystemConfig(testConfig); + } + + @Test + void testGetUrl() { + assertEquals("http://test.url", config.getUrl()); + } + + @Test + void testRequestPath() { + assertEquals("testPath", config.getRequestPath()); + } + + @Test + void testGetTimeout() { + assertEquals(1000, config.getTimeout()); + } + + @Test + void testGetApiKey() { + assertEquals("testApiKey", config.getApiKey()); + } +} \ No newline at end of file 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 new file mode 100644 index 00000000000..6e8fd4b3895 --- /dev/null +++ b/rskj-core/src/test/java/co/rsk/mine/gas/provider/MinGasPriceProviderFactoryTest.java @@ -0,0 +1,85 @@ +package co.rsk.mine.gas.provider; + +import co.rsk.config.mining.StableMinGasPriceSystemConfig; +import co.rsk.mine.gas.provider.web.WebMinGasPriceProvider; +import com.typesafe.config.Config; +import com.typesafe.config.ConfigFactory; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class MinGasPriceProviderFactoryTest { + + + @Test + void createFixedMinGasPriceProvider() { + Config testConfig = ConfigFactory.parseString( + "enabled=true\n" + + "refreshRate=10\n" + + "minStableGasPrice=100\n" + + "method=FIXED" + ); + StableMinGasPriceSystemConfig config = new StableMinGasPriceSystemConfig(testConfig); + + MinGasPriceProvider provider = MinGasPriceProviderFactory.create(100L, config); + + assertTrue(provider instanceof FixedMinGasPriceProvider); + assertEquals(100, provider.getMinGasPrice()); + assertEquals(MinGasPriceProviderType.FIXED, provider.getType()); + } + + @Test + void createWithNullConfig() { + MinGasPriceProvider provider = MinGasPriceProviderFactory.create(100L, null); + assertTrue(provider instanceof FixedMinGasPriceProvider); + assertEquals(100, provider.getMinGasPrice()); + assertEquals(MinGasPriceProviderType.FIXED, provider.getType()); + } + + @Test + void createWebProviderMethod() { + Config testConfig = ConfigFactory.parseString( + "enabled=true \n" + + "refreshRate=10\n" + + "minStableGasPrice=100\n" + + "method=WEB\n" + + "web.url=url\n" + + "web.timeout=1000 \n" + + "web.apiKey=1234\n" + + "web.requestPath=price" + ); + + StableMinGasPriceSystemConfig disabledConfig = new StableMinGasPriceSystemConfig(testConfig); + + MinGasPriceProvider provider = MinGasPriceProviderFactory.create(100L, disabledConfig); + + assertTrue(provider instanceof WebMinGasPriceProvider); + assertEquals(100, provider.getMinGasPrice()); + assertEquals(MinGasPriceProviderType.WEB, provider.getType()); + } + + @Test + void createWithDisabledConfigReturnFixed() { + Config testConfig = ConfigFactory.parseString( + "enabled=false \n" + + "refreshRate=10\n" + + "minStableGasPrice=100\n" + + "method=WEB\n" + + "web.url=url\n" + + "web.timeout=1000 \n" + + "web.apiKey=1234\n" + + "web.jsonPath=price" + ); + + StableMinGasPriceSystemConfig disabledConfig = new StableMinGasPriceSystemConfig(testConfig); + + MinGasPriceProvider provider = MinGasPriceProviderFactory.create(100L, disabledConfig); + + assertTrue(provider instanceof FixedMinGasPriceProvider); + assertEquals(100, provider.getMinGasPrice()); + assertEquals(MinGasPriceProviderType.FIXED, provider.getType()); + } + + +} 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 new file mode 100644 index 00000000000..2f84a91177a --- /dev/null +++ b/rskj-core/src/test/java/co/rsk/mine/gas/provider/StableMinGasPriceProviderTest.java @@ -0,0 +1,67 @@ +package co.rsk.mine.gas.provider; + +import co.rsk.core.Coin; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.*; + +class StableMinGasPriceProviderTest { + private MinGasPriceProvider fallBackProvider; + private StableMinGasPriceProvider stableMinGasPriceProvider; + + @BeforeEach + void setUp() { + fallBackProvider = Mockito.mock(MinGasPriceProvider.class); + when(fallBackProvider.getMinGasPrice()).thenReturn(10L); + when(fallBackProvider.getType()).thenReturn(MinGasPriceProviderType.FIXED); + stableMinGasPriceProvider = new TestStableMingGasPriceProvider(fallBackProvider); + } + + @Test + void testGetMinGasPrice() { + long result = stableMinGasPriceProvider.getMinGasPrice(); + assertEquals(1L, result); + verify(fallBackProvider, times(0)).getMinGasPrice(); + } + + @Test + void GetMinGasPriceUsesFallbackWhenReturnIsNull() { + stableMinGasPriceProvider = new TestStableMingGasPriceProvider(fallBackProvider) { + @Override + public Long getStableMinGasPrice() { + return null; + } + }; + + long result = stableMinGasPriceProvider.getMinGasPrice(); + + assertEquals(10L, result); + verify(fallBackProvider, times(1)).getMinGasPrice(); + } + + @Test + void testGetMinGasPriceAsCoin() { + Coin result = stableMinGasPriceProvider.getMinGasPriceAsCoin(); + assertEquals(Coin.valueOf(1L), result); + } + + public static class TestStableMingGasPriceProvider extends StableMinGasPriceProvider { + + protected TestStableMingGasPriceProvider(MinGasPriceProvider fallBackProvider) { + super(fallBackProvider); + } + + @Override + public MinGasPriceProviderType getType() { + return MinGasPriceProviderType.FIXED; + } + + @Override + public Long getStableMinGasPrice() { + return 1L; + } + } +} \ No newline at end of file From bf975c54d41ca5c02742c2d20f2f9723734aeb18 Mon Sep 17 00:00:00 2001 From: Angel Soto Date: Fri, 17 May 2024 13:18:40 +0200 Subject: [PATCH 05/17] fixing sonar issue --- .../StableMinGasPriceProviderFactory.java | 15 --------------- .../onchain/OnChainMinGasPriceProvider.java | 8 +++++++- 2 files changed, 7 insertions(+), 16 deletions(-) delete mode 100644 rskj-core/src/main/java/co/rsk/mine/gas/provider/StableMinGasPriceProviderFactory.java diff --git a/rskj-core/src/main/java/co/rsk/mine/gas/provider/StableMinGasPriceProviderFactory.java b/rskj-core/src/main/java/co/rsk/mine/gas/provider/StableMinGasPriceProviderFactory.java deleted file mode 100644 index 24ead01e416..00000000000 --- a/rskj-core/src/main/java/co/rsk/mine/gas/provider/StableMinGasPriceProviderFactory.java +++ /dev/null @@ -1,15 +0,0 @@ -package co.rsk.mine.gas.provider; - -import co.rsk.config.mining.StableMinGasPriceSystemConfig; - -public abstract class StableMinGasPriceProviderFactory { - private final StableMinGasPriceSystemConfig config; - private final MinGasPriceProvider fallbackProvider; - - public StableMinGasPriceProviderFactory(StableMinGasPriceSystemConfig config, MinGasPriceProvider fallbackProvider) { - this.config = config; - this.fallbackProvider = fallbackProvider; - } - - protected abstract StableMinGasPriceProvider create(); -} 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 ba35804c848..cc278ef105b 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 @@ -6,9 +6,11 @@ import co.rsk.mine.gas.provider.StableMinGasPriceProvider; public class OnChainMinGasPriceProvider extends StableMinGasPriceProvider { + private final String address; - OnChainMinGasPriceProvider(MinGasPriceProvider fallBackProvider, OnChainMinGasPriceSystemConfig config) { + protected OnChainMinGasPriceProvider(MinGasPriceProvider fallBackProvider, OnChainMinGasPriceSystemConfig config) { super(fallBackProvider); + this.address = config.getAddress(); } @Override @@ -20,4 +22,8 @@ public MinGasPriceProviderType getType() { public Long getStableMinGasPrice() { return null; } + + public String getAddress() { + return address; + } } From 923447f4b3161efce91d0aff17f19fb8d0e21e2f Mon Sep 17 00:00:00 2001 From: Juraj Piar Date: Thu, 6 Jun 2024 23:53:51 +0100 Subject: [PATCH 06/17] 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 07/17] 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()); + } + } From 39d0e26f44e58726d6b8eda8dfa6a736979e2446 Mon Sep 17 00:00:00 2001 From: Angel Soto Date: Fri, 7 Jun 2024 10:08:08 +0200 Subject: [PATCH 08/17] Adding new Stable Gas Price Web Provider --- .../src/main/java/co/rsk/RskContext.java | 4 +- .../main/java/co/rsk/config/MiningConfig.java | 9 +- .../mining/StableMinGasPriceSystemConfig.java | 23 ++- .../mining/WebStableMinGasSystemConfig.java | 23 ++- .../provider/MinGasPriceProviderFactory.java | 10 +- .../provider/StableMinGasPriceProvider.java | 48 +++++-- .../onchain/OnChainMinGasPriceProvider.java | 20 +-- .../OnChainMinGasPriceProviderFactory.java | 14 -- .../provider/web/WebMinGasPriceProvider.java | 119 ++++++++++++--- .../web/WebStableMinGasPriceConfig.java | 92 ------------ .../WebStableMinGasPriceProviderFactory.java | 25 ---- .../java/co/rsk/net/http/HttpException.java | 28 ++++ .../co/rsk/net/http/SimpleHttpClient.java | 73 ++++++++++ .../test/java/co/rsk/config/ConfigUtils.java | 4 +- .../StableMinGasPriceSystemConfigTest.java | 17 +++ .../WebStableMinGasSystemConfigTest.java | 25 +++- .../java/co/rsk/mine/MainNetMinerTest.java | 3 +- .../java/co/rsk/mine/MinerManagerTest.java | 3 +- .../co/rsk/mine/TransactionModuleTest.java | 3 +- .../MinGasPriceProviderFactoryTest.java | 19 ++- .../StableMinGasPriceProviderTest.java | 39 +++-- .../OnChainMinGasPriceProviderTest.java | 14 +- .../web/WebMinGasPriceProviderTest.java | 136 ++++++++++++++++++ .../rsk/net/http/SimpleHttpClientIntTest.java | 111 ++++++++++++++ .../co/rsk/net/http/SimpleHttpTestServer.java | 101 +++++++++++++ .../modules/trace/TraceModuleImplTest.java | 5 +- .../ethereum/rpc/Web3ImplSnapshotTest.java | 3 +- 27 files changed, 741 insertions(+), 230 deletions(-) delete mode 100644 rskj-core/src/main/java/co/rsk/mine/gas/provider/onchain/OnChainMinGasPriceProviderFactory.java delete mode 100644 rskj-core/src/main/java/co/rsk/mine/gas/provider/web/WebStableMinGasPriceConfig.java delete mode 100644 rskj-core/src/main/java/co/rsk/mine/gas/provider/web/WebStableMinGasPriceProviderFactory.java create mode 100644 rskj-core/src/main/java/co/rsk/net/http/HttpException.java create mode 100644 rskj-core/src/main/java/co/rsk/net/http/SimpleHttpClient.java create mode 100644 rskj-core/src/test/java/co/rsk/mine/gas/provider/web/WebMinGasPriceProviderTest.java create mode 100644 rskj-core/src/test/java/co/rsk/net/http/SimpleHttpClientIntTest.java create mode 100644 rskj-core/src/test/java/co/rsk/net/http/SimpleHttpTestServer.java diff --git a/rskj-core/src/main/java/co/rsk/RskContext.java b/rskj-core/src/main/java/co/rsk/RskContext.java index 2848ec7c4d8..8ab7f2c244f 100644 --- a/rskj-core/src/main/java/co/rsk/RskContext.java +++ b/rskj-core/src/main/java/co/rsk/RskContext.java @@ -2165,9 +2165,7 @@ private MiningConfig getMiningConfig() { rskSystemProperties.getForceTargetGasLimit() ), rskSystemProperties.isMinerServerFixedClock(), - rskSystemProperties.workSubmissionRateLimitInMills(), - getMinGasPriceProvider() - ); + rskSystemProperties.workSubmissionRateLimitInMills()); } return miningConfig; diff --git a/rskj-core/src/main/java/co/rsk/config/MiningConfig.java b/rskj-core/src/main/java/co/rsk/config/MiningConfig.java index 5746b203349..bbdf30b8a96 100644 --- a/rskj-core/src/main/java/co/rsk/config/MiningConfig.java +++ b/rskj-core/src/main/java/co/rsk/config/MiningConfig.java @@ -19,7 +19,6 @@ package co.rsk.config; import co.rsk.core.RskAddress; -import co.rsk.mine.gas.provider.MinGasPriceProvider; /** * Wraps configuration for Mining, which is usually derived from configuration files. @@ -35,11 +34,10 @@ public class MiningConfig { private final GasLimitConfig gasLimit; private final boolean isFixedClock; private final long workSubmissionRateLimitInMills; - private final MinGasPriceProvider minGasPriceProvider; public MiningConfig(RskAddress coinbaseAddress, double minFeesNotifyInDollars, double minerGasUnitInDollars, int uncleListLimit, int uncleGenerationLimit, GasLimitConfig gasLimit, - boolean isFixedClock, long workSubmissionRateLimitInMills, MinGasPriceProvider minGasPriceProvider) { + boolean isFixedClock, long workSubmissionRateLimitInMills) { this.coinbaseAddress = coinbaseAddress; this.minFeesNotifyInDollars = minFeesNotifyInDollars; this.minerGasUnitInDollars = minerGasUnitInDollars; @@ -48,7 +46,6 @@ public MiningConfig(RskAddress coinbaseAddress, double minFeesNotifyInDollars, d this.gasLimit = gasLimit; this.isFixedClock = isFixedClock; this.workSubmissionRateLimitInMills = workSubmissionRateLimitInMills; - this.minGasPriceProvider = minGasPriceProvider; } public RskAddress getCoinbaseAddress() { @@ -82,8 +79,4 @@ public boolean isFixedClock() { public long getWorkSubmissionRateLimitInMills() { return workSubmissionRateLimitInMills; } - - public MinGasPriceProvider getMinGasPriceProvider() { - return minGasPriceProvider; - } } diff --git a/rskj-core/src/main/java/co/rsk/config/mining/StableMinGasPriceSystemConfig.java b/rskj-core/src/main/java/co/rsk/config/mining/StableMinGasPriceSystemConfig.java index 8513327647f..e7ae49da2cb 100644 --- a/rskj-core/src/main/java/co/rsk/config/mining/StableMinGasPriceSystemConfig.java +++ b/rskj-core/src/main/java/co/rsk/config/mining/StableMinGasPriceSystemConfig.java @@ -1,3 +1,20 @@ +/* + * This file is part of RskJ + * Copyright (C) 2024 RSK Labs Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ package co.rsk.config.mining; import co.rsk.mine.gas.provider.MinGasPriceProviderType; @@ -11,7 +28,7 @@ public class StableMinGasPriceSystemConfig { private static final String METHOD_PROPERTY = "method"; private final Integer refreshRate; - private final Integer minStableGasPrice; + private final Long minStableGasPrice; private final boolean enabled; private final MinGasPriceProviderType method; private final Config config; @@ -19,7 +36,7 @@ public class StableMinGasPriceSystemConfig { public StableMinGasPriceSystemConfig(Config config) { enabled = config.getBoolean(ENABLED_PROPERTY); refreshRate = config.getInt(REFRESH_RATE_PROPERTY); - minStableGasPrice = config.getInt(MIN_STABLE_GAS_PRICE_PROPERTY); + minStableGasPrice = config.getLong(MIN_STABLE_GAS_PRICE_PROPERTY); method = config.getEnum(MinGasPriceProviderType.class, METHOD_PROPERTY); this.config = config; } @@ -32,7 +49,7 @@ public int getRefreshRate() { return refreshRate; } - public int getMinStableGasPrice() { + public Long getMinStableGasPrice() { return minStableGasPrice; } diff --git a/rskj-core/src/main/java/co/rsk/config/mining/WebStableMinGasSystemConfig.java b/rskj-core/src/main/java/co/rsk/config/mining/WebStableMinGasSystemConfig.java index b8ef3aa792a..eaf6de82745 100644 --- a/rskj-core/src/main/java/co/rsk/config/mining/WebStableMinGasSystemConfig.java +++ b/rskj-core/src/main/java/co/rsk/config/mining/WebStableMinGasSystemConfig.java @@ -1,3 +1,20 @@ +/* + * This file is part of RskJ + * Copyright (C) 2024 RSK Labs Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ package co.rsk.config.mining; import com.typesafe.config.Config; @@ -7,18 +24,15 @@ public class WebStableMinGasSystemConfig { private static final String URL_PROPERTY = "url"; private static final String REQUEST_PATH = "requestPath"; private static final String TIMEOUT_PROPERTY = "timeout"; - private static final String API_KEY_PROPERTY = "apiKey"; private final String url; private final String requestPath; private final int timeout; - private final String apiKey; public WebStableMinGasSystemConfig(Config config) { this.url = config.getString(URL_PROPERTY); this.requestPath = config.getString(REQUEST_PATH); this.timeout = config.getInt(TIMEOUT_PROPERTY); - this.apiKey = config.getString(API_KEY_PROPERTY); } public String getUrl() { @@ -33,7 +47,4 @@ public int getTimeout() { return timeout; } - public String getApiKey() { - return apiKey; - } } 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 a2ce007f83b..ecb78364183 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 @@ -2,8 +2,7 @@ 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 co.rsk.mine.gas.provider.web.WebMinGasPriceProvider; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -17,6 +16,7 @@ private MinGasPriceProviderFactory() { 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()); return fixedMinGasPriceProvider; @@ -24,18 +24,18 @@ public static MinGasPriceProvider create(long fixedMinGasPrice, StableMinGasPric if (!stableMinGasPriceSystemConfig.isEnabled()) { return fixedMinGasPriceProvider; } + MinGasPriceProviderType method = stableMinGasPriceSystemConfig.getMethod(); if (method == null) { logger.error("Could not find valid method in config, using fallback provider: {}", fixedMinGasPriceProvider.getType().name()); return fixedMinGasPriceProvider; } - switch (method) { case WEB: - return WebStableMinGasPriceProviderFactory.create(stableMinGasPriceSystemConfig, fixedMinGasPriceProvider); + return new WebMinGasPriceProvider(stableMinGasPriceSystemConfig, fixedMinGasPriceProvider); case ON_CHAIN: - return OnChainMinGasPriceProviderFactory.create(stableMinGasPriceSystemConfig, fixedMinGasPriceProvider, getContextCallback); + return new OnChainMinGasPriceProvider(fixedMinGasPriceProvider, stableMinGasPriceSystemConfig.getMinStableGasPrice(), stableMinGasPriceSystemConfig.getOnChainConfig(), 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 fd03cf6ae66..38324434db2 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,27 +1,57 @@ +/* + * This file is part of RskJ + * Copyright (C) 2024 RSK Labs Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ package co.rsk.mine.gas.provider; import co.rsk.core.Coin; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.Optional; + public abstract class StableMinGasPriceProvider implements MinGasPriceProvider { private static final Logger logger = LoggerFactory.getLogger("StableMinGasPrice"); - protected final MinGasPriceProvider fallBackProvider; - - protected StableMinGasPriceProvider(MinGasPriceProvider fallBackProvider) { + private final MinGasPriceProvider fallBackProvider; + private final long minStableGasPrice; + protected StableMinGasPriceProvider(MinGasPriceProvider fallBackProvider, long minStableGasPrice) { + this.minStableGasPrice = minStableGasPrice; this.fallBackProvider = fallBackProvider; } - public abstract Long getStableMinGasPrice(); + protected abstract Optional getBtcExchangeRate(); @Override public long getMinGasPrice() { - Long stableMinGasPrice = getStableMinGasPrice(); - if (stableMinGasPrice == null) { - logger.error("Could not get stable min gas price from method {}, using fallback provider: {}", this.getType().name(), fallBackProvider.getType().name()); - return fallBackProvider.getMinGasPrice(); + Optional btcValueOpt = getBtcExchangeRate(); + if (btcValueOpt.isPresent()) { + long btcValue = btcValueOpt.get(); + if (btcValue >= 0) { + return calculateMinGasPriceBasedOnBtcPrice(btcValue); + } + } + logger.error("Could not get stable min gas price from method {}, using fallback provider: {}", this.getType().name(), fallBackProvider.getType().name()); + return fallBackProvider.getMinGasPrice(); + } + + private long calculateMinGasPriceBasedOnBtcPrice(long btcValue) { + if(minStableGasPrice == 0 || btcValue == 0) { + return 0; } - return stableMinGasPrice; + return minStableGasPrice / btcValue; } @Override 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 fb582590449..ce3dee06c9e 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 @@ -14,21 +14,23 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.Optional; + 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; - @FunctionalInterface public interface GetContextCallback { EthModule getEthModule(); } + private final GetContextCallback getContextCallback; - protected OnChainMinGasPriceProvider(MinGasPriceProvider fallBackProvider, OnChainMinGasPriceSystemConfig config, GetContextCallback getContextCallback) { - super(fallBackProvider); + public OnChainMinGasPriceProvider(MinGasPriceProvider fallBackProvider, long minStableGasPrice, OnChainMinGasPriceSystemConfig config, GetContextCallback getContextCallback) { + super(fallBackProvider, minStableGasPrice); this.getContextCallback = getContextCallback; this.toAddress = config.address(); this.fromAddress = config.from(); @@ -41,11 +43,11 @@ public MinGasPriceProviderType getType() { } @Override - public Long getStableMinGasPrice() { + protected Optional getBtcExchangeRate() { EthModule ethModule = this.getContextCallback.getEthModule(); if (ethModule == null) { logger.error("Could not get eth module"); - return fallBackProvider.getMinGasPrice(); + return Optional.empty(); } CallArgumentsParam callArguments = new CallArgumentsParam( @@ -64,13 +66,11 @@ public Long getStableMinGasPrice() { String callOutput = ethModule.call(callArguments, new BlockIdentifierParam("latest")); // Parse the output of the call to get the exchange rate. Will not work with bytes32 values! - return HexUtils.jsonHexToLong( - callOutput - ); + return Optional.of(HexUtils.jsonHexToLong( + callOutput)); } catch (Exception e) { logger.error("Error calling eth module", e); - - return fallBackProvider.getMinGasPrice(); + return Optional.empty(); } } 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 deleted file mode 100644 index 794c8375cbe..00000000000 --- a/rskj-core/src/main/java/co/rsk/mine/gas/provider/onchain/OnChainMinGasPriceProviderFactory.java +++ /dev/null @@ -1,14 +0,0 @@ -package co.rsk.mine.gas.provider.onchain; - -import co.rsk.config.mining.StableMinGasPriceSystemConfig; -import co.rsk.mine.gas.provider.MinGasPriceProvider; - -public class OnChainMinGasPriceProviderFactory { - - private OnChainMinGasPriceProviderFactory() { - } - - 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..b31a5af1290 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 @@ -1,27 +1,113 @@ +/* + * This file is part of RskJ + * Copyright (C) 2024 RSK Labs Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ package co.rsk.mine.gas.provider.web; +import co.rsk.config.mining.StableMinGasPriceSystemConfig; +import co.rsk.config.mining.WebStableMinGasSystemConfig; import co.rsk.mine.gas.provider.MinGasPriceProvider; import co.rsk.mine.gas.provider.MinGasPriceProviderType; import co.rsk.mine.gas.provider.StableMinGasPriceProvider; +import co.rsk.net.http.SimpleHttpClient; +import com.fasterxml.jackson.core.JsonPointer; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.time.Instant; +import java.util.Optional; public class WebMinGasPriceProvider extends StableMinGasPriceProvider { + private static final Logger logger = LoggerFactory.getLogger("GasPriceProvider"); private final String url; - private final String jsonPath; - private final String apiKey; + private final JsonPointer jsonPath; private final int timeout; - private final int refreshRate; + private final int refreshRateMillis; + private final SimpleHttpClient httpClient; + private final ObjectMapper objectMapper; + private Long lastPrice; + private int lastUpdateTimeStamp; + - WebMinGasPriceProvider(MinGasPriceProvider fallBackProvider, WebStableMinGasPriceConfig config) { - super(fallBackProvider); - url = config.getUrl(); - jsonPath = config.getJsonPath(); - apiKey = config.getApiKey(); - timeout = config.getTimeout(); - refreshRate = config.getRefreshRate(); + public WebMinGasPriceProvider(StableMinGasPriceSystemConfig config, MinGasPriceProvider fallBackProvider) { + super(fallBackProvider, config.getMinStableGasPrice()); + WebStableMinGasSystemConfig webConfig = config.getWebConfig(); + url = webConfig.getUrl(); + jsonPath = JsonPointer.valueOf(webConfig.getRequestPath()); + timeout = webConfig.getTimeout(); + refreshRateMillis = config.getRefreshRate() * 1000; + httpClient = new SimpleHttpClient(webConfig.getTimeout()); + objectMapper = new ObjectMapper(); + } + public WebMinGasPriceProvider(StableMinGasPriceSystemConfig config, MinGasPriceProvider fallBackProvider, SimpleHttpClient httpClient) { + super(fallBackProvider, config.getMinStableGasPrice()); + WebStableMinGasSystemConfig webConfig = config.getWebConfig(); + url = webConfig.getUrl(); + jsonPath = JsonPointer.valueOf(webConfig.getRequestPath()); + timeout = webConfig.getTimeout(); + refreshRateMillis = config.getRefreshRate() * 1000; + this.httpClient = httpClient; + objectMapper = new ObjectMapper(); } @Override - public Long getStableMinGasPrice() { + protected Optional getBtcExchangeRate() { + int currentTime = (int) Instant.now().getEpochSecond(); + if (currentTime - lastUpdateTimeStamp >= refreshRateMillis) { + fetchPrice(); + } + // time it is always updated, it is not taken into account if the price was really updated or not. + lastUpdateTimeStamp = currentTime; + return Optional.ofNullable(lastPrice); + } + + private void fetchPrice() { + String response = getResponseFromWeb(); + if (!StringUtils.isBlank(response)) { + Long price = parsePrice(response); + if (price != null && price > 0) { + lastPrice = price; + } + } + } + + private Long parsePrice(String response) { + try { + JsonNode jObject = objectMapper.readTree(response); + if (jObject.at(jsonPath).isMissingNode()) { + return null; + } + return objectMapper.readTree(response).at(jsonPath).asLong(); + } catch (Exception e) { + logger.error("Error parsing min gas price from web provider: {}", e.getMessage()); + return null; + } + } + + private String getResponseFromWeb() { + try { + String response = httpClient.doGet(url); + logger.debug("Response from web: {}", response); + return response; + } catch (Exception e) { + logger.error("Error getting min gas price from web provider: {}", e.getMessage()); + } return null; } @@ -34,20 +120,9 @@ public String getUrl() { return url; } - public String getJsonPath() { - return jsonPath; - } - - public String getApiKey() { - return apiKey; - } - public int getTimeout() { return timeout; } - public int getRefreshRate() { - return refreshRate; - } } diff --git a/rskj-core/src/main/java/co/rsk/mine/gas/provider/web/WebStableMinGasPriceConfig.java b/rskj-core/src/main/java/co/rsk/mine/gas/provider/web/WebStableMinGasPriceConfig.java deleted file mode 100644 index 9d232ecd88e..00000000000 --- a/rskj-core/src/main/java/co/rsk/mine/gas/provider/web/WebStableMinGasPriceConfig.java +++ /dev/null @@ -1,92 +0,0 @@ -package co.rsk.mine.gas.provider.web; - -public class WebStableMinGasPriceConfig { - private final String url; - private final String jsonPath; - private final int timeout; - private final String apiKey; - private final long minStableGasPrice; - private final int refreshRate; - - public WebStableMinGasPriceConfig(String url, String jsonPath, int timeout, String apiKey, long minStableGasPrice, int refreshRate) { - this.url = url; - this.jsonPath = jsonPath; - this.timeout = timeout; - this.apiKey = apiKey; - this.minStableGasPrice = minStableGasPrice; - this.refreshRate = refreshRate; - } - - public String getUrl() { - return url; - } - - public String getJsonPath() { - return jsonPath; - } - - public int getTimeout() { - return timeout; - } - - public String getApiKey() { - return apiKey; - } - - public long getMinStableGasPrice() { - return minStableGasPrice; - } - - public int getRefreshRate() { - return refreshRate; - } - - public static Builder builder() { - return new Builder(); - } - - public static class Builder { - private String url; - private String jsonPath; - private int timeout; - private String apiKey; - private long minStableGasPrice; - private int refreshRate; - - public Builder setUrl(String url) { - this.url = url; - return this; - } - - public Builder setJsonPath(String jsonPath) { - this.jsonPath = jsonPath; - return this; - } - - public Builder setTimeout(int timeout) { - this.timeout = timeout; - return this; - } - - public Builder setApiKey(String apiKey) { - this.apiKey = apiKey; - return this; - } - - public Builder setMinStableGasPrice(long minStableGasPrice) { - this.minStableGasPrice = minStableGasPrice; - return this; - } - - public Builder setRefreshRate(int refreshRate) { - this.refreshRate = refreshRate; - return this; - } - - public WebStableMinGasPriceConfig build() { - return new WebStableMinGasPriceConfig(url, jsonPath, timeout, apiKey, minStableGasPrice, refreshRate); - } - } - - -} 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 deleted file mode 100644 index 8036e0bde74..00000000000 --- a/rskj-core/src/main/java/co/rsk/mine/gas/provider/web/WebStableMinGasPriceProviderFactory.java +++ /dev/null @@ -1,25 +0,0 @@ -package co.rsk.mine.gas.provider.web; - -import co.rsk.config.mining.WebStableMinGasSystemConfig; -import co.rsk.config.mining.StableMinGasPriceSystemConfig; -import co.rsk.mine.gas.provider.MinGasPriceProvider; -import co.rsk.mine.gas.provider.StableMinGasPriceProvider; - -public class WebStableMinGasPriceProviderFactory { - - private WebStableMinGasPriceProviderFactory() { - } - - public static StableMinGasPriceProvider create(StableMinGasPriceSystemConfig config, MinGasPriceProvider fallbackProvider) { - WebStableMinGasSystemConfig httpGetSystemConfig = config.getWebConfig(); - WebStableMinGasPriceConfig httpGetStableMinGasPriceConfig = WebStableMinGasPriceConfig.builder().setUrl(httpGetSystemConfig.getUrl()) - .setJsonPath(httpGetSystemConfig.getRequestPath()) - .setTimeout(httpGetSystemConfig.getTimeout()) - .setApiKey(httpGetSystemConfig.getApiKey()) - .setMinStableGasPrice(config.getMinStableGasPrice()) - .setRefreshRate(config.getRefreshRate()) - .build(); - return new WebMinGasPriceProvider(fallbackProvider, httpGetStableMinGasPriceConfig); - } -} - diff --git a/rskj-core/src/main/java/co/rsk/net/http/HttpException.java b/rskj-core/src/main/java/co/rsk/net/http/HttpException.java new file mode 100644 index 00000000000..c7c77b54414 --- /dev/null +++ b/rskj-core/src/main/java/co/rsk/net/http/HttpException.java @@ -0,0 +1,28 @@ +/* + * This file is part of RskJ + * Copyright (C) 2024 RSK Labs Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ +package co.rsk.net.http; + +public class HttpException extends Exception { + + private static final long serialVersionUID = 9209168000899420627L; + + public HttpException(String message) { + super(message); + } + +} diff --git a/rskj-core/src/main/java/co/rsk/net/http/SimpleHttpClient.java b/rskj-core/src/main/java/co/rsk/net/http/SimpleHttpClient.java new file mode 100644 index 00000000000..177515760c5 --- /dev/null +++ b/rskj-core/src/main/java/co/rsk/net/http/SimpleHttpClient.java @@ -0,0 +1,73 @@ +/* + * This file is part of RskJ + * Copyright (C) 2024 RSK Labs Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ +package co.rsk.net.http; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.UnknownHostException; + +public class SimpleHttpClient { + private static final Logger logger = LoggerFactory.getLogger("simpleHttp"); + private static final String GET_METHOD = "GET"; + private final int timeoutMillis; + + public SimpleHttpClient(int timeoutMillis) { + this.timeoutMillis = timeoutMillis; + } + + public String doGet(String targetUrl) throws HttpException { + StringBuilder response = new StringBuilder(); + try { + URL url = new URL(targetUrl); + HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + conn.setRequestMethod(GET_METHOD); + conn.setConnectTimeout(timeoutMillis); // Set connection timeout to 30 seconds + conn.setReadTimeout(timeoutMillis); // Set read timeout to 30 seconds + int responseCode = conn.getResponseCode(); + + if (responseCode >= 300 || responseCode < 200) { + String responseMessage = conn.getResponseMessage(); + throw new HttpException("Http request failed with code : " + responseCode + " - " + responseMessage); + } + + BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream())); + String line; + while ((line = reader.readLine()) != null) { + response.append(line); + } + reader.close(); + } catch (HttpException httpException) { + throw httpException; + } catch (UnknownHostException unknownHostException) { + logger.error("Unknown host from url: {}. {}", targetUrl, unknownHostException.getMessage()); + throw new HttpException("Unknown host from url: " + targetUrl); + } catch (Exception e) { + logger.error("Http request failed.", e); + throw new HttpException("Http request failed with error : " + e.getMessage()); + } + + return response.toString(); + } + + +} diff --git a/rskj-core/src/test/java/co/rsk/config/ConfigUtils.java b/rskj-core/src/test/java/co/rsk/config/ConfigUtils.java index 3ca7ef199e4..8a7ba3829ba 100644 --- a/rskj-core/src/test/java/co/rsk/config/ConfigUtils.java +++ b/rskj-core/src/test/java/co/rsk/config/ConfigUtils.java @@ -18,7 +18,6 @@ package co.rsk.config; import co.rsk.core.RskAddress; -import co.rsk.mine.gas.provider.FixedMinGasPriceProvider; public class ConfigUtils { public static MiningConfig getDefaultMiningConfig() { @@ -31,8 +30,7 @@ public static MiningConfig getDefaultMiningConfig() { 7, new GasLimitConfig(3000000, 500000, true), true, - 0L, - new FixedMinGasPriceProvider(0) + 0L ); } } diff --git a/rskj-core/src/test/java/co/rsk/config/mining/StableMinGasPriceSystemConfigTest.java b/rskj-core/src/test/java/co/rsk/config/mining/StableMinGasPriceSystemConfigTest.java index c128d9966d2..66a4f68987f 100644 --- a/rskj-core/src/test/java/co/rsk/config/mining/StableMinGasPriceSystemConfigTest.java +++ b/rskj-core/src/test/java/co/rsk/config/mining/StableMinGasPriceSystemConfigTest.java @@ -1,3 +1,20 @@ +/* + * This file is part of RskJ + * Copyright (C) 2024 RSK Labs Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ package co.rsk.config.mining; import co.rsk.mine.gas.provider.MinGasPriceProviderType; diff --git a/rskj-core/src/test/java/co/rsk/config/mining/WebStableMinGasSystemConfigTest.java b/rskj-core/src/test/java/co/rsk/config/mining/WebStableMinGasSystemConfigTest.java index 29d3be68745..804f8aba092 100644 --- a/rskj-core/src/test/java/co/rsk/config/mining/WebStableMinGasSystemConfigTest.java +++ b/rskj-core/src/test/java/co/rsk/config/mining/WebStableMinGasSystemConfigTest.java @@ -1,3 +1,20 @@ +/* + * This file is part of RskJ + * Copyright (C) 2024 RSK Labs Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ package co.rsk.config.mining; import com.typesafe.config.Config; @@ -15,8 +32,7 @@ void setUp() { Config testConfig = ConfigFactory.parseString( "url=\"http://test.url\"\n" + "requestPath=testPath\n" + - "timeout=1000\n" + - "apiKey=testApiKey" + "timeout=1000\n" ); config = new WebStableMinGasSystemConfig(testConfig); } @@ -35,9 +51,4 @@ void testRequestPath() { void testGetTimeout() { assertEquals(1000, config.getTimeout()); } - - @Test - void testGetApiKey() { - assertEquals("testApiKey", config.getApiKey()); - } } \ No newline at end of file diff --git a/rskj-core/src/test/java/co/rsk/mine/MainNetMinerTest.java b/rskj-core/src/test/java/co/rsk/mine/MainNetMinerTest.java index 1c70d23f547..8abb85f99a4 100644 --- a/rskj-core/src/test/java/co/rsk/mine/MainNetMinerTest.java +++ b/rskj-core/src/test/java/co/rsk/mine/MainNetMinerTest.java @@ -29,6 +29,7 @@ import co.rsk.core.bc.MiningMainchainView; import co.rsk.core.genesis.TestGenesisLoader; import co.rsk.db.RepositoryLocator; +import co.rsk.mine.gas.provider.FixedMinGasPriceProvider; import co.rsk.net.NodeBlockProcessor; import co.rsk.test.builders.BlockChainBuilder; import co.rsk.validators.BlockUnclesValidationRule; @@ -238,7 +239,7 @@ private BlockToMineBuilder blockToMineBuilder() { clock, blockFactory, blockExecutor, - new MinimumGasPriceCalculator(miningConfig.getMinGasPriceProvider()), + new MinimumGasPriceCalculator(new FixedMinGasPriceProvider(config.minerMinGasPrice())), new MinerUtils(), new BlockTxSignatureCache(new ReceivedTxSignatureCache()) ); diff --git a/rskj-core/src/test/java/co/rsk/mine/MinerManagerTest.java b/rskj-core/src/test/java/co/rsk/mine/MinerManagerTest.java index 7c62508dc90..9d436ad49e3 100644 --- a/rskj-core/src/test/java/co/rsk/mine/MinerManagerTest.java +++ b/rskj-core/src/test/java/co/rsk/mine/MinerManagerTest.java @@ -25,6 +25,7 @@ import co.rsk.core.bc.BlockExecutor; import co.rsk.core.bc.MiningMainchainView; import co.rsk.db.RepositoryLocator; +import co.rsk.mine.gas.provider.FixedMinGasPriceProvider; import co.rsk.net.NodeBlockProcessor; import co.rsk.validators.BlockValidationRule; import co.rsk.validators.ProofOfWorkRule; @@ -290,7 +291,7 @@ private MinerServerImpl getMinerServer() { clock, blockFactory, blockExecutor, - new MinimumGasPriceCalculator(miningConfig.getMinGasPriceProvider()), + new MinimumGasPriceCalculator(new FixedMinGasPriceProvider(config.minerMinGasPrice())), new MinerUtils(), new BlockTxSignatureCache(new ReceivedTxSignatureCache()) // TODO -> should it be ReceivedTxSignatureCache? See Miner Server Test for reference ), diff --git a/rskj-core/src/test/java/co/rsk/mine/TransactionModuleTest.java b/rskj-core/src/test/java/co/rsk/mine/TransactionModuleTest.java index 05be6bcf0c2..e2ff31e8e8e 100644 --- a/rskj-core/src/test/java/co/rsk/mine/TransactionModuleTest.java +++ b/rskj-core/src/test/java/co/rsk/mine/TransactionModuleTest.java @@ -26,6 +26,7 @@ import co.rsk.db.RepositorySnapshot; import co.rsk.db.StateRootHandler; import co.rsk.db.StateRootsStoreImpl; +import co.rsk.mine.gas.provider.FixedMinGasPriceProvider; import co.rsk.net.TransactionGateway; import co.rsk.net.handler.quota.TxQuotaChecker; import co.rsk.peg.BridgeSupportFactory; @@ -612,7 +613,7 @@ private Web3Impl internalCreateEnvironment(Blockchain blockchain, minerClock, blockFactory, blockExecutor, - new MinimumGasPriceCalculator(miningConfig.getMinGasPriceProvider()), + new MinimumGasPriceCalculator(new FixedMinGasPriceProvider(config.minerMinGasPrice())), new MinerUtils(), new BlockTxSignatureCache(new ReceivedTxSignatureCache()) ), 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 61f5b376e24..a953392a144 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 @@ -1,3 +1,20 @@ +/* + * This file is part of RskJ + * Copyright (C) 2024 RSK Labs Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ package co.rsk.mine.gas.provider; import co.rsk.config.mining.StableMinGasPriceSystemConfig; @@ -47,7 +64,7 @@ void createWebProviderMethod() { "web.url=url\n" + "web.timeout=1000 \n" + "web.apiKey=1234\n" + - "web.requestPath=price" + "web.requestPath=/price" ); StableMinGasPriceSystemConfig disabledConfig = new StableMinGasPriceSystemConfig(testConfig); 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 3a012c730cf..c430bfab2f2 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 @@ -1,3 +1,20 @@ +/* + * This file is part of RskJ + * Copyright (C) 2024 RSK Labs Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ package co.rsk.mine.gas.provider; import co.rsk.core.Coin; @@ -5,6 +22,8 @@ import org.junit.jupiter.api.Test; import org.mockito.Mockito; +import java.util.Optional; + import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.*; @@ -17,22 +36,22 @@ void setUp() { fallBackProvider = Mockito.mock(MinGasPriceProvider.class); when(fallBackProvider.getMinGasPrice()).thenReturn(10L); when(fallBackProvider.getType()).thenReturn(MinGasPriceProviderType.FIXED); - stableMinGasPriceProvider = new TestStableMingGasPriceProvider(fallBackProvider); + stableMinGasPriceProvider = new TestStableMingGasPriceProvider(fallBackProvider, 100); } @Test void testGetMinGasPrice() { long result = stableMinGasPriceProvider.getMinGasPrice(); - assertEquals(1L, result); + assertEquals(6L, result); verify(fallBackProvider, times(0)).getMinGasPrice(); } @Test void GetMinGasPriceUsesFallbackWhenReturnIsNull() { - stableMinGasPriceProvider = new TestStableMingGasPriceProvider(fallBackProvider) { + stableMinGasPriceProvider = new TestStableMingGasPriceProvider(fallBackProvider, 100) { @Override - public Long getStableMinGasPrice() { - return null; + public Optional getBtcExchangeRate() { + return Optional.empty(); } }; @@ -45,13 +64,13 @@ public Long getStableMinGasPrice() { @Test void testGetMinGasPriceAsCoin() { Coin result = stableMinGasPriceProvider.getMinGasPriceAsCoin(); - assertEquals(Coin.valueOf(1L), result); + assertEquals(Coin.valueOf(6L), result); } public static class TestStableMingGasPriceProvider extends StableMinGasPriceProvider { - protected TestStableMingGasPriceProvider(MinGasPriceProvider fallBackProvider) { - super(fallBackProvider); + protected TestStableMingGasPriceProvider(MinGasPriceProvider fallBackProvider, long minStableGasPrice) { + super(fallBackProvider, minStableGasPrice); } @Override @@ -60,8 +79,8 @@ public MinGasPriceProviderType getType() { } @Override - public Long getStableMinGasPrice() { - return 1L; + public Optional getBtcExchangeRate() { + return Optional.of(15L); } } } 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 4568c18cc96..b0562bca9d1 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 @@ -13,6 +13,7 @@ import org.junit.jupiter.params.provider.NullSource; import org.junit.jupiter.params.provider.ValueSource; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -46,6 +47,7 @@ public void beforeEach() { onChainMinGasPriceProvider = new OnChainMinGasPriceProvider( fallback_mock, + fallback_minGasPrice_fake, onChainMinGasPriceSystemConfig_mock, () -> ethModule_mock ); @@ -70,7 +72,7 @@ void constructorSetsFieldsCorrectly(String data_input) { when(config.from()).thenReturn("0xfrom"); when(config.data()).thenReturn(data_input); - OnChainMinGasPriceProvider provider = new OnChainMinGasPriceProvider(fallbackProvider, config, () -> ethModule_mock); + OnChainMinGasPriceProvider provider = new OnChainMinGasPriceProvider(fallbackProvider, fallback_minGasPrice_fake, config, () -> ethModule_mock); Assertions.assertEquals("0xaddress", provider.getToAddress()); } @@ -84,7 +86,7 @@ void constructorSetsFieldsToNullWhenConfigReturnsNull() { when(config.from()).thenReturn(null); when(config.data()).thenReturn(null); - OnChainMinGasPriceProvider provider = new OnChainMinGasPriceProvider(fallbackProvider, config, () -> ethModule_mock); + OnChainMinGasPriceProvider provider = new OnChainMinGasPriceProvider(fallbackProvider, fallback_minGasPrice_fake, config, () -> ethModule_mock); Assertions.assertNull(provider.getToAddress()); Assertions.assertNull(provider.getFromAddress()); @@ -96,9 +98,10 @@ void getStableMinGasPrice_callsEthModulesCallMethod() { String expectedPrice = "0x21"; when(ethModule_mock.call(any(), any())).thenReturn(expectedPrice); + assertTrue(onChainMinGasPriceProvider.getBtcExchangeRate().isPresent()); Assertions.assertEquals( HexUtils.jsonHexToLong(expectedPrice), - onChainMinGasPriceProvider.getStableMinGasPrice() + onChainMinGasPriceProvider.getBtcExchangeRate().get() ); } @@ -108,9 +111,10 @@ void getStableMinGasPrice_callsEthModulesCallMethod() { void getStableMinGasPrice_callsFallback_whenNoData(String data_input) { when(onChainMinGasPriceSystemConfig_mock.data()).thenReturn(data_input); + assertTrue(onChainMinGasPriceProvider.getBtcExchangeRate().isPresent()); Assertions.assertEquals( fallback_minGasPrice_fake, - onChainMinGasPriceProvider.getStableMinGasPrice(), + onChainMinGasPriceProvider.getBtcExchangeRate().get(), "For " + data_input + ": " ); } @@ -120,7 +124,7 @@ void getStableMinGasPrice_callsFallback_whenNoData(String data_input) { void getStableMinGasPrice_callsFallback_whenEthModuleIsNull() { Assertions.assertEquals( fallback_minGasPrice_fake, - onChainMinGasPriceProvider.getStableMinGasPrice() + onChainMinGasPriceProvider.getBtcExchangeRate().get() ); } diff --git a/rskj-core/src/test/java/co/rsk/mine/gas/provider/web/WebMinGasPriceProviderTest.java b/rskj-core/src/test/java/co/rsk/mine/gas/provider/web/WebMinGasPriceProviderTest.java new file mode 100644 index 00000000000..284abbd0d49 --- /dev/null +++ b/rskj-core/src/test/java/co/rsk/mine/gas/provider/web/WebMinGasPriceProviderTest.java @@ -0,0 +1,136 @@ +/* + * This file is part of RskJ + * Copyright (C) 2024 RSK Labs Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ +package co.rsk.mine.gas.provider.web; + +import co.rsk.config.mining.StableMinGasPriceSystemConfig; +import co.rsk.config.mining.WebStableMinGasSystemConfig; +import co.rsk.mine.gas.provider.MinGasPriceProvider; +import co.rsk.mine.gas.provider.MinGasPriceProviderType; +import co.rsk.net.http.HttpException; +import co.rsk.net.http.SimpleHttpClient; +import org.junit.jupiter.api.Test; + +import java.util.Optional; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.*; + +class WebMinGasPriceProviderTest { + + @Test + void returnsMappedPriceFromWebClient() throws HttpException { + MinGasPriceProvider fallbackProvider = mock(MinGasPriceProvider.class); + when(fallbackProvider.getType()).thenReturn(MinGasPriceProviderType.FIXED); + + SimpleHttpClient httpClient = mock(SimpleHttpClient.class); + when(httpClient.doGet(anyString())).thenReturn("{\"bitcoin\":{\"usd\":10000}}"); + StableMinGasPriceSystemConfig config = createStableMinGasPriceSystemConfig(); + WebMinGasPriceProvider provider = new WebMinGasPriceProvider(config, fallbackProvider, httpClient); + + Optional result = provider.getBtcExchangeRate(); + verify(fallbackProvider, times(0)).getMinGasPrice(); + assertTrue(result.isPresent()); + assertEquals(10000L, result.get()); + } + + @Test + void whenRequestingTheValueTwiceCachedValueIsUsed() throws HttpException { + MinGasPriceProvider fallbackProvider = mock(MinGasPriceProvider.class); + when(fallbackProvider.getType()).thenReturn(MinGasPriceProviderType.FIXED); + + SimpleHttpClient httpClient = mock(SimpleHttpClient.class); + when(httpClient.doGet(anyString())).thenReturn("{\"bitcoin\":{\"usd\":10000}}"); + StableMinGasPriceSystemConfig config = createStableMinGasPriceSystemConfig(); + WebMinGasPriceProvider provider = spy(new WebMinGasPriceProvider(config, fallbackProvider, httpClient)); + + provider.getMinGasPrice(); + provider.getMinGasPrice(); + + verify(provider, times(2)).getMinGasPrice(); + verify(httpClient, times(1)).doGet(anyString()); + } + + @Test + void whenEmptyResponseReturnsFallbackProvider() throws HttpException { + MinGasPriceProvider fallbackProvider = mock(MinGasPriceProvider.class); + when(fallbackProvider.getMinGasPrice()).thenReturn(10L); + when(fallbackProvider.getType()).thenReturn(MinGasPriceProviderType.FIXED); + + SimpleHttpClient httpClient = mock(SimpleHttpClient.class); + when(httpClient.doGet(anyString())).thenReturn(""); + StableMinGasPriceSystemConfig config = createStableMinGasPriceSystemConfig(); + WebMinGasPriceProvider provider = new WebMinGasPriceProvider(config, fallbackProvider, httpClient); + + Long result = provider.getMinGasPrice(); + verify(fallbackProvider, times(1)).getMinGasPrice(); + assertEquals(10L, result); + } + + @Test + void whenErrorReturnsFallbackProvider() throws HttpException { + MinGasPriceProvider fallbackProvider = mock(MinGasPriceProvider.class); + when(fallbackProvider.getMinGasPrice()).thenReturn(10L); + when(fallbackProvider.getType()).thenReturn(MinGasPriceProviderType.FIXED); + + SimpleHttpClient httpClient = mock(SimpleHttpClient.class); + when(httpClient.doGet(anyString())).thenThrow(new HttpException("Error")); + StableMinGasPriceSystemConfig config = createStableMinGasPriceSystemConfig(); + WebMinGasPriceProvider provider = new WebMinGasPriceProvider(config, fallbackProvider, httpClient); + + Long result = provider.getMinGasPrice(); + verify(fallbackProvider, times(1)).getMinGasPrice(); + assertEquals(10L, result); + } + + @Test + void whenPathIsWrongReturnsFallBack() throws HttpException { + MinGasPriceProvider fallbackProvider = mock(MinGasPriceProvider.class); + when(fallbackProvider.getMinGasPrice()).thenReturn(10L); + when(fallbackProvider.getType()).thenReturn(MinGasPriceProviderType.FIXED); + + SimpleHttpClient httpClient = mock(SimpleHttpClient.class); + when(httpClient.doGet(anyString())).thenReturn("{\"btc\":{\"usd\":10000}}"); + StableMinGasPriceSystemConfig config = createStableMinGasPriceSystemConfig(); + WebMinGasPriceProvider provider = new WebMinGasPriceProvider(config, fallbackProvider, httpClient); + + Long result = provider.getMinGasPrice(); + + verify(fallbackProvider, times(1)).getMinGasPrice(); + assertEquals(10L, result); + } + + private StableMinGasPriceSystemConfig createStableMinGasPriceSystemConfig() { + StableMinGasPriceSystemConfig config = mock(StableMinGasPriceSystemConfig.class); + WebStableMinGasSystemConfig webConfig = createWebStableSystemConfig(); + when(config.getWebConfig()).thenReturn(webConfig); + when(config.getMinStableGasPrice()).thenReturn(4265280000000L); + when(config.getRefreshRate()).thenReturn(30); + return config; + } + + private WebStableMinGasSystemConfig createWebStableSystemConfig() { + WebStableMinGasSystemConfig config = mock(WebStableMinGasSystemConfig.class); + when(config.getRequestPath()).thenReturn("/bitcoin/usd"); + when(config.getUrl()).thenReturn("https://rsk.co/price?ids=bitcoin&vs_currencies=usd"); + when(config.getTimeout()).thenReturn(3000); + return config; + } + +} \ No newline at end of file diff --git a/rskj-core/src/test/java/co/rsk/net/http/SimpleHttpClientIntTest.java b/rskj-core/src/test/java/co/rsk/net/http/SimpleHttpClientIntTest.java new file mode 100644 index 00000000000..1c4c1d6a426 --- /dev/null +++ b/rskj-core/src/test/java/co/rsk/net/http/SimpleHttpClientIntTest.java @@ -0,0 +1,111 @@ +/* + * This file is part of RskJ + * Copyright (C) 2024 RSK Labs Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ +package co.rsk.net.http; + +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.util.Random; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +@Disabled("Use this class to check the behavior of the SimpleHttpClient class. Disabled by default to not run in CI.") +public class SimpleHttpClientIntTest { + private static SimpleHttpTestServer server; + private static String baseUrl; + private static int port; + + + @BeforeAll + public static void setUp() throws Exception { + port = generateRandomPort(); + server = new SimpleHttpTestServer(); + Thread serverThread = new Thread(new Runnable() { + @Override + public void run() { + try { + server.start(port); + } catch (IOException e) { + e.printStackTrace(); + } + } + }); + serverThread.setDaemon(true); + serverThread.start(); + // Give the server a second to ensure it's up and running + Thread.sleep(1000); + baseUrl = "http://localhost:" + port; + } + + @AfterAll + public static void tearDown() { + server.stop(); + } + + @Test + void testGetRequest() throws HttpException { + SimpleHttpClient client = new SimpleHttpClient(25000); // 5 seconds timeout + String response = client.doGet(baseUrl + SimpleHttpTestServer.HELLO_PATH); + assertEquals(SimpleHttpTestServer.HELLO_RESPONSE, response); + } + + @Test + void testNotFoundRequest() { + SimpleHttpClient client = new SimpleHttpClient(25000); + HttpException exception = assertThrows(HttpException.class, () -> { + client.doGet(baseUrl + SimpleHttpTestServer.NOT_FOUND_PATH); + }); + assertEquals("Http request failed with code : 404 - Not Found", exception.getMessage()); + } + + @Test + void testInternalServerError() { + SimpleHttpClient client = new SimpleHttpClient(25000); + HttpException exception = assertThrows(HttpException.class, () -> { + client.doGet(baseUrl + SimpleHttpTestServer.ERROR_PATH); + }); + assertEquals("Http request failed with code : 500 - Internal Server Error", exception.getMessage()); + } + + @Test + void testInvalidUrl() { + SimpleHttpClient client = new SimpleHttpClient(25000); + assertThrows(HttpException.class, () -> { + client.doGet("invalid_url"); + }); + } + + @Test + void testTimeout() { + SimpleHttpClient client = new SimpleHttpClient(1); // set timeout to 1 ms + assertThrows(HttpException.class, () -> { + client.doGet(baseUrl + SimpleHttpTestServer.SLOW_PATH); + }); + } + + private static int generateRandomPort() { + Random random = new Random(); + int minPort = 49152; + int maxPort = 65535; + return random.nextInt((maxPort - minPort) + 1) + minPort; + } +} diff --git a/rskj-core/src/test/java/co/rsk/net/http/SimpleHttpTestServer.java b/rskj-core/src/test/java/co/rsk/net/http/SimpleHttpTestServer.java new file mode 100644 index 00000000000..42140f780e4 --- /dev/null +++ b/rskj-core/src/test/java/co/rsk/net/http/SimpleHttpTestServer.java @@ -0,0 +1,101 @@ +/* + * This file is part of RskJ + * Copyright (C) 2024 RSK Labs Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ +package co.rsk.net.http; + +import com.sun.net.httpserver.HttpServer; +import com.sun.net.httpserver.HttpHandler; +import com.sun.net.httpserver.HttpExchange; + +import java.io.IOException; +import java.io.OutputStream; +import java.net.InetSocketAddress; + +public class SimpleHttpTestServer { + + protected static final String HELLO_RESPONSE = "Hello, world!"; + protected static final String NOT_FOUND_RESPONSE = "Not Found"; + protected static final String ERROR_RESPONSE = "Internal Server Error"; + protected static final String SLOW_RESPONSE = "Slow Response"; + protected static final String HELLO_PATH = "/hello"; + protected static final String NOT_FOUND_PATH = "/notfound"; + protected static final String ERROR_PATH = "/error"; + protected static final String SLOW_PATH = "/slow"; private HttpServer server; + + public void start(int port) throws IOException { + server = HttpServer.create(new InetSocketAddress(port), 0); + server.createContext(HELLO_PATH, new HelloHandler()); + server.createContext(NOT_FOUND_PATH, new NotFoundHandler()); + server.createContext(ERROR_PATH, new ErrorHandler()); + server.createContext(SLOW_PATH, new SlowHandler()); + server.setExecutor(null); // creates a default executor + server.start(); + } + + public void stop() { + server.stop(0); + } + + static class HelloHandler implements HttpHandler { + @Override + public void handle(HttpExchange t) throws IOException { + String response = HELLO_RESPONSE; + t.sendResponseHeaders(200, response.length()); + OutputStream os = t.getResponseBody(); + os.write(response.getBytes()); + os.close(); + } + } + + static class NotFoundHandler implements HttpHandler { + @Override + public void handle(HttpExchange t) throws IOException { + String response = NOT_FOUND_RESPONSE; + t.sendResponseHeaders(404, response.length()); + OutputStream os = t.getResponseBody(); + os.write(response.getBytes()); + os.close(); + } + } + + static class ErrorHandler implements HttpHandler { + @Override + public void handle(HttpExchange t) throws IOException { + String response = ERROR_RESPONSE; + t.sendResponseHeaders(500, response.length()); + OutputStream os = t.getResponseBody(); + os.write(response.getBytes()); + os.close(); + } + } + + static class SlowHandler implements HttpHandler { + @Override + public void handle(HttpExchange t) throws IOException { + try { + Thread.sleep(5000); // sleep for 5 seconds to simulate slow response + } catch (InterruptedException e) { + e.printStackTrace(); + } + String response = SLOW_RESPONSE; + t.sendResponseHeaders(200, response.length()); + OutputStream os = t.getResponseBody(); + os.write(response.getBytes()); + os.close(); + } + } +} diff --git a/rskj-core/src/test/java/co/rsk/rpc/modules/trace/TraceModuleImplTest.java b/rskj-core/src/test/java/co/rsk/rpc/modules/trace/TraceModuleImplTest.java index 435cbf276c6..5bb6f6853db 100644 --- a/rskj-core/src/test/java/co/rsk/rpc/modules/trace/TraceModuleImplTest.java +++ b/rskj-core/src/test/java/co/rsk/rpc/modules/trace/TraceModuleImplTest.java @@ -436,8 +436,7 @@ private static ExecutionBlockRetriever createExecutionBlockRetriever(World world rskSystemProperties.getForceTargetGasLimit() ), rskSystemProperties.isMinerServerFixedClock(), - rskSystemProperties.workSubmissionRateLimitInMills(), - new FixedMinGasPriceProvider(rskSystemProperties.minerMinGasPrice()) + rskSystemProperties.workSubmissionRateLimitInMills() ); BlockToMineBuilder builder = new BlockToMineBuilder( rskSystemProperties.getActivationConfig(), @@ -455,7 +454,7 @@ private static ExecutionBlockRetriever createExecutionBlockRetriever(World world new MinerClock(miningConfig.isFixedClock(), Clock.systemUTC()), new BlockFactory(rskSystemProperties.getActivationConfig()), world.getBlockExecutor(), - new MinimumGasPriceCalculator(miningConfig.getMinGasPriceProvider()), + new MinimumGasPriceCalculator(new FixedMinGasPriceProvider(rskSystemProperties.minerMinGasPrice())), new MinerUtils(), world.getBlockTxSignatureCache() ); diff --git a/rskj-core/src/test/java/org/ethereum/rpc/Web3ImplSnapshotTest.java b/rskj-core/src/test/java/org/ethereum/rpc/Web3ImplSnapshotTest.java index 000b37ec4b5..9084e7a08e9 100644 --- a/rskj-core/src/test/java/org/ethereum/rpc/Web3ImplSnapshotTest.java +++ b/rskj-core/src/test/java/org/ethereum/rpc/Web3ImplSnapshotTest.java @@ -26,6 +26,7 @@ import co.rsk.core.bc.BlockChainStatus; import co.rsk.core.bc.MiningMainchainView; import co.rsk.mine.*; +import co.rsk.mine.gas.provider.FixedMinGasPriceProvider; import co.rsk.rpc.modules.debug.DebugModule; import co.rsk.rpc.modules.debug.DebugModuleImpl; import co.rsk.rpc.modules.evm.EvmModule; @@ -233,7 +234,7 @@ private MinerServer getMinerServerForTest(SimpleEthereum ethereum, MinerClock cl clock, blockFactory, factory.getBlockExecutor(), - new MinimumGasPriceCalculator(miningConfig.getMinGasPriceProvider()), + new MinimumGasPriceCalculator(new FixedMinGasPriceProvider(config.minerMinGasPrice())), new MinerUtils(), new BlockTxSignatureCache(new ReceivedTxSignatureCache()) ), From 26fa303effd11089bd7b7f77d99862e6fbc41399 Mon Sep 17 00:00:00 2001 From: Angel Soto Date: Thu, 13 Jun 2024 19:28:37 +0200 Subject: [PATCH 09/17] Updating tests --- .../OnChainMinGasPriceProviderTest.java | 21 ++++++------------- 1 file changed, 6 insertions(+), 15 deletions(-) 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 b0562bca9d1..2449831bbad 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 @@ -13,17 +13,14 @@ import org.junit.jupiter.params.provider.NullSource; import org.junit.jupiter.params.provider.ValueSource; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; 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; @@ -40,8 +37,11 @@ public void beforeEach() { when(fallback_mock.getMinGasPrice()).thenReturn(fallback_minGasPrice_fake); onChainMinGasPriceSystemConfig_mock = mock(OnChainMinGasPriceSystemConfig.class); + String oracle_address = "0xbffBD993FF1d229B0FfE55668F2009d20d4F7C5f"; when(onChainMinGasPriceSystemConfig_mock.address()).thenReturn(oracle_address); + String from_address = "0xbffBD993FF1d229B0FfE55668F2009d20d4F7C5f"; when(onChainMinGasPriceSystemConfig_mock.from()).thenReturn(from_address); + String data = "0x"; when(onChainMinGasPriceSystemConfig_mock.data()).thenReturn(data); @@ -60,7 +60,6 @@ public void afterEach() { } - @ParameterizedTest @NullSource @ValueSource(strings = {"0x123", "0xabc"}) @@ -111,21 +110,13 @@ void getStableMinGasPrice_callsEthModulesCallMethod() { void getStableMinGasPrice_callsFallback_whenNoData(String data_input) { when(onChainMinGasPriceSystemConfig_mock.data()).thenReturn(data_input); - assertTrue(onChainMinGasPriceProvider.getBtcExchangeRate().isPresent()); - Assertions.assertEquals( - fallback_minGasPrice_fake, - onChainMinGasPriceProvider.getBtcExchangeRate().get(), - "For " + data_input + ": " - ); + assertFalse(onChainMinGasPriceProvider.getBtcExchangeRate().isPresent()); } @Test void getStableMinGasPrice_callsFallback_whenEthModuleIsNull() { - Assertions.assertEquals( - fallback_minGasPrice_fake, - onChainMinGasPriceProvider.getBtcExchangeRate().get() - ); + assertFalse(onChainMinGasPriceProvider.getBtcExchangeRate().isPresent()); } @Test From 6b106265a6470797791e3f69ef2e6e40a965fbaf Mon Sep 17 00:00:00 2001 From: Angel Soto Date: Thu, 20 Jun 2024 12:22:37 +0200 Subject: [PATCH 10/17] Addressing pr comments with a small refactor --- .../OnChainMinGasPriceSystemConfig.java | 7 ++-- .../provider/MinGasPriceProviderFactory.java | 2 +- .../provider/StableMinGasPriceProvider.java | 3 +- .../onchain/OnChainMinGasPriceProvider.java | 13 ++++--- .../co/rsk/net/http/SimpleHttpClient.java | 4 +-- .../OnChainMinGasPriceSystemConfigTest.java | 6 ++-- .../OnChainMinGasPriceProviderTest.java | 36 ++++++++++--------- 7 files changed, 39 insertions(+), 32 deletions(-) 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 018ca648bce..607945e36ee 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 @@ -4,7 +4,6 @@ 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"; @@ -18,15 +17,15 @@ public OnChainMinGasPriceSystemConfig(Config config) { data = config.getString(DATA_PROPERTY); } - public String address() { + public String getAddress() { return address; } - public String from() { + public String getFrom() { return from; } - public String data() { + public String getData() { 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 ecb78364183..f1e4a8a917e 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 @@ -35,7 +35,7 @@ public static MinGasPriceProvider create(long fixedMinGasPrice, StableMinGasPric case WEB: return new WebMinGasPriceProvider(stableMinGasPriceSystemConfig, fixedMinGasPriceProvider); case ON_CHAIN: - return new OnChainMinGasPriceProvider(fixedMinGasPriceProvider, stableMinGasPriceSystemConfig.getMinStableGasPrice(), stableMinGasPriceSystemConfig.getOnChainConfig(), getContextCallback); + return new OnChainMinGasPriceProvider(fixedMinGasPriceProvider, stableMinGasPriceSystemConfig, 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 38324434db2..a5bdfd7d3a0 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 @@ -27,6 +27,7 @@ public abstract class StableMinGasPriceProvider implements MinGasPriceProvider { private static final Logger logger = LoggerFactory.getLogger("StableMinGasPrice"); private final MinGasPriceProvider fallBackProvider; private final long minStableGasPrice; + protected StableMinGasPriceProvider(MinGasPriceProvider fallBackProvider, long minStableGasPrice) { this.minStableGasPrice = minStableGasPrice; this.fallBackProvider = fallBackProvider; @@ -48,7 +49,7 @@ public long getMinGasPrice() { } private long calculateMinGasPriceBasedOnBtcPrice(long btcValue) { - if(minStableGasPrice == 0 || btcValue == 0) { + if (minStableGasPrice == 0 || btcValue == 0) { return 0; } return minStableGasPrice / btcValue; 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 ce3dee06c9e..9e8ef4cf64e 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 @@ -1,6 +1,7 @@ package co.rsk.mine.gas.provider.onchain; import co.rsk.config.mining.OnChainMinGasPriceSystemConfig; +import co.rsk.config.mining.StableMinGasPriceSystemConfig; import co.rsk.mine.gas.provider.MinGasPriceProvider; import co.rsk.mine.gas.provider.MinGasPriceProviderType; import co.rsk.mine.gas.provider.StableMinGasPriceProvider; @@ -22,6 +23,7 @@ public class OnChainMinGasPriceProvider extends StableMinGasPriceProvider { private final String toAddress; private final String fromAddress; private final String data; + @FunctionalInterface public interface GetContextCallback { EthModule getEthModule(); @@ -29,12 +31,13 @@ public interface GetContextCallback { private final GetContextCallback getContextCallback; - public OnChainMinGasPriceProvider(MinGasPriceProvider fallBackProvider, long minStableGasPrice, OnChainMinGasPriceSystemConfig config, GetContextCallback getContextCallback) { - super(fallBackProvider, minStableGasPrice); + public OnChainMinGasPriceProvider(MinGasPriceProvider fallBackProvider, StableMinGasPriceSystemConfig config, GetContextCallback getContextCallback) { + super(fallBackProvider, config.getMinStableGasPrice()); this.getContextCallback = getContextCallback; - this.toAddress = config.address(); - this.fromAddress = config.from(); - this.data = config.data(); + OnChainMinGasPriceSystemConfig oConfig = config.getOnChainConfig(); + this.toAddress = oConfig.getAddress(); + this.fromAddress = oConfig.getFrom(); + this.data = oConfig.getData(); } @Override diff --git a/rskj-core/src/main/java/co/rsk/net/http/SimpleHttpClient.java b/rskj-core/src/main/java/co/rsk/net/http/SimpleHttpClient.java index 177515760c5..c4868336c4b 100644 --- a/rskj-core/src/main/java/co/rsk/net/http/SimpleHttpClient.java +++ b/rskj-core/src/main/java/co/rsk/net/http/SimpleHttpClient.java @@ -41,8 +41,8 @@ public String doGet(String targetUrl) throws HttpException { URL url = new URL(targetUrl); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setRequestMethod(GET_METHOD); - conn.setConnectTimeout(timeoutMillis); // Set connection timeout to 30 seconds - conn.setReadTimeout(timeoutMillis); // Set read timeout to 30 seconds + conn.setConnectTimeout(timeoutMillis); + conn.setReadTimeout(timeoutMillis); int responseCode = conn.getResponseCode(); if (responseCode >= 300 || responseCode < 200) { 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 index 2458b275c83..40155c7ef2a 100644 --- a/rskj-core/src/test/java/co/rsk/config/mining/OnChainMinGasPriceSystemConfigTest.java +++ b/rskj-core/src/test/java/co/rsk/config/mining/OnChainMinGasPriceSystemConfigTest.java @@ -25,16 +25,16 @@ void setUp() { @Test void testAddress() { - assertEquals(address, config.address()); + assertEquals(address, config.getAddress()); } @Test void testFrom() { - assertEquals(from, config.from()); + assertEquals(from, config.getFrom()); } @Test void testData() { - assertEquals(data, config.data()); + assertEquals(data, config.getData()); } } 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 2449831bbad..04addde4c19 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 @@ -1,6 +1,7 @@ package co.rsk.mine.gas.provider.onchain; import co.rsk.config.mining.OnChainMinGasPriceSystemConfig; +import co.rsk.config.mining.StableMinGasPriceSystemConfig; import co.rsk.mine.gas.provider.MinGasPriceProvider; import co.rsk.mine.gas.provider.MinGasPriceProviderType; import co.rsk.util.HexUtils; @@ -20,12 +21,11 @@ import static org.mockito.Mockito.when; class OnChainMinGasPriceProviderTest { - private final long fallback_minGasPrice_fake = 1234567890L; private EthModule ethModule_mock; private MinGasPriceProvider fallback_mock; private OnChainMinGasPriceSystemConfig onChainMinGasPriceSystemConfig_mock; - private OnChainMinGasPriceProvider onChainMinGasPriceProvider; + private StableMinGasPriceSystemConfig stableMinGasPriceSystemConfig; @BeforeEach public void beforeEach() { @@ -34,21 +34,25 @@ public void beforeEach() { fallback_mock = mock(MinGasPriceProvider.class); when(fallback_mock.getType()).thenReturn(MinGasPriceProviderType.FIXED); + long fallback_minGasPrice_fake = 1234567890L; when(fallback_mock.getMinGasPrice()).thenReturn(fallback_minGasPrice_fake); onChainMinGasPriceSystemConfig_mock = mock(OnChainMinGasPriceSystemConfig.class); String oracle_address = "0xbffBD993FF1d229B0FfE55668F2009d20d4F7C5f"; - when(onChainMinGasPriceSystemConfig_mock.address()).thenReturn(oracle_address); + when(onChainMinGasPriceSystemConfig_mock.getAddress()).thenReturn(oracle_address); String from_address = "0xbffBD993FF1d229B0FfE55668F2009d20d4F7C5f"; - when(onChainMinGasPriceSystemConfig_mock.from()).thenReturn(from_address); + when(onChainMinGasPriceSystemConfig_mock.getFrom()).thenReturn(from_address); String data = "0x"; - when(onChainMinGasPriceSystemConfig_mock.data()).thenReturn(data); + when(onChainMinGasPriceSystemConfig_mock.getData()).thenReturn(data); + + stableMinGasPriceSystemConfig = mock(StableMinGasPriceSystemConfig.class); + when(stableMinGasPriceSystemConfig.getOnChainConfig()).thenReturn(onChainMinGasPriceSystemConfig_mock); + when(stableMinGasPriceSystemConfig.getMinStableGasPrice()).thenReturn(fallback_minGasPrice_fake); onChainMinGasPriceProvider = new OnChainMinGasPriceProvider( fallback_mock, - fallback_minGasPrice_fake, - onChainMinGasPriceSystemConfig_mock, + stableMinGasPriceSystemConfig, () -> ethModule_mock ); } @@ -67,11 +71,11 @@ 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); + when(config.getAddress()).thenReturn("0xaddress"); + when(config.getFrom()).thenReturn("0xfrom"); + when(config.getData()).thenReturn(data_input); - OnChainMinGasPriceProvider provider = new OnChainMinGasPriceProvider(fallbackProvider, fallback_minGasPrice_fake, config, () -> ethModule_mock); + OnChainMinGasPriceProvider provider = new OnChainMinGasPriceProvider(fallbackProvider, stableMinGasPriceSystemConfig, () -> ethModule_mock); Assertions.assertEquals("0xaddress", provider.getToAddress()); } @@ -81,11 +85,11 @@ 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); + when(config.getAddress()).thenReturn(null); + when(config.getFrom()).thenReturn(null); + when(config.getData()).thenReturn(null); - OnChainMinGasPriceProvider provider = new OnChainMinGasPriceProvider(fallbackProvider, fallback_minGasPrice_fake, config, () -> ethModule_mock); + OnChainMinGasPriceProvider provider = new OnChainMinGasPriceProvider(fallbackProvider, stableMinGasPriceSystemConfig, () -> ethModule_mock); Assertions.assertNull(provider.getToAddress()); Assertions.assertNull(provider.getFromAddress()); @@ -108,7 +112,7 @@ void getStableMinGasPrice_callsEthModulesCallMethod() { @NullSource @ValueSource(strings = {"", "0x"}) void getStableMinGasPrice_callsFallback_whenNoData(String data_input) { - when(onChainMinGasPriceSystemConfig_mock.data()).thenReturn(data_input); + when(onChainMinGasPriceSystemConfig_mock.getData()).thenReturn(data_input); assertFalse(onChainMinGasPriceProvider.getBtcExchangeRate().isPresent()); } From 4d5e1d8df57f32fb8694a1555f542eb93fa11a85 Mon Sep 17 00:00:00 2001 From: Angel Soto Date: Thu, 20 Jun 2024 17:56:55 +0200 Subject: [PATCH 11/17] fix test --- .../provider/onchain/OnChainMinGasPriceProviderTest.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) 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 04addde4c19..cab65e3ce86 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 @@ -69,7 +69,7 @@ public void afterEach() { @ValueSource(strings = {"0x123", "0xabc"}) void constructorSetsFieldsCorrectly(String data_input) { MinGasPriceProvider fallbackProvider = mock(MinGasPriceProvider.class); - OnChainMinGasPriceSystemConfig config = mock(OnChainMinGasPriceSystemConfig.class); + OnChainMinGasPriceSystemConfig config = stableMinGasPriceSystemConfig.getOnChainConfig(); when(config.getAddress()).thenReturn("0xaddress"); when(config.getFrom()).thenReturn("0xfrom"); @@ -83,12 +83,12 @@ void constructorSetsFieldsCorrectly(String data_input) { @Test void constructorSetsFieldsToNullWhenConfigReturnsNull() { MinGasPriceProvider fallbackProvider = mock(MinGasPriceProvider.class); - OnChainMinGasPriceSystemConfig config = mock(OnChainMinGasPriceSystemConfig.class); - + OnChainMinGasPriceSystemConfig config = stableMinGasPriceSystemConfig.getOnChainConfig(); when(config.getAddress()).thenReturn(null); when(config.getFrom()).thenReturn(null); when(config.getData()).thenReturn(null); + OnChainMinGasPriceProvider provider = new OnChainMinGasPriceProvider(fallbackProvider, stableMinGasPriceSystemConfig, () -> ethModule_mock); Assertions.assertNull(provider.getToAddress()); From 002510e717fc22f58c3b4c4c567f4abe9bdb221a Mon Sep 17 00:00:00 2001 From: Angel Soto Date: Thu, 20 Jun 2024 19:32:47 +0200 Subject: [PATCH 12/17] Addressing PR improvement and unifiying refresh rate logic into the abstract provider --- .../provider/StableMinGasPriceProvider.java | 33 ++++++++++++++----- .../onchain/OnChainMinGasPriceProvider.java | 2 +- .../provider/web/WebMinGasPriceProvider.java | 27 ++++----------- .../co/rsk/net/http/SimpleHttpClient.java | 13 ++++---- .../StableMinGasPriceProviderTest.java | 22 ++++++++++--- 5 files changed, 56 insertions(+), 41 deletions(-) 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 a5bdfd7d3a0..ff415c0f6d6 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 @@ -21,30 +21,38 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.time.Instant; import java.util.Optional; public abstract class StableMinGasPriceProvider implements MinGasPriceProvider { private static final Logger logger = LoggerFactory.getLogger("StableMinGasPrice"); private final MinGasPriceProvider fallBackProvider; private final long minStableGasPrice; + private Long lastMinGasPrice; + private long lastUpdateTimeStamp; + private final int refreshRateMillis; - protected StableMinGasPriceProvider(MinGasPriceProvider fallBackProvider, long minStableGasPrice) { + + protected StableMinGasPriceProvider(MinGasPriceProvider fallBackProvider, long minStableGasPrice, int refreshRateInSeconds) { this.minStableGasPrice = minStableGasPrice; this.fallBackProvider = fallBackProvider; + this.lastMinGasPrice = 0L; + this.refreshRateMillis = refreshRateInSeconds * 1000; } protected abstract Optional getBtcExchangeRate(); @Override public long getMinGasPrice() { - Optional btcValueOpt = getBtcExchangeRate(); - if (btcValueOpt.isPresent()) { - long btcValue = btcValueOpt.get(); - if (btcValue >= 0) { - return calculateMinGasPriceBasedOnBtcPrice(btcValue); - } + long currentTime = Instant.now().getEpochSecond(); + if (currentTime - lastUpdateTimeStamp >= refreshRateMillis) { + fetchPrice(); + } + // time it is always updated, it is not taken into account if the price was really updated or not. + lastUpdateTimeStamp = currentTime; + if (lastMinGasPrice != null && lastMinGasPrice > 0) { + return lastMinGasPrice; } - logger.error("Could not get stable min gas price from method {}, using fallback provider: {}", this.getType().name(), fallBackProvider.getType().name()); return fallBackProvider.getMinGasPrice(); } @@ -59,4 +67,13 @@ private long calculateMinGasPriceBasedOnBtcPrice(long btcValue) { public Coin getMinGasPriceAsCoin() { return Coin.valueOf(getMinGasPrice()); } + + private void fetchPrice() { + Optional priceResponse = getBtcExchangeRate(); + if (priceResponse.isPresent() && priceResponse.get() > 0) { + lastMinGasPrice = calculateMinGasPriceBasedOnBtcPrice(priceResponse.get()); + } else { + logger.warn("Gas price was not updated as it was not possible to obtain valid price from provider"); + } + } } 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 9e8ef4cf64e..a3673c93489 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 @@ -32,7 +32,7 @@ public interface GetContextCallback { private final GetContextCallback getContextCallback; public OnChainMinGasPriceProvider(MinGasPriceProvider fallBackProvider, StableMinGasPriceSystemConfig config, GetContextCallback getContextCallback) { - super(fallBackProvider, config.getMinStableGasPrice()); + super(fallBackProvider, config.getMinStableGasPrice(), config.getRefreshRate()); this.getContextCallback = getContextCallback; OnChainMinGasPriceSystemConfig oConfig = config.getOnChainConfig(); this.toAddress = oConfig.getAddress(); 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 b31a5af1290..de9ce1fbfc0 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 @@ -30,7 +30,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.time.Instant; import java.util.Optional; public class WebMinGasPriceProvider extends StableMinGasPriceProvider { @@ -38,53 +37,39 @@ public class WebMinGasPriceProvider extends StableMinGasPriceProvider { private final String url; private final JsonPointer jsonPath; private final int timeout; - private final int refreshRateMillis; private final SimpleHttpClient httpClient; private final ObjectMapper objectMapper; - private Long lastPrice; - private int lastUpdateTimeStamp; public WebMinGasPriceProvider(StableMinGasPriceSystemConfig config, MinGasPriceProvider fallBackProvider) { - super(fallBackProvider, config.getMinStableGasPrice()); + super(fallBackProvider, config.getMinStableGasPrice(), config.getRefreshRate()); WebStableMinGasSystemConfig webConfig = config.getWebConfig(); url = webConfig.getUrl(); jsonPath = JsonPointer.valueOf(webConfig.getRequestPath()); timeout = webConfig.getTimeout(); - refreshRateMillis = config.getRefreshRate() * 1000; httpClient = new SimpleHttpClient(webConfig.getTimeout()); objectMapper = new ObjectMapper(); } + public WebMinGasPriceProvider(StableMinGasPriceSystemConfig config, MinGasPriceProvider fallBackProvider, SimpleHttpClient httpClient) { - super(fallBackProvider, config.getMinStableGasPrice()); + super(fallBackProvider, config.getMinStableGasPrice(), config.getRefreshRate()); WebStableMinGasSystemConfig webConfig = config.getWebConfig(); url = webConfig.getUrl(); jsonPath = JsonPointer.valueOf(webConfig.getRequestPath()); timeout = webConfig.getTimeout(); - refreshRateMillis = config.getRefreshRate() * 1000; this.httpClient = httpClient; objectMapper = new ObjectMapper(); } @Override protected Optional getBtcExchangeRate() { - int currentTime = (int) Instant.now().getEpochSecond(); - if (currentTime - lastUpdateTimeStamp >= refreshRateMillis) { - fetchPrice(); - } - // time it is always updated, it is not taken into account if the price was really updated or not. - lastUpdateTimeStamp = currentTime; - return Optional.ofNullable(lastPrice); - } - - private void fetchPrice() { String response = getResponseFromWeb(); if (!StringUtils.isBlank(response)) { Long price = parsePrice(response); - if (price != null && price > 0) { - lastPrice = price; - } + return Optional.ofNullable(price); } + logger.error("Error getting min gas price from web provider, empty response."); + return Optional.empty(); } private Long parsePrice(String response) { diff --git a/rskj-core/src/main/java/co/rsk/net/http/SimpleHttpClient.java b/rskj-core/src/main/java/co/rsk/net/http/SimpleHttpClient.java index c4868336c4b..43ce735498a 100644 --- a/rskj-core/src/main/java/co/rsk/net/http/SimpleHttpClient.java +++ b/rskj-core/src/main/java/co/rsk/net/http/SimpleHttpClient.java @@ -38,8 +38,7 @@ public SimpleHttpClient(int timeoutMillis) { public String doGet(String targetUrl) throws HttpException { StringBuilder response = new StringBuilder(); try { - URL url = new URL(targetUrl); - HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + HttpURLConnection conn = (HttpURLConnection) new URL(targetUrl).openConnection(); conn.setRequestMethod(GET_METHOD); conn.setConnectTimeout(timeoutMillis); conn.setReadTimeout(timeoutMillis); @@ -50,12 +49,12 @@ public String doGet(String targetUrl) throws HttpException { throw new HttpException("Http request failed with code : " + responseCode + " - " + responseMessage); } - BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream())); - String line; - while ((line = reader.readLine()) != null) { - response.append(line); + try (BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()))) { + String line; + while ((line = reader.readLine()) != null) { + response.append(line); + } } - reader.close(); } catch (HttpException httpException) { throw httpException; } catch (UnknownHostException unknownHostException) { 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 c430bfab2f2..0a0d0b21e2d 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 @@ -36,7 +36,7 @@ void setUp() { fallBackProvider = Mockito.mock(MinGasPriceProvider.class); when(fallBackProvider.getMinGasPrice()).thenReturn(10L); when(fallBackProvider.getType()).thenReturn(MinGasPriceProviderType.FIXED); - stableMinGasPriceProvider = new TestStableMingGasPriceProvider(fallBackProvider, 100); + stableMinGasPriceProvider = new TestStableMingGasPriceProvider(fallBackProvider, 100, 10); } @Test @@ -48,7 +48,7 @@ void testGetMinGasPrice() { @Test void GetMinGasPriceUsesFallbackWhenReturnIsNull() { - stableMinGasPriceProvider = new TestStableMingGasPriceProvider(fallBackProvider, 100) { + stableMinGasPriceProvider = new TestStableMingGasPriceProvider(fallBackProvider, 100, 10) { @Override public Optional getBtcExchangeRate() { return Optional.empty(); @@ -61,16 +61,30 @@ public Optional getBtcExchangeRate() { verify(fallBackProvider, times(1)).getMinGasPrice(); } + @Test + void whenRequestingTheValueTwiceCachedValueIsUsed() { + MinGasPriceProvider fallbackProvider = mock(MinGasPriceProvider.class); + when(fallbackProvider.getType()).thenReturn(MinGasPriceProviderType.FIXED); + + stableMinGasPriceProvider = spy(new TestStableMingGasPriceProvider(fallBackProvider, 100, 10)); + + stableMinGasPriceProvider.getMinGasPrice(); + stableMinGasPriceProvider.getMinGasPrice(); + + verify(stableMinGasPriceProvider, times(2)).getMinGasPrice(); + verify(stableMinGasPriceProvider, times(1)).getBtcExchangeRate(); + } @Test void testGetMinGasPriceAsCoin() { Coin result = stableMinGasPriceProvider.getMinGasPriceAsCoin(); assertEquals(Coin.valueOf(6L), result); } + public static class TestStableMingGasPriceProvider extends StableMinGasPriceProvider { - protected TestStableMingGasPriceProvider(MinGasPriceProvider fallBackProvider, long minStableGasPrice) { - super(fallBackProvider, minStableGasPrice); + protected TestStableMingGasPriceProvider(MinGasPriceProvider fallBackProvider, long minStableGasPrice, int refreshRateSeconds) { + super(fallBackProvider, minStableGasPrice, refreshRateSeconds); } @Override From 9c5f7220a4b119fc2e82c2a5ac700af8633f21a2 Mon Sep 17 00:00:00 2001 From: Volodymyr Kravets Date: Wed, 17 Jul 2024 14:54:04 +0300 Subject: [PATCH 13/17] feat(stableMinGasPrice): refactoring --- .../src/main/java/co/rsk/RskContext.java | 3 +- .../EthCallMinGasPriceSystemConfig.java | 48 ++++++++++++++ ...a => HttpGetStableMinGasSystemConfig.java} | 15 ++--- .../OnChainMinGasPriceSystemConfig.java | 31 --------- .../mining/StableMinGasPriceSystemConfig.java | 26 ++++---- ...r.java => EthCallMinGasPriceProvider.java} | 53 ++++++++------- .../provider/FixedMinGasPriceProvider.java | 19 +++++- ...r.java => HttpGetMinGasPriceProvider.java} | 35 ++++------ .../gas/provider/MinGasPriceProvider.java | 18 +++++ .../provider/MinGasPriceProviderFactory.java | 36 +++++++--- .../gas/provider/MinGasPriceProviderType.java | 22 ++++++- rskj-core/src/main/resources/expected.conf | 12 +++- rskj-core/src/main/resources/reference.conf | 28 +++++++- .../EthCallMinGasPriceSystemConfigTest.java | 58 ++++++++++++++++ ... HttpGetStableMinGasSystemConfigTest.java} | 10 +-- .../OnChainMinGasPriceSystemConfigTest.java | 40 ----------- .../StableMinGasPriceSystemConfigTest.java | 10 +-- .../gas/FixedMinGasPriceProviderTest.java | 21 +++++- ...va => EthCallMinGasPriceProviderTest.java} | 66 ++++++++++++------- ...va => HttpGetMinGasPriceProviderTest.java} | 28 ++++---- .../MinGasPriceProviderFactoryTest.java | 32 ++++----- 21 files changed, 382 insertions(+), 229 deletions(-) create mode 100644 rskj-core/src/main/java/co/rsk/config/mining/EthCallMinGasPriceSystemConfig.java rename rskj-core/src/main/java/co/rsk/config/mining/{WebStableMinGasSystemConfig.java => HttpGetStableMinGasSystemConfig.java} (75%) delete mode 100644 rskj-core/src/main/java/co/rsk/config/mining/OnChainMinGasPriceSystemConfig.java rename rskj-core/src/main/java/co/rsk/mine/gas/provider/{onchain/OnChainMinGasPriceProvider.java => EthCallMinGasPriceProvider.java} (57%) rename rskj-core/src/main/java/co/rsk/mine/gas/provider/{web/WebMinGasPriceProvider.java => HttpGetMinGasPriceProvider.java} (69%) create mode 100644 rskj-core/src/test/java/co/rsk/config/mining/EthCallMinGasPriceSystemConfigTest.java rename rskj-core/src/test/java/co/rsk/config/mining/{WebStableMinGasSystemConfigTest.java => HttpGetStableMinGasSystemConfigTest.java} (84%) delete mode 100644 rskj-core/src/test/java/co/rsk/config/mining/OnChainMinGasPriceSystemConfigTest.java rename rskj-core/src/test/java/co/rsk/mine/gas/provider/{onchain/OnChainMinGasPriceProviderTest.java => EthCallMinGasPriceProviderTest.java} (63%) rename rskj-core/src/test/java/co/rsk/mine/gas/provider/{web/WebMinGasPriceProviderTest.java => HttpGetMinGasPriceProviderTest.java} (81%) diff --git a/rskj-core/src/main/java/co/rsk/RskContext.java b/rskj-core/src/main/java/co/rsk/RskContext.java index c4650a91ff8..aaf85ce6f3b 100644 --- a/rskj-core/src/main/java/co/rsk/RskContext.java +++ b/rskj-core/src/main/java/co/rsk/RskContext.java @@ -256,9 +256,8 @@ public class RskContext implements NodeContext, NodeBootstrapper { private TxQuotaChecker txQuotaChecker; private GasPriceTracker gasPriceTracker; private BlockChainFlusher blockChainFlusher; - private final Map dbPathToDbKindMap = new HashMap<>(); - private MinGasPriceProvider minGasPriceProvider; + private final Map dbPathToDbKindMap = new HashMap<>(); private volatile boolean closed; diff --git a/rskj-core/src/main/java/co/rsk/config/mining/EthCallMinGasPriceSystemConfig.java b/rskj-core/src/main/java/co/rsk/config/mining/EthCallMinGasPriceSystemConfig.java new file mode 100644 index 00000000000..7c178321dc8 --- /dev/null +++ b/rskj-core/src/main/java/co/rsk/config/mining/EthCallMinGasPriceSystemConfig.java @@ -0,0 +1,48 @@ +/* + * This file is part of RskJ + * Copyright (C) 2024 RSK Labs Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package co.rsk.config.mining; + +import com.typesafe.config.Config; + +public class EthCallMinGasPriceSystemConfig { + private static final String FROM_PROPERTY = "from"; + private static final String TO_PROPERTY = "to"; + private static final String DATA_PROPERTY = "data"; + private final String address; + private final String from; + private final String data; + + public EthCallMinGasPriceSystemConfig(Config config) { + address = config.getString(TO_PROPERTY); + from = config.getString(FROM_PROPERTY); + data = config.getString(DATA_PROPERTY); + } + + public String getAddress() { + return address; + } + + public String getFrom() { + return from; + } + + public String getData() { + return data; + } +} diff --git a/rskj-core/src/main/java/co/rsk/config/mining/WebStableMinGasSystemConfig.java b/rskj-core/src/main/java/co/rsk/config/mining/HttpGetStableMinGasSystemConfig.java similarity index 75% rename from rskj-core/src/main/java/co/rsk/config/mining/WebStableMinGasSystemConfig.java rename to rskj-core/src/main/java/co/rsk/config/mining/HttpGetStableMinGasSystemConfig.java index eaf6de82745..97daac0f0fe 100644 --- a/rskj-core/src/main/java/co/rsk/config/mining/WebStableMinGasSystemConfig.java +++ b/rskj-core/src/main/java/co/rsk/config/mining/HttpGetStableMinGasSystemConfig.java @@ -19,19 +19,18 @@ import com.typesafe.config.Config; -public class WebStableMinGasSystemConfig { - public static final String WEB_STABLE_GAS_PRICE_CONFIG_PATH = "web"; +public class HttpGetStableMinGasSystemConfig { private static final String URL_PROPERTY = "url"; - private static final String REQUEST_PATH = "requestPath"; + private static final String JSON_PATH = "jsonPath"; private static final String TIMEOUT_PROPERTY = "timeout"; private final String url; - private final String requestPath; + private final String jsonPath; private final int timeout; - public WebStableMinGasSystemConfig(Config config) { + public HttpGetStableMinGasSystemConfig(Config config) { this.url = config.getString(URL_PROPERTY); - this.requestPath = config.getString(REQUEST_PATH); + this.jsonPath = config.getString(JSON_PATH); this.timeout = config.getInt(TIMEOUT_PROPERTY); } @@ -39,8 +38,8 @@ public String getUrl() { return url; } - public String getRequestPath() { - return requestPath; + public String getJsonPath() { + return jsonPath; } public int getTimeout() { 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 deleted file mode 100644 index 607945e36ee..00000000000 --- a/rskj-core/src/main/java/co/rsk/config/mining/OnChainMinGasPriceSystemConfig.java +++ /dev/null @@ -1,31 +0,0 @@ -package co.rsk.config.mining; - -import com.typesafe.config.Config; - -public class OnChainMinGasPriceSystemConfig { - public static final String ONCHAIN_STABLE_GAS_PRICE_CONFIG_PATH = "onChain"; - 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) { - address = config.getString(ADDRESS_PROPERTY); - from = config.getString(FROM_PROPERTY); - data = config.getString(DATA_PROPERTY); - } - - public String getAddress() { - return address; - } - - public String getFrom() { - return from; - } - - public String getData() { - return data; - } -} diff --git a/rskj-core/src/main/java/co/rsk/config/mining/StableMinGasPriceSystemConfig.java b/rskj-core/src/main/java/co/rsk/config/mining/StableMinGasPriceSystemConfig.java index e7ae49da2cb..56387f24847 100644 --- a/rskj-core/src/main/java/co/rsk/config/mining/StableMinGasPriceSystemConfig.java +++ b/rskj-core/src/main/java/co/rsk/config/mining/StableMinGasPriceSystemConfig.java @@ -22,10 +22,12 @@ public class StableMinGasPriceSystemConfig { public static final String STABLE_GAS_PRICE_CONFIG_PATH_PROPERTY = "miner.stableGasPrice"; + private static final String ENABLED_PROPERTY = "enabled"; private static final String REFRESH_RATE_PROPERTY = "refreshRate"; private static final String MIN_STABLE_GAS_PRICE_PROPERTY = "minStableGasPrice"; - private static final String METHOD_PROPERTY = "method"; + private static final String METHOD_PROPERTY = "source.method"; + private static final String PARAMS_PROPERTY = "source.params"; private final Integer refreshRate; private final Long minStableGasPrice; @@ -34,17 +36,13 @@ public class StableMinGasPriceSystemConfig { private final Config config; public StableMinGasPriceSystemConfig(Config config) { - enabled = config.getBoolean(ENABLED_PROPERTY); - refreshRate = config.getInt(REFRESH_RATE_PROPERTY); - minStableGasPrice = config.getLong(MIN_STABLE_GAS_PRICE_PROPERTY); - method = config.getEnum(MinGasPriceProviderType.class, METHOD_PROPERTY); + this.enabled = config.hasPath(ENABLED_PROPERTY) && config.getBoolean(ENABLED_PROPERTY); + this.refreshRate = this.enabled && config.hasPath(REFRESH_RATE_PROPERTY) ? config.getInt(REFRESH_RATE_PROPERTY) : 0; + this.minStableGasPrice = this.enabled && config.hasPath(MIN_STABLE_GAS_PRICE_PROPERTY) ? config.getLong(MIN_STABLE_GAS_PRICE_PROPERTY) : 0; + this.method = this.enabled ? config.getEnum(MinGasPriceProviderType.class, METHOD_PROPERTY) : MinGasPriceProviderType.FIXED; this.config = config; } - public boolean isValid() { - return true; - } - public int getRefreshRate() { return refreshRate; } @@ -57,16 +55,14 @@ public boolean isEnabled() { return enabled; } - public WebStableMinGasSystemConfig getWebConfig() { - return new WebStableMinGasSystemConfig(config.getConfig(WebStableMinGasSystemConfig.WEB_STABLE_GAS_PRICE_CONFIG_PATH)); + public HttpGetStableMinGasSystemConfig getHttpGetConfig() { + return new HttpGetStableMinGasSystemConfig(config.getConfig(PARAMS_PROPERTY)); } - public OnChainMinGasPriceSystemConfig getOnChainConfig() { - return new OnChainMinGasPriceSystemConfig(config.getConfig(OnChainMinGasPriceSystemConfig.ONCHAIN_STABLE_GAS_PRICE_CONFIG_PATH)); + public EthCallMinGasPriceSystemConfig getEthCallConfig() { + return new EthCallMinGasPriceSystemConfig(config.getConfig(PARAMS_PROPERTY)); } - - public MinGasPriceProviderType getMethod() { return method; } 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/EthCallMinGasPriceProvider.java similarity index 57% rename from rskj-core/src/main/java/co/rsk/mine/gas/provider/onchain/OnChainMinGasPriceProvider.java rename to rskj-core/src/main/java/co/rsk/mine/gas/provider/EthCallMinGasPriceProvider.java index a3673c93489..f2967946168 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/EthCallMinGasPriceProvider.java @@ -1,40 +1,47 @@ -package co.rsk.mine.gas.provider.onchain; +/* + * This file is part of RskJ + * Copyright (C) 2024 RSK Labs Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ -import co.rsk.config.mining.OnChainMinGasPriceSystemConfig; +package co.rsk.mine.gas.provider; + +import co.rsk.config.mining.EthCallMinGasPriceSystemConfig; import co.rsk.config.mining.StableMinGasPriceSystemConfig; -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.ethereum.rpc.parameters.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.Optional; +import java.util.function.Supplier; -public class OnChainMinGasPriceProvider extends StableMinGasPriceProvider { - private static final Logger logger = LoggerFactory.getLogger(OnChainMinGasPriceProvider.class); +public class EthCallMinGasPriceProvider extends StableMinGasPriceProvider { + private static final Logger logger = LoggerFactory.getLogger(EthCallMinGasPriceProvider.class); private final String toAddress; private final String fromAddress; private final String data; - @FunctionalInterface - public interface GetContextCallback { - EthModule getEthModule(); - } - - private final GetContextCallback getContextCallback; + private final Supplier ethModuleSupplier; - public OnChainMinGasPriceProvider(MinGasPriceProvider fallBackProvider, StableMinGasPriceSystemConfig config, GetContextCallback getContextCallback) { + public EthCallMinGasPriceProvider(MinGasPriceProvider fallBackProvider, StableMinGasPriceSystemConfig config, Supplier ethModuleSupplier) { super(fallBackProvider, config.getMinStableGasPrice(), config.getRefreshRate()); - this.getContextCallback = getContextCallback; - OnChainMinGasPriceSystemConfig oConfig = config.getOnChainConfig(); + this.ethModuleSupplier = ethModuleSupplier; + EthCallMinGasPriceSystemConfig oConfig = config.getEthCallConfig(); this.toAddress = oConfig.getAddress(); this.fromAddress = oConfig.getFrom(); this.data = oConfig.getData(); @@ -42,12 +49,12 @@ public OnChainMinGasPriceProvider(MinGasPriceProvider fallBackProvider, StableMi @Override public MinGasPriceProviderType getType() { - return MinGasPriceProviderType.ON_CHAIN; + return MinGasPriceProviderType.ETH_CALL; } @Override protected Optional getBtcExchangeRate() { - EthModule ethModule = this.getContextCallback.getEthModule(); + EthModule ethModule = ethModuleSupplier.get(); if (ethModule == null) { logger.error("Could not get eth module"); return Optional.empty(); diff --git a/rskj-core/src/main/java/co/rsk/mine/gas/provider/FixedMinGasPriceProvider.java b/rskj-core/src/main/java/co/rsk/mine/gas/provider/FixedMinGasPriceProvider.java index 847887a4a3e..2c20ba731c7 100644 --- a/rskj-core/src/main/java/co/rsk/mine/gas/provider/FixedMinGasPriceProvider.java +++ b/rskj-core/src/main/java/co/rsk/mine/gas/provider/FixedMinGasPriceProvider.java @@ -1,10 +1,27 @@ +/* + * This file is part of RskJ + * Copyright (C) 2024 RSK Labs Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + package co.rsk.mine.gas.provider; import co.rsk.core.Coin; public class FixedMinGasPriceProvider implements MinGasPriceProvider { - private final long minGasPrice; public FixedMinGasPriceProvider(long minGasPrice) { 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/HttpGetMinGasPriceProvider.java similarity index 69% rename from rskj-core/src/main/java/co/rsk/mine/gas/provider/web/WebMinGasPriceProvider.java rename to rskj-core/src/main/java/co/rsk/mine/gas/provider/HttpGetMinGasPriceProvider.java index de9ce1fbfc0..ad985720266 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/HttpGetMinGasPriceProvider.java @@ -15,13 +15,10 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ -package co.rsk.mine.gas.provider.web; +package co.rsk.mine.gas.provider; import co.rsk.config.mining.StableMinGasPriceSystemConfig; -import co.rsk.config.mining.WebStableMinGasSystemConfig; -import co.rsk.mine.gas.provider.MinGasPriceProvider; -import co.rsk.mine.gas.provider.MinGasPriceProviderType; -import co.rsk.mine.gas.provider.StableMinGasPriceProvider; +import co.rsk.config.mining.HttpGetStableMinGasSystemConfig; import co.rsk.net.http.SimpleHttpClient; import com.fasterxml.jackson.core.JsonPointer; import com.fasterxml.jackson.databind.JsonNode; @@ -32,7 +29,7 @@ import java.util.Optional; -public class WebMinGasPriceProvider extends StableMinGasPriceProvider { +public class HttpGetMinGasPriceProvider extends StableMinGasPriceProvider { private static final Logger logger = LoggerFactory.getLogger("GasPriceProvider"); private final String url; private final JsonPointer jsonPath; @@ -40,22 +37,21 @@ public class WebMinGasPriceProvider extends StableMinGasPriceProvider { private final SimpleHttpClient httpClient; private final ObjectMapper objectMapper; - - public WebMinGasPriceProvider(StableMinGasPriceSystemConfig config, MinGasPriceProvider fallBackProvider) { + public HttpGetMinGasPriceProvider(StableMinGasPriceSystemConfig config, MinGasPriceProvider fallBackProvider) { super(fallBackProvider, config.getMinStableGasPrice(), config.getRefreshRate()); - WebStableMinGasSystemConfig webConfig = config.getWebConfig(); - url = webConfig.getUrl(); - jsonPath = JsonPointer.valueOf(webConfig.getRequestPath()); - timeout = webConfig.getTimeout(); - httpClient = new SimpleHttpClient(webConfig.getTimeout()); + HttpGetStableMinGasSystemConfig httpGetConfig = config.getHttpGetConfig(); + url = httpGetConfig.getUrl(); + jsonPath = JsonPointer.valueOf(httpGetConfig.getJsonPath()); + timeout = httpGetConfig.getTimeout(); + httpClient = new SimpleHttpClient(httpGetConfig.getTimeout()); objectMapper = new ObjectMapper(); } - public WebMinGasPriceProvider(StableMinGasPriceSystemConfig config, MinGasPriceProvider fallBackProvider, SimpleHttpClient httpClient) { + public HttpGetMinGasPriceProvider(StableMinGasPriceSystemConfig config, MinGasPriceProvider fallBackProvider, SimpleHttpClient httpClient) { super(fallBackProvider, config.getMinStableGasPrice(), config.getRefreshRate()); - WebStableMinGasSystemConfig webConfig = config.getWebConfig(); + HttpGetStableMinGasSystemConfig webConfig = config.getHttpGetConfig(); url = webConfig.getUrl(); - jsonPath = JsonPointer.valueOf(webConfig.getRequestPath()); + jsonPath = JsonPointer.valueOf(webConfig.getJsonPath()); timeout = webConfig.getTimeout(); this.httpClient = httpClient; objectMapper = new ObjectMapper(); @@ -68,7 +64,6 @@ protected Optional getBtcExchangeRate() { Long price = parsePrice(response); return Optional.ofNullable(price); } - logger.error("Error getting min gas price from web provider, empty response."); return Optional.empty(); } @@ -87,9 +82,7 @@ private Long parsePrice(String response) { private String getResponseFromWeb() { try { - String response = httpClient.doGet(url); - logger.debug("Response from web: {}", response); - return response; + return httpClient.doGet(url); } catch (Exception e) { logger.error("Error getting min gas price from web provider: {}", e.getMessage()); } @@ -98,7 +91,7 @@ private String getResponseFromWeb() { @Override public MinGasPriceProviderType getType() { - return MinGasPriceProviderType.WEB; + return MinGasPriceProviderType.HTTP_GET; } public String getUrl() { diff --git a/rskj-core/src/main/java/co/rsk/mine/gas/provider/MinGasPriceProvider.java b/rskj-core/src/main/java/co/rsk/mine/gas/provider/MinGasPriceProvider.java index f5f0369a7c7..688495faae1 100644 --- a/rskj-core/src/main/java/co/rsk/mine/gas/provider/MinGasPriceProvider.java +++ b/rskj-core/src/main/java/co/rsk/mine/gas/provider/MinGasPriceProvider.java @@ -1,3 +1,21 @@ +/* + * This file is part of RskJ + * Copyright (C) 2024 RSK Labs Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + package co.rsk.mine.gas.provider; import co.rsk.core.Coin; 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 f1e4a8a917e..844619cf4a5 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,11 +1,30 @@ +/* + * This file is part of RskJ + * Copyright (C) 2024 RSK Labs Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + 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.web.WebMinGasPriceProvider; +import co.rsk.rpc.modules.eth.EthModule; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.function.Supplier; + public class MinGasPriceProviderFactory { @@ -14,7 +33,7 @@ public class MinGasPriceProviderFactory { private MinGasPriceProviderFactory() { } - public static MinGasPriceProvider create(long fixedMinGasPrice, StableMinGasPriceSystemConfig stableMinGasPriceSystemConfig, OnChainMinGasPriceProvider.GetContextCallback getContextCallback) { + public static MinGasPriceProvider create(long fixedMinGasPrice, StableMinGasPriceSystemConfig stableMinGasPriceSystemConfig, Supplier ethModuleSupplier) { FixedMinGasPriceProvider fixedMinGasPriceProvider = new FixedMinGasPriceProvider(fixedMinGasPrice); if (stableMinGasPriceSystemConfig == null) { @@ -32,14 +51,15 @@ public static MinGasPriceProvider create(long fixedMinGasPrice, StableMinGasPric } switch (method) { - case WEB: - return new WebMinGasPriceProvider(stableMinGasPriceSystemConfig, fixedMinGasPriceProvider); - case ON_CHAIN: - return new OnChainMinGasPriceProvider(fixedMinGasPriceProvider, stableMinGasPriceSystemConfig, getContextCallback); + case HTTP_GET: + return new HttpGetMinGasPriceProvider(stableMinGasPriceSystemConfig, fixedMinGasPriceProvider); + case ETH_CALL: + return new EthCallMinGasPriceProvider(fixedMinGasPriceProvider, stableMinGasPriceSystemConfig, ethModuleSupplier); + case FIXED: + return fixedMinGasPriceProvider; 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/MinGasPriceProviderType.java b/rskj-core/src/main/java/co/rsk/mine/gas/provider/MinGasPriceProviderType.java index 4de2f99777c..0d6f2e7cf99 100644 --- a/rskj-core/src/main/java/co/rsk/mine/gas/provider/MinGasPriceProviderType.java +++ b/rskj-core/src/main/java/co/rsk/mine/gas/provider/MinGasPriceProviderType.java @@ -1,7 +1,25 @@ +/* + * This file is part of RskJ + * Copyright (C) 2024 RSK Labs Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + package co.rsk.mine.gas.provider; public enum MinGasPriceProviderType { FIXED, - WEB, - ON_CHAIN + HTTP_GET, + ETH_CALL } diff --git a/rskj-core/src/main/resources/expected.conf b/rskj-core/src/main/resources/expected.conf index b7ab1c90dfc..41dba8f87c3 100644 --- a/rskj-core/src/main/resources/expected.conf +++ b/rskj-core/src/main/resources/expected.conf @@ -191,9 +191,19 @@ miner = { } stableGasPrice { enabled = + source { + method = + params { + url = + jsonPath = + timeout = + from = + to = + data = + } + } minStableGasPrice = refreshRate = - method = } coinbase.secret = reward.address =
diff --git a/rskj-core/src/main/resources/reference.conf b/rskj-core/src/main/resources/reference.conf index 4a93bc621ad..c1860f6bb93 100644 --- a/rskj-core/src/main/resources/reference.conf +++ b/rskj-core/src/main/resources/reference.conf @@ -201,11 +201,33 @@ miner { # The time the miner client will wait to refresh the current work from the miner server delayBetweenRefreshes = 1 second } + stableGasPrice { enabled = false - minStableGasPrice = 0 - refreshRate = 0 - method = FIXED + + # source { + # # method options: HTTP_GET | ETH_CALL + # # Examples: + # + # method = "HTTP-GET" + # params { + # url = "https://domain.info/ticker" + # jsonPath = "/USD/buy" + # timeout = 2 seconds + # } + # + # # OR + # + # method = "ETH_CALL" + # params { + # from: "0xcd2a3d9f938e13cd947ec05abc7fe734df8dd825", + # to: "0xcd2a3d9f938e13cd947ec05abc7fe734df8dd826", + # data: "0x8300df49" + # } + # } + # + # minStableGasPrice = 4265280000000 # 0.00000426528 USD per gas unit + # refreshRate = 6 hours } } diff --git a/rskj-core/src/test/java/co/rsk/config/mining/EthCallMinGasPriceSystemConfigTest.java b/rskj-core/src/test/java/co/rsk/config/mining/EthCallMinGasPriceSystemConfigTest.java new file mode 100644 index 00000000000..295abaec0ce --- /dev/null +++ b/rskj-core/src/test/java/co/rsk/config/mining/EthCallMinGasPriceSystemConfigTest.java @@ -0,0 +1,58 @@ +/* + * This file is part of RskJ + * Copyright (C) 2024 RSK Labs Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +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 EthCallMinGasPriceSystemConfigTest { + private EthCallMinGasPriceSystemConfig config; + private String to = "0x77045E71a7A2c50903d88e564cD72fab11e82051"; + private String from = "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826"; + private String data = "0x98d5fdca"; + + @BeforeEach + void setUp() { + Config testConfig = ConfigFactory.parseString( + "to=\"" + to + "\"\n" + + "from=\"" + from + "\"\n" + + "data=\"" + data + "\"" + ); + config = new EthCallMinGasPriceSystemConfig(testConfig); + } + + @Test + void testAddress() { + assertEquals(to, config.getAddress()); + } + + @Test + void testFrom() { + assertEquals(from, config.getFrom()); + } + + @Test + void testData() { + assertEquals(data, config.getData()); + } +} diff --git a/rskj-core/src/test/java/co/rsk/config/mining/WebStableMinGasSystemConfigTest.java b/rskj-core/src/test/java/co/rsk/config/mining/HttpGetStableMinGasSystemConfigTest.java similarity index 84% rename from rskj-core/src/test/java/co/rsk/config/mining/WebStableMinGasSystemConfigTest.java rename to rskj-core/src/test/java/co/rsk/config/mining/HttpGetStableMinGasSystemConfigTest.java index 804f8aba092..02752bb490b 100644 --- a/rskj-core/src/test/java/co/rsk/config/mining/WebStableMinGasSystemConfigTest.java +++ b/rskj-core/src/test/java/co/rsk/config/mining/HttpGetStableMinGasSystemConfigTest.java @@ -24,17 +24,17 @@ import static org.junit.jupiter.api.Assertions.*; -class WebStableMinGasSystemConfigTest { - private WebStableMinGasSystemConfig config; +class HttpGetStableMinGasSystemConfigTest { + private HttpGetStableMinGasSystemConfig config; @BeforeEach void setUp() { Config testConfig = ConfigFactory.parseString( "url=\"http://test.url\"\n" + - "requestPath=testPath\n" + + "jsonPath=testPath\n" + "timeout=1000\n" ); - config = new WebStableMinGasSystemConfig(testConfig); + config = new HttpGetStableMinGasSystemConfig(testConfig); } @Test @@ -44,7 +44,7 @@ void testGetUrl() { @Test void testRequestPath() { - assertEquals("testPath", config.getRequestPath()); + assertEquals("testPath", config.getJsonPath()); } @Test 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 deleted file mode 100644 index 40155c7ef2a..00000000000 --- a/rskj-core/src/test/java/co/rsk/config/mining/OnChainMinGasPriceSystemConfigTest.java +++ /dev/null @@ -1,40 +0,0 @@ -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.getAddress()); - } - - @Test - void testFrom() { - assertEquals(from, config.getFrom()); - } - - @Test - void testData() { - assertEquals(data, config.getData()); - } -} diff --git a/rskj-core/src/test/java/co/rsk/config/mining/StableMinGasPriceSystemConfigTest.java b/rskj-core/src/test/java/co/rsk/config/mining/StableMinGasPriceSystemConfigTest.java index 66a4f68987f..5ce62749f78 100644 --- a/rskj-core/src/test/java/co/rsk/config/mining/StableMinGasPriceSystemConfigTest.java +++ b/rskj-core/src/test/java/co/rsk/config/mining/StableMinGasPriceSystemConfigTest.java @@ -36,16 +36,11 @@ void setUp() { "enabled=true\n" + "refreshRate=10\n" + "minStableGasPrice=100\n" + - "method=FIXED" + "source={ method=FIXED }" ); config = new StableMinGasPriceSystemConfig(testConfig); } - @Test - void testIsValid() { - assertTrue(config.isValid()); - } - @Test void testGetRefreshRate() { assertEquals(10, config.getRefreshRate()); @@ -72,14 +67,13 @@ void wrongMethodShouldThrowException() { "enabled=true\n" + "refreshRate=10\n" + "minStableGasPrice=100\n" + - "method=INVALID" + "source={ method=INVALID }" ); assertThrows( ConfigException.BadValue.class, () -> new StableMinGasPriceSystemConfig(testConfig), "Expected to throw Config exception, but it didn't" ); - } @Test diff --git a/rskj-core/src/test/java/co/rsk/mine/gas/FixedMinGasPriceProviderTest.java b/rskj-core/src/test/java/co/rsk/mine/gas/FixedMinGasPriceProviderTest.java index e6f547de530..8fef8654e1c 100644 --- a/rskj-core/src/test/java/co/rsk/mine/gas/FixedMinGasPriceProviderTest.java +++ b/rskj-core/src/test/java/co/rsk/mine/gas/FixedMinGasPriceProviderTest.java @@ -1,3 +1,21 @@ +/* + * This file is part of RskJ + * Copyright (C) 2024 RSK Labs Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + package co.rsk.mine.gas; import co.rsk.core.Coin; @@ -9,7 +27,6 @@ class FixedMinGasPriceProviderTest { - @Test void testConstructorAndGetMinGasPrice() { long minGasPrice = 100L; @@ -30,4 +47,4 @@ void testGetMinGasPriceAsCoin() { FixedMinGasPriceProvider provider = new FixedMinGasPriceProvider(minGasPrice); assertEquals(Coin.valueOf(minGasPrice), provider.getMinGasPriceAsCoin()); } -} \ 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/EthCallMinGasPriceProviderTest.java similarity index 63% rename from rskj-core/src/test/java/co/rsk/mine/gas/provider/onchain/OnChainMinGasPriceProviderTest.java rename to rskj-core/src/test/java/co/rsk/mine/gas/provider/EthCallMinGasPriceProviderTest.java index cab65e3ce86..25ac24e9c52 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/EthCallMinGasPriceProviderTest.java @@ -1,14 +1,30 @@ -package co.rsk.mine.gas.provider.onchain; - -import co.rsk.config.mining.OnChainMinGasPriceSystemConfig; +/* + * This file is part of RskJ + * Copyright (C) 2024 RSK Labs Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package co.rsk.mine.gas.provider; + +import co.rsk.config.mining.EthCallMinGasPriceSystemConfig; import co.rsk.config.mining.StableMinGasPriceSystemConfig; -import co.rsk.mine.gas.provider.MinGasPriceProvider; -import co.rsk.mine.gas.provider.MinGasPriceProviderType; +import co.rsk.rpc.modules.eth.EthModule; 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; @@ -20,11 +36,11 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -class OnChainMinGasPriceProviderTest { +class EthCallMinGasPriceProviderTest { private EthModule ethModule_mock; private MinGasPriceProvider fallback_mock; - private OnChainMinGasPriceSystemConfig onChainMinGasPriceSystemConfig_mock; - private OnChainMinGasPriceProvider onChainMinGasPriceProvider; + private EthCallMinGasPriceSystemConfig ethCallMinGasPriceSystemConfig_mock; + private EthCallMinGasPriceProvider ethCallMinGasPriceProvider; private StableMinGasPriceSystemConfig stableMinGasPriceSystemConfig; @BeforeEach @@ -37,20 +53,20 @@ public void beforeEach() { long fallback_minGasPrice_fake = 1234567890L; when(fallback_mock.getMinGasPrice()).thenReturn(fallback_minGasPrice_fake); - onChainMinGasPriceSystemConfig_mock = mock(OnChainMinGasPriceSystemConfig.class); + ethCallMinGasPriceSystemConfig_mock = mock(EthCallMinGasPriceSystemConfig.class); String oracle_address = "0xbffBD993FF1d229B0FfE55668F2009d20d4F7C5f"; - when(onChainMinGasPriceSystemConfig_mock.getAddress()).thenReturn(oracle_address); + when(ethCallMinGasPriceSystemConfig_mock.getAddress()).thenReturn(oracle_address); String from_address = "0xbffBD993FF1d229B0FfE55668F2009d20d4F7C5f"; - when(onChainMinGasPriceSystemConfig_mock.getFrom()).thenReturn(from_address); + when(ethCallMinGasPriceSystemConfig_mock.getFrom()).thenReturn(from_address); String data = "0x"; - when(onChainMinGasPriceSystemConfig_mock.getData()).thenReturn(data); + when(ethCallMinGasPriceSystemConfig_mock.getData()).thenReturn(data); stableMinGasPriceSystemConfig = mock(StableMinGasPriceSystemConfig.class); - when(stableMinGasPriceSystemConfig.getOnChainConfig()).thenReturn(onChainMinGasPriceSystemConfig_mock); + when(stableMinGasPriceSystemConfig.getEthCallConfig()).thenReturn(ethCallMinGasPriceSystemConfig_mock); when(stableMinGasPriceSystemConfig.getMinStableGasPrice()).thenReturn(fallback_minGasPrice_fake); - onChainMinGasPriceProvider = new OnChainMinGasPriceProvider( + ethCallMinGasPriceProvider = new EthCallMinGasPriceProvider( fallback_mock, stableMinGasPriceSystemConfig, () -> ethModule_mock @@ -69,13 +85,13 @@ public void afterEach() { @ValueSource(strings = {"0x123", "0xabc"}) void constructorSetsFieldsCorrectly(String data_input) { MinGasPriceProvider fallbackProvider = mock(MinGasPriceProvider.class); - OnChainMinGasPriceSystemConfig config = stableMinGasPriceSystemConfig.getOnChainConfig(); + EthCallMinGasPriceSystemConfig config = stableMinGasPriceSystemConfig.getEthCallConfig(); when(config.getAddress()).thenReturn("0xaddress"); when(config.getFrom()).thenReturn("0xfrom"); when(config.getData()).thenReturn(data_input); - OnChainMinGasPriceProvider provider = new OnChainMinGasPriceProvider(fallbackProvider, stableMinGasPriceSystemConfig, () -> ethModule_mock); + EthCallMinGasPriceProvider provider = new EthCallMinGasPriceProvider(fallbackProvider, stableMinGasPriceSystemConfig, () -> ethModule_mock); Assertions.assertEquals("0xaddress", provider.getToAddress()); } @@ -83,13 +99,13 @@ void constructorSetsFieldsCorrectly(String data_input) { @Test void constructorSetsFieldsToNullWhenConfigReturnsNull() { MinGasPriceProvider fallbackProvider = mock(MinGasPriceProvider.class); - OnChainMinGasPriceSystemConfig config = stableMinGasPriceSystemConfig.getOnChainConfig(); + EthCallMinGasPriceSystemConfig config = stableMinGasPriceSystemConfig.getEthCallConfig(); when(config.getAddress()).thenReturn(null); when(config.getFrom()).thenReturn(null); when(config.getData()).thenReturn(null); - OnChainMinGasPriceProvider provider = new OnChainMinGasPriceProvider(fallbackProvider, stableMinGasPriceSystemConfig, () -> ethModule_mock); + EthCallMinGasPriceProvider provider = new EthCallMinGasPriceProvider(fallbackProvider, stableMinGasPriceSystemConfig, () -> ethModule_mock); Assertions.assertNull(provider.getToAddress()); Assertions.assertNull(provider.getFromAddress()); @@ -101,10 +117,10 @@ void getStableMinGasPrice_callsEthModulesCallMethod() { String expectedPrice = "0x21"; when(ethModule_mock.call(any(), any())).thenReturn(expectedPrice); - assertTrue(onChainMinGasPriceProvider.getBtcExchangeRate().isPresent()); + assertTrue(ethCallMinGasPriceProvider.getBtcExchangeRate().isPresent()); Assertions.assertEquals( HexUtils.jsonHexToLong(expectedPrice), - onChainMinGasPriceProvider.getBtcExchangeRate().get() + ethCallMinGasPriceProvider.getBtcExchangeRate().get() ); } @@ -112,20 +128,20 @@ void getStableMinGasPrice_callsEthModulesCallMethod() { @NullSource @ValueSource(strings = {"", "0x"}) void getStableMinGasPrice_callsFallback_whenNoData(String data_input) { - when(onChainMinGasPriceSystemConfig_mock.getData()).thenReturn(data_input); + when(ethCallMinGasPriceSystemConfig_mock.getData()).thenReturn(data_input); - assertFalse(onChainMinGasPriceProvider.getBtcExchangeRate().isPresent()); + assertFalse(ethCallMinGasPriceProvider.getBtcExchangeRate().isPresent()); } @Test void getStableMinGasPrice_callsFallback_whenEthModuleIsNull() { - assertFalse(onChainMinGasPriceProvider.getBtcExchangeRate().isPresent()); + assertFalse(ethCallMinGasPriceProvider.getBtcExchangeRate().isPresent()); } @Test void getType_returnsOnChain() { - Assertions.assertEquals(MinGasPriceProviderType.ON_CHAIN, onChainMinGasPriceProvider.getType()); + Assertions.assertEquals(MinGasPriceProviderType.ETH_CALL, ethCallMinGasPriceProvider.getType()); } } diff --git a/rskj-core/src/test/java/co/rsk/mine/gas/provider/web/WebMinGasPriceProviderTest.java b/rskj-core/src/test/java/co/rsk/mine/gas/provider/HttpGetMinGasPriceProviderTest.java similarity index 81% rename from rskj-core/src/test/java/co/rsk/mine/gas/provider/web/WebMinGasPriceProviderTest.java rename to rskj-core/src/test/java/co/rsk/mine/gas/provider/HttpGetMinGasPriceProviderTest.java index 284abbd0d49..0dec6b7382a 100644 --- a/rskj-core/src/test/java/co/rsk/mine/gas/provider/web/WebMinGasPriceProviderTest.java +++ b/rskj-core/src/test/java/co/rsk/mine/gas/provider/HttpGetMinGasPriceProviderTest.java @@ -15,12 +15,10 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ -package co.rsk.mine.gas.provider.web; +package co.rsk.mine.gas.provider; +import co.rsk.config.mining.HttpGetStableMinGasSystemConfig; import co.rsk.config.mining.StableMinGasPriceSystemConfig; -import co.rsk.config.mining.WebStableMinGasSystemConfig; -import co.rsk.mine.gas.provider.MinGasPriceProvider; -import co.rsk.mine.gas.provider.MinGasPriceProviderType; import co.rsk.net.http.HttpException; import co.rsk.net.http.SimpleHttpClient; import org.junit.jupiter.api.Test; @@ -32,7 +30,7 @@ import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.*; -class WebMinGasPriceProviderTest { +class HttpGetMinGasPriceProviderTest { @Test void returnsMappedPriceFromWebClient() throws HttpException { @@ -42,7 +40,7 @@ void returnsMappedPriceFromWebClient() throws HttpException { SimpleHttpClient httpClient = mock(SimpleHttpClient.class); when(httpClient.doGet(anyString())).thenReturn("{\"bitcoin\":{\"usd\":10000}}"); StableMinGasPriceSystemConfig config = createStableMinGasPriceSystemConfig(); - WebMinGasPriceProvider provider = new WebMinGasPriceProvider(config, fallbackProvider, httpClient); + HttpGetMinGasPriceProvider provider = new HttpGetMinGasPriceProvider(config, fallbackProvider, httpClient); Optional result = provider.getBtcExchangeRate(); verify(fallbackProvider, times(0)).getMinGasPrice(); @@ -58,7 +56,7 @@ void whenRequestingTheValueTwiceCachedValueIsUsed() throws HttpException { SimpleHttpClient httpClient = mock(SimpleHttpClient.class); when(httpClient.doGet(anyString())).thenReturn("{\"bitcoin\":{\"usd\":10000}}"); StableMinGasPriceSystemConfig config = createStableMinGasPriceSystemConfig(); - WebMinGasPriceProvider provider = spy(new WebMinGasPriceProvider(config, fallbackProvider, httpClient)); + HttpGetMinGasPriceProvider provider = spy(new HttpGetMinGasPriceProvider(config, fallbackProvider, httpClient)); provider.getMinGasPrice(); provider.getMinGasPrice(); @@ -76,7 +74,7 @@ void whenEmptyResponseReturnsFallbackProvider() throws HttpException { SimpleHttpClient httpClient = mock(SimpleHttpClient.class); when(httpClient.doGet(anyString())).thenReturn(""); StableMinGasPriceSystemConfig config = createStableMinGasPriceSystemConfig(); - WebMinGasPriceProvider provider = new WebMinGasPriceProvider(config, fallbackProvider, httpClient); + HttpGetMinGasPriceProvider provider = new HttpGetMinGasPriceProvider(config, fallbackProvider, httpClient); Long result = provider.getMinGasPrice(); verify(fallbackProvider, times(1)).getMinGasPrice(); @@ -92,7 +90,7 @@ void whenErrorReturnsFallbackProvider() throws HttpException { SimpleHttpClient httpClient = mock(SimpleHttpClient.class); when(httpClient.doGet(anyString())).thenThrow(new HttpException("Error")); StableMinGasPriceSystemConfig config = createStableMinGasPriceSystemConfig(); - WebMinGasPriceProvider provider = new WebMinGasPriceProvider(config, fallbackProvider, httpClient); + HttpGetMinGasPriceProvider provider = new HttpGetMinGasPriceProvider(config, fallbackProvider, httpClient); Long result = provider.getMinGasPrice(); verify(fallbackProvider, times(1)).getMinGasPrice(); @@ -108,7 +106,7 @@ void whenPathIsWrongReturnsFallBack() throws HttpException { SimpleHttpClient httpClient = mock(SimpleHttpClient.class); when(httpClient.doGet(anyString())).thenReturn("{\"btc\":{\"usd\":10000}}"); StableMinGasPriceSystemConfig config = createStableMinGasPriceSystemConfig(); - WebMinGasPriceProvider provider = new WebMinGasPriceProvider(config, fallbackProvider, httpClient); + HttpGetMinGasPriceProvider provider = new HttpGetMinGasPriceProvider(config, fallbackProvider, httpClient); Long result = provider.getMinGasPrice(); @@ -118,16 +116,16 @@ void whenPathIsWrongReturnsFallBack() throws HttpException { private StableMinGasPriceSystemConfig createStableMinGasPriceSystemConfig() { StableMinGasPriceSystemConfig config = mock(StableMinGasPriceSystemConfig.class); - WebStableMinGasSystemConfig webConfig = createWebStableSystemConfig(); - when(config.getWebConfig()).thenReturn(webConfig); + HttpGetStableMinGasSystemConfig webConfig = createWebStableSystemConfig(); + when(config.getHttpGetConfig()).thenReturn(webConfig); when(config.getMinStableGasPrice()).thenReturn(4265280000000L); when(config.getRefreshRate()).thenReturn(30); return config; } - private WebStableMinGasSystemConfig createWebStableSystemConfig() { - WebStableMinGasSystemConfig config = mock(WebStableMinGasSystemConfig.class); - when(config.getRequestPath()).thenReturn("/bitcoin/usd"); + private HttpGetStableMinGasSystemConfig createWebStableSystemConfig() { + HttpGetStableMinGasSystemConfig config = mock(HttpGetStableMinGasSystemConfig.class); + when(config.getJsonPath()).thenReturn("/bitcoin/usd"); when(config.getUrl()).thenReturn("https://rsk.co/price?ids=bitcoin&vs_currencies=usd"); when(config.getTimeout()).thenReturn(3000); return config; 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 a953392a144..96a85b8028f 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 @@ -18,7 +18,6 @@ package co.rsk.mine.gas.provider; import co.rsk.config.mining.StableMinGasPriceSystemConfig; -import co.rsk.mine.gas.provider.web.WebMinGasPriceProvider; import com.typesafe.config.Config; import com.typesafe.config.ConfigFactory; import org.junit.jupiter.api.Test; @@ -28,14 +27,13 @@ class MinGasPriceProviderFactoryTest { - @Test void createFixedMinGasPriceProvider() { Config testConfig = ConfigFactory.parseString( "enabled=true\n" + "refreshRate=10\n" + "minStableGasPrice=100\n" + - "method=FIXED" + "source={ method=FIXED }" ); StableMinGasPriceSystemConfig config = new StableMinGasPriceSystemConfig(testConfig); @@ -57,36 +55,34 @@ void createWithNullConfig() { @Test void createWebProviderMethod() { Config testConfig = ConfigFactory.parseString( - "enabled=true \n" + + "enabled=true\n" + "refreshRate=10\n" + "minStableGasPrice=100\n" + - "method=WEB\n" + - "web.url=url\n" + - "web.timeout=1000 \n" + - "web.apiKey=1234\n" + - "web.requestPath=/price" + "source.method=HTTP_GET\n" + + "source.params.url=url\n" + + "source.params.timeout=1000\n" + + "source.params.jsonPath=/price" ); StableMinGasPriceSystemConfig disabledConfig = new StableMinGasPriceSystemConfig(testConfig); MinGasPriceProvider provider = MinGasPriceProviderFactory.create(100L, disabledConfig, () -> null); - assertTrue(provider instanceof WebMinGasPriceProvider); + assertTrue(provider instanceof HttpGetMinGasPriceProvider); assertEquals(100, provider.getMinGasPrice()); - assertEquals(MinGasPriceProviderType.WEB, provider.getType()); + assertEquals(MinGasPriceProviderType.HTTP_GET, provider.getType()); } @Test void createWithDisabledConfigReturnFixed() { Config testConfig = ConfigFactory.parseString( - "enabled=false \n" + + "enabled=false\n" + "refreshRate=10\n" + "minStableGasPrice=100\n" + - "method=WEB\n" + - "web.url=url\n" + - "web.timeout=1000 \n" + - "web.apiKey=1234\n" + - "web.jsonPath=price" + "source.method=HTTP_GET\n" + + "source.params.url=url\n" + + "source.params.timeout=1000 \n" + + "source.params.jsonPath=price" ); StableMinGasPriceSystemConfig disabledConfig = new StableMinGasPriceSystemConfig(testConfig); @@ -97,6 +93,4 @@ void createWithDisabledConfigReturnFixed() { assertEquals(100, provider.getMinGasPrice()); assertEquals(MinGasPriceProviderType.FIXED, provider.getType()); } - - } From e360b7e230f1c2c9d5c5583583d71d806499d69f Mon Sep 17 00:00:00 2001 From: Volodymyr Kravets Date: Thu, 18 Jul 2024 11:17:05 +0300 Subject: [PATCH 14/17] feat(stableMinGasPrice): review suggestions --- .../provider/EthCallMinGasPriceProvider.java | 8 ++++---- .../provider/HttpGetMinGasPriceProvider.java | 18 ++++++------------ 2 files changed, 10 insertions(+), 16 deletions(-) diff --git a/rskj-core/src/main/java/co/rsk/mine/gas/provider/EthCallMinGasPriceProvider.java b/rskj-core/src/main/java/co/rsk/mine/gas/provider/EthCallMinGasPriceProvider.java index f2967946168..66b54c6122e 100644 --- a/rskj-core/src/main/java/co/rsk/mine/gas/provider/EthCallMinGasPriceProvider.java +++ b/rskj-core/src/main/java/co/rsk/mine/gas/provider/EthCallMinGasPriceProvider.java @@ -41,10 +41,10 @@ public class EthCallMinGasPriceProvider extends StableMinGasPriceProvider { public EthCallMinGasPriceProvider(MinGasPriceProvider fallBackProvider, StableMinGasPriceSystemConfig config, Supplier ethModuleSupplier) { super(fallBackProvider, config.getMinStableGasPrice(), config.getRefreshRate()); this.ethModuleSupplier = ethModuleSupplier; - EthCallMinGasPriceSystemConfig oConfig = config.getEthCallConfig(); - this.toAddress = oConfig.getAddress(); - this.fromAddress = oConfig.getFrom(); - this.data = oConfig.getData(); + EthCallMinGasPriceSystemConfig ethCallConfig = config.getEthCallConfig(); + this.toAddress = ethCallConfig.getAddress(); + this.fromAddress = ethCallConfig.getFrom(); + this.data = ethCallConfig.getData(); } @Override diff --git a/rskj-core/src/main/java/co/rsk/mine/gas/provider/HttpGetMinGasPriceProvider.java b/rskj-core/src/main/java/co/rsk/mine/gas/provider/HttpGetMinGasPriceProvider.java index ad985720266..2e9d203a94d 100644 --- a/rskj-core/src/main/java/co/rsk/mine/gas/provider/HttpGetMinGasPriceProvider.java +++ b/rskj-core/src/main/java/co/rsk/mine/gas/provider/HttpGetMinGasPriceProvider.java @@ -38,23 +38,17 @@ public class HttpGetMinGasPriceProvider extends StableMinGasPriceProvider { private final ObjectMapper objectMapper; public HttpGetMinGasPriceProvider(StableMinGasPriceSystemConfig config, MinGasPriceProvider fallBackProvider) { - super(fallBackProvider, config.getMinStableGasPrice(), config.getRefreshRate()); - HttpGetStableMinGasSystemConfig httpGetConfig = config.getHttpGetConfig(); - url = httpGetConfig.getUrl(); - jsonPath = JsonPointer.valueOf(httpGetConfig.getJsonPath()); - timeout = httpGetConfig.getTimeout(); - httpClient = new SimpleHttpClient(httpGetConfig.getTimeout()); - objectMapper = new ObjectMapper(); + this(config, fallBackProvider, new SimpleHttpClient(config.getHttpGetConfig().getTimeout())); } public HttpGetMinGasPriceProvider(StableMinGasPriceSystemConfig config, MinGasPriceProvider fallBackProvider, SimpleHttpClient httpClient) { super(fallBackProvider, config.getMinStableGasPrice(), config.getRefreshRate()); - HttpGetStableMinGasSystemConfig webConfig = config.getHttpGetConfig(); - url = webConfig.getUrl(); - jsonPath = JsonPointer.valueOf(webConfig.getJsonPath()); - timeout = webConfig.getTimeout(); + HttpGetStableMinGasSystemConfig httpGetConfig = config.getHttpGetConfig(); + this.url = httpGetConfig.getUrl(); + this.jsonPath = JsonPointer.valueOf(httpGetConfig.getJsonPath()); + this.timeout = httpGetConfig.getTimeout(); this.httpClient = httpClient; - objectMapper = new ObjectMapper(); + this.objectMapper = new ObjectMapper(); } @Override From 1bf9d53a883d254c46e117804e32c874337890ca Mon Sep 17 00:00:00 2001 From: Volodymyr Kravets Date: Thu, 12 Sep 2024 17:05:27 +0300 Subject: [PATCH 15/17] fix(stableMinGasPrice): fix time units conversion --- .../HttpGetStableMinGasSystemConfig.java | 13 ++++--- .../mining/StableMinGasPriceSystemConfig.java | 8 ++-- .../provider/EthCallMinGasPriceProvider.java | 7 +--- .../provider/HttpGetMinGasPriceProvider.java | 10 +---- .../provider/StableMinGasPriceProvider.java | 38 ++++++++++++------- .../co/rsk/net/http/SimpleHttpClient.java | 7 +++- rskj-core/src/main/resources/reference.conf | 7 +++- .../HttpGetStableMinGasSystemConfigTest.java | 6 ++- .../StableMinGasPriceSystemConfigTest.java | 6 ++- .../HttpGetMinGasPriceProviderTest.java | 5 ++- .../StableMinGasPriceProviderTest.java | 11 +++--- 11 files changed, 69 insertions(+), 49 deletions(-) diff --git a/rskj-core/src/main/java/co/rsk/config/mining/HttpGetStableMinGasSystemConfig.java b/rskj-core/src/main/java/co/rsk/config/mining/HttpGetStableMinGasSystemConfig.java index 97daac0f0fe..07bdc20d90e 100644 --- a/rskj-core/src/main/java/co/rsk/config/mining/HttpGetStableMinGasSystemConfig.java +++ b/rskj-core/src/main/java/co/rsk/config/mining/HttpGetStableMinGasSystemConfig.java @@ -19,6 +19,9 @@ import com.typesafe.config.Config; +import java.time.Duration; +import java.util.Objects; + public class HttpGetStableMinGasSystemConfig { private static final String URL_PROPERTY = "url"; private static final String JSON_PATH = "jsonPath"; @@ -26,12 +29,12 @@ public class HttpGetStableMinGasSystemConfig { private final String url; private final String jsonPath; - private final int timeout; + private final Duration timeout; public HttpGetStableMinGasSystemConfig(Config config) { - this.url = config.getString(URL_PROPERTY); - this.jsonPath = config.getString(JSON_PATH); - this.timeout = config.getInt(TIMEOUT_PROPERTY); + this.url = Objects.requireNonNull(config.getString(URL_PROPERTY)); + this.jsonPath = Objects.requireNonNull(config.getString(JSON_PATH)); + this.timeout = Objects.requireNonNull(config.getDuration(TIMEOUT_PROPERTY)); } public String getUrl() { @@ -42,7 +45,7 @@ public String getJsonPath() { return jsonPath; } - public int getTimeout() { + public Duration getTimeout() { return timeout; } diff --git a/rskj-core/src/main/java/co/rsk/config/mining/StableMinGasPriceSystemConfig.java b/rskj-core/src/main/java/co/rsk/config/mining/StableMinGasPriceSystemConfig.java index 56387f24847..36a3fc06318 100644 --- a/rskj-core/src/main/java/co/rsk/config/mining/StableMinGasPriceSystemConfig.java +++ b/rskj-core/src/main/java/co/rsk/config/mining/StableMinGasPriceSystemConfig.java @@ -20,6 +20,8 @@ import co.rsk.mine.gas.provider.MinGasPriceProviderType; import com.typesafe.config.Config; +import java.time.Duration; + public class StableMinGasPriceSystemConfig { public static final String STABLE_GAS_PRICE_CONFIG_PATH_PROPERTY = "miner.stableGasPrice"; @@ -29,7 +31,7 @@ public class StableMinGasPriceSystemConfig { private static final String METHOD_PROPERTY = "source.method"; private static final String PARAMS_PROPERTY = "source.params"; - private final Integer refreshRate; + private final Duration refreshRate; private final Long minStableGasPrice; private final boolean enabled; private final MinGasPriceProviderType method; @@ -37,13 +39,13 @@ public class StableMinGasPriceSystemConfig { public StableMinGasPriceSystemConfig(Config config) { this.enabled = config.hasPath(ENABLED_PROPERTY) && config.getBoolean(ENABLED_PROPERTY); - this.refreshRate = this.enabled && config.hasPath(REFRESH_RATE_PROPERTY) ? config.getInt(REFRESH_RATE_PROPERTY) : 0; + this.refreshRate = this.enabled && config.hasPath(REFRESH_RATE_PROPERTY) ? config.getDuration(REFRESH_RATE_PROPERTY) : Duration.ZERO; this.minStableGasPrice = this.enabled && config.hasPath(MIN_STABLE_GAS_PRICE_PROPERTY) ? config.getLong(MIN_STABLE_GAS_PRICE_PROPERTY) : 0; this.method = this.enabled ? config.getEnum(MinGasPriceProviderType.class, METHOD_PROPERTY) : MinGasPriceProviderType.FIXED; this.config = config; } - public int getRefreshRate() { + public Duration getRefreshRate() { return refreshRate; } diff --git a/rskj-core/src/main/java/co/rsk/mine/gas/provider/EthCallMinGasPriceProvider.java b/rskj-core/src/main/java/co/rsk/mine/gas/provider/EthCallMinGasPriceProvider.java index 66b54c6122e..e1dce2d3afa 100644 --- a/rskj-core/src/main/java/co/rsk/mine/gas/provider/EthCallMinGasPriceProvider.java +++ b/rskj-core/src/main/java/co/rsk/mine/gas/provider/EthCallMinGasPriceProvider.java @@ -26,6 +26,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.Objects; import java.util.Optional; import java.util.function.Supplier; @@ -54,11 +55,7 @@ public MinGasPriceProviderType getType() { @Override protected Optional getBtcExchangeRate() { - EthModule ethModule = ethModuleSupplier.get(); - if (ethModule == null) { - logger.error("Could not get eth module"); - return Optional.empty(); - } + EthModule ethModule = Objects.requireNonNull(ethModuleSupplier.get()); CallArgumentsParam callArguments = new CallArgumentsParam( new HexAddressParam(fromAddress), diff --git a/rskj-core/src/main/java/co/rsk/mine/gas/provider/HttpGetMinGasPriceProvider.java b/rskj-core/src/main/java/co/rsk/mine/gas/provider/HttpGetMinGasPriceProvider.java index 2e9d203a94d..31c1999e743 100644 --- a/rskj-core/src/main/java/co/rsk/mine/gas/provider/HttpGetMinGasPriceProvider.java +++ b/rskj-core/src/main/java/co/rsk/mine/gas/provider/HttpGetMinGasPriceProvider.java @@ -33,12 +33,11 @@ public class HttpGetMinGasPriceProvider extends StableMinGasPriceProvider { private static final Logger logger = LoggerFactory.getLogger("GasPriceProvider"); private final String url; private final JsonPointer jsonPath; - private final int timeout; private final SimpleHttpClient httpClient; private final ObjectMapper objectMapper; public HttpGetMinGasPriceProvider(StableMinGasPriceSystemConfig config, MinGasPriceProvider fallBackProvider) { - this(config, fallBackProvider, new SimpleHttpClient(config.getHttpGetConfig().getTimeout())); + this(config, fallBackProvider, new SimpleHttpClient(config.getHttpGetConfig().getTimeout().toMillis())); } public HttpGetMinGasPriceProvider(StableMinGasPriceSystemConfig config, MinGasPriceProvider fallBackProvider, SimpleHttpClient httpClient) { @@ -46,7 +45,6 @@ public HttpGetMinGasPriceProvider(StableMinGasPriceSystemConfig config, MinGasPr HttpGetStableMinGasSystemConfig httpGetConfig = config.getHttpGetConfig(); this.url = httpGetConfig.getUrl(); this.jsonPath = JsonPointer.valueOf(httpGetConfig.getJsonPath()); - this.timeout = httpGetConfig.getTimeout(); this.httpClient = httpClient; this.objectMapper = new ObjectMapper(); } @@ -69,7 +67,7 @@ private Long parsePrice(String response) { } return objectMapper.readTree(response).at(jsonPath).asLong(); } catch (Exception e) { - logger.error("Error parsing min gas price from web provider: {}", e.getMessage()); + logger.error("Error parsing min gas price from web provider", e); return null; } } @@ -92,9 +90,5 @@ public String getUrl() { return url; } - public int getTimeout() { - return timeout; - } - } 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 ff415c0f6d6..d6828e756a0 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 @@ -21,38 +21,41 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.time.Instant; +import java.time.Duration; import java.util.Optional; public abstract class StableMinGasPriceProvider implements MinGasPriceProvider { private static final Logger logger = LoggerFactory.getLogger("StableMinGasPrice"); + private static final int ERR_NUM_OF_FAILURES = 20; private final MinGasPriceProvider fallBackProvider; private final long minStableGasPrice; private Long lastMinGasPrice; - private long lastUpdateTimeStamp; - private final int refreshRateMillis; + private long lastUpdateTimeMillis; + private int numOfFailures; + private final long refreshRateInMillis; - - protected StableMinGasPriceProvider(MinGasPriceProvider fallBackProvider, long minStableGasPrice, int refreshRateInSeconds) { + protected StableMinGasPriceProvider(MinGasPriceProvider fallBackProvider, long minStableGasPrice, Duration refreshRate) { this.minStableGasPrice = minStableGasPrice; this.fallBackProvider = fallBackProvider; this.lastMinGasPrice = 0L; - this.refreshRateMillis = refreshRateInSeconds * 1000; + this.refreshRateInMillis = refreshRate.toMillis(); } protected abstract Optional getBtcExchangeRate(); @Override public long getMinGasPrice() { - long currentTime = Instant.now().getEpochSecond(); - if (currentTime - lastUpdateTimeStamp >= refreshRateMillis) { - fetchPrice(); + long currentTimeMillis = System.currentTimeMillis(); + if (currentTimeMillis - lastUpdateTimeMillis >= refreshRateInMillis) { + if (fetchPrice()) { + lastUpdateTimeMillis = currentTimeMillis; + } } - // time it is always updated, it is not taken into account if the price was really updated or not. - lastUpdateTimeStamp = currentTime; + if (lastMinGasPrice != null && lastMinGasPrice > 0) { return lastMinGasPrice; } + return fallBackProvider.getMinGasPrice(); } @@ -68,12 +71,21 @@ public Coin getMinGasPriceAsCoin() { return Coin.valueOf(getMinGasPrice()); } - private void fetchPrice() { + private boolean fetchPrice() { Optional priceResponse = getBtcExchangeRate(); if (priceResponse.isPresent() && priceResponse.get() > 0) { lastMinGasPrice = calculateMinGasPriceBasedOnBtcPrice(priceResponse.get()); + numOfFailures = 0; + return true; + } + + numOfFailures++; + if (numOfFailures >= ERR_NUM_OF_FAILURES) { + logger.error("Gas price was not updated as it was not possible to obtain valid price from provider. Check your provider setup. Number of failed attempts: {}", numOfFailures); } else { - logger.warn("Gas price was not updated as it was not possible to obtain valid price from provider"); + logger.warn("Gas price was not updated as it was not possible to obtain valid price from provider. Number of failed attempts: {}", numOfFailures); } + + return false; } } diff --git a/rskj-core/src/main/java/co/rsk/net/http/SimpleHttpClient.java b/rskj-core/src/main/java/co/rsk/net/http/SimpleHttpClient.java index 43ce735498a..b287247349c 100644 --- a/rskj-core/src/main/java/co/rsk/net/http/SimpleHttpClient.java +++ b/rskj-core/src/main/java/co/rsk/net/http/SimpleHttpClient.java @@ -31,8 +31,11 @@ public class SimpleHttpClient { private static final String GET_METHOD = "GET"; private final int timeoutMillis; - public SimpleHttpClient(int timeoutMillis) { - this.timeoutMillis = timeoutMillis; + public SimpleHttpClient(long timeoutMillis) { + if (timeoutMillis > Integer.MAX_VALUE) { + throw new IllegalArgumentException("Timeout value is too large."); + } + this.timeoutMillis = (int) timeoutMillis; } public String doGet(String targetUrl) throws HttpException { diff --git a/rskj-core/src/main/resources/reference.conf b/rskj-core/src/main/resources/reference.conf index c1860f6bb93..3293fd6e326 100644 --- a/rskj-core/src/main/resources/reference.conf +++ b/rskj-core/src/main/resources/reference.conf @@ -209,11 +209,11 @@ miner { # # method options: HTTP_GET | ETH_CALL # # Examples: # - # method = "HTTP-GET" + # method = "HTTP_GET" # params { # url = "https://domain.info/ticker" # jsonPath = "/USD/buy" - # timeout = 2 seconds + # timeout = 2 seconds # Value's type is `Duration`, e.g. 1.1 seconds, 2.5 minutes, 3 hours, 4 days. # } # # # OR @@ -227,6 +227,9 @@ miner { # } # # minStableGasPrice = 4265280000000 # 0.00000426528 USD per gas unit + # + # # The time the miner client will wait to refresh price from the source. + # # Value's type is `Duration`, e.g. 1.1 seconds, 2.5 minutes, 3 hours, 4 days. # refreshRate = 6 hours } } diff --git a/rskj-core/src/test/java/co/rsk/config/mining/HttpGetStableMinGasSystemConfigTest.java b/rskj-core/src/test/java/co/rsk/config/mining/HttpGetStableMinGasSystemConfigTest.java index 02752bb490b..ffde165c373 100644 --- a/rskj-core/src/test/java/co/rsk/config/mining/HttpGetStableMinGasSystemConfigTest.java +++ b/rskj-core/src/test/java/co/rsk/config/mining/HttpGetStableMinGasSystemConfigTest.java @@ -22,6 +22,8 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import java.time.Duration; + import static org.junit.jupiter.api.Assertions.*; class HttpGetStableMinGasSystemConfigTest { @@ -32,7 +34,7 @@ void setUp() { Config testConfig = ConfigFactory.parseString( "url=\"http://test.url\"\n" + "jsonPath=testPath\n" + - "timeout=1000\n" + "timeout=1000 milliseconds\n" ); config = new HttpGetStableMinGasSystemConfig(testConfig); } @@ -49,6 +51,6 @@ void testRequestPath() { @Test void testGetTimeout() { - assertEquals(1000, config.getTimeout()); + assertEquals(Duration.ofMillis(1000), config.getTimeout()); } } \ No newline at end of file diff --git a/rskj-core/src/test/java/co/rsk/config/mining/StableMinGasPriceSystemConfigTest.java b/rskj-core/src/test/java/co/rsk/config/mining/StableMinGasPriceSystemConfigTest.java index 5ce62749f78..77da16e799d 100644 --- a/rskj-core/src/test/java/co/rsk/config/mining/StableMinGasPriceSystemConfigTest.java +++ b/rskj-core/src/test/java/co/rsk/config/mining/StableMinGasPriceSystemConfigTest.java @@ -24,6 +24,8 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import java.time.Duration; + import static org.junit.jupiter.api.Assertions.*; class StableMinGasPriceSystemConfigTest { @@ -34,7 +36,7 @@ class StableMinGasPriceSystemConfigTest { void setUp() { Config testConfig = ConfigFactory.parseString( "enabled=true\n" + - "refreshRate=10\n" + + "refreshRate=10 hours\n" + "minStableGasPrice=100\n" + "source={ method=FIXED }" ); @@ -43,7 +45,7 @@ void setUp() { @Test void testGetRefreshRate() { - assertEquals(10, config.getRefreshRate()); + assertEquals(Duration.ofHours(10), config.getRefreshRate()); } @Test diff --git a/rskj-core/src/test/java/co/rsk/mine/gas/provider/HttpGetMinGasPriceProviderTest.java b/rskj-core/src/test/java/co/rsk/mine/gas/provider/HttpGetMinGasPriceProviderTest.java index 0dec6b7382a..102ad7e34b1 100644 --- a/rskj-core/src/test/java/co/rsk/mine/gas/provider/HttpGetMinGasPriceProviderTest.java +++ b/rskj-core/src/test/java/co/rsk/mine/gas/provider/HttpGetMinGasPriceProviderTest.java @@ -23,6 +23,7 @@ import co.rsk.net.http.SimpleHttpClient; import org.junit.jupiter.api.Test; +import java.time.Duration; import java.util.Optional; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -119,7 +120,7 @@ private StableMinGasPriceSystemConfig createStableMinGasPriceSystemConfig() { HttpGetStableMinGasSystemConfig webConfig = createWebStableSystemConfig(); when(config.getHttpGetConfig()).thenReturn(webConfig); when(config.getMinStableGasPrice()).thenReturn(4265280000000L); - when(config.getRefreshRate()).thenReturn(30); + when(config.getRefreshRate()).thenReturn(Duration.ofSeconds(30)); return config; } @@ -127,7 +128,7 @@ private HttpGetStableMinGasSystemConfig createWebStableSystemConfig() { HttpGetStableMinGasSystemConfig config = mock(HttpGetStableMinGasSystemConfig.class); when(config.getJsonPath()).thenReturn("/bitcoin/usd"); when(config.getUrl()).thenReturn("https://rsk.co/price?ids=bitcoin&vs_currencies=usd"); - when(config.getTimeout()).thenReturn(3000); + when(config.getTimeout()).thenReturn(Duration.ofMillis(3000)); return config; } 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 0a0d0b21e2d..a49d671752d 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 @@ -22,6 +22,7 @@ import org.junit.jupiter.api.Test; import org.mockito.Mockito; +import java.time.Duration; import java.util.Optional; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -36,7 +37,7 @@ void setUp() { fallBackProvider = Mockito.mock(MinGasPriceProvider.class); when(fallBackProvider.getMinGasPrice()).thenReturn(10L); when(fallBackProvider.getType()).thenReturn(MinGasPriceProviderType.FIXED); - stableMinGasPriceProvider = new TestStableMingGasPriceProvider(fallBackProvider, 100, 10); + stableMinGasPriceProvider = new TestStableMingGasPriceProvider(fallBackProvider, 100, Duration.ofSeconds(10)); } @Test @@ -48,7 +49,7 @@ void testGetMinGasPrice() { @Test void GetMinGasPriceUsesFallbackWhenReturnIsNull() { - stableMinGasPriceProvider = new TestStableMingGasPriceProvider(fallBackProvider, 100, 10) { + stableMinGasPriceProvider = new TestStableMingGasPriceProvider(fallBackProvider, 100, Duration.ofSeconds(10)) { @Override public Optional getBtcExchangeRate() { return Optional.empty(); @@ -66,7 +67,7 @@ void whenRequestingTheValueTwiceCachedValueIsUsed() { MinGasPriceProvider fallbackProvider = mock(MinGasPriceProvider.class); when(fallbackProvider.getType()).thenReturn(MinGasPriceProviderType.FIXED); - stableMinGasPriceProvider = spy(new TestStableMingGasPriceProvider(fallBackProvider, 100, 10)); + stableMinGasPriceProvider = spy(new TestStableMingGasPriceProvider(fallBackProvider, 100, Duration.ofSeconds(10))); stableMinGasPriceProvider.getMinGasPrice(); stableMinGasPriceProvider.getMinGasPrice(); @@ -83,8 +84,8 @@ void testGetMinGasPriceAsCoin() { public static class TestStableMingGasPriceProvider extends StableMinGasPriceProvider { - protected TestStableMingGasPriceProvider(MinGasPriceProvider fallBackProvider, long minStableGasPrice, int refreshRateSeconds) { - super(fallBackProvider, minStableGasPrice, refreshRateSeconds); + protected TestStableMingGasPriceProvider(MinGasPriceProvider fallBackProvider, long minStableGasPrice, Duration refreshRate) { + super(fallBackProvider, minStableGasPrice, refreshRate); } @Override From 1265ac9a8e30d0ad1d3bcd4e8197c69e911013eb Mon Sep 17 00:00:00 2001 From: Volodymyr Kravets Date: Fri, 13 Sep 2024 14:33:27 +0300 Subject: [PATCH 16/17] fix(stableMinGasPrice): fetch prices in background --- .../provider/StableMinGasPriceProvider.java | 88 +++++++++++++++---- .../HttpGetMinGasPriceProviderTest.java | 10 +-- .../StableMinGasPriceProviderTest.java | 10 +-- 3 files changed, 79 insertions(+), 29 deletions(-) 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 d6828e756a0..225847a631c 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 @@ -18,26 +18,34 @@ package co.rsk.mine.gas.provider; import co.rsk.core.Coin; +import com.google.common.annotations.VisibleForTesting; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.time.Duration; import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; public abstract class StableMinGasPriceProvider implements MinGasPriceProvider { private static final Logger logger = LoggerFactory.getLogger("StableMinGasPrice"); private static final int ERR_NUM_OF_FAILURES = 20; + private final MinGasPriceProvider fallBackProvider; private final long minStableGasPrice; - private Long lastMinGasPrice; - private long lastUpdateTimeMillis; - private int numOfFailures; private final long refreshRateInMillis; + private final AtomicInteger numOfFailures = new AtomicInteger(); + private final AtomicReference> priceFuture = new AtomicReference<>(); + + private volatile long lastMinGasPrice; + private volatile long lastUpdateTimeMillis; protected StableMinGasPriceProvider(MinGasPriceProvider fallBackProvider, long minStableGasPrice, Duration refreshRate) { this.minStableGasPrice = minStableGasPrice; this.fallBackProvider = fallBackProvider; - this.lastMinGasPrice = 0L; this.refreshRateInMillis = refreshRate.toMillis(); } @@ -45,14 +53,41 @@ protected StableMinGasPriceProvider(MinGasPriceProvider fallBackProvider, long m @Override public long getMinGasPrice() { + return getMinGasPrice(false); + } + + @VisibleForTesting + public long getMinGasPrice(boolean wait) { long currentTimeMillis = System.currentTimeMillis(); if (currentTimeMillis - lastUpdateTimeMillis >= refreshRateInMillis) { - if (fetchPrice()) { - lastUpdateTimeMillis = currentTimeMillis; + Future priceFuture = fetchPriceAsync(); + if (wait || priceFuture.isDone()) { + try { + return priceFuture.get(); + } catch (InterruptedException e) { + logger.error("Min gas price fetching was interrupted", e); + Thread.currentThread().interrupt(); + } catch (ExecutionException e) { + logger.error("Min gas price fetching was failed", e); + } } } - if (lastMinGasPrice != null && lastMinGasPrice > 0) { + return getLastMinGasPrice(); + } + + @Override + public Coin getMinGasPriceAsCoin() { + return Coin.valueOf(getMinGasPrice()); + } + + @VisibleForTesting + public Coin getMinGasPriceAsCoin(boolean wait) { + return Coin.valueOf(getMinGasPrice(wait)); + } + + private long getLastMinGasPrice() { + if (lastMinGasPrice > 0) { return lastMinGasPrice; } @@ -66,26 +101,41 @@ private long calculateMinGasPriceBasedOnBtcPrice(long btcValue) { return minStableGasPrice / btcValue; } - @Override - public Coin getMinGasPriceAsCoin() { - return Coin.valueOf(getMinGasPrice()); + private synchronized Future fetchPriceAsync() { + Future curFuture = priceFuture.get(); + if (curFuture != null) { + return curFuture; + } + + CompletableFuture newFuture = new CompletableFuture<>(); + priceFuture.set(newFuture); + + new Thread(() -> { + Optional priceResponse = fetchPriceSync(); + newFuture.complete(priceResponse.orElse(getLastMinGasPrice())); + priceFuture.set(null); + }).start(); + + return newFuture; } - private boolean fetchPrice() { + private Optional fetchPriceSync() { Optional priceResponse = getBtcExchangeRate(); if (priceResponse.isPresent() && priceResponse.get() > 0) { - lastMinGasPrice = calculateMinGasPriceBasedOnBtcPrice(priceResponse.get()); - numOfFailures = 0; - return true; + long result = calculateMinGasPriceBasedOnBtcPrice(priceResponse.get()); + lastMinGasPrice = result; + lastUpdateTimeMillis = System.currentTimeMillis(); + numOfFailures.set(0); + return Optional.of(result); } - numOfFailures++; - if (numOfFailures >= ERR_NUM_OF_FAILURES) { - logger.error("Gas price was not updated as it was not possible to obtain valid price from provider. Check your provider setup. Number of failed attempts: {}", numOfFailures); + int curNumOfFailures = numOfFailures.incrementAndGet(); + if (curNumOfFailures >= ERR_NUM_OF_FAILURES) { + logger.error("Gas price was not updated as it was not possible to obtain valid price from provider. Check your provider setup. Number of failed attempts: {}", curNumOfFailures); } else { - logger.warn("Gas price was not updated as it was not possible to obtain valid price from provider. Number of failed attempts: {}", numOfFailures); + logger.warn("Gas price was not updated as it was not possible to obtain valid price from provider. Number of failed attempts: {}", curNumOfFailures); } - return false; + return Optional.empty(); } } diff --git a/rskj-core/src/test/java/co/rsk/mine/gas/provider/HttpGetMinGasPriceProviderTest.java b/rskj-core/src/test/java/co/rsk/mine/gas/provider/HttpGetMinGasPriceProviderTest.java index 102ad7e34b1..231ff946ca1 100644 --- a/rskj-core/src/test/java/co/rsk/mine/gas/provider/HttpGetMinGasPriceProviderTest.java +++ b/rskj-core/src/test/java/co/rsk/mine/gas/provider/HttpGetMinGasPriceProviderTest.java @@ -60,9 +60,9 @@ void whenRequestingTheValueTwiceCachedValueIsUsed() throws HttpException { HttpGetMinGasPriceProvider provider = spy(new HttpGetMinGasPriceProvider(config, fallbackProvider, httpClient)); provider.getMinGasPrice(); - provider.getMinGasPrice(); + provider.getMinGasPrice(true); - verify(provider, times(2)).getMinGasPrice(); + verify(provider, times(2)).getMinGasPrice(anyBoolean()); verify(httpClient, times(1)).doGet(anyString()); } @@ -77,7 +77,7 @@ void whenEmptyResponseReturnsFallbackProvider() throws HttpException { StableMinGasPriceSystemConfig config = createStableMinGasPriceSystemConfig(); HttpGetMinGasPriceProvider provider = new HttpGetMinGasPriceProvider(config, fallbackProvider, httpClient); - Long result = provider.getMinGasPrice(); + Long result = provider.getMinGasPrice(true); verify(fallbackProvider, times(1)).getMinGasPrice(); assertEquals(10L, result); } @@ -93,7 +93,7 @@ void whenErrorReturnsFallbackProvider() throws HttpException { StableMinGasPriceSystemConfig config = createStableMinGasPriceSystemConfig(); HttpGetMinGasPriceProvider provider = new HttpGetMinGasPriceProvider(config, fallbackProvider, httpClient); - Long result = provider.getMinGasPrice(); + Long result = provider.getMinGasPrice(true); verify(fallbackProvider, times(1)).getMinGasPrice(); assertEquals(10L, result); } @@ -109,7 +109,7 @@ void whenPathIsWrongReturnsFallBack() throws HttpException { StableMinGasPriceSystemConfig config = createStableMinGasPriceSystemConfig(); HttpGetMinGasPriceProvider provider = new HttpGetMinGasPriceProvider(config, fallbackProvider, httpClient); - Long result = provider.getMinGasPrice(); + Long result = provider.getMinGasPrice(true); verify(fallbackProvider, times(1)).getMinGasPrice(); assertEquals(10L, result); 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 a49d671752d..5b4269f9faf 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 @@ -42,7 +42,7 @@ void setUp() { @Test void testGetMinGasPrice() { - long result = stableMinGasPriceProvider.getMinGasPrice(); + long result = stableMinGasPriceProvider.getMinGasPrice(true); assertEquals(6L, result); verify(fallBackProvider, times(0)).getMinGasPrice(); } @@ -56,7 +56,7 @@ public Optional getBtcExchangeRate() { } }; - long result = stableMinGasPriceProvider.getMinGasPrice(); + long result = stableMinGasPriceProvider.getMinGasPrice(true); assertEquals(10L, result); verify(fallBackProvider, times(1)).getMinGasPrice(); @@ -70,14 +70,14 @@ void whenRequestingTheValueTwiceCachedValueIsUsed() { stableMinGasPriceProvider = spy(new TestStableMingGasPriceProvider(fallBackProvider, 100, Duration.ofSeconds(10))); stableMinGasPriceProvider.getMinGasPrice(); - stableMinGasPriceProvider.getMinGasPrice(); + stableMinGasPriceProvider.getMinGasPrice(true); - verify(stableMinGasPriceProvider, times(2)).getMinGasPrice(); + verify(stableMinGasPriceProvider, times(2)).getMinGasPrice(anyBoolean()); verify(stableMinGasPriceProvider, times(1)).getBtcExchangeRate(); } @Test void testGetMinGasPriceAsCoin() { - Coin result = stableMinGasPriceProvider.getMinGasPriceAsCoin(); + Coin result = stableMinGasPriceProvider.getMinGasPriceAsCoin(true); assertEquals(Coin.valueOf(6L), result); } From 8cecf4378fc25bc79a2ad8fcdb4e56b54cb27ad5 Mon Sep 17 00:00:00 2001 From: Volodymyr Kravets Date: Mon, 16 Sep 2024 16:52:54 +0300 Subject: [PATCH 17/17] fix(stableMinGasPrice): apply naming suggestions --- .../gas/provider/StableMinGasPriceProvider.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) 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 225847a631c..72f83d02a74 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 @@ -82,7 +82,7 @@ public Coin getMinGasPriceAsCoin() { } @VisibleForTesting - public Coin getMinGasPriceAsCoin(boolean wait) { + Coin getMinGasPriceAsCoin(boolean wait) { return Coin.valueOf(getMinGasPrice(wait)); } @@ -102,9 +102,9 @@ private long calculateMinGasPriceBasedOnBtcPrice(long btcValue) { } private synchronized Future fetchPriceAsync() { - Future curFuture = priceFuture.get(); - if (curFuture != null) { - return curFuture; + Future future = priceFuture.get(); + if (future != null) { + return future; } CompletableFuture newFuture = new CompletableFuture<>(); @@ -129,11 +129,11 @@ private Optional fetchPriceSync() { return Optional.of(result); } - int curNumOfFailures = numOfFailures.incrementAndGet(); - if (curNumOfFailures >= ERR_NUM_OF_FAILURES) { - logger.error("Gas price was not updated as it was not possible to obtain valid price from provider. Check your provider setup. Number of failed attempts: {}", curNumOfFailures); + int failedAttempts = numOfFailures.incrementAndGet(); + if (failedAttempts >= ERR_NUM_OF_FAILURES) { + logger.error("Gas price was not updated as it was not possible to obtain valid price from provider. Check your provider setup. Number of failed attempts: {}", failedAttempts); } else { - logger.warn("Gas price was not updated as it was not possible to obtain valid price from provider. Number of failed attempts: {}", curNumOfFailures); + logger.warn("Gas price was not updated as it was not possible to obtain valid price from provider. Number of failed attempts: {}", failedAttempts); } return Optional.empty();