mirror of
https://github.com/vacp2p/status-linea-besu.git
synced 2026-01-08 21:38:15 -05:00
Transaction simulation service (#6686)
Signed-off-by: Fabio Di Fabio <fabio.difabio@consensys.net>
This commit is contained in:
@@ -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 =
|
||||
|
||||
Reference in New Issue
Block a user