Transaction simulation service (#6686)

Signed-off-by: Fabio Di Fabio <fabio.difabio@consensys.net>
pull/6725/head
Fabio Di Fabio 8 months ago committed by GitHub
parent efd1bc7070
commit 4cc6b744cf
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 1
      CHANGELOG.md
  2. 1
      acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/BesuNode.java
  3. 55
      acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/ThreadBesuNodeRunner.java
  4. 19
      acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/configuration/BesuNodeFactory.java
  5. 8
      acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/configuration/NodeConfigurationFactory.java
  6. 9
      acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/transaction/NodeRequests.java
  7. 2
      besu/build.gradle
  8. 17
      besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java
  9. 84
      besu/src/main/java/org/hyperledger/besu/services/TransactionSimulationServiceImpl.java
  10. 11
      besu/src/test/java/org/hyperledger/besu/RunnerTest.java
  11. 3
      besu/src/test/java/org/hyperledger/besu/chainimport/JsonBlockImporterTest.java
  12. 2
      besu/src/test/java/org/hyperledger/besu/cli/CommandTestAbstract.java
  13. 2
      consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/validator/ValidatorContractController.java
  14. 4
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AbstractEstimateGas.java
  15. 2
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugTraceCall.java
  16. 2
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthCall.java
  17. 2
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthEstimateGas.java
  18. 2
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/TraceCall.java
  19. 2
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/TraceCallMany.java
  20. 2
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/TraceRawTransaction.java
  21. 6
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthCallTest.java
  22. 2
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthCreateAccessListTest.java
  23. 2
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthEstimateGasTest.java
  24. 4
      ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockTransactionSelectorTest.java
  25. 27
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/processing/TransactionProcessingResult.java
  26. 51
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/CallParameter.java
  27. 19
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/TransactionSimulator.java
  28. 52
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/TransactionSimulatorResult.java
  29. 4
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionValidatorTest.java
  30. 3
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/PermissionTransactionValidatorTest.java
  31. 2
      ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/NodeSmartContractPermissioningController.java
  32. 2
      ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/NodeSmartContractV2PermissioningController.java
  33. 2
      ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/TransactionSmartContractPermissioningController.java
  34. 2
      plugin-api/build.gradle
  35. 7
      plugin-api/src/main/java/org/hyperledger/besu/plugin/data/TransactionProcessingResult.java
  36. 54
      plugin-api/src/main/java/org/hyperledger/besu/plugin/data/TransactionSimulationResult.java
  37. 42
      plugin-api/src/main/java/org/hyperledger/besu/plugin/services/TransactionSimulationService.java
  38. 8
      testutil/src/main/java/org/hyperledger/besu/testutil/JsonTestParameters.java

@ -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)

