Skip to content

Commit

Permalink
Transaction simulation service (hyperledger#6686)
Browse files Browse the repository at this point in the history
Signed-off-by: Fabio Di Fabio <[email protected]>
  • Loading branch information
fab-10 authored Mar 13, 2024
1 parent efd1bc7 commit 4cc6b74
Show file tree
Hide file tree
Showing 38 changed files with 424 additions and 95 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
- Update Vert.x to 4.5.4 [#6666](https://github.com/hyperledger/besu/pull/6666)
- Refactor and extend `TransactionPoolValidatorService` [#6636](https://github.com/hyperledger/besu/pull/6636)
- Transaction call object to accept both `input` and `data` field simultaneously if they are set to equal values [#6702](https://github.com/hyperledger/besu/pull/6702)
- Introduce `TransactionSimulationService` [#6686](https://github.com/hyperledger/besu/pull/6686)

### Bug fixes
- Fix txpool dump/restore race condition [#6665](https://github.com/hyperledger/besu/pull/6665)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -436,6 +436,7 @@ public NodeRequests nodeRequests() {

nodeRequests =
new NodeRequests(
web3jService,
new JsonRpc2_0Web3j(web3jService, 2000, Async.defaultExecutorService()),
new CliqueRequestFactory(web3jService),
new BftRequestFactory(web3jService, bftType),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import org.hyperledger.besu.cryptoservices.KeyPairSecurityModule;
import org.hyperledger.besu.cryptoservices.NodeKey;
import org.hyperledger.besu.ethereum.GasLimitCalculator;
import org.hyperledger.besu.ethereum.api.ApiConfiguration;
import org.hyperledger.besu.ethereum.api.graphql.GraphQLConfiguration;
import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters;
import org.hyperledger.besu.ethereum.eth.EthProtocolConfiguration;
Expand All @@ -37,13 +38,15 @@
import org.hyperledger.besu.ethereum.p2p.peers.EnodeURLImpl;
import org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueStorageProvider;
import org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueStorageProviderBuilder;
import org.hyperledger.besu.ethereum.transaction.TransactionSimulator;
import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration;
import org.hyperledger.besu.evm.internal.EvmConfiguration;
import org.hyperledger.besu.metrics.MetricsSystemFactory;
import org.hyperledger.besu.metrics.ObservableMetricsSystem;
import org.hyperledger.besu.plugin.data.EnodeURL;
import org.hyperledger.besu.plugin.services.BesuConfiguration;
import org.hyperledger.besu.plugin.services.BesuEvents;
import org.hyperledger.besu.plugin.services.BlockchainService;
import org.hyperledger.besu.plugin.services.PermissioningService;
import org.hyperledger.besu.plugin.services.PicoCLIOptions;
import org.hyperledger.besu.plugin.services.PrivacyPluginService;
Expand All @@ -52,10 +55,12 @@
import org.hyperledger.besu.plugin.services.StorageService;
import org.hyperledger.besu.plugin.services.TransactionPoolValidatorService;
import org.hyperledger.besu.plugin.services.TransactionSelectionService;
import org.hyperledger.besu.plugin.services.TransactionSimulationService;
import org.hyperledger.besu.plugin.services.storage.rocksdb.RocksDBPlugin;
import org.hyperledger.besu.services.BesuConfigurationImpl;
import org.hyperledger.besu.services.BesuEventsImpl;
import org.hyperledger.besu.services.BesuPluginContextImpl;
import org.hyperledger.besu.services.BlockchainServiceImpl;
import org.hyperledger.besu.services.PermissioningServiceImpl;
import org.hyperledger.besu.services.PicoCLIOptionsImpl;
import org.hyperledger.besu.services.PrivacyPluginServiceImpl;
Expand All @@ -64,6 +69,7 @@
import org.hyperledger.besu.services.StorageServiceImpl;
import org.hyperledger.besu.services.TransactionPoolValidatorServiceImpl;
import org.hyperledger.besu.services.TransactionSelectionServiceImpl;
import org.hyperledger.besu.services.TransactionSimulationServiceImpl;

import java.io.File;
import java.nio.file.Path;
Expand Down Expand Up @@ -95,18 +101,27 @@ private BesuPluginContextImpl buildPluginContext(
final BesuNode node,
final StorageServiceImpl storageService,
final SecurityModuleServiceImpl securityModuleService,
final TransactionSimulationServiceImpl transactionSimulationServiceImpl,
final TransactionSelectionServiceImpl transactionSelectionServiceImpl,
final TransactionPoolValidatorServiceImpl transactionPoolValidatorServiceImpl,
final BlockchainServiceImpl blockchainServiceImpl,
final RpcEndpointServiceImpl rpcEndpointServiceImpl,
final BesuConfiguration commonPluginConfiguration) {
final CommandLine commandLine = new CommandLine(CommandSpec.create());
final BesuPluginContextImpl besuPluginContext = new BesuPluginContextImpl();
besuPluginContext.addService(StorageService.class, storageService);
besuPluginContext.addService(SecurityModuleService.class, securityModuleService);
besuPluginContext.addService(PicoCLIOptions.class, new PicoCLIOptionsImpl(commandLine));
besuPluginContext.addService(RpcEndpointService.class, new RpcEndpointServiceImpl());
besuPluginContext.addService(RpcEndpointService.class, rpcEndpointServiceImpl);
besuPluginContext.addService(
TransactionSelectionService.class, transactionSelectionServiceImpl);
besuPluginContext.addService(
TransactionPoolValidatorService.class, new TransactionPoolValidatorServiceImpl());
TransactionPoolValidatorService.class, transactionPoolValidatorServiceImpl);
besuPluginContext.addService(
TransactionSimulationService.class, transactionSimulationServiceImpl);
besuPluginContext.addService(BlockchainService.class, blockchainServiceImpl);
besuPluginContext.addService(BesuConfiguration.class, commonPluginConfiguration);

final Path pluginsPath;
final String pluginDir = System.getProperty("besu.plugins.dir");
if (pluginDir == null || pluginDir.isEmpty()) {
Expand Down Expand Up @@ -147,8 +162,14 @@ public void startNode(final BesuNode node) {

final StorageServiceImpl storageService = new StorageServiceImpl();
final SecurityModuleServiceImpl securityModuleService = new SecurityModuleServiceImpl();
final TransactionSimulationServiceImpl transactionSimulationServiceImpl =
new TransactionSimulationServiceImpl();
final TransactionSelectionServiceImpl transactionSelectionServiceImpl =
new TransactionSelectionServiceImpl();
final TransactionPoolValidatorServiceImpl transactionPoolValidatorServiceImpl =
new TransactionPoolValidatorServiceImpl();
final BlockchainServiceImpl blockchainServiceImpl = new BlockchainServiceImpl();
final RpcEndpointServiceImpl rpcEndpointServiceImpl = new RpcEndpointServiceImpl();
final Path dataDir = node.homeDirectory();
final BesuConfigurationImpl commonPluginConfiguration = new BesuConfigurationImpl();
final var miningParameters =
Expand All @@ -169,7 +190,11 @@ public void startNode(final BesuNode node) {
node,
storageService,
securityModuleService,
transactionSimulationServiceImpl,
transactionSelectionServiceImpl,
transactionPoolValidatorServiceImpl,
blockchainServiceImpl,
rpcEndpointServiceImpl,
commonPluginConfiguration));

GlobalOpenTelemetry.resetForTest();
Expand Down Expand Up @@ -203,6 +228,7 @@ public void startNode(final BesuNode node) {
ImmutableTransactionPoolConfiguration.builder()
.from(node.getTransactionPoolConfiguration())
.strictTransactionReplayProtectionEnabled(node.isStrictTxReplayProtectionEnabled())
.transactionPoolValidatorService(transactionPoolValidatorServiceImpl)
.build();

final int maxPeers = 25;
Expand Down Expand Up @@ -236,6 +262,10 @@ public void startNode(final BesuNode node) {

final BesuController besuController = builder.build();

initTransactionSimulationService(
transactionSimulationServiceImpl, besuController, node.getApiConfiguration());
initBlockchainService(blockchainServiceImpl, besuController);

final RunnerBuilder runnerBuilder = new RunnerBuilder();
runnerBuilder.permissioningConfiguration(node.getPermissioningConfiguration());
runnerBuilder.apiConfiguration(node.getApiConfiguration());
Expand Down Expand Up @@ -265,7 +295,7 @@ public void startNode(final BesuNode node) {
.besuPluginContext(new BesuPluginContextImpl())
.autoLogBloomCaching(false)
.storageProvider(storageProvider)
.rpcEndpointService(new RpcEndpointServiceImpl());
.rpcEndpointService(rpcEndpointServiceImpl);
node.engineRpcConfiguration().ifPresent(runnerBuilder::engineJsonRpcConfiguration);

final Runner runner = runnerBuilder.build();
Expand All @@ -289,6 +319,25 @@ public void startNode(final BesuNode node) {
MDC.remove("node");
}

private void initBlockchainService(
final BlockchainServiceImpl blockchainServiceImpl, final BesuController besuController) {
blockchainServiceImpl.init(
besuController.getProtocolContext(), besuController.getProtocolSchedule());
}

private void initTransactionSimulationService(
final TransactionSimulationServiceImpl transactionSimulationService,
final BesuController besuController,
final ApiConfiguration apiConfiguration) {
transactionSimulationService.init(
besuController.getProtocolContext().getBlockchain(),
new TransactionSimulator(
besuController.getProtocolContext().getBlockchain(),
besuController.getProtocolContext().getWorldStateArchive(),
besuController.getProtocolSchedule(),
apiConfiguration.getGasCap()));
}

@Override
public void stopNode(final BesuNode node) {
final BesuPluginContextImpl pluginContext = besuPluginContextMap.remove(node);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.function.UnaryOperator;

import io.vertx.core.Vertx;
Expand Down Expand Up @@ -376,17 +377,27 @@ public BesuNode createCliqueNode(final String name) throws IOException {

public BesuNode createCliqueNode(final String name, final CliqueOptions cliqueOptions)
throws IOException {
return createCliqueNodeWithExtraCliOptions(name, cliqueOptions, List.of());
return createCliqueNodeWithExtraCliOptionsAndRpcApis(name, cliqueOptions, List.of());
}

public BesuNode createCliqueNodeWithExtraCliOptions(
public BesuNode createCliqueNodeWithExtraCliOptionsAndRpcApis(
final String name, final CliqueOptions cliqueOptions, final List<String> extraCliOptions)
throws IOException {
return createCliqueNodeWithExtraCliOptionsAndRpcApis(
name, cliqueOptions, extraCliOptions, Set.of());
}

public BesuNode createCliqueNodeWithExtraCliOptionsAndRpcApis(
final String name,
final CliqueOptions cliqueOptions,
final List<String> extraCliOptions,
final Set<String> extraRpcApis)
throws IOException {
return create(
new BesuNodeConfigurationBuilder()
.name(name)
.miningEnabled()
.jsonRpcConfiguration(node.createJsonRpcWithCliqueEnabledConfig())
.jsonRpcConfiguration(node.createJsonRpcWithCliqueEnabledConfig(extraRpcApis))
.webSocketConfiguration(node.createWebSocketEnabledConfig())
.devMode(false)
.jsonRpcTxPool()
Expand Down Expand Up @@ -584,7 +595,7 @@ public BesuNode createCliqueNodeWithValidators(final String name, final String..
new BesuNodeConfigurationBuilder()
.name(name)
.miningEnabled()
.jsonRpcConfiguration(node.createJsonRpcWithCliqueEnabledConfig())
.jsonRpcConfiguration(node.createJsonRpcWithCliqueEnabledConfig(Set.of()))
.webSocketConfiguration(node.createWebSocketEnabledConfig())
.jsonRpcTxPool()
.devMode(false)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,10 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;

public class NodeConfigurationFactory {

Expand All @@ -44,8 +46,10 @@ public Optional<String> createGenesisConfigForValidators(
return genesisConfigProvider.create(nodes);
}

public JsonRpcConfiguration createJsonRpcWithCliqueEnabledConfig() {
return createJsonRpcWithRpcApiEnabledConfig(CLIQUE.name());
public JsonRpcConfiguration createJsonRpcWithCliqueEnabledConfig(final Set<String> extraRpcApis) {
final var enabledApis = new HashSet<>(extraRpcApis);
enabledApis.add(CLIQUE.name());
return createJsonRpcWithRpcApiEnabledConfig(enabledApis.toArray(String[]::new));
}

public JsonRpcConfiguration createJsonRpcWithIbft2EnabledConfig(final boolean minerEnabled) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,11 @@
import java.util.Optional;

import org.web3j.protocol.Web3j;
import org.web3j.protocol.Web3jService;
import org.web3j.protocol.websocket.WebSocketService;

public class NodeRequests {

private final Web3jService web3jService;
private final Web3j netEth;
private final CliqueRequestFactory clique;
private final BftRequestFactory bft;
Expand All @@ -44,6 +45,7 @@ public class NodeRequests {
private final TxPoolRequestFactory txPool;

public NodeRequests(
final Web3jService web3jService,
final Web3j netEth,
final CliqueRequestFactory clique,
final BftRequestFactory bft,
Expand All @@ -55,6 +57,7 @@ public NodeRequests(
final TxPoolRequestFactory txPool,
final Optional<WebSocketService> websocketService,
final LoginRequestFactory login) {
this.web3jService = web3jService;
this.netEth = netEth;
this.clique = clique;
this.bft = bft;
Expand Down Expand Up @@ -116,4 +119,8 @@ public void shutdown() {
netEth.shutdown();
websocketService.ifPresent(WebSocketService::close);
}

public Web3jService getWeb3jService() {
return web3jService;
}
}
2 changes: 2 additions & 0 deletions besu/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ jar {
}

dependencies {
api project(':datatypes')

api 'org.slf4j:slf4j-api'

implementation project(':config')
Expand Down
17 changes: 17 additions & 0 deletions besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@
import org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier;
import org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueStorageProvider;
import org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueStorageProviderBuilder;
import org.hyperledger.besu.ethereum.transaction.TransactionSimulator;
import org.hyperledger.besu.ethereum.trie.forest.pruner.PrunerConfiguration;
import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration;
import org.hyperledger.besu.evm.precompile.AbstractAltBnPrecompiledContract;
Expand Down Expand Up @@ -167,6 +168,7 @@
import org.hyperledger.besu.plugin.services.TraceService;
import org.hyperledger.besu.plugin.services.TransactionPoolValidatorService;
import org.hyperledger.besu.plugin.services.TransactionSelectionService;
import org.hyperledger.besu.plugin.services.TransactionSimulationService;
import org.hyperledger.besu.plugin.services.exception.StorageException;
import org.hyperledger.besu.plugin.services.metrics.MetricCategory;
import org.hyperledger.besu.plugin.services.metrics.MetricCategoryRegistry;
Expand All @@ -187,6 +189,7 @@
import org.hyperledger.besu.services.TraceServiceImpl;
import org.hyperledger.besu.services.TransactionPoolValidatorServiceImpl;
import org.hyperledger.besu.services.TransactionSelectionServiceImpl;
import org.hyperledger.besu.services.TransactionSimulationServiceImpl;
import org.hyperledger.besu.services.kvstore.InMemoryStoragePlugin;
import org.hyperledger.besu.util.InvalidConfigurationException;
import org.hyperledger.besu.util.LogConfigurator;
Expand Down Expand Up @@ -370,6 +373,7 @@ public class BesuCommand implements DefaultCommandValues, Runnable {

private final TransactionSelectionServiceImpl transactionSelectionServiceImpl;
private final TransactionPoolValidatorServiceImpl transactionValidatorServiceImpl;
private final TransactionSimulationServiceImpl transactionSimulationServiceImpl;
private final BlockchainServiceImpl blockchainServiceImpl;

static class P2PDiscoveryOptionGroup {
Expand Down Expand Up @@ -956,6 +960,7 @@ public BesuCommand(
new RpcEndpointServiceImpl(),
new TransactionSelectionServiceImpl(),
new TransactionPoolValidatorServiceImpl(),
new TransactionSimulationServiceImpl(),
new BlockchainServiceImpl());
}

Expand All @@ -978,6 +983,7 @@ public BesuCommand(
* @param rpcEndpointServiceImpl instance of RpcEndpointServiceImpl
* @param transactionSelectionServiceImpl instance of TransactionSelectionServiceImpl
* @param transactionValidatorServiceImpl instance of TransactionValidatorServiceImpl
* @param transactionSimulationServiceImpl instance of TransactionSimulationServiceImpl
* @param blockchainServiceImpl instance of BlockchainServiceImpl
*/
@VisibleForTesting
Expand All @@ -998,6 +1004,7 @@ protected BesuCommand(
final RpcEndpointServiceImpl rpcEndpointServiceImpl,
final TransactionSelectionServiceImpl transactionSelectionServiceImpl,
final TransactionPoolValidatorServiceImpl transactionValidatorServiceImpl,
final TransactionSimulationServiceImpl transactionSimulationServiceImpl,
final BlockchainServiceImpl blockchainServiceImpl) {
this.besuComponent = besuComponent;
this.logger = besuComponent.getBesuCommandLogger();
Expand All @@ -1018,6 +1025,7 @@ protected BesuCommand(
this.rpcEndpointServiceImpl = rpcEndpointServiceImpl;
this.transactionSelectionServiceImpl = transactionSelectionServiceImpl;
this.transactionValidatorServiceImpl = transactionValidatorServiceImpl;
this.transactionSimulationServiceImpl = transactionSimulationServiceImpl;
this.blockchainServiceImpl = blockchainServiceImpl;
}

Expand Down Expand Up @@ -1210,6 +1218,8 @@ private void preparePlugins() {
TransactionSelectionService.class, transactionSelectionServiceImpl);
besuPluginContext.addService(
TransactionPoolValidatorService.class, transactionValidatorServiceImpl);
besuPluginContext.addService(
TransactionSimulationService.class, transactionSimulationServiceImpl);
besuPluginContext.addService(BlockchainService.class, blockchainServiceImpl);

// register built-in plugins
Expand Down Expand Up @@ -1293,6 +1303,13 @@ private Runner buildRunner() {
private void startPlugins() {
blockchainServiceImpl.init(
besuController.getProtocolContext(), besuController.getProtocolSchedule());
transactionSimulationServiceImpl.init(
besuController.getProtocolContext().getBlockchain(),
new TransactionSimulator(
besuController.getProtocolContext().getBlockchain(),
besuController.getProtocolContext().getWorldStateArchive(),
besuController.getProtocolSchedule(),
apiConfiguration.getGasCap()));

besuPluginContext.addService(
BesuEvents.class,
Expand Down
Loading

0 comments on commit 4cc6b74

Please sign in to comment.