Skip to content

Commit

Permalink
[stratum] add proxy subscription + cleanup + Netty integration (hyper…
Browse files Browse the repository at this point in the history
…ledger#5129)

* Allow lenient hex param in eth_submitHashRate

* Migrate Stratum tests to Junit5

* Introduce MockitoExtension in Stratum tests

* Convert start/stop Stratum method to Vert.x future

* Use Stratum only with PowCoordinator

* Call JSON-RPC implementations from Stratum proxy

* Subscribe to newWork on proxy login

* Replace HTTP processing with Netty pipelines

---------

Signed-off-by: Diego López León <dieguitoll@gmail.com>
  • Loading branch information
diega authored Apr 14, 2023
1 parent 534a369 commit f68b97b
Show file tree
Hide file tree
Showing 19 changed files with 880 additions and 640 deletions.
5 changes: 4 additions & 1 deletion besu/src/main/java/org/hyperledger/besu/Runner.java
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,10 @@ public void startExternalServices() {
service ->
waitForServiceToStart(
"ipcJsonRpc", service.start().toCompletionStage().toCompletableFuture()));
stratumServer.ifPresent(server -> waitForServiceToStart("stratum", server.start()));
stratumServer.ifPresent(
server ->
waitForServiceToStart(
"stratum", server.start().toCompletionStage().toCompletableFuture()));
autoTransactionLogBloomCachingService.ifPresent(AutoTransactionLogBloomCachingService::start);
ethStatsService.ifPresent(EthStatsService::start);
}
Expand Down
10 changes: 5 additions & 5 deletions besu/src/main/java/org/hyperledger/besu/RunnerBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
import org.hyperledger.besu.cli.config.EthNetworkConfig;
import org.hyperledger.besu.cli.config.NetworkName;
import org.hyperledger.besu.cli.options.stable.EthstatsOptions;
import org.hyperledger.besu.consensus.merge.blockcreation.TransitionCoordinator;
import org.hyperledger.besu.controller.BesuController;
import org.hyperledger.besu.cryptoservices.NodeKey;
import org.hyperledger.besu.ethereum.ProtocolContext;
Expand Down Expand Up @@ -67,6 +66,7 @@
import org.hyperledger.besu.ethereum.api.query.BlockchainQueries;
import org.hyperledger.besu.ethereum.api.query.PrivacyQueries;
import org.hyperledger.besu.ethereum.blockcreation.MiningCoordinator;
import org.hyperledger.besu.ethereum.blockcreation.PoWMiningCoordinator;
import org.hyperledger.besu.ethereum.chain.Blockchain;
import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.core.MiningParameters;
Expand Down Expand Up @@ -742,10 +742,10 @@ public Runner build() {
Optional<StratumServer> stratumServer = Optional.empty();

if (miningParameters.isStratumMiningEnabled()) {
var powMiningCoordinator = miningCoordinator;
if (miningCoordinator instanceof TransitionCoordinator) {
LOG.debug("fetching powMiningCoordinator from TransitionCoordinator");
powMiningCoordinator = ((TransitionCoordinator) miningCoordinator).getPreMergeObject();
if (!(miningCoordinator instanceof PoWMiningCoordinator powMiningCoordinator)) {
throw new IllegalArgumentException(
"Stratum server requires an PoWMiningCoordinator not "
+ ((miningCoordinator == null) ? "null" : miningCoordinator.getClass().getName()));
}
stratumServer =
Optional.of(
Expand Down
52 changes: 0 additions & 52 deletions besu/src/test/java/org/hyperledger/besu/RunnerBuilderTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,6 @@
import static org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier.BLOCKCHAIN;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import org.hyperledger.besu.cli.config.EthNetworkConfig;
Expand All @@ -32,7 +29,6 @@
import org.hyperledger.besu.consensus.common.bft.protocol.BftProtocolManager;
import org.hyperledger.besu.consensus.ibft.protocol.IbftSubProtocol;
import org.hyperledger.besu.consensus.merge.blockcreation.MergeMiningCoordinator;
import org.hyperledger.besu.consensus.merge.blockcreation.TransitionCoordinator;
import org.hyperledger.besu.controller.BesuController;
import org.hyperledger.besu.crypto.SECP256K1;
import org.hyperledger.besu.cryptoservices.KeyPairSecurityModule;
Expand All @@ -44,7 +40,6 @@
import org.hyperledger.besu.ethereum.api.jsonrpc.ipc.JsonRpcIpcConfiguration;
import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.WebSocketConfiguration;
import org.hyperledger.besu.ethereum.blockcreation.MiningCoordinator;
import org.hyperledger.besu.ethereum.blockcreation.PoWMiningCoordinator;
import org.hyperledger.besu.ethereum.chain.DefaultBlockchain;
import org.hyperledger.besu.ethereum.chain.MutableBlockchain;
import org.hyperledger.besu.ethereum.core.Block;
Expand Down Expand Up @@ -398,51 +393,4 @@ public void noEngineApiNoServiceForMethods() {
assertThat(runner.getJsonRpcPort()).isPresent();
assertThat(runner.getEngineJsonRpcPort()).isEmpty();
}

@Test
public void assertTransitionStratumConfiguration() {
final JsonRpcConfiguration jrpc = JsonRpcConfiguration.createDefault();
jrpc.setEnabled(true);
final JsonRpcConfiguration engine = JsonRpcConfiguration.createEngineDefault();
engine.setEnabled(true);
final EthNetworkConfig mockMainnet = mock(EthNetworkConfig.class);
when(mockMainnet.getNetworkId()).thenReturn(BigInteger.ONE);
MergeConfigOptions.setMergeEnabled(true);
final MiningParameters mockMiningParams = mock(MiningParameters.class);
when(besuController.getMiningParameters()).thenReturn(mockMiningParams);
when(mockMiningParams.isStratumMiningEnabled()).thenReturn(true);
final TransitionCoordinator mockTransitionCoordinator =
spy(
new TransitionCoordinator(
mock(PoWMiningCoordinator.class), mock(MergeMiningCoordinator.class)));
when(besuController.getMiningCoordinator()).thenReturn(mockTransitionCoordinator);

new RunnerBuilder()
.discovery(true)
.p2pListenInterface("0.0.0.0")
.p2pListenPort(30303)
.p2pAdvertisedHost("127.0.0.1")
.p2pEnabled(true)
.natMethod(NatMethod.NONE)
.besuController(besuController)
.ethNetworkConfig(mockMainnet)
.metricsSystem(mock(ObservableMetricsSystem.class))
.permissioningService(mock(PermissioningServiceImpl.class))
.jsonRpcConfiguration(jrpc)
.engineJsonRpcConfiguration(engine)
.graphQLConfiguration(mock(GraphQLConfiguration.class))
.webSocketConfiguration(mock(WebSocketConfiguration.class))
.jsonRpcIpcConfiguration(mock(JsonRpcIpcConfiguration.class))
.metricsConfiguration(mock(MetricsConfiguration.class))
.vertx(Vertx.vertx())
.dataDir(dataDir.getRoot().toPath())
.storageProvider(mock(KeyValueStorageProvider.class))
.rpcEndpointService(new RpcEndpointServiceImpl())
.besuPluginContext(mock(BesuPluginContextImpl.class))
.networkingConfiguration(NetworkingConfiguration.create())
.build();

verify(mockTransitionCoordinator, times(1)).getPreMergeObject();
verify(mockTransitionCoordinator, times(1)).addEthHashObserver(any());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
import org.hyperledger.besu.ethereum.mainnet.EpochCalculator;
import org.hyperledger.besu.ethereum.mainnet.PoWSolverInputs;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

import com.google.common.io.BaseEncoding;
Expand Down Expand Up @@ -56,21 +58,24 @@ public String getName() {
@Override
public JsonRpcResponse response(final JsonRpcRequestContext requestContext) {
final Optional<PoWSolverInputs> solver = miner.getWorkDefinition();
final Object requestId = requestContext.getRequest().getId();
if (solver.isPresent()) {
final PoWSolverInputs rawResult = solver.get();
final byte[] dagSeed =
DirectAcyclicGraphSeed.dagSeed(rawResult.getBlockNumber(), epochCalculator);
final String[] result = {
rawResult.getPrePowHash().toHexString(),
"0x" + BaseEncoding.base16().lowerCase().encode(dagSeed),
rawResult.getTarget().toHexString(),
Quantity.create(rawResult.getBlockNumber())
};
return new JsonRpcSuccessResponse(requestContext.getRequest().getId(), result);
final List<String> response = new ArrayList<>(rawResponse(rawResult));
response.add(Quantity.create(rawResult.getBlockNumber()));
return new JsonRpcSuccessResponse(requestId, response);
} else {
LOG.trace("Mining is not operational, eth_getWork request cannot be processed");
return new JsonRpcErrorResponse(
requestContext.getRequest().getId(), JsonRpcError.NO_MINING_WORK_FOUND);
return new JsonRpcErrorResponse(requestId, JsonRpcError.NO_MINING_WORK_FOUND);
}
}

public List<String> rawResponse(final PoWSolverInputs rawResult) {
final byte[] dagSeed =
DirectAcyclicGraphSeed.dagSeed(rawResult.getBlockNumber(), epochCalculator);
return List.of(
rawResult.getPrePowHash().toHexString(),
"0x" + BaseEncoding.base16().lowerCase().encode(dagSeed),
rawResult.getTarget().toHexString());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,6 @@ public JsonRpcResponse response(final JsonRpcRequestContext requestContext) {
return new JsonRpcSuccessResponse(
requestContext.getRequest().getId(),
miningCoordinator.submitHashRate(
id, Bytes.fromHexString(hashRate).toBigInteger().longValue()));
id, Bytes.fromHexStringLenient(hashRate).toBigInteger().longValue()));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import org.hyperledger.besu.ethereum.mainnet.EpochCalculator;
import org.hyperledger.besu.ethereum.mainnet.PoWSolverInputs;

import java.util.List;
import java.util.Optional;

import com.google.common.io.BaseEncoding;
Expand Down Expand Up @@ -66,12 +67,12 @@ public void shouldReturnCorrectResultOnGenesisDAG() {
final JsonRpcRequestContext request = requestWithParams();
final PoWSolverInputs values =
new PoWSolverInputs(UInt256.fromHexString(hexValue), Bytes.fromHexString(hexValue), 0);
final String[] expectedValue = {
"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"0x0000000000000000000000000000000000000000000000000000000000000000",
"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"0x0"
};
final List<String> expectedValue =
List.of(
"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"0x0000000000000000000000000000000000000000000000000000000000000000",
"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"0x0");
final JsonRpcResponse expectedResponse =
new JsonRpcSuccessResponse(request.getRequest().getId(), expectedValue);
when(miningCoordinator.getWorkDefinition()).thenReturn(Optional.of(values));
Expand All @@ -86,17 +87,17 @@ public void shouldReturnCorrectResultOnHighBlockSeed() {
final PoWSolverInputs values =
new PoWSolverInputs(UInt256.fromHexString(hexValue), Bytes.fromHexString(hexValue), 30000);

final String[] expectedValue = {
"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"0x"
+ BaseEncoding.base16()
.lowerCase()
.encode(
DirectAcyclicGraphSeed.dagSeed(
30000, new EpochCalculator.DefaultEpochCalculator())),
"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"0x7530"
};
final List<String> expectedValue =
List.of(
"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"0x"
+ BaseEncoding.base16()
.lowerCase()
.encode(
DirectAcyclicGraphSeed.dagSeed(
30000, new EpochCalculator.DefaultEpochCalculator())),
"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"0x7530");
final JsonRpcResponse expectedResponse =
new JsonRpcSuccessResponse(request.getRequest().getId(), expectedValue);
when(miningCoordinator.getWorkDefinition()).thenReturn(Optional.of(values));
Expand All @@ -114,15 +115,15 @@ public void shouldReturnCorrectResultOnHighBlockSeedEcip1099() {
final PoWSolverInputs values =
new PoWSolverInputs(UInt256.fromHexString(hexValue), Bytes.fromHexString(hexValue), 60000);

final String[] expectedValue = {
"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"0x"
+ BaseEncoding.base16()
.lowerCase()
.encode(DirectAcyclicGraphSeed.dagSeed(60000, epochCalculator)),
"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"0xea60"
};
final List<String> expectedValue =
List.of(
"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"0x"
+ BaseEncoding.base16()
.lowerCase()
.encode(DirectAcyclicGraphSeed.dagSeed(60000, epochCalculator)),
"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"0xea60");
final JsonRpcResponse expectedResponse =
new JsonRpcSuccessResponse(request.getRequest().getId(), expectedValue);
when(miningCoordinator.getWorkDefinition()).thenReturn(Optional.of(values));
Expand Down
6 changes: 3 additions & 3 deletions ethereum/stratum/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,10 @@ dependencies {
testImplementation project(':testutil')

testImplementation 'com.fasterxml.jackson.core:jackson-databind'
testImplementation 'junit:junit'
testImplementation 'io.vertx:vertx-junit5'
testImplementation 'io.vertx:vertx-web-client'
testImplementation 'org.assertj:assertj-core'
testImplementation 'org.junit.jupiter:junit-jupiter'
testImplementation 'org.mockito:mockito-core'

testRuntimeOnly 'org.junit.vintage:junit-vintage-engine'
testImplementation 'org.mockito:mockito-junit-jupiter'
}
Loading

0 comments on commit f68b97b

Please sign in to comment.