Skip to content

Commit 4cc6b74

Browse files
authored
Transaction simulation service (#6686)
Signed-off-by: Fabio Di Fabio <fabio.difabio@consensys.net>
1 parent efd1bc7 commit 4cc6b74

File tree

38 files changed

+424
-95
lines changed

38 files changed

+424
-95
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
- Update Vert.x to 4.5.4 [#6666](https://github.com/hyperledger/besu/pull/6666)
2121
- Refactor and extend `TransactionPoolValidatorService` [#6636](https://github.com/hyperledger/besu/pull/6636)
2222
- 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)
23+
- Introduce `TransactionSimulationService` [#6686](https://github.com/hyperledger/besu/pull/6686)
2324

2425
### Bug fixes
2526
- Fix txpool dump/restore race condition [#6665](https://github.com/hyperledger/besu/pull/6665)

acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/BesuNode.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -436,6 +436,7 @@ public NodeRequests nodeRequests() {
436436

437437
nodeRequests =
438438
new NodeRequests(
439+
web3jService,
439440
new JsonRpc2_0Web3j(web3jService, 2000, Async.defaultExecutorService()),
440441
new CliqueRequestFactory(web3jService),
441442
new BftRequestFactory(web3jService, bftType),

acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/ThreadBesuNodeRunner.java

Lines changed: 52 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import org.hyperledger.besu.cryptoservices.KeyPairSecurityModule;
2929
import org.hyperledger.besu.cryptoservices.NodeKey;
3030
import org.hyperledger.besu.ethereum.GasLimitCalculator;
31+
import org.hyperledger.besu.ethereum.api.ApiConfiguration;
3132
import org.hyperledger.besu.ethereum.api.graphql.GraphQLConfiguration;
3233
import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters;
3334
import org.hyperledger.besu.ethereum.eth.EthProtocolConfiguration;
@@ -37,13 +38,15 @@
3738
import org.hyperledger.besu.ethereum.p2p.peers.EnodeURLImpl;
3839
import org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueStorageProvider;
3940
import org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueStorageProviderBuilder;
41+
import org.hyperledger.besu.ethereum.transaction.TransactionSimulator;
4042
import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration;
4143
import org.hyperledger.besu.evm.internal.EvmConfiguration;
4244
import org.hyperledger.besu.metrics.MetricsSystemFactory;
4345
import org.hyperledger.besu.metrics.ObservableMetricsSystem;
4446
import org.hyperledger.besu.plugin.data.EnodeURL;
4547
import org.hyperledger.besu.plugin.services.BesuConfiguration;
4648
import org.hyperledger.besu.plugin.services.BesuEvents;
49+
import org.hyperledger.besu.plugin.services.BlockchainService;
4750
import org.hyperledger.besu.plugin.services.PermissioningService;
4851
import org.hyperledger.besu.plugin.services.PicoCLIOptions;
4952
import org.hyperledger.besu.plugin.services.PrivacyPluginService;
@@ -52,10 +55,12 @@
5255
import org.hyperledger.besu.plugin.services.StorageService;
5356
import org.hyperledger.besu.plugin.services.TransactionPoolValidatorService;
5457
import org.hyperledger.besu.plugin.services.TransactionSelectionService;
58+
import org.hyperledger.besu.plugin.services.TransactionSimulationService;
5559
import org.hyperledger.besu.plugin.services.storage.rocksdb.RocksDBPlugin;
5660
import org.hyperledger.besu.services.BesuConfigurationImpl;
5761
import org.hyperledger.besu.services.BesuEventsImpl;
5862
import org.hyperledger.besu.services.BesuPluginContextImpl;
63+
import org.hyperledger.besu.services.BlockchainServiceImpl;
5964
import org.hyperledger.besu.services.PermissioningServiceImpl;
6065
import org.hyperledger.besu.services.PicoCLIOptionsImpl;
6166
import org.hyperledger.besu.services.PrivacyPluginServiceImpl;
@@ -64,6 +69,7 @@
6469
import org.hyperledger.besu.services.StorageServiceImpl;
6570
import org.hyperledger.besu.services.TransactionPoolValidatorServiceImpl;
6671
import org.hyperledger.besu.services.TransactionSelectionServiceImpl;
72+
import org.hyperledger.besu.services.TransactionSimulationServiceImpl;
6773

6874
import java.io.File;
6975
import java.nio.file.Path;
@@ -95,18 +101,27 @@ private BesuPluginContextImpl buildPluginContext(
95101
final BesuNode node,
96102
final StorageServiceImpl storageService,
97103
final SecurityModuleServiceImpl securityModuleService,
104+
final TransactionSimulationServiceImpl transactionSimulationServiceImpl,
98105
final TransactionSelectionServiceImpl transactionSelectionServiceImpl,
106+
final TransactionPoolValidatorServiceImpl transactionPoolValidatorServiceImpl,
107+
final BlockchainServiceImpl blockchainServiceImpl,
108+
final RpcEndpointServiceImpl rpcEndpointServiceImpl,
99109
final BesuConfiguration commonPluginConfiguration) {
100110
final CommandLine commandLine = new CommandLine(CommandSpec.create());
101111
final BesuPluginContextImpl besuPluginContext = new BesuPluginContextImpl();
102112
besuPluginContext.addService(StorageService.class, storageService);
103113
besuPluginContext.addService(SecurityModuleService.class, securityModuleService);
104114
besuPluginContext.addService(PicoCLIOptions.class, new PicoCLIOptionsImpl(commandLine));
105-
besuPluginContext.addService(RpcEndpointService.class, new RpcEndpointServiceImpl());
115+
besuPluginContext.addService(RpcEndpointService.class, rpcEndpointServiceImpl);
106116
besuPluginContext.addService(
107117
TransactionSelectionService.class, transactionSelectionServiceImpl);
108118
besuPluginContext.addService(
109-
TransactionPoolValidatorService.class, new TransactionPoolValidatorServiceImpl());
119+
TransactionPoolValidatorService.class, transactionPoolValidatorServiceImpl);
120+
besuPluginContext.addService(
121+
TransactionSimulationService.class, transactionSimulationServiceImpl);
122+
besuPluginContext.addService(BlockchainService.class, blockchainServiceImpl);
123+
besuPluginContext.addService(BesuConfiguration.class, commonPluginConfiguration);
124+
110125
final Path pluginsPath;
111126
final String pluginDir = System.getProperty("besu.plugins.dir");
112127
if (pluginDir == null || pluginDir.isEmpty()) {
@@ -147,8 +162,14 @@ public void startNode(final BesuNode node) {
147162

148163
final StorageServiceImpl storageService = new StorageServiceImpl();
149164
final SecurityModuleServiceImpl securityModuleService = new SecurityModuleServiceImpl();
165+
final TransactionSimulationServiceImpl transactionSimulationServiceImpl =
166+
new TransactionSimulationServiceImpl();
150167
final TransactionSelectionServiceImpl transactionSelectionServiceImpl =
151168
new TransactionSelectionServiceImpl();
169+
final TransactionPoolValidatorServiceImpl transactionPoolValidatorServiceImpl =
170+
new TransactionPoolValidatorServiceImpl();
171+
final BlockchainServiceImpl blockchainServiceImpl = new BlockchainServiceImpl();
172+
final RpcEndpointServiceImpl rpcEndpointServiceImpl = new RpcEndpointServiceImpl();
152173
final Path dataDir = node.homeDirectory();
153174
final BesuConfigurationImpl commonPluginConfiguration = new BesuConfigurationImpl();
154175
final var miningParameters =
@@ -169,7 +190,11 @@ public void startNode(final BesuNode node) {
169190
node,
170191
storageService,
171192
securityModuleService,
193+
transactionSimulationServiceImpl,
172194
transactionSelectionServiceImpl,
195+
transactionPoolValidatorServiceImpl,
196+
blockchainServiceImpl,
197+
rpcEndpointServiceImpl,
173198
commonPluginConfiguration));
174199

175200
GlobalOpenTelemetry.resetForTest();
@@ -203,6 +228,7 @@ public void startNode(final BesuNode node) {
203228
ImmutableTransactionPoolConfiguration.builder()
204229
.from(node.getTransactionPoolConfiguration())
205230
.strictTransactionReplayProtectionEnabled(node.isStrictTxReplayProtectionEnabled())
231+
.transactionPoolValidatorService(transactionPoolValidatorServiceImpl)
206232
.build();
207233

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

237263
final BesuController besuController = builder.build();
238264

265+
initTransactionSimulationService(
266+
transactionSimulationServiceImpl, besuController, node.getApiConfiguration());
267+
initBlockchainService(blockchainServiceImpl, besuController);
268+
239269
final RunnerBuilder runnerBuilder = new RunnerBuilder();
240270
runnerBuilder.permissioningConfiguration(node.getPermissioningConfiguration());
241271
runnerBuilder.apiConfiguration(node.getApiConfiguration());
@@ -265,7 +295,7 @@ public void startNode(final BesuNode node) {
265295
.besuPluginContext(new BesuPluginContextImpl())
266296
.autoLogBloomCaching(false)
267297
.storageProvider(storageProvider)
268-
.rpcEndpointService(new RpcEndpointServiceImpl());
298+
.rpcEndpointService(rpcEndpointServiceImpl);
269299
node.engineRpcConfiguration().ifPresent(runnerBuilder::engineJsonRpcConfiguration);
270300

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

322+
private void initBlockchainService(
323+
final BlockchainServiceImpl blockchainServiceImpl, final BesuController besuController) {
324+
blockchainServiceImpl.init(
325+
besuController.getProtocolContext(), besuController.getProtocolSchedule());
326+
}
327+
328+
private void initTransactionSimulationService(
329+
final TransactionSimulationServiceImpl transactionSimulationService,
330+
final BesuController besuController,
331+
final ApiConfiguration apiConfiguration) {
332+
transactionSimulationService.init(
333+
besuController.getProtocolContext().getBlockchain(),
334+
new TransactionSimulator(
335+
besuController.getProtocolContext().getBlockchain(),
336+
besuController.getProtocolContext().getWorldStateArchive(),
337+
besuController.getProtocolSchedule(),
338+
apiConfiguration.getGasCap()));
339+
}
340+
292341
@Override
293342
public void stopNode(final BesuNode node) {
294343
final BesuPluginContextImpl pluginContext = besuPluginContextMap.remove(node);

acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/configuration/BesuNodeFactory.java

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
import java.util.ArrayList;
5050
import java.util.List;
5151
import java.util.Optional;
52+
import java.util.Set;
5253
import java.util.function.UnaryOperator;
5354

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

377378
public BesuNode createCliqueNode(final String name, final CliqueOptions cliqueOptions)
378379
throws IOException {
379-
return createCliqueNodeWithExtraCliOptions(name, cliqueOptions, List.of());
380+
return createCliqueNodeWithExtraCliOptionsAndRpcApis(name, cliqueOptions, List.of());
380381
}
381382

382-
public BesuNode createCliqueNodeWithExtraCliOptions(
383+
public BesuNode createCliqueNodeWithExtraCliOptionsAndRpcApis(
383384
final String name, final CliqueOptions cliqueOptions, final List<String> extraCliOptions)
384385
throws IOException {
386+
return createCliqueNodeWithExtraCliOptionsAndRpcApis(
387+
name, cliqueOptions, extraCliOptions, Set.of());
388+
}
389+
390+
public BesuNode createCliqueNodeWithExtraCliOptionsAndRpcApis(
391+
final String name,
392+
final CliqueOptions cliqueOptions,
393+
final List<String> extraCliOptions,
394+
final Set<String> extraRpcApis)
395+
throws IOException {
385396
return create(
386397
new BesuNodeConfigurationBuilder()
387398
.name(name)
388399
.miningEnabled()
389-
.jsonRpcConfiguration(node.createJsonRpcWithCliqueEnabledConfig())
400+
.jsonRpcConfiguration(node.createJsonRpcWithCliqueEnabledConfig(extraRpcApis))
390401
.webSocketConfiguration(node.createWebSocketEnabledConfig())
391402
.devMode(false)
392403
.jsonRpcTxPool()
@@ -584,7 +595,7 @@ public BesuNode createCliqueNodeWithValidators(final String name, final String..
584595
new BesuNodeConfigurationBuilder()
585596
.name(name)
586597
.miningEnabled()
587-
.jsonRpcConfiguration(node.createJsonRpcWithCliqueEnabledConfig())
598+
.jsonRpcConfiguration(node.createJsonRpcWithCliqueEnabledConfig(Set.of()))
588599
.webSocketConfiguration(node.createWebSocketEnabledConfig())
589600
.jsonRpcTxPool()
590601
.devMode(false)

acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/configuration/NodeConfigurationFactory.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,10 @@
3030
import java.util.ArrayList;
3131
import java.util.Arrays;
3232
import java.util.Collection;
33+
import java.util.HashSet;
3334
import java.util.List;
3435
import java.util.Optional;
36+
import java.util.Set;
3537

3638
public class NodeConfigurationFactory {
3739

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

47-
public JsonRpcConfiguration createJsonRpcWithCliqueEnabledConfig() {
48-
return createJsonRpcWithRpcApiEnabledConfig(CLIQUE.name());
49+
public JsonRpcConfiguration createJsonRpcWithCliqueEnabledConfig(final Set<String> extraRpcApis) {
50+
final var enabledApis = new HashSet<>(extraRpcApis);
51+
enabledApis.add(CLIQUE.name());
52+
return createJsonRpcWithRpcApiEnabledConfig(enabledApis.toArray(String[]::new));
4953
}
5054

5155
public JsonRpcConfiguration createJsonRpcWithIbft2EnabledConfig(final boolean minerEnabled) {

acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/transaction/NodeRequests.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,11 @@
2727
import java.util.Optional;
2828

2929
import org.web3j.protocol.Web3j;
30+
import org.web3j.protocol.Web3jService;
3031
import org.web3j.protocol.websocket.WebSocketService;
3132

3233
public class NodeRequests {
33-
34+
private final Web3jService web3jService;
3435
private final Web3j netEth;
3536
private final CliqueRequestFactory clique;
3637
private final BftRequestFactory bft;
@@ -44,6 +45,7 @@ public class NodeRequests {
4445
private final TxPoolRequestFactory txPool;
4546

4647
public NodeRequests(
48+
final Web3jService web3jService,
4749
final Web3j netEth,
4850
final CliqueRequestFactory clique,
4951
final BftRequestFactory bft,
@@ -55,6 +57,7 @@ public NodeRequests(
5557
final TxPoolRequestFactory txPool,
5658
final Optional<WebSocketService> websocketService,
5759
final LoginRequestFactory login) {
60+
this.web3jService = web3jService;
5861
this.netEth = netEth;
5962
this.clique = clique;
6063
this.bft = bft;
@@ -116,4 +119,8 @@ public void shutdown() {
116119
netEth.shutdown();
117120
websocketService.ifPresent(WebSocketService::close);
118121
}
122+
123+
public Web3jService getWeb3jService() {
124+
return web3jService;
125+
}
119126
}

besu/build.gradle

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ jar {
2828
}
2929

3030
dependencies {
31+
api project(':datatypes')
32+
3133
api 'org.slf4j:slf4j-api'
3234

3335
implementation project(':config')

besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@
139139
import org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier;
140140
import org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueStorageProvider;
141141
import org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueStorageProviderBuilder;
142+
import org.hyperledger.besu.ethereum.transaction.TransactionSimulator;
142143
import org.hyperledger.besu.ethereum.trie.forest.pruner.PrunerConfiguration;
143144
import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration;
144145
import org.hyperledger.besu.evm.precompile.AbstractAltBnPrecompiledContract;
@@ -167,6 +168,7 @@
167168
import org.hyperledger.besu.plugin.services.TraceService;
168169
import org.hyperledger.besu.plugin.services.TransactionPoolValidatorService;
169170
import org.hyperledger.besu.plugin.services.TransactionSelectionService;
171+
import org.hyperledger.besu.plugin.services.TransactionSimulationService;
170172
import org.hyperledger.besu.plugin.services.exception.StorageException;
171173
import org.hyperledger.besu.plugin.services.metrics.MetricCategory;
172174
import org.hyperledger.besu.plugin.services.metrics.MetricCategoryRegistry;
@@ -187,6 +189,7 @@
187189
import org.hyperledger.besu.services.TraceServiceImpl;
188190
import org.hyperledger.besu.services.TransactionPoolValidatorServiceImpl;
189191
import org.hyperledger.besu.services.TransactionSelectionServiceImpl;
192+
import org.hyperledger.besu.services.TransactionSimulationServiceImpl;
190193
import org.hyperledger.besu.services.kvstore.InMemoryStoragePlugin;
191194
import org.hyperledger.besu.util.InvalidConfigurationException;
192195
import org.hyperledger.besu.util.LogConfigurator;
@@ -370,6 +373,7 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
370373

371374
private final TransactionSelectionServiceImpl transactionSelectionServiceImpl;
372375
private final TransactionPoolValidatorServiceImpl transactionValidatorServiceImpl;
376+
private final TransactionSimulationServiceImpl transactionSimulationServiceImpl;
373377
private final BlockchainServiceImpl blockchainServiceImpl;
374378

375379
static class P2PDiscoveryOptionGroup {
@@ -956,6 +960,7 @@ public BesuCommand(
956960
new RpcEndpointServiceImpl(),
957961
new TransactionSelectionServiceImpl(),
958962
new TransactionPoolValidatorServiceImpl(),
963+
new TransactionSimulationServiceImpl(),
959964
new BlockchainServiceImpl());
960965
}
961966

@@ -978,6 +983,7 @@ public BesuCommand(
978983
* @param rpcEndpointServiceImpl instance of RpcEndpointServiceImpl
979984
* @param transactionSelectionServiceImpl instance of TransactionSelectionServiceImpl
980985
* @param transactionValidatorServiceImpl instance of TransactionValidatorServiceImpl
986+
* @param transactionSimulationServiceImpl instance of TransactionSimulationServiceImpl
981987
* @param blockchainServiceImpl instance of BlockchainServiceImpl
982988
*/
983989
@VisibleForTesting
@@ -998,6 +1004,7 @@ protected BesuCommand(
9981004
final RpcEndpointServiceImpl rpcEndpointServiceImpl,
9991005
final TransactionSelectionServiceImpl transactionSelectionServiceImpl,
10001006
final TransactionPoolValidatorServiceImpl transactionValidatorServiceImpl,
1007+
final TransactionSimulationServiceImpl transactionSimulationServiceImpl,
10011008
final BlockchainServiceImpl blockchainServiceImpl) {
10021009
this.besuComponent = besuComponent;
10031010
this.logger = besuComponent.getBesuCommandLogger();
@@ -1018,6 +1025,7 @@ protected BesuCommand(
10181025
this.rpcEndpointServiceImpl = rpcEndpointServiceImpl;
10191026
this.transactionSelectionServiceImpl = transactionSelectionServiceImpl;
10201027
this.transactionValidatorServiceImpl = transactionValidatorServiceImpl;
1028+
this.transactionSimulationServiceImpl = transactionSimulationServiceImpl;
10211029
this.blockchainServiceImpl = blockchainServiceImpl;
10221030
}
10231031

@@ -1210,6 +1218,8 @@ private void preparePlugins() {
12101218
TransactionSelectionService.class, transactionSelectionServiceImpl);
12111219
besuPluginContext.addService(
12121220
TransactionPoolValidatorService.class, transactionValidatorServiceImpl);
1221+
besuPluginContext.addService(
1222+
TransactionSimulationService.class, transactionSimulationServiceImpl);
12131223
besuPluginContext.addService(BlockchainService.class, blockchainServiceImpl);
12141224

12151225
// register built-in plugins
@@ -1293,6 +1303,13 @@ private Runner buildRunner() {
12931303
private void startPlugins() {
12941304
blockchainServiceImpl.init(
12951305
besuController.getProtocolContext(), besuController.getProtocolSchedule());
1306+
transactionSimulationServiceImpl.init(
1307+
besuController.getProtocolContext().getBlockchain(),
1308+
new TransactionSimulator(
1309+
besuController.getProtocolContext().getBlockchain(),
1310+
besuController.getProtocolContext().getWorldStateArchive(),
1311+
besuController.getProtocolSchedule(),
1312+
apiConfiguration.getGasCap()));
12961313

12971314
besuPluginContext.addService(
12981315
BesuEvents.class,

0 commit comments

Comments
 (0)