Skip to content

Commit

Permalink
Merge pull request #2220 from rsksmart/gas-price-config
Browse files Browse the repository at this point in the history
Gas price config
  • Loading branch information
Vovchyk authored Jan 29, 2024
2 parents 12fdadd + dafb20a commit d8ad1c1
Show file tree
Hide file tree
Showing 10 changed files with 86 additions and 10 deletions.
4 changes: 3 additions & 1 deletion rskj-core/src/main/java/co/rsk/RskContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -555,8 +555,10 @@ public synchronized Ethereum getRsk() {
public GasPriceTracker getGasPriceTracker() {
checkIfNotClosed();

double gasPriceMultiplier = getRskSystemProperties().gasPriceMultiplier();

if (this.gasPriceTracker == null) {
this.gasPriceTracker = GasPriceTracker.create(getBlockStore());
this.gasPriceTracker = GasPriceTracker.create(getBlockStore(), gasPriceMultiplier);
}
return this.gasPriceTracker;
}
Expand Down
11 changes: 11 additions & 0 deletions rskj-core/src/main/java/co/rsk/config/RskSystemProperties.java
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ public class RskSystemProperties extends SystemProperties {
private static final String RPC_MODULES_PATH = "rpc.modules";
private static final String RPC_ETH_GET_LOGS_MAX_BLOCKS_TO_QUERY = "rpc.logs.maxBlocksToQuery";
private static final String RPC_ETH_GET_LOGS_MAX_LOGS_TO_RETURN = "rpc.logs.maxLogsToReturn";
private static final String RPC_GAS_PRICE_MULTIPLIER_CONFIG = "rpc.gasPriceMultiplier";

private static final int CHUNK_SIZE = 192;

Expand Down Expand Up @@ -185,6 +186,16 @@ public boolean isWalletEnabled() {
return getBoolean("wallet.enabled", false);
}

public double gasPriceMultiplier() {
double gasPriceMultiplier = getDouble(RPC_GAS_PRICE_MULTIPLIER_CONFIG, 1.1);

if(gasPriceMultiplier >= 0) {
return gasPriceMultiplier;
} else {
throw new RskConfigurationException(RPC_GAS_PRICE_MULTIPLIER_CONFIG + " cannot be a negative number");
}
}

public List<WalletAccount> walletAccounts() {
if (!configFromFiles.hasPath("wallet.accounts")) {
return Collections.emptyList();
Expand Down
18 changes: 12 additions & 6 deletions rskj-core/src/main/java/org/ethereum/listener/GasPriceTracker.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.math.BigInteger;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;

Expand All @@ -51,15 +51,15 @@ public class GasPriceTracker extends EthereumListenerAdapter {

private static final double BLOCK_COMPLETION_PERCENT_FOR_FEE_MARKET_WORKING = 0.9;

private static final BigInteger BI_10 = BigInteger.valueOf(10);
private static final BigInteger BI_11 = BigInteger.valueOf(11);
private static final double DEFAULT_GAS_PRICE_MULTIPLIER = 1.1;

private final Coin[] txWindow = new Coin[TX_WINDOW_SIZE];

private final Double[] blockWindow = new Double[BLOCK_WINDOW_SIZE];

private final AtomicReference<Coin> bestBlockPriceRef = new AtomicReference<>();
private final BlockStore blockStore;
private final double gasPriceMultiplier;

private Coin defaultPrice = Coin.valueOf(20_000_000_000L);
private int txIdx = TX_WINDOW_SIZE - 1;
Expand All @@ -68,12 +68,17 @@ public class GasPriceTracker extends EthereumListenerAdapter {

private Coin lastVal;

private GasPriceTracker(BlockStore blockStore) {
private GasPriceTracker(BlockStore blockStore, Double configMultiplier) {
this.blockStore = blockStore;
this.gasPriceMultiplier = configMultiplier;
}

public static GasPriceTracker create(BlockStore blockStore) {
GasPriceTracker gasPriceTracker = new GasPriceTracker(blockStore);
return create(blockStore, DEFAULT_GAS_PRICE_MULTIPLIER);
}

public static GasPriceTracker create(BlockStore blockStore, Double configMultiplier) {
GasPriceTracker gasPriceTracker = new GasPriceTracker(blockStore, configMultiplier);
gasPriceTracker.initializeWindowsFromDB();
return gasPriceTracker;
}
Expand Down Expand Up @@ -122,7 +127,8 @@ public synchronized Coin getGasPrice() {
return lastVal;
}

return Coin.max(lastVal, bestBlockPrice.multiply(BI_11).divide(BI_10));
return Coin.max(lastVal, new Coin(new BigDecimal(bestBlockPrice.asBigInteger())
.multiply(BigDecimal.valueOf(gasPriceMultiplier)).toBigInteger()));
}

public synchronized boolean isFeeMarketWorking() {
Expand Down
1 change: 0 additions & 1 deletion rskj-core/src/main/java/org/ethereum/util/Utils.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@

import org.bouncycastle.util.encoders.DecoderException;
import org.bouncycastle.util.encoders.Hex;

import java.lang.reflect.Array;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
Expand Down
1 change: 1 addition & 0 deletions rskj-core/src/main/resources/expected.conf
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,7 @@ rpc = {
callGasCap = <number>
timeout = <number>
maxResponseSize = <number>
gasPriceMultiplier = <gasPriceMultiplier>
providers = {
web = {
cors = <cors>
Expand Down
4 changes: 4 additions & 0 deletions rskj-core/src/main/resources/reference.conf
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,10 @@ rpc {
# Maximum Response size allowed in bytes. If value is 0 then there is no limit.
maxResponseSize = 0

# This property can be set to a numeric value by the node operator to over write the percentage for the
# gas price multiplier used to calculate the gas price returned by eth_gasPrice
gasPriceMultiplier = 1.1

providers {
web {
cors = "localhost"
Expand Down
38 changes: 38 additions & 0 deletions rskj-core/src/test/java/co/rsk/config/RskSystemPropertiesTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@
import co.rsk.cli.RskCli;
import co.rsk.rpc.ModuleDescription;
import com.typesafe.config.Config;
import com.typesafe.config.ConfigException;
import com.typesafe.config.ConfigFactory;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
Expand Down Expand Up @@ -223,4 +225,40 @@ void testGetRpcModulesWithObject() {
assertEquals(9000, netModule.getTimeout());
assertEquals(30000, netModule.getMethodTimeout("eth_getBlockByHash"));
}

@Test
void testGasPriceMultiplier() {
assertEquals(1.05, config.gasPriceMultiplier());
}

@Test
void testGasPriceMultiplierWithNull() {
// Set miner.gasPriceMultiplier to null which yields the same result as not finding the path
TestSystemProperties testSystemProperties = new TestSystemProperties(rawConfig ->
ConfigFactory.parseString("{" +
"rpc.gasPriceMultiplier = null" +
" }").withFallback(rawConfig));

assertEquals(1.1, testSystemProperties.gasPriceMultiplier());
}

@Test
void testGasPriceMultiplierThrowsErrorForInvalidType() {
TestSystemProperties testSystemProperties = new TestSystemProperties(rawConfig ->
ConfigFactory.parseString("{" +
"rpc.gasPriceMultiplier = invalid" +
" }").withFallback(rawConfig));

Assertions.assertThrows(ConfigException.WrongType.class, testSystemProperties::gasPriceMultiplier);
}

@Test
void testGasPriceMultiplierThrowsErrorForNegativeValue() {
TestSystemProperties testSystemProperties = new TestSystemProperties(rawConfig ->
ConfigFactory.parseString("{" +
"rpc.gasPriceMultiplier = -1" +
" }").withFallback(rawConfig));

Assertions.assertThrows(RskConfigurationException.class, testSystemProperties::gasPriceMultiplier);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@

class EthereumImplTest {


@Test
void getGasPrice_returns_GasPriceTrackerValue_when_feeMarketWorking_is_true() {
GasPriceTracker gasPriceTracker = mock(GasPriceTracker.class);
Expand Down Expand Up @@ -60,4 +59,4 @@ void getGasPrice_returns_correctedBestBlockValue_when_feeMarketWorking_is_false(

assertEquals(12, price.asBigInteger().intValue());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,21 @@ void getGasPrice_PriceWindowFilled_BestBlockReceivedWithGreaterPrice_ReturnsBest
assertEquals(Coin.valueOf(55_000_000_000L), actualResult);
}

@Test
void getGasPrice_PriceWindowFilled_BestBlockReceivedWithGreaterPrice_GasPriceMultiplierOverWritten_ReturnsBestBlockAdjustedPriceWithNewBuffer() {
GasPriceTracker gasPriceTracker = GasPriceTracker.create(blockStore, 1.05);

Block bestBlock = makeBlock(Coin.valueOf(50_000_000_000L), 0, i -> null);
Block block = makeBlock(Coin.valueOf(30_000_000_000L), TOTAL_SLOTS, i -> makeTx(Coin.valueOf(40_000_000_000L)));

gasPriceTracker.onBestBlock(bestBlock, Collections.emptyList());
gasPriceTracker.onBlock(block, Collections.emptyList());

Coin actualResult = gasPriceTracker.getGasPrice();

assertEquals(Coin.valueOf(52_500_000_000L), actualResult);
}

@Test
void isFeeMarketWorking_falseWhenNotEnoughBlocks() {
GasPriceTracker gasPriceTracker = GasPriceTracker.create(blockStore);
Expand Down
1 change: 1 addition & 0 deletions rskj-core/src/test/resources/test-rskj.conf
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,7 @@ sync {
}

rpc = {
gasPriceMultiplier = 1.05
callGasCap: 50000000,
timeout: 0,
maxResponseSize: 0,
Expand Down

0 comments on commit d8ad1c1

Please sign in to comment.