Skip to content

Commit

Permalink
feat(smgp): adds context fetching callback to providers
Browse files Browse the repository at this point in the history
  • Loading branch information
jurajpiar committed Jun 7, 2024
1 parent bf975c5 commit 782ccf8
Show file tree
Hide file tree
Showing 11 changed files with 182 additions and 28 deletions.
4 changes: 2 additions & 2 deletions rskj-core/src/main/java/co/rsk/RskContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -2222,4 +2222,4 @@ private void checkIfNotClosed() {
throw new IllegalStateException("RSK Context is closed and cannot be in use anymore");
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Expand All @@ -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;
Expand Down
Original file line number Diff line number Diff line change
@@ -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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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())
Expand All @@ -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);
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -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());
Expand All @@ -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());
Expand All @@ -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());
Expand All @@ -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());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ void testGetMinGasPriceAsCoin() {
public static class TestStableMingGasPriceProvider extends StableMinGasPriceProvider {

protected TestStableMingGasPriceProvider(MinGasPriceProvider fallBackProvider) {
super(fallBackProvider);
super(fallBackProvider, () -> null);
}

@Override
Expand All @@ -64,4 +64,4 @@ public Long getStableMinGasPrice() {
return 1L;
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
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_failedCallReturnsZero() {
when(ethModule_mock.call(any(), any())).thenReturn(null);

Assertions.assertEquals(0, onChainMinGasPriceProvider.getStableMinGasPrice());
}

@Test
public void getStableMinGasPrice_returnsCallReturnValue() {
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_shouldFallback_whenNoData(String data_input) {
when(onChainMinGasPriceSystemConfig_mock.data()).thenReturn(data_input);

Assertions.assertEquals(
fallback_minGasPrice_fake,
onChainMinGasPriceProvider.getStableMinGasPrice(),
"For " + data_input + ": "
);
}

}

0 comments on commit 782ccf8

Please sign in to comment.