Skip to content

Commit

Permalink
Updating how eth_gasPrice is calculated
Browse files Browse the repository at this point in the history
  • Loading branch information
asoto-iov committed Nov 15, 2023
1 parent a424e49 commit e3f26f9
Show file tree
Hide file tree
Showing 8 changed files with 119 additions and 47 deletions.
3 changes: 2 additions & 1 deletion rskj-core/src/main/java/co/rsk/RskContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -544,7 +544,8 @@ public synchronized Ethereum getRsk() {
getTransactionGateway(),
getCompositeEthereumListener(),
getBlockchain(),
getGasPriceTracker()
getGasPriceTracker(),
rskSystemProperties.getMinGasPriceMultiplier()
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ public abstract class SystemProperties {
private static final String PROPERTY_RPC_GAS_ESTIMATION_CAP = "rpc.gasEstimationCap";
private static final String PROPERTY_RPC_CALL_GAS_CAP = "rpc.callGasCap";
private static final String PROPERTY_RPC_MAX_RESPONSE_SIZE = "rpc.maxResponseSize";
private static final String PROPERTY_RPC_MIN_GAS_PRICE_MULTIPLIER = "rpc.minGasPriceMultiplier";
private static final String PROPERTY_RPC_TIMEOUT = "rpc.timeout";

public static final String PROPERTY_PUBLIC_IP = "public.ip";
Expand Down Expand Up @@ -738,6 +739,14 @@ public long getCallGasCap() {
return configFromFiles.getLong(PROPERTY_RPC_CALL_GAS_CAP);
}

public double getMinGasPriceMultiplier() {
if (!configFromFiles.hasPath(PROPERTY_RPC_MIN_GAS_PRICE_MULTIPLIER)) {
return 1.1;
}

return configFromFiles.getDouble(PROPERTY_RPC_MIN_GAS_PRICE_MULTIPLIER);
}

public long getRpcTimeout() {
if (!configFromFiles.hasPath(PROPERTY_RPC_TIMEOUT)) {
return 0L;
Expand Down
12 changes: 10 additions & 2 deletions rskj-core/src/main/java/org/ethereum/facade/EthereumImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import org.ethereum.net.server.ChannelManager;

import javax.annotation.Nonnull;
import java.math.BigDecimal;

public class EthereumImpl implements Ethereum {

Expand All @@ -36,13 +37,15 @@ public class EthereumImpl implements Ethereum {
private final CompositeEthereumListener compositeEthereumListener;
private final Blockchain blockchain;
private final GasPriceTracker gasPriceTracker;
private final Double minGasPriceMultiplier;

public EthereumImpl(
ChannelManager channelManager,
TransactionGateway transactionGateway,
CompositeEthereumListener compositeEthereumListener,
Blockchain blockchain,
GasPriceTracker gasPriceTracker) {
GasPriceTracker gasPriceTracker,
Double minGasPriceMultiplier) {
this.channelManager = channelManager;
this.transactionGateway = transactionGateway;

Expand All @@ -51,6 +54,7 @@ public EthereumImpl(

this.gasPriceTracker = gasPriceTracker;
compositeEthereumListener.addListener(gasPriceTracker);
this.minGasPriceMultiplier = minGasPriceMultiplier;
}

@Override
Expand Down Expand Up @@ -80,6 +84,10 @@ public TransactionPoolAddResult submitTransaction(Transaction transaction) {

@Override
public Coin getGasPrice() {
return gasPriceTracker.getGasPrice();
if (gasPriceTracker.isFeeMarketWorking()) {
return gasPriceTracker.getGasPrice();
}
double estimatedGasPrice = blockchain.getBestBlock().getMinimumGasPrice().asBigInteger().doubleValue() * minGasPriceMultiplier;
return new Coin(BigDecimal.valueOf(estimatedGasPrice).toBigInteger());
}
}
34 changes: 17 additions & 17 deletions rskj-core/src/main/java/org/ethereum/listener/GasPriceTracker.java
Original file line number Diff line number Diff line change
Expand Up @@ -68,16 +68,16 @@ public class GasPriceTracker extends EthereumListenerAdapter {

private Coin lastVal;

private GasPriceTracker(BlockStore blockStore) {
this.blockStore = blockStore;
}

public static GasPriceTracker create(BlockStore blockStore) {
GasPriceTracker gasPriceTracker = new GasPriceTracker(blockStore);
gasPriceTracker.initializeWindowsFromDB();
return gasPriceTracker;
}

private GasPriceTracker(BlockStore blockStore) {
this.blockStore = blockStore;
}

@Override
public void onBestBlock(Block block, List<TransactionReceipt> receipts) {
bestBlockPriceRef.set(block.getMinimumGasPrice());
Expand Down Expand Up @@ -109,20 +109,20 @@ private void onTransaction(Transaction tx) {
public synchronized Coin getGasPrice() {
if (txWindow[0] == null) { // for some reason, not filled yet (i.e. not enough blocks on DB)
return defaultPrice;
} else {
if (lastVal == null) {
Coin[] values = Arrays.copyOf(txWindow, TX_WINDOW_SIZE);
Arrays.sort(values);
lastVal = values[values.length / 4]; // 25% percentile
}

Coin bestBlockPrice = bestBlockPriceRef.get();
if (bestBlockPrice == null) {
return lastVal;
} else {
return Coin.max(lastVal, bestBlockPrice.multiply(BI_11).divide(BI_10));
}
}

if (lastVal == null) {
Coin[] values = Arrays.copyOf(txWindow, TX_WINDOW_SIZE);
Arrays.sort(values);
lastVal = values[values.length / 4]; // 25% percentile
}

Coin bestBlockPrice = bestBlockPriceRef.get();
if (bestBlockPrice == null) {
return lastVal;
}

return Coin.max(lastVal, bestBlockPrice.multiply(BI_11).divide(BI_10));
}

public synchronized boolean isFeeMarketWorking() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ void defaultValues() {
assertEquals(0, config.minerMinGasPrice());
assertEquals(0, config.minerGasUnitInDollars(), 0.001);
assertEquals(0, config.minerMinFeesNotifyInDollars(), 0.001);
assertEquals(1.1, config.getMinGasPriceMultiplier());

assertFalse(config.getIsHeartBeatEnabled());
}
Expand Down
58 changes: 32 additions & 26 deletions rskj-core/src/test/java/co/rsk/mine/MinerServerTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -190,35 +190,35 @@ void submitBitcoinBlockTwoTags() {
MinerClock clock = new MinerClock(true, Clock.systemUTC());
MinerServer minerServer = makeMinerServer(ethereumImpl, unclesValidationRule, clock);
try {
byte[] extraData = ByteBuffer.allocate(4).putInt(1).array();
minerServer.setExtraData(extraData);
minerServer.start();
MinerWork work = minerServer.getWork();
byte[] extraData = ByteBuffer.allocate(4).putInt(1).array();
minerServer.setExtraData(extraData);
minerServer.start();
MinerWork work = minerServer.getWork();

extraData = ByteBuffer.allocate(4).putInt(2).array();
minerServer.setExtraData(extraData);
minerServer.buildBlockToMine(false);
MinerWork work2 = minerServer.getWork(); // only the tag is used
Assertions.assertNotEquals(work2.getBlockHashForMergedMining(),work.getBlockHashForMergedMining());
extraData = ByteBuffer.allocate(4).putInt(2).array();
minerServer.setExtraData(extraData);
minerServer.buildBlockToMine(false);
MinerWork work2 = minerServer.getWork(); // only the tag is used
Assertions.assertNotEquals(work2.getBlockHashForMergedMining(), work.getBlockHashForMergedMining());

BtcBlock bitcoinMergedMiningBlock = getMergedMiningBlockWithTwoTags(work,work2);
BtcBlock bitcoinMergedMiningBlock = getMergedMiningBlockWithTwoTags(work, work2);

findNonce(work, bitcoinMergedMiningBlock);
SubmitBlockResult result;
result = minerServer.submitBitcoinBlock(work2.getBlockHashForMergedMining(), bitcoinMergedMiningBlock,true);
findNonce(work, bitcoinMergedMiningBlock);
SubmitBlockResult result;
result = minerServer.submitBitcoinBlock(work2.getBlockHashForMergedMining(), bitcoinMergedMiningBlock, true);


Assertions.assertEquals("OK", result.getStatus());
Assertions.assertNotNull(result.getBlockInfo());
Assertions.assertEquals("0x1", result.getBlockInfo().getBlockIncludedHeight());
Assertions.assertEquals("0x494d504f525445445f42455354", result.getBlockInfo().getBlockImportedResult());
Assertions.assertEquals("OK", result.getStatus());
Assertions.assertNotNull(result.getBlockInfo());
Assertions.assertEquals("0x1", result.getBlockInfo().getBlockIncludedHeight());
Assertions.assertEquals("0x494d504f525445445f42455354", result.getBlockInfo().getBlockImportedResult());

// Submit again the save PoW for a different header
result = minerServer.submitBitcoinBlock(work.getBlockHashForMergedMining(), bitcoinMergedMiningBlock,false);
// Submit again the save PoW for a different header
result = minerServer.submitBitcoinBlock(work.getBlockHashForMergedMining(), bitcoinMergedMiningBlock, false);

Assertions.assertEquals("ERROR", result.getStatus());
Assertions.assertEquals("ERROR", result.getStatus());

verify(ethereumImpl, times(1)).addNewMinedBlock(any());
verify(ethereumImpl, times(1)).addNewMinedBlock(any());
} finally {
minerServer.stop();
}
Expand Down Expand Up @@ -408,9 +408,8 @@ void workWithNoTransactionsZeroFees() {

minerServer.start();
try {
MinerWork work = minerServer.getWork();

assertEquals("0", work.getFeesPaidToMiner());
MinerWork work = minerServer.getWork();
assertEquals("0", work.getFeesPaidToMiner());
} finally {
minerServer.stop();
}
Expand Down Expand Up @@ -729,7 +728,14 @@ void onBestBlockBuildBlockToMine() {
void onNewTxBuildBlockToMine() throws InterruptedException {

// prepare for miner server
Ethereum ethereum = spy(new EthereumImpl(null, null, compositeEthereumListener, standardBlockchain, mock(GasPriceTracker.class)) );
Ethereum ethereum = spy(new EthereumImpl(
null,
null,
compositeEthereumListener,
standardBlockchain,
mock(GasPriceTracker.class),
rskTestContext.getRskSystemProperties().getMinGasPriceMultiplier())
);
doReturn(ImportResult.IMPORTED_BEST).when(ethereum).addNewMinedBlock(any());

BlockUnclesValidationRule unclesValidationRule = mock(BlockUnclesValidationRule.class);
Expand All @@ -741,7 +747,7 @@ void onNewTxBuildBlockToMine() throws InterruptedException {
when(blockProcessor.hasBetterBlockToSync()).thenReturn(false);

// create the transaction
World world = new World((BlockChainImpl) standardBlockchain, blockStore, rskTestContext.getReceiptStore(), rskTestContext.getTrieStore(), repository, transactionPool, (Genesis)null);
World world = new World((BlockChainImpl) standardBlockchain, blockStore, rskTestContext.getReceiptStore(), rskTestContext.getTrieStore(), repository, transactionPool, (Genesis) null);

Account sender = new AccountBuilder(world).name("sender").balance(new Coin(BigInteger.valueOf(2000))).build();
Account receiver = new AccountBuilder(world).name("receiver").build();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -580,7 +580,8 @@ private Web3Impl internalCreateEnvironment(Blockchain blockchain,
transactionGateway,
compositeEthereumListener,
blockchain,
GasPriceTracker.create(blockStore)
GasPriceTracker.create(blockStore),
config.getMinGasPriceMultiplier()
);
MinerClock minerClock = new MinerClock(true, Clock.systemUTC());
this.transactionExecutorFactory = transactionExecutorFactory;
Expand Down
46 changes: 46 additions & 0 deletions rskj-core/src/test/java/org/ethereum/facade/EthereumImplTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package org.ethereum.facade;

import co.rsk.core.Coin;
import org.ethereum.core.Block;
import org.ethereum.core.Blockchain;
import org.ethereum.listener.CompositeEthereumListener;
import org.ethereum.listener.GasPriceTracker;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

class EthereumImplTest {

Check notice

Code scanning / CodeQL

Unused classes and interfaces Note test

Unused class: EthereumImplTest is not referenced within this codebase. If not used as an external API it should be removed.


@Test
void getGasPrice_returns_GasPriceTrackerValue_when_feeMarketWorking_is_true() {
GasPriceTracker gasPriceTracker = mock(GasPriceTracker.class);

when(gasPriceTracker.isFeeMarketWorking()).thenReturn(true);
when(gasPriceTracker.getGasPrice()).thenReturn(Coin.valueOf(10));

Ethereum ethereum = new EthereumImpl(null, null, new CompositeEthereumListener(), null, gasPriceTracker, null);
Coin price = ethereum.getGasPrice();

assertEquals(10, price.asBigInteger().intValue());
}

@Test
void getGasPrice_returns_correctedBestBlockValue_when_feeMarketWorking_is_false(){
GasPriceTracker gasPriceTracker = mock(GasPriceTracker.class);
Blockchain blockchain = mock(Blockchain.class);
Double minGasPriceMultiplier = 1.2;
Block bestBlock = mock(Block.class);

when(gasPriceTracker.isFeeMarketWorking()).thenReturn(false);
when(bestBlock.getMinimumGasPrice()).thenReturn(Coin.valueOf(10));
when(blockchain.getBestBlock()).thenReturn(bestBlock);

Ethereum ethereum = new EthereumImpl(null, null, new CompositeEthereumListener(), blockchain, gasPriceTracker, minGasPriceMultiplier);
Coin price = ethereum.getGasPrice();

assertEquals(12, price.asBigInteger().intValue());
}
}

0 comments on commit e3f26f9

Please sign in to comment.