@ -436,6 +436,7 @@ public class BesuNode implements NodeConfiguration, RunnableNode, AutoCloseable
nodeRequests =
new NodeRequests(
web3jService,
new JsonRpc2_0Web3j(web3jService, 2000, Async.defaultExecutorService()),
new CliqueRequestFactory(web3jService),
new BftRequestFactory(web3jService, bftType),

@ -28,6 +28,7 @@ import org.hyperledger.besu.crypto.KeyPairUtil;
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;
@ -37,6 +38,7 @@ import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfigurati
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;
@ -44,6 +46,7 @@ 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;
@ -52,10 +55,12 @@ import org.hyperledger.besu.plugin.services.SecurityModuleService;
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;
@ -64,6 +69,7 @@ import org.hyperledger.besu.services.SecurityModuleServiceImpl;
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;
@ -95,18 +101,27 @@ public class ThreadBesuNodeRunner implements BesuNodeRunner {
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()) {
@ -147,8 +162,14 @@ public class ThreadBesuNodeRunner implements BesuNodeRunner {
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 =
@ -169,7 +190,11 @@ public class ThreadBesuNodeRunner implements BesuNodeRunner {
node,
storageService,
securityModuleService,
transactionSimulationServiceImpl,
transactionSelectionServiceImpl,
transactionPoolValidatorServiceImpl,
blockchainServiceImpl,
rpcEndpointServiceImpl,
commonPluginConfiguration));
GlobalOpenTelemetry.resetForTest();
@ -203,6 +228,7 @@ public class ThreadBesuNodeRunner implements BesuNodeRunner {
ImmutableTransactionPoolConfiguration.builder()
.from(node.getTransactionPoolConfiguration())
.strictTransactionReplayProtectionEnabled(node.isStrictTxReplayProtectionEnabled())
.transactionPoolValidatorService(transactionPoolValidatorServiceImpl)
.build();
final int maxPeers = 25;
@ -236,6 +262,10 @@ public class ThreadBesuNodeRunner implements BesuNodeRunner {
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());
@ -265,7 +295,7 @@ public class ThreadBesuNodeRunner implements BesuNodeRunner {
.besuPluginContext(new BesuPluginContextImpl())
.autoLogBloomCaching(false)
.storageProvider(storageProvider)
.rpcEndpointService(new RpcEndpointServiceImpl());
.rpcEndpointService(rpcEndpointServiceImpl);
node.engineRpcConfiguration().ifPresent(runnerBuilder::engineJsonRpcConfiguration);
final Runner runner = runnerBuilder.build();
@ -289,6 +319,25 @@ public class ThreadBesuNodeRunner implements BesuNodeRunner {
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);

@ -49,6 +49,7 @@ import java.nio.file.Paths;
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;
@ -376,17 +377,27 @@ public class BesuNodeFactory {
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()
@ -584,7 +595,7 @@ public class BesuNodeFactory {
new BesuNodeConfigurationBuilder()
.name(name)
.miningEnabled()
.jsonRpcConfiguration(node.createJsonRpcWithCliqueEnabledConfig())
.jsonRpcConfiguration(node.createJsonRpcWithCliqueEnabledConfig(Set.of()))
.webSocketConfiguration(node.createWebSocketEnabledConfig())
.jsonRpcTxPool()
.devMode(false)

@ -30,8 +30,10 @@ import org.hyperledger.besu.tests.acceptance.dsl.node.configuration.genesis.Gene
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 {
@ -44,8 +46,10 @@ public class NodeConfigurationFactory {
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) {

@ -27,10 +27,11 @@ import org.hyperledger.besu.tests.acceptance.dsl.transaction.txpool.TxPoolReques
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;
@ -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,
@ -55,6 +57,7 @@ public class NodeRequests {
final TxPoolRequestFactory txPool,
final Optional<WebSocketService> websocketService,
final LoginRequestFactory login) {
this.web3jService = web3jService;
this.netEth = netEth;
this.clique = clique;
this.bft = bft;
@ -116,4 +119,8 @@ public class NodeRequests {
netEth.shutdown();
websocketService.ifPresent(WebSocketService::close);
}
public Web3jService getWeb3jService() {
return web3jService;
}
}

@ -28,6 +28,8 @@ jar {
}
dependencies {
api project(':datatypes')
api 'org.slf4j:slf4j-api'
implementation project(':config')

@ -139,6 +139,7 @@ import org.hyperledger.besu.ethereum.storage.StorageProvider;
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;
@ -167,6 +168,7 @@ import org.hyperledger.besu.plugin.services.StorageService;
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;
@ -187,6 +189,7 @@ import org.hyperledger.besu.services.StorageServiceImpl;
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;
@ -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 {
@ -956,6 +960,7 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
new RpcEndpointServiceImpl(),
new TransactionSelectionServiceImpl(),
new TransactionPoolValidatorServiceImpl(),
new TransactionSimulationServiceImpl(),
new BlockchainServiceImpl());
}
@ -978,6 +983,7 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
* @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
@ -998,6 +1004,7 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
final RpcEndpointServiceImpl rpcEndpointServiceImpl,
final TransactionSelectionServiceImpl transactionSelectionServiceImpl,
final TransactionPoolValidatorServiceImpl transactionValidatorServiceImpl,
final TransactionSimulationServiceImpl transactionSimulationServiceImpl,
final BlockchainServiceImpl blockchainServiceImpl) {
this.besuComponent = besuComponent;
this.logger = besuComponent.getBesuCommandLogger();
@ -1018,6 +1025,7 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
this.rpcEndpointServiceImpl = rpcEndpointServiceImpl;
this.transactionSelectionServiceImpl = transactionSelectionServiceImpl;
this.transactionValidatorServiceImpl = transactionValidatorServiceImpl;
this.transactionSimulationServiceImpl = transactionSimulationServiceImpl;
this.blockchainServiceImpl = blockchainServiceImpl;
}
@ -1210,6 +1218,8 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
TransactionSelectionService.class, transactionSelectionServiceImpl);
besuPluginContext.addService(
TransactionPoolValidatorService.class, transactionValidatorServiceImpl);
besuPluginContext.addService(
TransactionSimulationService.class, transactionSimulationServiceImpl);
besuPluginContext.addService(BlockchainService.class, blockchainServiceImpl);
// register built-in plugins
@ -1293,6 +1303,13 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
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,

@ -0,0 +1,84 @@
/*
* Copyright Hyperledger Besu Contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.services;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.datatypes.Transaction;
import org.hyperledger.besu.ethereum.chain.Blockchain;
import org.hyperledger.besu.ethereum.mainnet.ImmutableTransactionValidationParams;
import org.hyperledger.besu.ethereum.mainnet.TransactionValidationParams;
import org.hyperledger.besu.ethereum.transaction.CallParameter;
import org.hyperledger.besu.ethereum.transaction.TransactionSimulator;
import org.hyperledger.besu.evm.tracing.OperationTracer;
import org.hyperledger.besu.plugin.Unstable;
import org.hyperledger.besu.plugin.data.TransactionSimulationResult;
import org.hyperledger.besu.plugin.services.TransactionSimulationService;
import java.util.Optional;
/** TransactionSimulationServiceImpl */
@Unstable
public class TransactionSimulationServiceImpl implements TransactionSimulationService {
private static final TransactionValidationParams SIMULATOR_ALLOWING_EXCEEDING_BALANCE =
ImmutableTransactionValidationParams.builder()
.from(TransactionValidationParams.transactionSimulator())
.isAllowExceedingBalance(true)
.build();
private Blockchain blockchain;
private TransactionSimulator transactionSimulator;
/** Create an instance to be configured */
public TransactionSimulationServiceImpl() {}
/**
* Configure the service
*
* @param blockchain the blockchain
* @param transactionSimulator transaction simulator
*/
public void init(final Blockchain blockchain, final TransactionSimulator transactionSimulator) {
this.blockchain = blockchain;
this.transactionSimulator = transactionSimulator;
}
@Override
public Optional<TransactionSimulationResult> simulate(
final Transaction transaction,
final Hash blockHash,
final OperationTracer operationTracer,
final boolean isAllowExceedingBalance) {
final CallParameter callParameter = CallParameter.fromTransaction(transaction);
final var blockHeader =
blockchain
.getBlockHeader(blockHash)
.or(() -> blockchain.getBlockHeaderSafe(blockHash))
.orElseThrow(
() ->
new IllegalStateException(
"Block header not yet present for chain head hash: " + blockHash));
return transactionSimulator
.process(
callParameter,
isAllowExceedingBalance
? SIMULATOR_ALLOWING_EXCEEDING_BALANCE
: TransactionValidationParams.transactionSimulator(),
operationTracer,
blockHeader)
.map(res -> new TransactionSimulationResult(transaction, res.result()));
}
}

@ -180,7 +180,8 @@ public final class RunnerTest {
aheadDbNodeKey,
createKeyValueStorageProvider(
dataDirAhead, dbAhead, dataStorageConfiguration, miningParameters),
noOpMetricsSystem);
noOpMetricsSystem,
miningParameters);
setupState(
blockCount, controllerAhead.getProtocolSchedule(), controllerAhead.getProtocolContext());
@ -235,7 +236,8 @@ public final class RunnerTest {
dataDirBehind,
behindDbNodeKey,
new InMemoryKeyValueStorageProvider(),
noOpMetricsSystem);
noOpMetricsSystem,
miningParameters);
final EnodeURL aheadEnode = runnerAhead.getLocalEnode().get();
final EthNetworkConfig behindEthNetworkConfiguration =
@ -452,14 +454,15 @@ public final class RunnerTest {
final Path dataDir,
final NodeKey nodeKey,
final StorageProvider storageProvider,
final ObservableMetricsSystem metricsSystem) {
final ObservableMetricsSystem metricsSystem,
final MiningParameters miningParameters) {
return new MainnetBesuControllerBuilder()
.genesisConfigFile(genesisConfig)
.synchronizerConfiguration(syncConfig)
.ethProtocolConfiguration(EthProtocolConfiguration.defaultConfig())
.dataDirectory(dataDir)
.networkId(NETWORK_ID)
.miningParameters(MiningParameters.newDefault())
.miningParameters(miningParameters)
.nodeKey(nodeKey)
.storageProvider(storageProvider)
.metricsSystem(metricsSystem)

@ -432,8 +432,7 @@ public abstract class JsonBlockImporterTest {
return createController(genesisConfigFile);
}
protected BesuController createController(final GenesisConfigFile genesisConfigFile)
throws IOException {
protected BesuController createController(final GenesisConfigFile genesisConfigFile) {
return new BesuController.Builder()
.fromGenesisConfig(genesisConfigFile, SyncMode.FAST)
.synchronizerConfiguration(SynchronizerConfiguration.builder().build())

@ -92,6 +92,7 @@ import org.hyperledger.besu.services.SecurityModuleServiceImpl;
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 org.hyperledger.besu.services.kvstore.InMemoryKeyValueStorage;
import java.io.ByteArrayOutputStream;
@ -573,6 +574,7 @@ public abstract class CommandTestAbstract {
rpcEndpointServiceImpl,
new TransactionSelectionServiceImpl(),
new TransactionPoolValidatorServiceImpl(),
new TransactionSimulationServiceImpl(),
new BlockchainServiceImpl());
}

@ -107,7 +107,7 @@ public class ValidatorContractController {
if (result.isSuccessful()) {
final List<Type> decodedList =
FunctionReturnDecoder.decode(
result.getResult().getOutput().toHexString(), function.getOutputParameters());
result.result().getOutput().toHexString(), function.getOutputParameters());
if (decodedList.isEmpty()) {
throw new IllegalStateException(

@ -90,7 +90,7 @@ public abstract class AbstractEstimateGas implements JsonRpcMethod {
Math.pow(SUB_CALL_REMAINING_GAS_RATIO, operationTracer.getMaxDepth());
// and minimum gas remaining is necessary for some operation (additionalStipend)
final long gasStipend = operationTracer.getStipendNeeded();
final long gasUsedByTransaction = result.getResult().getEstimateGasUsedByTransaction();
final long gasUsedByTransaction = result.result().getEstimateGasUsedByTransaction();
return ((long) ((gasUsedByTransaction + gasStipend) * subCallMultiplier));
}
@ -123,7 +123,7 @@ public abstract class AbstractEstimateGas implements JsonRpcMethod {
JsonRpcErrorConverter.convertTransactionInvalidReason(
validationResult.getInvalidReason()));
} else {
final TransactionProcessingResult resultTrx = result.getResult();
final TransactionProcessingResult resultTrx = result.result();
if (resultTrx != null && resultTrx.getRevertReason().isPresent()) {
return errorResponse(
request,

@ -83,7 +83,7 @@ public class DebugTraceCall extends AbstractTraceCall {
final TransactionTrace transactionTrace =
new TransactionTrace(
result.getTransaction(), result.getResult(), tracer.getTraceFrames());
result.transaction(), result.result(), tracer.getTraceFrames());
return new DebugTraceTransactionResult(transactionTrace);
});

@ -117,7 +117,7 @@ public class EthCall extends AbstractBlockParameterOrBlockHashMethod {
JsonRpcErrorConverter.convertTransactionInvalidReason(
validationResult.getInvalidReason()));
} else {
final TransactionProcessingResult resultTrx = result.getResult();
final TransactionProcessingResult resultTrx = result.result();
if (resultTrx != null && resultTrx.getRevertReason().isPresent()) {
return errorResponse(
request,

@ -85,7 +85,7 @@ public class EthEstimateGas extends AbstractEstimateGas {
return errorResponse(requestContext, gasUsed.get());
}
var low = gasUsed.get().getResult().getEstimateGasUsedByTransaction();
var low = gasUsed.get().result().getEstimateGasUsedByTransaction();
var lowResult =
executeSimulation(
blockHeader,

@ -73,7 +73,7 @@ public class TraceCall extends AbstractTraceCall {
final TransactionTrace transactionTrace =
new TransactionTrace(
result.getTransaction(), result.getResult(), tracer.getTraceFrames());
result.transaction(), result.result(), tracer.getTraceFrames());
final Block block =
blockchainQueriesSupplier.get().getBlockchain().getChainHeadBlock();

@ -166,7 +166,7 @@ public class TraceCallMany extends TraceCall implements JsonRpcMethod {
final TransactionTrace transactionTrace =
new TransactionTrace(
simulatorResult.getTransaction(), simulatorResult.getResult(), tracer.getTraceFrames());
simulatorResult.transaction(), simulatorResult.result(), tracer.getTraceFrames());
final Block block = blockchainQueriesSupplier.get().getBlockchain().getChainHeadBlock();

@ -102,7 +102,7 @@ public class TraceRawTransaction extends AbstractTraceByBlock implements JsonRpc
result -> {
final TransactionTrace transactionTrace =
new TransactionTrace(
result.getTransaction(), result.getResult(), tracer.getTraceFrames());
result.transaction(), result.result(), tracer.getTraceFrames());
final Optional<Block> maybeBlock =
blockchainQueriesSupplier
.get()

@ -197,7 +197,7 @@ public class EthCallTest {
final TransactionSimulatorResult result = mock(TransactionSimulatorResult.class);
when(result.isSuccessful()).thenReturn(false);
when(result.getValidationResult()).thenReturn(ValidationResult.valid());
when(result.getResult()).thenReturn(processingResult);
when(result.result()).thenReturn(processingResult);
verify(transactionSimulator).process(any(), any(), any(), mapperCaptor.capture(), any());
assertThat(mapperCaptor.getValue().apply(mock(MutableWorldState.class), Optional.of(result)))
.isEqualTo(Optional.of(expectedResponse));
@ -236,7 +236,7 @@ public class EthCallTest {
final TransactionSimulatorResult result = mock(TransactionSimulatorResult.class);
when(result.isSuccessful()).thenReturn(false);
when(result.getValidationResult()).thenReturn(ValidationResult.valid());
when(result.getResult()).thenReturn(processingResult);
when(result.result()).thenReturn(processingResult);
verify(transactionSimulator).process(any(), any(), any(), mapperCaptor.capture(), any());
assertThat(mapperCaptor.getValue().apply(mock(MutableWorldState.class), Optional.of(result)))
.isEqualTo(Optional.of(expectedResponse));
@ -277,7 +277,7 @@ public class EthCallTest {
final TransactionSimulatorResult result = mock(TransactionSimulatorResult.class);
when(result.isSuccessful()).thenReturn(false);
when(result.getValidationResult()).thenReturn(ValidationResult.valid());
when(result.getResult()).thenReturn(processingResult);
when(result.result()).thenReturn(processingResult);
verify(transactionSimulator).process(any(), any(), any(), mapperCaptor.capture(), any());
System.out.println(result);

@ -300,7 +300,7 @@ public class EthCreateAccessListTest {
when(mockResult.getEstimateGasUsedByTransaction()).thenReturn(estimateGas);
when(mockResult.getRevertReason())
.thenReturn(isReverted ? Optional.of(Bytes.of(0)) : Optional.empty());
when(mockTxSimResult.getResult()).thenReturn(mockResult);
when(mockTxSimResult.result()).thenReturn(mockResult);
when(mockTxSimResult.isSuccessful()).thenReturn(isSuccessful);
}

@ -451,7 +451,7 @@ public class EthEstimateGasTest {
when(mockResult.getEstimateGasUsedByTransaction()).thenReturn(estimateGas);
when(mockResult.getRevertReason()).thenReturn(revertReason);
when(mockTxSimResult.getResult()).thenReturn(mockResult);
when(mockTxSimResult.result()).thenReturn(mockResult);
when(mockTxSimResult.isSuccessful()).thenReturn(isSuccessful);
return mockTxSimResult;
}

@ -195,6 +195,10 @@ public abstract class AbstractBlockTransactionSelectorTest {
return false;
}
protected Wei getMinGasPrice() {
return Wei.ONE;
}
protected ProcessableBlockHeader createBlock(final long gasLimit) {
return createBlock(gasLimit, Wei.ONE);
}

@ -204,4 +204,31 @@ public class TransactionProcessingResult
public Optional<Bytes> getRevertReason() {
return revertReason;
}
@Override
public Optional<String> getInvalidReason() {
return (validationResult.isValid()
? Optional.empty()
: Optional.of(validationResult.getErrorMessage()));
}
@Override
public String toString() {
return "TransactionProcessingResult{"
+ "status="
+ status
+ ", estimateGasUsedByTransaction="
+ estimateGasUsedByTransaction
+ ", gasRemaining="
+ gasRemaining
+ ", logs="
+ logs
+ ", output="
+ output
+ ", validationResult="
+ validationResult
+ ", revertReason="
+ revertReason
+ '}';
}
}

@ -199,18 +199,61 @@ public class CallParameter {
blobVersionedHashes);
}
@Override
public String toString() {
return "CallParameter{"
+ "from="
+ from
+ ", to="
+ to
+ ", gasLimit="
+ gasLimit
+ ", maxPriorityFeePerGas="
+ maxPriorityFeePerGas.map(Wei::toHumanReadableString).orElse("N/A")
+ ", maxFeePerGas="
+ maxFeePerGas.map(Wei::toHumanReadableString).orElse("N/A")
+ ", maxFeePerBlobGas="
+ maxFeePerBlobGas.map(Wei::toHumanReadableString).orElse("N/A")
+ ", gasPrice="
+ (gasPrice != null ? gasPrice.toHumanReadableString() : "N/A")
+ ", value="
+ (value != null ? value.toHumanReadableString() : "N/A")
+ ", payloadSize="
+ (payload != null ? payload.size() : "null")
+ ", accessListSize="
+ accessList.map(List::size)
+ ", blobVersionedHashesSize="
+ blobVersionedHashes.map(List::size)
+ '}';
}
public static CallParameter fromTransaction(final Transaction tx) {
return new CallParameter(
tx.getSender(),
tx.getTo().orElseGet(() -> null),
tx.getTo().orElse(null),
tx.getGasLimit(),
Wei.fromQuantity(tx.getGasPrice().orElseGet(() -> Wei.ZERO)),
Optional.of(Wei.fromQuantity(tx.getMaxPriorityFeePerGas().orElseGet(() -> Wei.ZERO))),
tx.getGasPrice().orElse(Wei.ZERO),
tx.getMaxPriorityFeePerGas(),
tx.getMaxFeePerGas(),
Wei.fromQuantity(tx.getValue()),
tx.getValue(),
tx.getPayload(),
tx.getAccessList(),
tx.getMaxFeePerBlobGas(),
tx.getVersionedHashes());
}
public static CallParameter fromTransaction(final org.hyperledger.besu.datatypes.Transaction tx) {
return new CallParameter(
tx.getSender(),
tx.getTo().orElse(null),
tx.getGasLimit(),
tx.getGasPrice().map(Wei::fromQuantity).orElse(Wei.ZERO),
tx.getMaxPriorityFeePerGas().map(Wei::fromQuantity),
tx.getMaxFeePerGas().map(Wei::fromQuantity),
Wei.fromQuantity(tx.getValue()),
tx.getPayload(),
tx.getAccessList(),
tx.getMaxFeePerBlobGas().map(Wei::fromQuantity),
tx.getVersionedHashes());
}
}

@ -106,7 +106,21 @@ public class TransactionSimulator {
header);
}
public Optional<TransactionSimulatorResult> process(
final CallParameter callParams,
final TransactionValidationParams transactionValidationParams,
final OperationTracer operationTracer,
final BlockHeader blockHeader) {
return process(
callParams,
transactionValidationParams,
operationTracer,
(mutableWorldState, transactionSimulatorResult) -> transactionSimulatorResult,
blockHeader);
}
public Optional<TransactionSimulatorResult> processAtHead(final CallParameter callParams) {
final var chainHeadHash = blockchain.getChainHeadHash();
return process(
callParams,
ImmutableTransactionValidationParams.builder()
@ -115,7 +129,10 @@ public class TransactionSimulator {
.build(),
OperationTracer.NO_TRACING,
(mutableWorldState, transactionSimulatorResult) -> transactionSimulatorResult,
blockchain.getChainHeadHeader());
blockchain
.getBlockHeader(chainHeadHash)
.or(() -> blockchain.getBlockHeaderSafe(chainHeadHash))
.orElse(null));
}
/**

@ -18,22 +18,10 @@ import org.hyperledger.besu.ethereum.core.Transaction;
import org.hyperledger.besu.ethereum.mainnet.ValidationResult;
import org.hyperledger.besu.ethereum.processing.TransactionProcessingResult;
import java.util.Objects;
import com.google.common.annotations.VisibleForTesting;
import org.apache.tuweni.bytes.Bytes;
public class TransactionSimulatorResult {
private final Transaction transaction;
private final TransactionProcessingResult result;
@VisibleForTesting
public TransactionSimulatorResult(
final Transaction transaction, final TransactionProcessingResult result) {
this.transaction = transaction;
this.result = result;
}
public record TransactionSimulatorResult(
Transaction transaction, TransactionProcessingResult result) {
public boolean isSuccessful() {
return result.isSuccessful();
@ -54,40 +42,4 @@ public class TransactionSimulatorResult {
public ValidationResult<TransactionInvalidReason> getValidationResult() {
return result.getValidationResult();
}
public TransactionProcessingResult getResult() {
return result;
}
public Transaction getTransaction() {
return transaction;
}
@Override
public boolean equals(final Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
final TransactionSimulatorResult that = (TransactionSimulatorResult) o;
return Objects.equals(transaction, that.transaction) && Objects.equals(result, that.result);
}
@Override
public int hashCode() {
return Objects.hash(transaction, result);
}
@Override
public String toString() {
return "TransactionSimulatorResult{"
+ "transaction="
+ transaction
+ ", "
+ "result="
+ result
+ "}";
}
}

@ -72,12 +72,12 @@ public class MainnetTransactionValidatorTest {
private static final Supplier<SignatureAlgorithm> SIGNATURE_ALGORITHM =
Suppliers.memoize(SignatureAlgorithmFactory::getInstance);
private static final KeyPair senderKeys = SIGNATURE_ALGORITHM.get().generateKeyPair();
protected static final KeyPair senderKeys = SIGNATURE_ALGORITHM.get().generateKeyPair();
private static final TransactionValidationParams transactionValidationParams =
processingBlockParams;
@Mock private GasCalculator gasCalculator;
@Mock protected GasCalculator gasCalculator;
private final Transaction basicTransaction =
new TransactionTestFixture()

@ -32,7 +32,6 @@ import org.hyperledger.besu.ethereum.core.Transaction;
import org.hyperledger.besu.ethereum.core.TransactionTestFixture;
import org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason;
import org.hyperledger.besu.evm.account.Account;
import org.hyperledger.besu.evm.gascalculator.GasCalculator;
import java.math.BigInteger;
import java.util.Optional;
@ -42,7 +41,6 @@ import com.google.common.base.Suppliers;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
@ExtendWith(MockitoExtension.class)
@ -51,7 +49,6 @@ public class PermissionTransactionValidatorTest extends MainnetTransactionValida
private static final Supplier<SignatureAlgorithm> SIGNATURE_ALGORITHM =
Suppliers.memoize(SignatureAlgorithmFactory::getInstance);
private static final KeyPair senderKeys = SIGNATURE_ALGORITHM.get().generateKeyPair();
@Mock private GasCalculator gasCalculator;
private final Transaction basicTransaction =
new TransactionTestFixture()

@ -71,7 +71,7 @@ public class NodeSmartContractPermissioningController
transactionSimulator.processAtHead(callParams);
if (result.isPresent()) {
switch (result.get().getResult().getStatus()) {
switch (result.get().result().getStatus()) {
case INVALID:
throw new IllegalStateException("Permissioning transaction found to be Invalid");
case FAILED:

@ -114,7 +114,7 @@ public class NodeSmartContractV2PermissioningController
}
private boolean parseResult(final TransactionSimulatorResult result) {
switch (result.getResult().getStatus()) {
switch (result.result().getStatus()) {
case INVALID:
throw new IllegalStateException("Invalid node permissioning smart contract call");
case FAILED:

@ -134,7 +134,7 @@ public class TransactionSmartContractPermissioningController
transactionSimulator.processAtHead(callParams);
if (result.isPresent()) {
switch (result.get().getResult().getStatus()) {
switch (result.get().result().getStatus()) {
case INVALID:
throw new IllegalStateException(
"Transaction permissioning transaction found to be Invalid");

@ -69,7 +69,7 @@ Calculated : ${currentHash}
tasks.register('checkAPIChanges', FileStateChecker) {
description = "Checks that the API for the Plugin-API project does not change without deliberate thought"
files = sourceSets.main.allJava.files
knownHash = 'B/pzTaARYvd/T9WtAXtX6vFbxoK5u82GigByKD0YP6M='
knownHash = 'ytjNiSzw9IR8YHyO4ikmqRTg1GTWkCX9QiQtwq2dRSg='
}
check.dependsOn('checkAPIChanges')

@ -88,4 +88,11 @@ public interface TransactionProcessingResult {
* @return the revert reason.
*/
Optional<Bytes> getRevertReason();
/**
* Return the reason why the transaction is invalid or empty if the transaction is successful
*
* @return the optional invalid reason as a string
*/
Optional<String> getInvalidReason();
}

@ -0,0 +1,54 @@
/*
* Copyright Hyperledger Besu Contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.plugin.data;
import org.hyperledger.besu.datatypes.Transaction;
/**
* TransactionSimulationResult
*
* @param transaction tx
* @param result res
*/
public record TransactionSimulationResult(
Transaction transaction, TransactionProcessingResult result) {
/**
* Was the simulation successful?
*
* @return boolean
*/
public boolean isSuccessful() {
return result.isSuccessful();
}
/**
* Was the transaction invalid?
*
* @return invalid
*/
public boolean isInvalid() {
return result.isInvalid();
}
/**
* Estimated gas used by the transaction
*
* @return estimated gas used
*/
public long getGasEstimate() {
return transaction.getGasLimit() - result.getGasRemaining();
}
}

@ -0,0 +1,42 @@
/*
* Copyright Hyperledger Besu Contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.plugin.services;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.datatypes.Transaction;
import org.hyperledger.besu.evm.tracing.OperationTracer;
import org.hyperledger.besu.plugin.Unstable;
import org.hyperledger.besu.plugin.data.TransactionSimulationResult;
import java.util.Optional;
/** Transaction simulation service interface */
@Unstable
public interface TransactionSimulationService extends BesuService {
/**
* Simulate transaction execution at the block identified by the hash
*
* @param transaction tx
* @param blockHash the hash of the block
* @param operationTracer the tracer
* @param isAllowExceedingBalance should ignore the sender balance during the simulation?
* @return the result of the simulation
*/
Optional<TransactionSimulationResult> simulate(
Transaction transaction,
Hash blockHash,
OperationTracer operationTracer,
boolean isAllowExceedingBalance);
}

@ -242,7 +242,13 @@ public class JsonTestParameters<S, T> {
return generate(getFilteredFiles(paths));
}
private Collection<Object[]> generate(final Collection<File> filteredFiles) {
/**
* Generate collection.
*
* @param filteredFiles the filtered files
* @return the collection
*/
public Collection<Object[]> generate(final Collection<File> filteredFiles) {
checkState(generator != null, "Missing generator function");
final Collector<T> collector =

Loading…
Cancel
Save