Merge branch 'main' into 7311-add-GetHeadersFromPeerTask

Signed-off-by: Matilda-Clerke <matilda.clerke@consensys.net>
pull/7781/head
Matilda-Clerke 5 days ago committed by GitHub
commit bedf3d0d5d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 1
      CHANGELOG.md
  2. 9
      acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/ThreadBesuNodeRunner.java
  3. 2
      besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java
  4. 35
      besu/src/main/java/org/hyperledger/besu/controller/BesuControllerBuilder.java
  5. 22
      besu/src/main/java/org/hyperledger/besu/controller/ConsensusScheduleBesuControllerBuilder.java
  6. 5
      besu/src/main/java/org/hyperledger/besu/controller/QbftBesuControllerBuilder.java
  7. 7
      besu/src/main/java/org/hyperledger/besu/controller/TransitionBesuControllerBuilder.java
  8. 18
      besu/src/main/java/org/hyperledger/besu/services/BlockchainServiceImpl.java
  9. 17
      besu/src/test/java/org/hyperledger/besu/controller/ConsensusScheduleBesuControllerBuilderTest.java
  10. 17
      consensus/clique/src/test/java/org/hyperledger/besu/consensus/clique/blockcreation/CliqueBlockCreatorTest.java
  11. 2
      consensus/clique/src/test/java/org/hyperledger/besu/consensus/clique/blockcreation/CliqueMinerExecutorTest.java
  12. 4
      consensus/common/src/main/java/org/hyperledger/besu/consensus/common/MigratingConsensusContext.java
  13. 36
      consensus/common/src/main/java/org/hyperledger/besu/consensus/common/MigratingProtocolContext.java
  14. 6
      consensus/common/src/test/java/org/hyperledger/besu/consensus/common/MigratingProtocolContextTest.java
  15. 2
      docs/Private-Txns-Migration.md
  16. 5
      ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcTestMethodsFactory.java
  17. 4
      ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/EthGetBlockByNumberLatestDesyncIntegrationTest.java
  18. 20
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthCall.java
  19. 37
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/TraceBlock.java
  20. 7
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/TraceCallMany.java
  21. 28
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/TraceFilter.java
  22. 25
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/TraceReplayBlockTransactions.java
  23. 6
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/JsonRpcMethodsFactory.java
  24. 15
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/TraceJsonRpcMethods.java
  25. 6
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/AbstractEthGraphQLHttpServiceTest.java
  26. 81
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthCallTest.java
  27. 4
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/TraceFilterTest.java
  28. 24
      ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/eth/eth_call_overrides_empty.json
  29. 32
      ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/eth/eth_call_stateOverride.json
  30. 34
      ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/eth/eth_call_stateOverride_insufficientBalance.json
  31. 7
      ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/BlockMinerTest.java
  32. 2
      ethereum/core/build.gradle
  33. 38
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/ConsensusContextFactory.java
  34. 29
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/ProtocolContext.java
  35. 32
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchain.java
  36. 66
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/TransactionSimulator.java
  37. 13
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/cache/BonsaiCachedMerkleTrieLoader.java
  38. 147
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/util/AccountOverride.java
  39. 27
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/util/AccountOverrideMap.java
  40. 11
      ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/BlockchainSetupUtil.java
  41. 24
      ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/ConsensusContextFixture.java
  42. 3
      ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/ExecutionContextTestFixture.java
  43. 41
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/transaction/TransactionSimulatorTest.java
  44. 5
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/AbstractIsolationTests.java
  45. 188
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/util/AccountOverrideParameterTest.java
  46. 4
      ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncTargetManagerTest.java
  47. 7
      ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/tasks/DetermineCommonAncestorTaskParameterizedTest.java
  48. 7
      ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/tasks/DetermineCommonAncestorTaskTest.java
  49. 4
      ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TestNode.java
  50. 1
      ethereum/p2p/build.gradle
  51. 7
      ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/BlockchainReferenceTestCaseSpec.java
  52. 1
      metrics/core/build.gradle
  53. 31
      metrics/core/src/main/java/org/hyperledger/besu/metrics/ObservableMetricsSystem.java
  54. 17
      metrics/core/src/main/java/org/hyperledger/besu/metrics/noop/NoOpMetricsSystem.java
  55. 15
      metrics/core/src/main/java/org/hyperledger/besu/metrics/opentelemetry/OpenTelemetrySystem.java
  56. 130
      metrics/core/src/main/java/org/hyperledger/besu/metrics/prometheus/PrometheusMetricsSystem.java
  57. 21
      metrics/core/src/test-support/java/org/hyperledger/besu/metrics/StubMetricsSystem.java
  58. 2
      metrics/rocksdb/build.gradle
  59. 87
      metrics/rocksdb/src/main/java/org/hyperledger/besu/metrics/rocksdb/RocksDBStats.java
  60. 2
      plugin-api/build.gradle
  61. 46
      plugin-api/src/main/java/org/hyperledger/besu/plugin/services/MetricsSystem.java
  62. 36
      plugin-api/src/main/java/org/hyperledger/besu/plugin/services/metrics/ExternalSummary.java
  63. 1
      plugins/rocksdb/build.gradle
  64. 6
      plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/RocksDBMetricsFactory.java

@ -15,6 +15,7 @@
- Update Java dependencies [#7786](https://github.com/hyperledger/besu/pull/7786) - Update Java dependencies [#7786](https://github.com/hyperledger/besu/pull/7786)
- Add a method to get all the transaction in the pool, to the `TransactionPoolService`, to easily access the transaction pool content from plugins [#7813](https://github.com/hyperledger/besu/pull/7813) - Add a method to get all the transaction in the pool, to the `TransactionPoolService`, to easily access the transaction pool content from plugins [#7813](https://github.com/hyperledger/besu/pull/7813)
- Add a method to check if a metric category is enabled to the plugin API [#7832](https://github.com/hyperledger/besu/pull/7832) - Add a method to check if a metric category is enabled to the plugin API [#7832](https://github.com/hyperledger/besu/pull/7832)
- Add account and state overrides to `eth_call` and `eth_estimateGas` [#7801](https://github.com/hyperledger/besu/pull/7801)
### Bug fixes ### Bug fixes
- Fix registering new metric categories from plugins [#7825](https://github.com/hyperledger/besu/pull/7825) - Fix registering new metric categories from plugins [#7825](https://github.com/hyperledger/besu/pull/7825)

@ -75,6 +75,7 @@ import org.hyperledger.besu.plugin.services.TransactionSelectionService;
import org.hyperledger.besu.plugin.services.TransactionSimulationService; import org.hyperledger.besu.plugin.services.TransactionSimulationService;
import org.hyperledger.besu.plugin.services.metrics.MetricCategoryRegistry; import org.hyperledger.besu.plugin.services.metrics.MetricCategoryRegistry;
import org.hyperledger.besu.plugin.services.storage.rocksdb.RocksDBPlugin; import org.hyperledger.besu.plugin.services.storage.rocksdb.RocksDBPlugin;
import org.hyperledger.besu.plugin.services.transactionpool.TransactionPoolService;
import org.hyperledger.besu.services.BesuConfigurationImpl; import org.hyperledger.besu.services.BesuConfigurationImpl;
import org.hyperledger.besu.services.BesuEventsImpl; import org.hyperledger.besu.services.BesuEventsImpl;
import org.hyperledger.besu.services.BesuPluginContextImpl; import org.hyperledger.besu.services.BesuPluginContextImpl;
@ -85,6 +86,7 @@ import org.hyperledger.besu.services.PrivacyPluginServiceImpl;
import org.hyperledger.besu.services.RpcEndpointServiceImpl; import org.hyperledger.besu.services.RpcEndpointServiceImpl;
import org.hyperledger.besu.services.SecurityModuleServiceImpl; import org.hyperledger.besu.services.SecurityModuleServiceImpl;
import org.hyperledger.besu.services.StorageServiceImpl; import org.hyperledger.besu.services.StorageServiceImpl;
import org.hyperledger.besu.services.TransactionPoolServiceImpl;
import org.hyperledger.besu.services.TransactionPoolValidatorServiceImpl; import org.hyperledger.besu.services.TransactionPoolValidatorServiceImpl;
import org.hyperledger.besu.services.TransactionSelectionServiceImpl; import org.hyperledger.besu.services.TransactionSelectionServiceImpl;
import org.hyperledger.besu.services.TransactionSimulationServiceImpl; import org.hyperledger.besu.services.TransactionSimulationServiceImpl;
@ -215,6 +217,9 @@ public class ThreadBesuNodeRunner implements BesuNodeRunner {
besuController.getTransactionPool(), besuController.getTransactionPool(),
besuController.getSyncState(), besuController.getSyncState(),
besuController.getProtocolContext().getBadBlockManager())); besuController.getProtocolContext().getBadBlockManager()));
besuPluginContext.addService(
TransactionPoolService.class,
new TransactionPoolServiceImpl(besuController.getTransactionPool()));
component.rpcEndpointService().init(runner.getInProcessRpcMethods()); component.rpcEndpointService().init(runner.getInProcessRpcMethods());
@ -327,7 +332,9 @@ public class ThreadBesuNodeRunner implements BesuNodeRunner {
@Singleton @Singleton
BlockchainServiceImpl provideBlockchainService(final BesuController besuController) { BlockchainServiceImpl provideBlockchainService(final BesuController besuController) {
BlockchainServiceImpl retval = new BlockchainServiceImpl(); BlockchainServiceImpl retval = new BlockchainServiceImpl();
retval.init(besuController.getProtocolContext(), besuController.getProtocolSchedule()); retval.init(
besuController.getProtocolContext().getBlockchain(),
besuController.getProtocolSchedule());
return retval; return retval;
} }

@ -1233,7 +1233,7 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
private void startPlugins(final Runner runner) { private void startPlugins(final Runner runner) {
blockchainServiceImpl.init( blockchainServiceImpl.init(
besuController.getProtocolContext(), besuController.getProtocolSchedule()); besuController.getProtocolContext().getBlockchain(), besuController.getProtocolSchedule());
transactionSimulationServiceImpl.init( transactionSimulationServiceImpl.init(
besuController.getProtocolContext().getBlockchain(), besuController.getProtocolContext().getBlockchain(),
new TransactionSimulator( new TransactionSimulator(

@ -26,7 +26,6 @@ import org.hyperledger.besu.consensus.qbft.BFTPivotSelectorFromPeers;
import org.hyperledger.besu.cryptoservices.NodeKey; import org.hyperledger.besu.cryptoservices.NodeKey;
import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.ethereum.ConsensusContext; import org.hyperledger.besu.ethereum.ConsensusContext;
import org.hyperledger.besu.ethereum.ConsensusContextFactory;
import org.hyperledger.besu.ethereum.GasLimitCalculator; import org.hyperledger.besu.ethereum.GasLimitCalculator;
import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.ProtocolContext;
import org.hyperledger.besu.ethereum.api.jsonrpc.methods.JsonRpcMethods; import org.hyperledger.besu.ethereum.api.jsonrpc.methods.JsonRpcMethods;
@ -605,9 +604,11 @@ public abstract class BesuControllerBuilder implements MiningParameterOverrides
genesisState.writeStateTo(worldStateArchive.getMutable()); genesisState.writeStateTo(worldStateArchive.getMutable());
} }
final var consensusContext =
createConsensusContext(blockchain, worldStateArchive, protocolSchedule);
final ProtocolContext protocolContext = final ProtocolContext protocolContext =
createProtocolContext( createProtocolContext(blockchain, worldStateArchive, consensusContext);
blockchain, worldStateArchive, protocolSchedule, this::createConsensusContext);
validateContext(protocolContext); validateContext(protocolContext);
protocolSchedule.setPublicWorldStateArchiveForPrivacyBlockProcessor( protocolSchedule.setPublicWorldStateArchiveForPrivacyBlockProcessor(
@ -624,7 +625,7 @@ public abstract class BesuControllerBuilder implements MiningParameterOverrides
ethereumWireProtocolConfiguration.isLegacyEth64ForkIdEnabled()); ethereumWireProtocolConfiguration.isLegacyEth64ForkIdEnabled());
final EthPeers ethPeers = final EthPeers ethPeers =
new EthPeers( new EthPeers(
getSupportedProtocol(), EthProtocol.NAME,
currentProtocolSpecSupplier, currentProtocolSpecSupplier,
clock, clock,
metricsSystem, metricsSystem,
@ -987,7 +988,7 @@ public abstract class BesuControllerBuilder implements MiningParameterOverrides
} }
/** /**
* Create mining coordinator mining coordinator. * Create mining coordinator.
* *
* @param protocolSchedule the protocol schedule * @param protocolSchedule the protocol schedule
* @param protocolContext the protocol context * @param protocolContext the protocol context
@ -1030,18 +1031,9 @@ public abstract class BesuControllerBuilder implements MiningParameterOverrides
* @return the consensus context * @return the consensus context
*/ */
protected abstract ConsensusContext createConsensusContext( protected abstract ConsensusContext createConsensusContext(
Blockchain blockchain, final Blockchain blockchain,
WorldStateArchive worldStateArchive, final WorldStateArchive worldStateArchive,
ProtocolSchedule protocolSchedule); final ProtocolSchedule protocolSchedule);
/**
* Gets supported protocol.
*
* @return the supported protocol
*/
protected String getSupportedProtocol() {
return EthProtocol.NAME;
}
/** /**
* Create eth protocol manager eth protocol manager. * Create eth protocol manager eth protocol manager.
@ -1092,17 +1084,14 @@ public abstract class BesuControllerBuilder implements MiningParameterOverrides
* *
* @param blockchain the blockchain * @param blockchain the blockchain
* @param worldStateArchive the world state archive * @param worldStateArchive the world state archive
* @param protocolSchedule the protocol schedule * @param consensusContext the consensus context
* @param consensusContextFactory the consensus context factory
* @return the protocol context * @return the protocol context
*/ */
protected ProtocolContext createProtocolContext( protected ProtocolContext createProtocolContext(
final MutableBlockchain blockchain, final MutableBlockchain blockchain,
final WorldStateArchive worldStateArchive, final WorldStateArchive worldStateArchive,
final ProtocolSchedule protocolSchedule, final ConsensusContext consensusContext) {
final ConsensusContextFactory consensusContextFactory) { return new ProtocolContext(blockchain, worldStateArchive, consensusContext, badBlockManager);
return ProtocolContext.init(
blockchain, worldStateArchive, protocolSchedule, consensusContextFactory, badBlockManager);
} }
private Optional<SnapProtocolManager> createSnapProtocolManager( private Optional<SnapProtocolManager> createSnapProtocolManager(

@ -20,13 +20,12 @@ import org.hyperledger.besu.config.GenesisConfigFile;
import org.hyperledger.besu.consensus.common.CombinedProtocolScheduleFactory; import org.hyperledger.besu.consensus.common.CombinedProtocolScheduleFactory;
import org.hyperledger.besu.consensus.common.ForkSpec; import org.hyperledger.besu.consensus.common.ForkSpec;
import org.hyperledger.besu.consensus.common.ForksSchedule; import org.hyperledger.besu.consensus.common.ForksSchedule;
import org.hyperledger.besu.consensus.common.MigratingContext; import org.hyperledger.besu.consensus.common.MigratingConsensusContext;
import org.hyperledger.besu.consensus.common.MigratingMiningCoordinator; import org.hyperledger.besu.consensus.common.MigratingMiningCoordinator;
import org.hyperledger.besu.consensus.common.MigratingProtocolContext; import org.hyperledger.besu.consensus.common.MigratingProtocolContext;
import org.hyperledger.besu.cryptoservices.NodeKey; import org.hyperledger.besu.cryptoservices.NodeKey;
import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.ethereum.ConsensusContext; import org.hyperledger.besu.ethereum.ConsensusContext;
import org.hyperledger.besu.ethereum.ConsensusContextFactory;
import org.hyperledger.besu.ethereum.GasLimitCalculator; import org.hyperledger.besu.ethereum.GasLimitCalculator;
import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.ProtocolContext;
import org.hyperledger.besu.ethereum.api.jsonrpc.methods.JsonRpcMethods; import org.hyperledger.besu.ethereum.api.jsonrpc.methods.JsonRpcMethods;
@ -171,10 +170,12 @@ public class ConsensusScheduleBesuControllerBuilder extends BesuControllerBuilde
protected ProtocolContext createProtocolContext( protected ProtocolContext createProtocolContext(
final MutableBlockchain blockchain, final MutableBlockchain blockchain,
final WorldStateArchive worldStateArchive, final WorldStateArchive worldStateArchive,
final ProtocolSchedule protocolSchedule, final ConsensusContext consensusContext) {
final ConsensusContextFactory consensusContextFactory) { return new MigratingProtocolContext(
return MigratingProtocolContext.init( blockchain,
blockchain, worldStateArchive, protocolSchedule, consensusContextFactory, badBlockManager); worldStateArchive,
consensusContext.as(MigratingConsensusContext.class),
badBlockManager);
} }
@Override @Override
@ -191,10 +192,10 @@ public class ConsensusScheduleBesuControllerBuilder extends BesuControllerBuilde
e.getValue() e.getValue()
.createConsensusContext( .createConsensusContext(
blockchain, worldStateArchive, protocolSchedule))) blockchain, worldStateArchive, protocolSchedule)))
.collect(Collectors.toList()); .toList();
final ForksSchedule<ConsensusContext> consensusContextsSchedule = final ForksSchedule<ConsensusContext> consensusContextsSchedule =
new ForksSchedule<>(consensusContextSpecs); new ForksSchedule<>(consensusContextSpecs);
return new MigratingContext(consensusContextsSchedule); return new MigratingConsensusContext(consensusContextsSchedule);
} }
@Override @Override
@ -230,11 +231,6 @@ public class ConsensusScheduleBesuControllerBuilder extends BesuControllerBuilde
besuControllerBuilderSchedule.get(GENESIS_BLOCK_NUMBER).validateContext(context); besuControllerBuilderSchedule.get(GENESIS_BLOCK_NUMBER).validateContext(context);
} }
@Override
protected String getSupportedProtocol() {
return besuControllerBuilderSchedule.get(0L).getSupportedProtocol();
}
@Override @Override
protected EthProtocolManager createEthProtocolManager( protected EthProtocolManager createEthProtocolManager(
final ProtocolContext protocolContext, final ProtocolContext protocolContext,

@ -113,10 +113,7 @@ public class QbftBesuControllerBuilder extends BftBesuControllerBuilder {
@Override @Override
protected Supplier<BftExtraDataCodec> bftExtraDataCodec() { protected Supplier<BftExtraDataCodec> bftExtraDataCodec() {
return Suppliers.memoize( return Suppliers.memoize(QbftExtraDataCodec::new);
() -> {
return new QbftExtraDataCodec();
});
} }
@Override @Override

@ -24,7 +24,6 @@ import org.hyperledger.besu.consensus.merge.blockcreation.TransitionCoordinator;
import org.hyperledger.besu.cryptoservices.NodeKey; import org.hyperledger.besu.cryptoservices.NodeKey;
import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.ethereum.ConsensusContext; import org.hyperledger.besu.ethereum.ConsensusContext;
import org.hyperledger.besu.ethereum.ConsensusContextFactory;
import org.hyperledger.besu.ethereum.GasLimitCalculator; import org.hyperledger.besu.ethereum.GasLimitCalculator;
import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.ProtocolContext;
import org.hyperledger.besu.ethereum.blockcreation.MiningCoordinator; import org.hyperledger.besu.ethereum.blockcreation.MiningCoordinator;
@ -197,11 +196,9 @@ public class TransitionBesuControllerBuilder extends BesuControllerBuilder {
protected ProtocolContext createProtocolContext( protected ProtocolContext createProtocolContext(
final MutableBlockchain blockchain, final MutableBlockchain blockchain,
final WorldStateArchive worldStateArchive, final WorldStateArchive worldStateArchive,
final ProtocolSchedule protocolSchedule, final ConsensusContext consensusContext) {
final ConsensusContextFactory consensusContextFactory) {
final ProtocolContext protocolContext = final ProtocolContext protocolContext =
super.createProtocolContext( super.createProtocolContext(blockchain, worldStateArchive, consensusContext);
blockchain, worldStateArchive, protocolSchedule, consensusContextFactory);
transitionProtocolSchedule.setProtocolContext(protocolContext); transitionProtocolSchedule.setProtocolContext(protocolContext);
return protocolContext; return protocolContext;
} }

@ -16,7 +16,6 @@ package org.hyperledger.besu.services;
import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.ProtocolContext;
import org.hyperledger.besu.ethereum.chain.MutableBlockchain; import org.hyperledger.besu.ethereum.chain.MutableBlockchain;
import org.hyperledger.besu.ethereum.core.Block; import org.hyperledger.besu.ethereum.core.Block;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
@ -40,7 +39,6 @@ import java.util.stream.Collectors;
@Unstable @Unstable
public class BlockchainServiceImpl implements BlockchainService { public class BlockchainServiceImpl implements BlockchainService {
private ProtocolContext protocolContext;
private ProtocolSchedule protocolSchedule; private ProtocolSchedule protocolSchedule;
private MutableBlockchain blockchain; private MutableBlockchain blockchain;
@ -50,13 +48,12 @@ public class BlockchainServiceImpl implements BlockchainService {
/** /**
* Initialize the Blockchain service. * Initialize the Blockchain service.
* *
* @param protocolContext the protocol context * @param blockchain the blockchain
* @param protocolSchedule the protocol schedule * @param protocolSchedule the protocol schedule
*/ */
public void init(final ProtocolContext protocolContext, final ProtocolSchedule protocolSchedule) { public void init(final MutableBlockchain blockchain, final ProtocolSchedule protocolSchedule) {
this.protocolContext = protocolContext;
this.protocolSchedule = protocolSchedule; this.protocolSchedule = protocolSchedule;
this.blockchain = protocolContext.getBlockchain(); this.blockchain = blockchain;
} }
/** /**
@ -67,25 +64,24 @@ public class BlockchainServiceImpl implements BlockchainService {
*/ */
@Override @Override
public Optional<BlockContext> getBlockByNumber(final long number) { public Optional<BlockContext> getBlockByNumber(final long number) {
return protocolContext return blockchain
.getBlockchain()
.getBlockByNumber(number) .getBlockByNumber(number)
.map(block -> blockContext(block::getHeader, block::getBody)); .map(block -> blockContext(block::getHeader, block::getBody));
} }
@Override @Override
public Hash getChainHeadHash() { public Hash getChainHeadHash() {
return protocolContext.getBlockchain().getChainHeadHash(); return blockchain.getChainHeadHash();
} }
@Override @Override
public BlockHeader getChainHeadHeader() { public BlockHeader getChainHeadHeader() {
return protocolContext.getBlockchain().getChainHeadHeader(); return blockchain.getChainHeadHeader();
} }
@Override @Override
public Optional<Wei> getNextBlockBaseFee() { public Optional<Wei> getNextBlockBaseFee() {
final var chainHeadHeader = protocolContext.getBlockchain().getChainHeadHeader(); final var chainHeadHeader = blockchain.getChainHeadHeader();
final var protocolSpec = final var protocolSpec =
protocolSchedule.getForNextBlockHeader(chainHeadHeader, System.currentTimeMillis()); protocolSchedule.getForNextBlockHeader(chainHeadHeader, System.currentTimeMillis());
return Optional.of(protocolSpec.getFeeMarket()) return Optional.of(protocolSpec.getFeeMarket())

@ -24,7 +24,7 @@ import org.hyperledger.besu.config.GenesisConfigFile;
import org.hyperledger.besu.config.StubGenesisConfigOptions; import org.hyperledger.besu.config.StubGenesisConfigOptions;
import org.hyperledger.besu.consensus.common.ForkSpec; import org.hyperledger.besu.consensus.common.ForkSpec;
import org.hyperledger.besu.consensus.common.ForksSchedule; import org.hyperledger.besu.consensus.common.ForksSchedule;
import org.hyperledger.besu.consensus.common.MigratingContext; import org.hyperledger.besu.consensus.common.MigratingConsensusContext;
import org.hyperledger.besu.consensus.common.MigratingMiningCoordinator; import org.hyperledger.besu.consensus.common.MigratingMiningCoordinator;
import org.hyperledger.besu.consensus.common.bft.blockcreation.BftMiningCoordinator; import org.hyperledger.besu.consensus.common.bft.blockcreation.BftMiningCoordinator;
import org.hyperledger.besu.ethereum.ConsensusContext; import org.hyperledger.besu.ethereum.ConsensusContext;
@ -170,8 +170,8 @@ public class ConsensusScheduleBesuControllerBuilderTest {
@Test @Test
public void createsMigratingContext() { public void createsMigratingContext() {
final ConsensusContext context1 = Mockito.mock(ConsensusContext.class); final ConsensusContext context1 = mock(ConsensusContext.class);
final ConsensusContext context2 = Mockito.mock(ConsensusContext.class); final ConsensusContext context2 = mock(ConsensusContext.class);
final Map<Long, BesuControllerBuilder> besuControllerBuilderSchedule = new TreeMap<>(); final Map<Long, BesuControllerBuilder> besuControllerBuilderSchedule = new TreeMap<>();
besuControllerBuilderSchedule.put(0L, besuControllerBuilder1); besuControllerBuilderSchedule.put(0L, besuControllerBuilder1);
@ -184,15 +184,14 @@ public class ConsensusScheduleBesuControllerBuilderTest {
new ConsensusScheduleBesuControllerBuilder(besuControllerBuilderSchedule); new ConsensusScheduleBesuControllerBuilder(besuControllerBuilderSchedule);
final ConsensusContext consensusContext = final ConsensusContext consensusContext =
controllerBuilder.createConsensusContext( controllerBuilder.createConsensusContext(
Mockito.mock(Blockchain.class), mock(Blockchain.class), mock(WorldStateArchive.class), mock(ProtocolSchedule.class));
Mockito.mock(WorldStateArchive.class),
Mockito.mock(ProtocolSchedule.class));
assertThat(consensusContext).isInstanceOf(MigratingContext.class); assertThat(consensusContext).isInstanceOf(MigratingConsensusContext.class);
final MigratingContext migratingContext = (MigratingContext) consensusContext; final MigratingConsensusContext migratingConsensusContext =
(MigratingConsensusContext) consensusContext;
final ForksSchedule<ConsensusContext> contextSchedule = final ForksSchedule<ConsensusContext> contextSchedule =
migratingContext.getConsensusContextSchedule(); migratingConsensusContext.getConsensusContextSchedule();
final NavigableSet<ForkSpec<ConsensusContext>> expectedConsensusContextSpecs = final NavigableSet<ForkSpec<ConsensusContext>> expectedConsensusContextSpecs =
new TreeSet<>(ForkSpec.COMPARATOR); new TreeSet<>(ForkSpec.COMPARATOR);

@ -52,6 +52,7 @@ import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture;
import org.hyperledger.besu.ethereum.core.ImmutableMiningConfiguration; import org.hyperledger.besu.ethereum.core.ImmutableMiningConfiguration;
import org.hyperledger.besu.ethereum.core.ImmutableMiningConfiguration.MutableInitValues; import org.hyperledger.besu.ethereum.core.ImmutableMiningConfiguration.MutableInitValues;
import org.hyperledger.besu.ethereum.core.MiningConfiguration; import org.hyperledger.besu.ethereum.core.MiningConfiguration;
import org.hyperledger.besu.ethereum.core.PrivacyParameters;
import org.hyperledger.besu.ethereum.core.Util; import org.hyperledger.besu.ethereum.core.Util;
import org.hyperledger.besu.ethereum.eth.manager.EthContext; import org.hyperledger.besu.ethereum.eth.manager.EthContext;
import org.hyperledger.besu.ethereum.eth.manager.EthScheduler; import org.hyperledger.besu.ethereum.eth.manager.EthScheduler;
@ -99,11 +100,20 @@ public class CliqueBlockCreatorTest {
@BeforeEach @BeforeEach
void setup() { void setup() {
final Address otherAddress = Util.publicKeyToAddress(otherKeyPair.getPublicKey());
validatorList.add(otherAddress);
validatorProvider = mock(ValidatorProvider.class);
voteProvider = mock(VoteProvider.class);
when(validatorProvider.getVoteProviderAtHead()).thenReturn(Optional.of(voteProvider));
when(validatorProvider.getValidatorsAfterBlock(any())).thenReturn(validatorList);
protocolSchedule = protocolSchedule =
CliqueProtocolSchedule.create( CliqueProtocolSchedule.create(
GenesisConfigFile.DEFAULT.getConfigOptions(), GenesisConfigFile.DEFAULT.getConfigOptions(),
new ForksSchedule<>(List.of()), new ForksSchedule<>(List.of()),
proposerNodeKey, proposerNodeKey,
PrivacyParameters.DEFAULT,
false, false,
EvmConfiguration.DEFAULT, EvmConfiguration.DEFAULT,
MiningConfiguration.MINING_DISABLED, MiningConfiguration.MINING_DISABLED,
@ -111,13 +121,6 @@ public class CliqueBlockCreatorTest {
false, false,
new NoOpMetricsSystem()); new NoOpMetricsSystem());
final Address otherAddress = Util.publicKeyToAddress(otherKeyPair.getPublicKey());
validatorList.add(otherAddress);
validatorProvider = mock(ValidatorProvider.class);
voteProvider = mock(VoteProvider.class);
when(validatorProvider.getVoteProviderAtHead()).thenReturn(Optional.of(voteProvider));
when(validatorProvider.getValidatorsAfterBlock(any())).thenReturn(validatorList);
final CliqueContext cliqueContext = new CliqueContext(validatorProvider, null, blockInterface); final CliqueContext cliqueContext = new CliqueContext(validatorProvider, null, blockInterface);
final Block genesis = final Block genesis =

@ -42,6 +42,7 @@ import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture;
import org.hyperledger.besu.ethereum.core.ImmutableMiningConfiguration; import org.hyperledger.besu.ethereum.core.ImmutableMiningConfiguration;
import org.hyperledger.besu.ethereum.core.ImmutableMiningConfiguration.MutableInitValues; import org.hyperledger.besu.ethereum.core.ImmutableMiningConfiguration.MutableInitValues;
import org.hyperledger.besu.ethereum.core.MiningConfiguration; import org.hyperledger.besu.ethereum.core.MiningConfiguration;
import org.hyperledger.besu.ethereum.core.PrivacyParameters;
import org.hyperledger.besu.ethereum.core.Util; import org.hyperledger.besu.ethereum.core.Util;
import org.hyperledger.besu.ethereum.eth.manager.EthContext; import org.hyperledger.besu.ethereum.eth.manager.EthContext;
import org.hyperledger.besu.ethereum.eth.manager.EthScheduler; import org.hyperledger.besu.ethereum.eth.manager.EthScheduler;
@ -103,6 +104,7 @@ public class CliqueMinerExecutorTest {
GENESIS_CONFIG_OPTIONS, GENESIS_CONFIG_OPTIONS,
new ForksSchedule<>(List.of()), new ForksSchedule<>(List.of()),
proposerNodeKey, proposerNodeKey,
PrivacyParameters.DEFAULT,
false, false,
EvmConfiguration.DEFAULT, EvmConfiguration.DEFAULT,
MiningConfiguration.MINING_DISABLED, MiningConfiguration.MINING_DISABLED,

@ -17,7 +17,7 @@ package org.hyperledger.besu.consensus.common;
import org.hyperledger.besu.ethereum.ConsensusContext; import org.hyperledger.besu.ethereum.ConsensusContext;
/** The Migrating context. */ /** The Migrating context. */
public class MigratingContext implements ConsensusContext { public class MigratingConsensusContext implements ConsensusContext {
private final ForksSchedule<ConsensusContext> consensusContextSchedule; private final ForksSchedule<ConsensusContext> consensusContextSchedule;
@ -26,7 +26,7 @@ public class MigratingContext implements ConsensusContext {
* *
* @param consensusContextSchedule the consensus context schedule * @param consensusContextSchedule the consensus context schedule
*/ */
public MigratingContext(final ForksSchedule<ConsensusContext> consensusContextSchedule) { public MigratingConsensusContext(final ForksSchedule<ConsensusContext> consensusContextSchedule) {
this.consensusContextSchedule = consensusContextSchedule; this.consensusContextSchedule = consensusContextSchedule;
} }

@ -15,11 +15,9 @@
package org.hyperledger.besu.consensus.common; package org.hyperledger.besu.consensus.common;
import org.hyperledger.besu.ethereum.ConsensusContext; import org.hyperledger.besu.ethereum.ConsensusContext;
import org.hyperledger.besu.ethereum.ConsensusContextFactory;
import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.ProtocolContext;
import org.hyperledger.besu.ethereum.chain.BadBlockManager; import org.hyperledger.besu.ethereum.chain.BadBlockManager;
import org.hyperledger.besu.ethereum.chain.MutableBlockchain; import org.hyperledger.besu.ethereum.chain.MutableBlockchain;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive;
/** The Migrating protocol context. */ /** The Migrating protocol context. */
@ -32,42 +30,16 @@ public class MigratingProtocolContext extends ProtocolContext {
* *
* @param blockchain the blockchain * @param blockchain the blockchain
* @param worldStateArchive the world state archive * @param worldStateArchive the world state archive
* @param consensusContextSchedule the consensus context schedule * @param migratingConsensusContext the consensus context
* @param badBlockManager the cache to use to keep invalid blocks * @param badBlockManager the cache to use to keep invalid blocks
*/ */
public MigratingProtocolContext( public MigratingProtocolContext(
final MutableBlockchain blockchain, final MutableBlockchain blockchain,
final WorldStateArchive worldStateArchive, final WorldStateArchive worldStateArchive,
final ForksSchedule<ConsensusContext> consensusContextSchedule, final MigratingConsensusContext migratingConsensusContext,
final BadBlockManager badBlockManager) { final BadBlockManager badBlockManager) {
super(blockchain, worldStateArchive, null, badBlockManager); super(blockchain, worldStateArchive, migratingConsensusContext, badBlockManager);
this.consensusContextSchedule = consensusContextSchedule; this.consensusContextSchedule = migratingConsensusContext.getConsensusContextSchedule();
}
/**
* Init protocol context.
*
* @param blockchain the blockchain
* @param worldStateArchive the world state archive
* @param protocolSchedule the protocol schedule
* @param consensusContextFactory the consensus context factory
* @param badBlockManager the cache to use to keep invalid blocks
* @return the protocol context
*/
public static ProtocolContext init(
final MutableBlockchain blockchain,
final WorldStateArchive worldStateArchive,
final ProtocolSchedule protocolSchedule,
final ConsensusContextFactory consensusContextFactory,
final BadBlockManager badBlockManager) {
final ConsensusContext consensusContext =
consensusContextFactory.create(blockchain, worldStateArchive, protocolSchedule);
final MigratingContext migratingContext = consensusContext.as(MigratingContext.class);
return new MigratingProtocolContext(
blockchain,
worldStateArchive,
migratingContext.getConsensusContextSchedule(),
badBlockManager);
} }
@Override @Override

@ -43,9 +43,13 @@ public class MigratingProtocolContextTest {
final ForksSchedule<ConsensusContext> contextSchedule = final ForksSchedule<ConsensusContext> contextSchedule =
new ForksSchedule<>(List.of(new ForkSpec<>(0L, context1), new ForkSpec<>(10L, context2))); new ForksSchedule<>(List.of(new ForkSpec<>(0L, context1), new ForkSpec<>(10L, context2)));
final MigratingProtocolContext migratingProtocolContext = final MigratingProtocolContext migratingProtocolContext =
new MigratingProtocolContext( new MigratingProtocolContext(
blockchain, worldStateArchive, contextSchedule, new BadBlockManager()); blockchain,
worldStateArchive,
new MigratingConsensusContext(contextSchedule),
new BadBlockManager());
assertThat(migratingProtocolContext.getConsensusContext(ConsensusContext.class)) assertThat(migratingProtocolContext.getConsensusContext(ConsensusContext.class))
.isSameAs(context1); .isSameAs(context1);

@ -12,7 +12,7 @@ state storage when upgrading to v1.4. It is not possible to upgrade to v1.4 with
## Private transactions created using v1.3.4 or earlier ## Private transactions created using v1.3.4 or earlier
A critical issue for privacy users with private transactions created using Hyperledger Besu v1.3.4 A critical issue for privacy users with private transactions created using Hyperledger Besu v1.3.4
or earlier has been identified. If you have a network with private transaction created using v1.3.4 or earlier has been identified. If you have a network with private transactions created using v1.3.4
or earlier, please read the following and take the appropriate steps: or earlier, please read the following and take the appropriate steps:
https://wiki.hyperledger.org/display/BESU/Critical+Issue+for+Privacy+Users https://wiki.hyperledger.org/display/BESU/Critical+Issue+for+Privacy+Users

@ -19,6 +19,7 @@ import static org.hyperledger.besu.ethereum.core.InMemoryKeyValueStorageProvider
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import org.hyperledger.besu.config.StubGenesisConfigOptions; import org.hyperledger.besu.config.StubGenesisConfigOptions;
import org.hyperledger.besu.ethereum.ConsensusContext;
import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.ProtocolContext;
import org.hyperledger.besu.ethereum.api.ImmutableApiConfiguration; import org.hyperledger.besu.ethereum.api.ImmutableApiConfiguration;
import org.hyperledger.besu.ethereum.api.graphql.GraphQLConfiguration; import org.hyperledger.besu.ethereum.api.graphql.GraphQLConfiguration;
@ -82,7 +83,9 @@ public class JsonRpcTestMethodsFactory {
this.blockchain = createInMemoryBlockchain(importer.getGenesisBlock()); this.blockchain = createInMemoryBlockchain(importer.getGenesisBlock());
this.stateArchive = createInMemoryWorldStateArchive(); this.stateArchive = createInMemoryWorldStateArchive();
this.importer.getGenesisState().writeStateTo(stateArchive.getMutable()); this.importer.getGenesisState().writeStateTo(stateArchive.getMutable());
this.context = new ProtocolContext(blockchain, stateArchive, null, new BadBlockManager()); this.context =
new ProtocolContext(
blockchain, stateArchive, mock(ConsensusContext.class), new BadBlockManager());
this.protocolSchedule = importer.getProtocolSchedule(); this.protocolSchedule = importer.getProtocolSchedule();
this.synchronizer = mock(Synchronizer.class); this.synchronizer = mock(Synchronizer.class);

@ -20,6 +20,7 @@ import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.ethereum.ConsensusContext;
import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.ProtocolContext;
import org.hyperledger.besu.ethereum.api.jsonrpc.BlockchainImporter; import org.hyperledger.besu.ethereum.api.jsonrpc.BlockchainImporter;
import org.hyperledger.besu.ethereum.api.jsonrpc.JsonRpcTestMethodsFactory; import org.hyperledger.besu.ethereum.api.jsonrpc.JsonRpcTestMethodsFactory;
@ -67,7 +68,8 @@ public class EthGetBlockByNumberLatestDesyncIntegrationTest {
InMemoryKeyValueStorageProvider.createInMemoryBlockchain(importer.getGenesisBlock()); InMemoryKeyValueStorageProvider.createInMemoryBlockchain(importer.getGenesisBlock());
WorldStateArchive state = InMemoryKeyValueStorageProvider.createInMemoryWorldStateArchive(); WorldStateArchive state = InMemoryKeyValueStorageProvider.createInMemoryWorldStateArchive();
importer.getGenesisState().writeStateTo(state.getMutable()); importer.getGenesisState().writeStateTo(state.getMutable());
ProtocolContext context = new ProtocolContext(chain, state, null, new BadBlockManager()); ProtocolContext context =
new ProtocolContext(chain, state, mock(ConsensusContext.class), new BadBlockManager());
for (final Block block : importer.getBlocks()) { for (final Block block : importer.getBlocks()) {
final ProtocolSchedule protocolSchedule = importer.getProtocolSchedule(); final ProtocolSchedule protocolSchedule = importer.getProtocolSchedule();

@ -23,6 +23,7 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.JsonRpcErrorConverter;
import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.exception.InvalidJsonRpcParameters; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.exception.InvalidJsonRpcParameters;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.exception.InvalidJsonRpcRequestException;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.BlockParameterOrBlockHash; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.BlockParameterOrBlockHash;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonCallParameter; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonCallParameter;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter.JsonRpcParameterException; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter.JsonRpcParameterException;
@ -40,8 +41,13 @@ import org.hyperledger.besu.ethereum.processing.TransactionProcessingResult;
import org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason; import org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason;
import org.hyperledger.besu.ethereum.transaction.TransactionSimulator; import org.hyperledger.besu.ethereum.transaction.TransactionSimulator;
import org.hyperledger.besu.ethereum.transaction.TransactionSimulatorResult; import org.hyperledger.besu.ethereum.transaction.TransactionSimulatorResult;
import org.hyperledger.besu.ethereum.util.AccountOverrideMap;
import org.hyperledger.besu.evm.tracing.OperationTracer; import org.hyperledger.besu.evm.tracing.OperationTracer;
import java.util.Optional;
import com.google.common.annotations.VisibleForTesting;
public class EthCall extends AbstractBlockParameterOrBlockHashMethod { public class EthCall extends AbstractBlockParameterOrBlockHashMethod {
private final TransactionSimulator transactionSimulator; private final TransactionSimulator transactionSimulator;
@ -81,10 +87,13 @@ public class EthCall extends AbstractBlockParameterOrBlockHashMethod {
protected Object resultByBlockHeader( protected Object resultByBlockHeader(
final JsonRpcRequestContext request, final BlockHeader header) { final JsonRpcRequestContext request, final BlockHeader header) {
JsonCallParameter callParams = JsonCallParameterUtil.validateAndGetCallParams(request); JsonCallParameter callParams = JsonCallParameterUtil.validateAndGetCallParams(request);
Optional<AccountOverrideMap> maybeStateOverrides = getAddressAccountOverrideMap(request);
// TODO implement for block overrides
return transactionSimulator return transactionSimulator
.process( .process(
callParams, callParams,
maybeStateOverrides,
buildTransactionValidationParams(header, callParams), buildTransactionValidationParams(header, callParams),
OperationTracer.NO_TRACING, OperationTracer.NO_TRACING,
(mutableWorldState, transactionSimulatorResult) -> (mutableWorldState, transactionSimulatorResult) ->
@ -108,6 +117,17 @@ public class EthCall extends AbstractBlockParameterOrBlockHashMethod {
.orElse(errorResponse(request, INTERNAL_ERROR)); .orElse(errorResponse(request, INTERNAL_ERROR));
} }
@VisibleForTesting
protected Optional<AccountOverrideMap> getAddressAccountOverrideMap(
final JsonRpcRequestContext request) {
try {
return request.getOptionalParameter(2, AccountOverrideMap.class);
} catch (JsonRpcParameterException e) {
throw new InvalidJsonRpcRequestException(
"Invalid account overrides parameter (index 2)", RpcErrorType.INVALID_CALL_PARAMS, e);
}
}
@Override @Override
public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { public JsonRpcResponse response(final JsonRpcRequestContext requestContext) {
return (JsonRpcResponse) handleParamTypes(requestContext); return (JsonRpcResponse) handleParamTypes(requestContext);

@ -25,7 +25,6 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcPara
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.processor.Tracer; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.processor.Tracer;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.processor.TransactionTrace; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.processor.TransactionTrace;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.tracing.flat.FlatTraceGenerator;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.tracing.flat.RewardTraceGenerator; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.tracing.flat.RewardTraceGenerator;
import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.api.query.BlockchainQueries;
import org.hyperledger.besu.ethereum.api.util.ArrayNodeWrapper; import org.hyperledger.besu.ethereum.api.util.ArrayNodeWrapper;
@ -41,12 +40,11 @@ import org.hyperledger.besu.ethereum.vm.DebugOperationTracer;
import org.hyperledger.besu.evm.worldstate.WorldUpdater; import org.hyperledger.besu.evm.worldstate.WorldUpdater;
import org.hyperledger.besu.metrics.BesuMetricCategory; import org.hyperledger.besu.metrics.BesuMetricCategory;
import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem;
import org.hyperledger.besu.metrics.prometheus.PrometheusMetricsSystem; import org.hyperledger.besu.plugin.services.MetricsSystem;
import org.hyperledger.besu.plugin.services.metrics.Counter; import org.hyperledger.besu.plugin.services.metrics.Counter;
import org.hyperledger.besu.plugin.services.metrics.LabelledMetric; import org.hyperledger.besu.plugin.services.metrics.LabelledMetric;
import org.hyperledger.besu.services.pipeline.Pipeline; import org.hyperledger.besu.services.pipeline.Pipeline;
import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
@ -58,10 +56,21 @@ public class TraceBlock extends AbstractBlockParameterMethod {
private static final Logger LOG = LoggerFactory.getLogger(TraceBlock.class); private static final Logger LOG = LoggerFactory.getLogger(TraceBlock.class);
private static final ObjectMapper MAPPER = new ObjectMapper(); private static final ObjectMapper MAPPER = new ObjectMapper();
protected final ProtocolSchedule protocolSchedule; protected final ProtocolSchedule protocolSchedule;
private final LabelledMetric<Counter> outputCounter;
public TraceBlock(final ProtocolSchedule protocolSchedule, final BlockchainQueries queries) { public TraceBlock(
final ProtocolSchedule protocolSchedule,
final BlockchainQueries queries,
final MetricsSystem metricsSystem) {
super(queries); super(queries);
this.protocolSchedule = protocolSchedule; this.protocolSchedule = protocolSchedule;
this.outputCounter =
metricsSystem.createLabelledCounter(
BesuMetricCategory.BLOCKCHAIN,
"transactions_traceblock_pipeline_processed_total",
"Number of transactions processed for each block",
"step",
"action");
} }
@Override @Override
@ -115,14 +124,6 @@ public class TraceBlock extends AbstractBlockParameterMethod {
final ChainUpdater chainUpdater = new ChainUpdater(traceableState); final ChainUpdater chainUpdater = new ChainUpdater(traceableState);
TransactionSource transactionSource = new TransactionSource(block); TransactionSource transactionSource = new TransactionSource(block);
final LabelledMetric<Counter> outputCounter =
new PrometheusMetricsSystem(BesuMetricCategory.DEFAULT_METRIC_CATEGORIES, false)
.createLabelledCounter(
BesuMetricCategory.BLOCKCHAIN,
"transactions_traceblock_pipeline_processed_total",
"Number of transactions processed for each block",
"step",
"action");
DebugOperationTracer debugOperationTracer = DebugOperationTracer debugOperationTracer =
new DebugOperationTracer(new TraceOptions(false, false, true), false); new DebugOperationTracer(new TraceOptions(false, false, true), false);
ExecuteTransactionStep executeTransactionStep = ExecuteTransactionStep executeTransactionStep =
@ -173,18 +174,6 @@ public class TraceBlock extends AbstractBlockParameterMethod {
.orElse(emptyResult()); .orElse(emptyResult());
} }
protected void generateTracesFromTransactionTraceAndBlock(
final Optional<FilterParameter> filterParameter,
final List<TransactionTrace> transactionTraces,
final Block block,
final ArrayNodeWrapper resultArrayNode) {
transactionTraces.forEach(
transactionTrace ->
FlatTraceGenerator.generateFromTransactionTraceAndBlock(
protocolSchedule, transactionTrace, block)
.forEachOrdered(resultArrayNode::addPOJO));
}
protected void generateRewardsFromBlock( protected void generateRewardsFromBlock(
final Optional<FilterParameter> maybeFilterParameter, final Optional<FilterParameter> maybeFilterParameter,
final Block block, final Block block,

@ -160,7 +160,12 @@ public class TraceCallMany extends TraceCall implements JsonRpcMethod {
new DebugOperationTracer(buildTraceOptions(traceTypes), false); new DebugOperationTracer(buildTraceOptions(traceTypes), false);
final Optional<TransactionSimulatorResult> maybeSimulatorResult = final Optional<TransactionSimulatorResult> maybeSimulatorResult =
transactionSimulator.processWithWorldUpdater( transactionSimulator.processWithWorldUpdater(
callParameter, buildTransactionValidationParams(), tracer, header, worldUpdater); callParameter,
Optional.empty(),
buildTransactionValidationParams(),
tracer,
header,
worldUpdater);
LOG.trace("Executing {} call for transaction {}", traceTypeParameter, callParameter); LOG.trace("Executing {} call for transaction {}", traceTypeParameter, callParameter);
if (maybeSimulatorResult.isEmpty()) { if (maybeSimulatorResult.isEmpty()) {

@ -23,7 +23,6 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.exception.InvalidJsonR
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.BlockParameter; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.BlockParameter;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.FilterParameter; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.FilterParameter;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter.JsonRpcParameterException; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter.JsonRpcParameterException;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.processor.BlockTracer;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.processor.Tracer; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.processor.Tracer;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.processor.TransactionTrace; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.processor.TransactionTrace;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse;
@ -45,7 +44,7 @@ import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec;
import org.hyperledger.besu.ethereum.vm.DebugOperationTracer; import org.hyperledger.besu.ethereum.vm.DebugOperationTracer;
import org.hyperledger.besu.metrics.BesuMetricCategory; import org.hyperledger.besu.metrics.BesuMetricCategory;
import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem;
import org.hyperledger.besu.metrics.prometheus.PrometheusMetricsSystem; import org.hyperledger.besu.plugin.services.MetricsSystem;
import org.hyperledger.besu.plugin.services.metrics.Counter; import org.hyperledger.besu.plugin.services.metrics.Counter;
import org.hyperledger.besu.plugin.services.metrics.LabelledMetric; import org.hyperledger.besu.plugin.services.metrics.LabelledMetric;
import org.hyperledger.besu.services.pipeline.Pipeline; import org.hyperledger.besu.services.pipeline.Pipeline;
@ -58,7 +57,6 @@ import java.util.Optional;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.function.Function; import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Stream; import java.util.stream.Stream;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
@ -68,17 +66,24 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
public class TraceFilter extends TraceBlock { public class TraceFilter extends TraceBlock {
private static final Logger LOG = LoggerFactory.getLogger(TraceFilter.class); private static final Logger LOG = LoggerFactory.getLogger(TraceFilter.class);
private final Long maxRange; private final Long maxRange;
private final LabelledMetric<Counter> outputCounter;
public TraceFilter( public TraceFilter(
final Supplier<BlockTracer> blockTracerSupplier,
final ProtocolSchedule protocolSchedule, final ProtocolSchedule protocolSchedule,
final BlockchainQueries blockchainQueries, final BlockchainQueries blockchainQueries,
final Long maxRange) { final Long maxRange,
super(protocolSchedule, blockchainQueries); final MetricsSystem metricsSystem) {
super(protocolSchedule, blockchainQueries, metricsSystem);
this.maxRange = maxRange; this.maxRange = maxRange;
this.outputCounter =
metricsSystem.createLabelledCounter(
BesuMetricCategory.BLOCKCHAIN,
"transactions_tracefilter_pipeline_processed_total",
"Number of transactions processed for trace_filter",
"step",
"action");
} }
@Override @Override
@ -157,15 +162,6 @@ public class TraceFilter extends TraceBlock {
final MainnetTransactionProcessor transactionProcessor = final MainnetTransactionProcessor transactionProcessor =
protocolSpec.getTransactionProcessor(); protocolSpec.getTransactionProcessor();
final ChainUpdater chainUpdater = new ChainUpdater(traceableState); final ChainUpdater chainUpdater = new ChainUpdater(traceableState);
final LabelledMetric<Counter> outputCounter =
new PrometheusMetricsSystem(
BesuMetricCategory.DEFAULT_METRIC_CATEGORIES, false)
.createLabelledCounter(
BesuMetricCategory.BLOCKCHAIN,
"transactions_tracefilter_pipeline_processed_total",
"Number of transactions processed for trace_filter",
"step",
"action");
DebugOperationTracer debugOperationTracer = DebugOperationTracer debugOperationTracer =
new DebugOperationTracer(new TraceOptions(false, false, true), false); new DebugOperationTracer(new TraceOptions(false, false, true), false);

@ -39,7 +39,7 @@ import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec;
import org.hyperledger.besu.ethereum.vm.DebugOperationTracer; import org.hyperledger.besu.ethereum.vm.DebugOperationTracer;
import org.hyperledger.besu.metrics.BesuMetricCategory; import org.hyperledger.besu.metrics.BesuMetricCategory;
import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem;
import org.hyperledger.besu.metrics.prometheus.PrometheusMetricsSystem; import org.hyperledger.besu.plugin.services.MetricsSystem;
import org.hyperledger.besu.plugin.services.metrics.Counter; import org.hyperledger.besu.plugin.services.metrics.Counter;
import org.hyperledger.besu.plugin.services.metrics.LabelledMetric; import org.hyperledger.besu.plugin.services.metrics.LabelledMetric;
import org.hyperledger.besu.services.pipeline.Pipeline; import org.hyperledger.besu.services.pipeline.Pipeline;
@ -57,13 +57,23 @@ import org.slf4j.LoggerFactory;
public class TraceReplayBlockTransactions extends AbstractBlockParameterMethod { public class TraceReplayBlockTransactions extends AbstractBlockParameterMethod {
private static final Logger LOG = LoggerFactory.getLogger(TraceReplayBlockTransactions.class); private static final Logger LOG = LoggerFactory.getLogger(TraceReplayBlockTransactions.class);
private final ProtocolSchedule protocolSchedule;
private static final ObjectMapper MAPPER = new ObjectMapper(); private static final ObjectMapper MAPPER = new ObjectMapper();
private final ProtocolSchedule protocolSchedule;
private final LabelledMetric<Counter> outputCounter;
public TraceReplayBlockTransactions( public TraceReplayBlockTransactions(
final ProtocolSchedule protocolSchedule, final BlockchainQueries queries) { final ProtocolSchedule protocolSchedule,
final BlockchainQueries queries,
final MetricsSystem metricsSystem) {
super(queries); super(queries);
this.protocolSchedule = protocolSchedule; this.protocolSchedule = protocolSchedule;
this.outputCounter =
metricsSystem.createLabelledCounter(
BesuMetricCategory.BLOCKCHAIN,
"transactions_tracereplayblock_pipeline_processed_total",
"Number of transactions processed for each block",
"step",
"action");
} }
@Override @Override
@ -131,14 +141,7 @@ public class TraceReplayBlockTransactions extends AbstractBlockParameterMethod {
final ChainUpdater chainUpdater = new ChainUpdater(traceableState); final ChainUpdater chainUpdater = new ChainUpdater(traceableState);
final TransactionSource transactionSource = new TransactionSource(block); final TransactionSource transactionSource = new TransactionSource(block);
final LabelledMetric<Counter> outputCounter =
new PrometheusMetricsSystem(BesuMetricCategory.DEFAULT_METRIC_CATEGORIES, false)
.createLabelledCounter(
BesuMetricCategory.BLOCKCHAIN,
"transactions_tracereplayblock_pipeline_processed_total",
"Number of transactions processed for each block",
"step",
"action");
final DebugOperationTracer debugOperationTracer = final DebugOperationTracer debugOperationTracer =
new DebugOperationTracer(new TraceOptions(false, false, true), false); new DebugOperationTracer(new TraceOptions(false, false, true), false);
final ExecuteTransactionStep executeTransactionStep = final ExecuteTransactionStep executeTransactionStep =

@ -151,7 +151,11 @@ public class JsonRpcMethodsFactory {
blockchainQueries, protocolSchedule, transactionPool, privacyParameters), blockchainQueries, protocolSchedule, transactionPool, privacyParameters),
new Web3JsonRpcMethods(clientNodeName), new Web3JsonRpcMethods(clientNodeName),
new TraceJsonRpcMethods( new TraceJsonRpcMethods(
blockchainQueries, protocolSchedule, protocolContext, apiConfiguration), blockchainQueries,
protocolSchedule,
protocolContext,
apiConfiguration,
metricsSystem),
new TxPoolJsonRpcMethods(transactionPool), new TxPoolJsonRpcMethods(transactionPool),
new PluginsJsonRpcMethods(namedPlugins)); new PluginsJsonRpcMethods(namedPlugins));

@ -31,6 +31,7 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.processor.BlockTracer;
import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.api.query.BlockchainQueries;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.ethereum.transaction.TransactionSimulator; import org.hyperledger.besu.ethereum.transaction.TransactionSimulator;
import org.hyperledger.besu.plugin.services.MetricsSystem;
import java.util.Map; import java.util.Map;
@ -38,19 +39,21 @@ public class TraceJsonRpcMethods extends ApiGroupJsonRpcMethods {
private final BlockchainQueries blockchainQueries; private final BlockchainQueries blockchainQueries;
private final ProtocolSchedule protocolSchedule; private final ProtocolSchedule protocolSchedule;
private final ApiConfiguration apiConfiguration; private final ApiConfiguration apiConfiguration;
private final ProtocolContext protocolContext; private final ProtocolContext protocolContext;
private final MetricsSystem metricsSystem;
TraceJsonRpcMethods( TraceJsonRpcMethods(
final BlockchainQueries blockchainQueries, final BlockchainQueries blockchainQueries,
final ProtocolSchedule protocolSchedule, final ProtocolSchedule protocolSchedule,
final ProtocolContext protocolContext, final ProtocolContext protocolContext,
final ApiConfiguration apiConfiguration) { final ApiConfiguration apiConfiguration,
final MetricsSystem metricsSystem) {
this.blockchainQueries = blockchainQueries; this.blockchainQueries = blockchainQueries;
this.protocolSchedule = protocolSchedule; this.protocolSchedule = protocolSchedule;
this.protocolContext = protocolContext; this.protocolContext = protocolContext;
this.apiConfiguration = apiConfiguration; this.apiConfiguration = apiConfiguration;
this.metricsSystem = metricsSystem;
} }
@Override @Override
@ -63,16 +66,16 @@ public class TraceJsonRpcMethods extends ApiGroupJsonRpcMethods {
final BlockReplay blockReplay = final BlockReplay blockReplay =
new BlockReplay(protocolSchedule, protocolContext, blockchainQueries.getBlockchain()); new BlockReplay(protocolSchedule, protocolContext, blockchainQueries.getBlockchain());
return mapOf( return mapOf(
new TraceReplayBlockTransactions(protocolSchedule, blockchainQueries), new TraceReplayBlockTransactions(protocolSchedule, blockchainQueries, metricsSystem),
new TraceFilter( new TraceFilter(
() -> new BlockTracer(blockReplay),
protocolSchedule, protocolSchedule,
blockchainQueries, blockchainQueries,
apiConfiguration.getMaxTraceFilterRange()), apiConfiguration.getMaxTraceFilterRange(),
metricsSystem),
new TraceGet(() -> new BlockTracer(blockReplay), blockchainQueries, protocolSchedule), new TraceGet(() -> new BlockTracer(blockReplay), blockchainQueries, protocolSchedule),
new TraceTransaction( new TraceTransaction(
() -> new BlockTracer(blockReplay), protocolSchedule, blockchainQueries), () -> new BlockTracer(blockReplay), protocolSchedule, blockchainQueries),
new TraceBlock(protocolSchedule, blockchainQueries), new TraceBlock(protocolSchedule, blockchainQueries, metricsSystem),
new TraceCall( new TraceCall(
blockchainQueries, blockchainQueries,
protocolSchedule, protocolSchedule,

@ -19,6 +19,7 @@ import static org.mockito.Mockito.when;
import org.hyperledger.besu.datatypes.TransactionType; import org.hyperledger.besu.datatypes.TransactionType;
import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.ConsensusContext;
import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.ProtocolContext;
import org.hyperledger.besu.ethereum.api.ImmutableApiConfiguration; import org.hyperledger.besu.ethereum.api.ImmutableApiConfiguration;
import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.api.query.BlockchainQueries;
@ -110,7 +111,10 @@ public abstract class AbstractEthGraphQLHttpServiceTest {
final MutableBlockchain blockchain = blockchainSetupUtil.getBlockchain(); final MutableBlockchain blockchain = blockchainSetupUtil.getBlockchain();
ProtocolContext context = ProtocolContext context =
new ProtocolContext( new ProtocolContext(
blockchain, blockchainSetupUtil.getWorldArchive(), null, new BadBlockManager()); blockchain,
blockchainSetupUtil.getWorldArchive(),
mock(ConsensusContext.class),
new BadBlockManager());
final BlockchainQueries blockchainQueries = final BlockchainQueries blockchainQueries =
new BlockchainQueries( new BlockchainQueries(
blockchainSetupUtil.getProtocolSchedule(), blockchainSetupUtil.getProtocolSchedule(),

@ -51,6 +51,8 @@ import org.hyperledger.besu.ethereum.transaction.CallParameter;
import org.hyperledger.besu.ethereum.transaction.PreCloseStateHandler; import org.hyperledger.besu.ethereum.transaction.PreCloseStateHandler;
import org.hyperledger.besu.ethereum.transaction.TransactionSimulator; import org.hyperledger.besu.ethereum.transaction.TransactionSimulator;
import org.hyperledger.besu.ethereum.transaction.TransactionSimulatorResult; import org.hyperledger.besu.ethereum.transaction.TransactionSimulatorResult;
import org.hyperledger.besu.ethereum.util.AccountOverride;
import org.hyperledger.besu.ethereum.util.AccountOverrideMap;
import java.util.Optional; import java.util.Optional;
@ -92,6 +94,33 @@ public class EthCallTest {
assertThat(method.getName()).isEqualTo("eth_call"); assertThat(method.getName()).isEqualTo("eth_call");
} }
@Test
public void noAccountOverrides() {
final JsonRpcRequestContext request = ethCallRequest(callParameter(), "latest");
Optional<AccountOverrideMap> overrideMap = method.getAddressAccountOverrideMap(request);
assertThat(overrideMap.isPresent()).isFalse();
}
@Test
public void someAccountOverrides() {
AccountOverrideMap expectedOverrides = new AccountOverrideMap();
AccountOverride override = new AccountOverride.Builder().withNonce(88L).build();
final Address address = Address.fromHexString("0xd9c9cd5f6779558b6e0ed4e6acf6b1947e7fa1f3");
expectedOverrides.put(address, override);
final JsonRpcRequestContext request =
ethCallRequestWithStateOverrides(callParameter(), "latest", expectedOverrides);
Optional<AccountOverrideMap> maybeOverrideMap = method.getAddressAccountOverrideMap(request);
assertThat(maybeOverrideMap.isPresent()).isTrue();
AccountOverrideMap overrideMap = maybeOverrideMap.get();
assertThat(overrideMap.keySet()).hasSize(1);
assertThat(overrideMap.values()).hasSize(1);
assertThat(overrideMap).containsKey(address);
assertThat(overrideMap).containsValue(override);
}
@Test @Test
public void shouldReturnInternalErrorWhenProcessorReturnsEmpty() { public void shouldReturnInternalErrorWhenProcessorReturnsEmpty() {
final JsonRpcRequestContext request = ethCallRequest(callParameter(), "latest"); final JsonRpcRequestContext request = ethCallRequest(callParameter(), "latest");
@ -99,7 +128,7 @@ public class EthCallTest {
when(blockchainQueries.getBlockchain()).thenReturn(blockchain); when(blockchainQueries.getBlockchain()).thenReturn(blockchain);
when(blockchain.getChainHead()).thenReturn(chainHead); when(blockchain.getChainHead()).thenReturn(chainHead);
when(transactionSimulator.process(any(), any(), any(), any(), any())) when(transactionSimulator.process(any(), any(), any(), any(), any(), any()))
.thenReturn(Optional.empty()); .thenReturn(Optional.empty());
final BlockHeader blockHeader = mock(BlockHeader.class); final BlockHeader blockHeader = mock(BlockHeader.class);
@ -109,7 +138,7 @@ public class EthCallTest {
final JsonRpcResponse response = method.response(request); final JsonRpcResponse response = method.response(request);
assertThat(response).usingRecursiveComparison().isEqualTo(expectedResponse); assertThat(response).usingRecursiveComparison().isEqualTo(expectedResponse);
verify(transactionSimulator).process(any(), any(), any(), any(), any()); verify(transactionSimulator).process(any(), any(), any(), any(), any(), any());
} }
@Test @Test
@ -130,12 +159,13 @@ public class EthCallTest {
when(result.isSuccessful()).thenReturn(true); when(result.isSuccessful()).thenReturn(true);
when(result.getValidationResult()).thenReturn(ValidationResult.valid()); when(result.getValidationResult()).thenReturn(ValidationResult.valid());
when(result.getOutput()).thenReturn(Bytes.of()); when(result.getOutput()).thenReturn(Bytes.of());
verify(transactionSimulator).process(any(), any(), any(), mapperCaptor.capture(), any()); verify(transactionSimulator)
.process(
eq(callParameter), eq(Optional.empty()), any(), any(), mapperCaptor.capture(), any());
assertThat(mapperCaptor.getValue().apply(mock(MutableWorldState.class), Optional.of(result))) assertThat(mapperCaptor.getValue().apply(mock(MutableWorldState.class), Optional.of(result)))
.isEqualTo(Optional.of(expectedResponse)); .isEqualTo(Optional.of(expectedResponse));
assertThat(response).usingRecursiveComparison().isEqualTo(expectedResponse); assertThat(response).usingRecursiveComparison().isEqualTo(expectedResponse);
verify(transactionSimulator).process(eq(callParameter), any(), any(), any(), any());
} }
@Test @Test
@ -158,7 +188,8 @@ public class EthCallTest {
when(result.getValidationResult()).thenReturn(ValidationResult.valid()); when(result.getValidationResult()).thenReturn(ValidationResult.valid());
when(result.getOutput()).thenReturn(Bytes.of(1)); when(result.getOutput()).thenReturn(Bytes.of(1));
verify(transactionSimulator) verify(transactionSimulator)
.process(eq(callParameter()), any(), any(), mapperCaptor.capture(), any()); .process(
eq(callParameter()), eq(Optional.empty()), any(), any(), mapperCaptor.capture(), any());
assertThat(mapperCaptor.getValue().apply(mock(MutableWorldState.class), Optional.of(result))) assertThat(mapperCaptor.getValue().apply(mock(MutableWorldState.class), Optional.of(result)))
.isEqualTo(Optional.of(expectedResponse)); .isEqualTo(Optional.of(expectedResponse));
@ -196,7 +227,8 @@ public class EthCallTest {
when(result.isSuccessful()).thenReturn(false); when(result.isSuccessful()).thenReturn(false);
when(result.getValidationResult()).thenReturn(ValidationResult.valid()); when(result.getValidationResult()).thenReturn(ValidationResult.valid());
when(result.result()).thenReturn(processingResult); when(result.result()).thenReturn(processingResult);
verify(transactionSimulator).process(any(), any(), any(), mapperCaptor.capture(), any()); verify(transactionSimulator)
.process(any(), eq(Optional.empty()), any(), any(), mapperCaptor.capture(), any());
assertThat(mapperCaptor.getValue().apply(mock(MutableWorldState.class), Optional.of(result))) assertThat(mapperCaptor.getValue().apply(mock(MutableWorldState.class), Optional.of(result)))
.isEqualTo(Optional.of(expectedResponse)); .isEqualTo(Optional.of(expectedResponse));
@ -235,7 +267,8 @@ public class EthCallTest {
when(result.isSuccessful()).thenReturn(false); when(result.isSuccessful()).thenReturn(false);
when(result.getValidationResult()).thenReturn(ValidationResult.valid()); when(result.getValidationResult()).thenReturn(ValidationResult.valid());
when(result.result()).thenReturn(processingResult); when(result.result()).thenReturn(processingResult);
verify(transactionSimulator).process(any(), any(), any(), mapperCaptor.capture(), any()); verify(transactionSimulator)
.process(any(), eq(Optional.empty()), any(), any(), mapperCaptor.capture(), any());
assertThat(mapperCaptor.getValue().apply(mock(MutableWorldState.class), Optional.of(result))) assertThat(mapperCaptor.getValue().apply(mock(MutableWorldState.class), Optional.of(result)))
.isEqualTo(Optional.of(expectedResponse)); .isEqualTo(Optional.of(expectedResponse));
@ -277,7 +310,8 @@ public class EthCallTest {
when(result.getValidationResult()).thenReturn(ValidationResult.valid()); when(result.getValidationResult()).thenReturn(ValidationResult.valid());
when(result.result()).thenReturn(processingResult); when(result.result()).thenReturn(processingResult);
verify(transactionSimulator).process(any(), any(), any(), mapperCaptor.capture(), any()); verify(transactionSimulator)
.process(any(), eq(Optional.empty()), any(), any(), mapperCaptor.capture(), any());
assertThat(mapperCaptor.getValue().apply(mock(MutableWorldState.class), Optional.of(result))) assertThat(mapperCaptor.getValue().apply(mock(MutableWorldState.class), Optional.of(result)))
.isEqualTo(Optional.of(expectedResponse)); .isEqualTo(Optional.of(expectedResponse));
@ -291,7 +325,7 @@ public class EthCallTest {
final JsonRpcRequestContext request = ethCallRequest(callParameter(), "latest"); final JsonRpcRequestContext request = ethCallRequest(callParameter(), "latest");
when(blockchainQueries.getBlockchain()).thenReturn(blockchain); when(blockchainQueries.getBlockchain()).thenReturn(blockchain);
when(blockchain.getChainHead()).thenReturn(chainHead); when(blockchain.getChainHead()).thenReturn(chainHead);
when(transactionSimulator.process(any(), any(), any(), any(), any())) when(transactionSimulator.process(any(), eq(Optional.empty()), any(), any(), any(), any()))
.thenReturn(Optional.empty()); .thenReturn(Optional.empty());
final BlockHeader blockHeader = mock(BlockHeader.class); final BlockHeader blockHeader = mock(BlockHeader.class);
@ -301,7 +335,7 @@ public class EthCallTest {
method.response(request); method.response(request);
verify(blockchainQueries, atLeastOnce()).getBlockchain(); verify(blockchainQueries, atLeastOnce()).getBlockchain();
verify(transactionSimulator).process(any(), any(), any(), any(), any()); verify(transactionSimulator).process(any(), eq(Optional.empty()), any(), any(), any(), any());
} }
@Test @Test
@ -315,7 +349,7 @@ public class EthCallTest {
method.response(request); method.response(request);
verify(blockchainQueries).getBlockHeaderByHash(eq(Hash.ZERO)); verify(blockchainQueries).getBlockHeaderByHash(eq(Hash.ZERO));
verify(transactionSimulator).process(any(), any(), any(), any(), any()); verify(transactionSimulator).process(any(), eq(Optional.empty()), any(), any(), any(), any());
} }
@Test @Test
@ -323,13 +357,13 @@ public class EthCallTest {
final JsonRpcRequestContext request = ethCallRequest(callParameter(), "safe"); final JsonRpcRequestContext request = ethCallRequest(callParameter(), "safe");
when(blockchainQueries.getBlockHeaderByHash(Hash.ZERO)).thenReturn(Optional.of(blockHeader)); when(blockchainQueries.getBlockHeaderByHash(Hash.ZERO)).thenReturn(Optional.of(blockHeader));
when(blockchainQueries.safeBlockHeader()).thenReturn(Optional.of(blockHeader)); when(blockchainQueries.safeBlockHeader()).thenReturn(Optional.of(blockHeader));
when(transactionSimulator.process(any(), any(), any(), any(), any())) when(transactionSimulator.process(any(), eq(Optional.empty()), any(), any(), any(), any()))
.thenReturn(Optional.empty()); .thenReturn(Optional.empty());
method.response(request); method.response(request);
verify(blockchainQueries).getBlockHeaderByHash(Hash.ZERO); verify(blockchainQueries).getBlockHeaderByHash(Hash.ZERO);
verify(blockchainQueries).safeBlockHeader(); verify(blockchainQueries).safeBlockHeader();
verify(transactionSimulator).process(any(), any(), any(), any(), any()); verify(transactionSimulator).process(any(), eq(Optional.empty()), any(), any(), any(), any());
} }
@Test @Test
@ -337,13 +371,13 @@ public class EthCallTest {
final JsonRpcRequestContext request = ethCallRequest(callParameter(), "finalized"); final JsonRpcRequestContext request = ethCallRequest(callParameter(), "finalized");
when(blockchainQueries.getBlockHeaderByHash(Hash.ZERO)).thenReturn(Optional.of(blockHeader)); when(blockchainQueries.getBlockHeaderByHash(Hash.ZERO)).thenReturn(Optional.of(blockHeader));
when(blockchainQueries.finalizedBlockHeader()).thenReturn(Optional.of(blockHeader)); when(blockchainQueries.finalizedBlockHeader()).thenReturn(Optional.of(blockHeader));
when(transactionSimulator.process(any(), any(), any(), any(), any())) when(transactionSimulator.process(any(), eq(Optional.empty()), any(), any(), any(), any()))
.thenReturn(Optional.empty()); .thenReturn(Optional.empty());
method.response(request); method.response(request);
verify(blockchainQueries).getBlockHeaderByHash(Hash.ZERO); verify(blockchainQueries).getBlockHeaderByHash(Hash.ZERO);
verify(blockchainQueries).finalizedBlockHeader(); verify(blockchainQueries).finalizedBlockHeader();
verify(transactionSimulator).process(any(), any(), any(), any(), any()); verify(transactionSimulator).process(any(), eq(Optional.empty()), any(), any(), any(), any());
} }
@Test @Test
@ -353,13 +387,13 @@ public class EthCallTest {
when(blockchainQueries.getBlockHashByNumber(anyLong())).thenReturn(Optional.of(Hash.ZERO)); when(blockchainQueries.getBlockHashByNumber(anyLong())).thenReturn(Optional.of(Hash.ZERO));
when(blockchainQueries.getBlockHeaderByHash(Hash.ZERO)) when(blockchainQueries.getBlockHeaderByHash(Hash.ZERO))
.thenReturn(Optional.of(mock(BlockHeader.class))); .thenReturn(Optional.of(mock(BlockHeader.class)));
when(transactionSimulator.process(any(), any(), any(), any(), any())) when(transactionSimulator.process(any(), eq(Optional.empty()), any(), any(), any(), any()))
.thenReturn(Optional.empty()); .thenReturn(Optional.empty());
method.response(request); method.response(request);
verify(blockchainQueries).getBlockHeaderByHash(eq(Hash.ZERO)); verify(blockchainQueries).getBlockHeaderByHash(eq(Hash.ZERO));
verify(transactionSimulator).process(any(), any(), any(), any(), any()); verify(transactionSimulator).process(any(), eq(Optional.empty()), any(), any(), any(), any());
} }
@Test @Test
@ -431,7 +465,7 @@ public class EthCallTest {
.build(); .build();
verify(transactionSimulator) verify(transactionSimulator)
.process(any(), eq(transactionValidationParams), any(), any(), any()); .process(any(), eq(Optional.empty()), eq(transactionValidationParams), any(), any(), any());
} }
private JsonCallParameter callParameter() { private JsonCallParameter callParameter() {
@ -458,8 +492,17 @@ public class EthCallTest {
new JsonRpcRequest("2.0", "eth_call", new Object[] {callParameter, blockNumberInHex})); new JsonRpcRequest("2.0", "eth_call", new Object[] {callParameter, blockNumberInHex}));
} }
private JsonRpcRequestContext ethCallRequestWithStateOverrides(
final CallParameter callParameter,
final String blockNumberInHex,
final AccountOverrideMap overrides) {
return new JsonRpcRequestContext(
new JsonRpcRequest(
"2.0", "eth_call", new Object[] {callParameter, blockNumberInHex, overrides}));
}
private void mockTransactionProcessorSuccessResult(final JsonRpcResponse jsonRpcResponse) { private void mockTransactionProcessorSuccessResult(final JsonRpcResponse jsonRpcResponse) {
when(transactionSimulator.process(any(), any(), any(), any(), any())) when(transactionSimulator.process(any(), eq(Optional.empty()), any(), any(), any(), any()))
.thenReturn(Optional.of(jsonRpcResponse)); .thenReturn(Optional.of(jsonRpcResponse));
} }
} }

@ -26,6 +26,7 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcRespon
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType;
import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.api.query.BlockchainQueries;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem;
import java.util.function.Supplier; import java.util.function.Supplier;
@ -69,7 +70,8 @@ public class TraceFilterTest {
new JsonRpcRequest("2.0", "trace_filter", new Object[] {filterParameter})); new JsonRpcRequest("2.0", "trace_filter", new Object[] {filterParameter}));
method = method =
new TraceFilter(blockTracerSupplier, protocolSchedule, blockchainQueries, maxFilterRange); new TraceFilter(
protocolSchedule, blockchainQueries, maxFilterRange, new NoOpMetricsSystem());
final JsonRpcResponse response = method.response(request); final JsonRpcResponse response = method.response(request);
assertThat(response).isInstanceOf(JsonRpcErrorResponse.class); assertThat(response).isInstanceOf(JsonRpcErrorResponse.class);

@ -0,0 +1,24 @@
{
"request": {
"id": 3,
"jsonrpc": "2.0",
"method": "eth_call",
"params": [
{
"to": "0x6295ee1b4f6dd65047762f924ecd367c17eabf8f",
"from": "a94f5374fce5edbc8e2a8697c15331677e6ebf0b",
"data": "0x12a7b914"
},
"latest",
{
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b": {}
}
]
},
"response": {
"jsonrpc": "2.0",
"id": 3,
"result": "0x0000000000000000000000000000000000000000000000000000000000000001"
},
"statusCode": 200
}

@ -0,0 +1,32 @@
{
"request": {
"id": 3,
"jsonrpc": "2.0",
"method": "eth_call",
"params": [
{
"to": "0x6295ee1b4f6dd65047762f924ecd367c17eabf8f",
"from": "a94f5374fce5edbc8e2a8697c15331677e6ebf0b",
"data": "0x12a7b914"
},
"latest",
{
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b": {
"balance": "0xde0b6b3a7640000",
"nonce": 88
},
"0xb9741079a300Cb3B8f324CdDB847c0d1d273a05E": {
"stateDiff": {
"0x1cf7945003fc5b59d2f6736f0704557aa805c4f2844084ccd1173b8d56946962": "0x000000000000000000000000000000000000000000000000000000110ed03bf7"
}
}
}
]
},
"response": {
"jsonrpc": "2.0",
"id": 3,
"result": "0x0000000000000000000000000000000000000000000000000000000000000001"
},
"statusCode": 200
}

@ -0,0 +1,34 @@
{
"request": {
"id": 3,
"jsonrpc": "2.0",
"method": "eth_call",
"params": [
{
"to": "0x6295ee1b4f6dd65047762f924ecd367c17eabf8f",
"from": "a94f5374fce5edbc8e2a8697c15331677e6ebf0b",
"value": "0x000002"
},
"latest",
{
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b": {
"balance": "0x000001"
},
"0xb9741079a300Cb3B8f324CdDB847c0d1d273a05E": {
"stateDiff": {
"0x1cf7945003fc5b59d2f6736f0704557aa805c4f2844084ccd1173b8d56946962": "0x000000000000000000000000000000000000000000000000000000110ed03bf7"
}
}
}
]
},
"response": {
"jsonrpc": "2.0",
"id": 3,
"error" : {
"code" : -32004,
"message" : "Upfront cost exceeds account balance"
}
},
"statusCode": 200
}

@ -22,6 +22,7 @@ import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import org.hyperledger.besu.ethereum.ConsensusContext;
import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.ProtocolContext;
import org.hyperledger.besu.ethereum.blockcreation.BlockCreator.BlockCreationResult; import org.hyperledger.besu.ethereum.blockcreation.BlockCreator.BlockCreationResult;
import org.hyperledger.besu.ethereum.blockcreation.txselection.TransactionSelectionResults; import org.hyperledger.besu.ethereum.blockcreation.txselection.TransactionSelectionResults;
@ -58,7 +59,7 @@ public class BlockMinerTest {
headerBuilder.buildHeader(), new BlockBody(Lists.newArrayList(), Lists.newArrayList())); headerBuilder.buildHeader(), new BlockBody(Lists.newArrayList(), Lists.newArrayList()));
final ProtocolContext protocolContext = final ProtocolContext protocolContext =
new ProtocolContext(null, null, null, new BadBlockManager()); new ProtocolContext(null, null, mock(ConsensusContext.class), new BadBlockManager());
final PoWBlockCreator blockCreator = mock(PoWBlockCreator.class); final PoWBlockCreator blockCreator = mock(PoWBlockCreator.class);
final Function<BlockHeader, PoWBlockCreator> blockCreatorSupplier = final Function<BlockHeader, PoWBlockCreator> blockCreatorSupplier =
@ -102,7 +103,7 @@ public class BlockMinerTest {
headerBuilder.buildHeader(), new BlockBody(Lists.newArrayList(), Lists.newArrayList())); headerBuilder.buildHeader(), new BlockBody(Lists.newArrayList(), Lists.newArrayList()));
final ProtocolContext protocolContext = final ProtocolContext protocolContext =
new ProtocolContext(null, null, null, new BadBlockManager()); new ProtocolContext(null, null, mock(ConsensusContext.class), new BadBlockManager());
final PoWBlockCreator blockCreator = mock(PoWBlockCreator.class); final PoWBlockCreator blockCreator = mock(PoWBlockCreator.class);
final Function<BlockHeader, PoWBlockCreator> blockCreatorSupplier = final Function<BlockHeader, PoWBlockCreator> blockCreatorSupplier =
@ -150,7 +151,7 @@ public class BlockMinerTest {
headerBuilder.buildHeader(), new BlockBody(Lists.newArrayList(), Lists.newArrayList())); headerBuilder.buildHeader(), new BlockBody(Lists.newArrayList(), Lists.newArrayList()));
final ProtocolContext protocolContext = final ProtocolContext protocolContext =
new ProtocolContext(null, null, null, new BadBlockManager()); new ProtocolContext(null, null, mock(ConsensusContext.class), new BadBlockManager());
final PoWBlockCreator blockCreator = mock(PoWBlockCreator.class); final PoWBlockCreator blockCreator = mock(PoWBlockCreator.class);
final Function<BlockHeader, PoWBlockCreator> blockCreatorSupplier = final Function<BlockHeader, PoWBlockCreator> blockCreatorSupplier =

@ -65,8 +65,6 @@ dependencies {
implementation 'org.immutables:value-annotations' implementation 'org.immutables:value-annotations'
implementation 'tech.pegasys:jc-kzg-4844' implementation 'tech.pegasys:jc-kzg-4844'
implementation 'io.prometheus:simpleclient_guava'
implementation 'org.xerial.snappy:snappy-java' implementation 'org.xerial.snappy:snappy-java'
annotationProcessor 'org.immutables:value' annotationProcessor 'org.immutables:value'

@ -1,38 +0,0 @@
/*
* Copyright ConsenSys AG.
*
* 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.ethereum;
import org.hyperledger.besu.ethereum.chain.Blockchain;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive;
/** The ConsensusContextFactory interface defines a method for creating a consensus context. */
@FunctionalInterface
public interface ConsensusContextFactory {
/**
* Creates a consensus context with the given blockchain, world state archive, and protocol
* schedule.
*
* @param blockchain the blockchain
* @param worldStateArchive the world state archive
* @param protocolSchedule the protocol schedule
* @return the created consensus context
*/
ConsensusContext create(
Blockchain blockchain,
WorldStateArchive worldStateArchive,
ProtocolSchedule protocolSchedule);
}

@ -16,7 +16,6 @@ package org.hyperledger.besu.ethereum;
import org.hyperledger.besu.ethereum.chain.BadBlockManager; import org.hyperledger.besu.ethereum.chain.BadBlockManager;
import org.hyperledger.besu.ethereum.chain.MutableBlockchain; import org.hyperledger.besu.ethereum.chain.MutableBlockchain;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive;
import java.util.Optional; import java.util.Optional;
@ -29,8 +28,8 @@ import java.util.Optional;
public class ProtocolContext { public class ProtocolContext {
private final MutableBlockchain blockchain; private final MutableBlockchain blockchain;
private final WorldStateArchive worldStateArchive; private final WorldStateArchive worldStateArchive;
private final BadBlockManager badBlockManager;
private final ConsensusContext consensusContext; private final ConsensusContext consensusContext;
private final BadBlockManager badBlockManager;
/** /**
* Constructs a new ProtocolContext with the given blockchain, world state archive, consensus * Constructs a new ProtocolContext with the given blockchain, world state archive, consensus
@ -38,7 +37,7 @@ public class ProtocolContext {
* *
* @param blockchain the blockchain of the protocol context * @param blockchain the blockchain of the protocol context
* @param worldStateArchive the world state archive of the protocol context * @param worldStateArchive the world state archive of the protocol context
* @param consensusContext the consensus context of the protocol context * @param consensusContext the consensus context
* @param badBlockManager the bad block manager of the protocol context * @param badBlockManager the bad block manager of the protocol context
*/ */
public ProtocolContext( public ProtocolContext(
@ -52,30 +51,6 @@ public class ProtocolContext {
this.badBlockManager = badBlockManager; this.badBlockManager = badBlockManager;
} }
/**
* Initializes a new ProtocolContext with the given blockchain, world state archive, protocol
* schedule, consensus context factory, and bad block manager.
*
* @param blockchain the blockchain of the protocol context
* @param worldStateArchive the world state archive of the protocol context
* @param protocolSchedule the protocol schedule of the protocol context
* @param consensusContextFactory the consensus context factory of the protocol context
* @param badBlockManager the bad block manager of the protocol context
* @return the initialized ProtocolContext
*/
public static ProtocolContext init(
final MutableBlockchain blockchain,
final WorldStateArchive worldStateArchive,
final ProtocolSchedule protocolSchedule,
final ConsensusContextFactory consensusContextFactory,
final BadBlockManager badBlockManager) {
return new ProtocolContext(
blockchain,
worldStateArchive,
consensusContextFactory.create(blockchain, worldStateArchive, protocolSchedule),
badBlockManager);
}
/** /**
* Gets the blockchain of the protocol context. * Gets the blockchain of the protocol context.
* *

@ -19,6 +19,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
import static java.util.Collections.emptyList; import static java.util.Collections.emptyList;
import static java.util.stream.Collectors.joining; import static java.util.stream.Collectors.joining;
import static java.util.stream.Collectors.toList; import static java.util.stream.Collectors.toList;
import static org.hyperledger.besu.metrics.BesuMetricCategory.BLOCKCHAIN;
import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.ethereum.chain.BlockchainStorage.Updater; import org.hyperledger.besu.ethereum.chain.BlockchainStorage.Updater;
@ -32,7 +33,6 @@ import org.hyperledger.besu.ethereum.core.Transaction;
import org.hyperledger.besu.ethereum.core.TransactionReceipt; import org.hyperledger.besu.ethereum.core.TransactionReceipt;
import org.hyperledger.besu.metrics.BesuMetricCategory; import org.hyperledger.besu.metrics.BesuMetricCategory;
import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem;
import org.hyperledger.besu.metrics.prometheus.PrometheusMetricsSystem;
import org.hyperledger.besu.plugin.services.MetricsSystem; import org.hyperledger.besu.plugin.services.MetricsSystem;
import org.hyperledger.besu.plugin.services.metrics.Counter; import org.hyperledger.besu.plugin.services.metrics.Counter;
import org.hyperledger.besu.util.InvalidConfigurationException; import org.hyperledger.besu.util.InvalidConfigurationException;
@ -56,7 +56,6 @@ import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheBuilder;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.google.common.collect.Streams; import com.google.common.collect.Streams;
import io.prometheus.client.guava.cache.CacheMetricsCollector;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -134,13 +133,12 @@ public class DefaultBlockchain implements MutableBlockchain {
totalDifficultyCache = totalDifficultyCache =
Optional.of( Optional.of(
CacheBuilder.newBuilder().recordStats().maximumSize(numberOfBlocksToCache).build()); CacheBuilder.newBuilder().recordStats().maximumSize(numberOfBlocksToCache).build());
CacheMetricsCollector cacheMetrics = new CacheMetricsCollector(); metricsSystem.createGuavaCacheCollector(BLOCKCHAIN, "blockHeaders", blockHeadersCache.get());
cacheMetrics.addCache("blockHeaders", blockHeadersCache.get()); metricsSystem.createGuavaCacheCollector(BLOCKCHAIN, "blockBodies", blockBodiesCache.get());
cacheMetrics.addCache("blockBodies", blockBodiesCache.get()); metricsSystem.createGuavaCacheCollector(
cacheMetrics.addCache("transactionReceipts", transactionReceiptsCache.get()); BLOCKCHAIN, "transactionReceipts", transactionReceiptsCache.get());
cacheMetrics.addCache("totalDifficulty", totalDifficultyCache.get()); metricsSystem.createGuavaCacheCollector(
if (metricsSystem instanceof PrometheusMetricsSystem prometheusMetricsSystem) BLOCKCHAIN, "totalDifficulty", totalDifficultyCache.get());
prometheusMetricsSystem.addCollector(BesuMetricCategory.BLOCKCHAIN, () -> cacheMetrics);
} else { } else {
blockHeadersCache = Optional.empty(); blockHeadersCache = Optional.empty();
blockBodiesCache = Optional.empty(); blockBodiesCache = Optional.empty();
@ -155,11 +153,11 @@ public class DefaultBlockchain implements MutableBlockchain {
private void createCounters(final MetricsSystem metricsSystem) { private void createCounters(final MetricsSystem metricsSystem) {
gasUsedCounter = gasUsedCounter =
metricsSystem.createCounter( metricsSystem.createCounter(
BesuMetricCategory.BLOCKCHAIN, "chain_head_gas_used_counter", "Counter for Gas used"); BLOCKCHAIN, "chain_head_gas_used_counter", "Counter for Gas used");
numberOfTransactionsCounter = numberOfTransactionsCounter =
metricsSystem.createCounter( metricsSystem.createCounter(
BesuMetricCategory.BLOCKCHAIN, BLOCKCHAIN,
"chain_head_transaction_count_counter", "chain_head_transaction_count_counter",
"Counter for the number of transactions"); "Counter for the number of transactions");
} }
@ -184,37 +182,37 @@ public class DefaultBlockchain implements MutableBlockchain {
this::getSafeBlockNumber); this::getSafeBlockNumber);
metricsSystem.createGauge( metricsSystem.createGauge(
BesuMetricCategory.BLOCKCHAIN, BLOCKCHAIN,
"difficulty_total", "difficulty_total",
"Total difficulty of the chainhead", "Total difficulty of the chainhead",
() -> this.getChainHead().getTotalDifficulty().toBigInteger().doubleValue()); () -> this.getChainHead().getTotalDifficulty().toBigInteger().doubleValue());
metricsSystem.createLongGauge( metricsSystem.createLongGauge(
BesuMetricCategory.BLOCKCHAIN, BLOCKCHAIN,
"chain_head_timestamp", "chain_head_timestamp",
"Timestamp from the current chain head", "Timestamp from the current chain head",
() -> getChainHeadHeader().getTimestamp()); () -> getChainHeadHeader().getTimestamp());
metricsSystem.createLongGauge( metricsSystem.createLongGauge(
BesuMetricCategory.BLOCKCHAIN, BLOCKCHAIN,
"chain_head_gas_used", "chain_head_gas_used",
"Gas used by the current chain head block", "Gas used by the current chain head block",
() -> getChainHeadHeader().getGasUsed()); () -> getChainHeadHeader().getGasUsed());
metricsSystem.createLongGauge( metricsSystem.createLongGauge(
BesuMetricCategory.BLOCKCHAIN, BLOCKCHAIN,
"chain_head_gas_limit", "chain_head_gas_limit",
"Block gas limit of the current chain head block", "Block gas limit of the current chain head block",
() -> getChainHeadHeader().getGasLimit()); () -> getChainHeadHeader().getGasLimit());
metricsSystem.createIntegerGauge( metricsSystem.createIntegerGauge(
BesuMetricCategory.BLOCKCHAIN, BLOCKCHAIN,
"chain_head_transaction_count", "chain_head_transaction_count",
"Number of transactions in the current chain head block", "Number of transactions in the current chain head block",
() -> chainHeadTransactionCount); () -> chainHeadTransactionCount);
metricsSystem.createIntegerGauge( metricsSystem.createIntegerGauge(
BesuMetricCategory.BLOCKCHAIN, BLOCKCHAIN,
"chain_head_ommer_count", "chain_head_ommer_count",
"Number of ommers in the current chain head block", "Number of ommers in the current chain head block",
() -> chainHeadOmmerCount); () -> chainHeadOmmerCount);

@ -34,10 +34,13 @@ import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec; import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec;
import org.hyperledger.besu.ethereum.mainnet.TransactionValidationParams; import org.hyperledger.besu.ethereum.mainnet.TransactionValidationParams;
import org.hyperledger.besu.ethereum.processing.TransactionProcessingResult; import org.hyperledger.besu.ethereum.processing.TransactionProcessingResult;
import org.hyperledger.besu.ethereum.util.AccountOverride;
import org.hyperledger.besu.ethereum.util.AccountOverrideMap;
import org.hyperledger.besu.ethereum.vm.CachingBlockHashLookup; import org.hyperledger.besu.ethereum.vm.CachingBlockHashLookup;
import org.hyperledger.besu.ethereum.vm.DebugOperationTracer; import org.hyperledger.besu.ethereum.vm.DebugOperationTracer;
import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive;
import org.hyperledger.besu.evm.account.Account; import org.hyperledger.besu.evm.account.Account;
import org.hyperledger.besu.evm.account.MutableAccount;
import org.hyperledger.besu.evm.tracing.OperationTracer; import org.hyperledger.besu.evm.tracing.OperationTracer;
import org.hyperledger.besu.evm.worldstate.WorldUpdater; import org.hyperledger.besu.evm.worldstate.WorldUpdater;
@ -46,8 +49,10 @@ import java.util.Optional;
import java.util.function.Supplier; import java.util.function.Supplier;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Suppliers; import com.google.common.base.Suppliers;
import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.units.bigints.UInt256;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -152,6 +157,35 @@ public class TransactionSimulator {
final OperationTracer operationTracer, final OperationTracer operationTracer,
final PreCloseStateHandler<U> preWorldStateCloseGuard, final PreCloseStateHandler<U> preWorldStateCloseGuard,
final BlockHeader header) { final BlockHeader header) {
return process(
callParams,
Optional.empty(),
transactionValidationParams,
operationTracer,
preWorldStateCloseGuard,
header);
}
/**
* Processes a transaction simulation with the provided parameters and executes pre-worldstate
* close actions.
*
* @param callParams The call parameters for the transaction.
* @param maybeStateOverrides The map of state overrides to apply to the state for this
* transaction.
* @param transactionValidationParams The validation parameters for the transaction.
* @param operationTracer The tracer for capturing operations during processing.
* @param preWorldStateCloseGuard The pre-worldstate close guard for executing pre-close actions.
* @param header The block header.
* @return An Optional containing the result of the processing.
*/
public <U> Optional<U> process(
final CallParameter callParams,
final Optional<AccountOverrideMap> maybeStateOverrides,
final TransactionValidationParams transactionValidationParams,
final OperationTracer operationTracer,
final PreCloseStateHandler<U> preWorldStateCloseGuard,
final BlockHeader header) {
if (header == null) { if (header == null) {
return Optional.empty(); return Optional.empty();
} }
@ -169,7 +203,12 @@ public class TransactionSimulator {
return preWorldStateCloseGuard.apply( return preWorldStateCloseGuard.apply(
ws, ws,
processWithWorldUpdater( processWithWorldUpdater(
callParams, transactionValidationParams, operationTracer, header, updater)); callParams,
maybeStateOverrides,
transactionValidationParams,
operationTracer,
header,
updater));
} catch (final Exception e) { } catch (final Exception e) {
return Optional.empty(); return Optional.empty();
@ -208,6 +247,7 @@ public class TransactionSimulator {
@Nonnull @Nonnull
public Optional<TransactionSimulatorResult> processWithWorldUpdater( public Optional<TransactionSimulatorResult> processWithWorldUpdater(
final CallParameter callParams, final CallParameter callParams,
final Optional<AccountOverrideMap> maybeStateOverrides,
final TransactionValidationParams transactionValidationParams, final TransactionValidationParams transactionValidationParams,
final OperationTracer operationTracer, final OperationTracer operationTracer,
final BlockHeader header, final BlockHeader header,
@ -226,6 +266,12 @@ public class TransactionSimulator {
.blockHeaderFunctions(protocolSpec.getBlockHeaderFunctions()) .blockHeaderFunctions(protocolSpec.getBlockHeaderFunctions())
.buildBlockHeader(); .buildBlockHeader();
} }
if (maybeStateOverrides.isPresent()) {
for (Address accountToOverride : maybeStateOverrides.get().keySet()) {
final AccountOverride overrides = maybeStateOverrides.get().get(accountToOverride);
applyOverrides(updater.getOrCreate(accountToOverride), overrides);
}
}
final Account sender = updater.get(senderAddress); final Account sender = updater.get(senderAddress);
final long nonce = sender != null ? sender.getNonce() : 0L; final long nonce = sender != null ? sender.getNonce() : 0L;
@ -284,6 +330,24 @@ public class TransactionSimulator {
return Optional.of(new TransactionSimulatorResult(transaction, result)); return Optional.of(new TransactionSimulatorResult(transaction, result));
} }
@VisibleForTesting
protected void applyOverrides(final MutableAccount account, final AccountOverride override) {
LOG.debug("applying overrides to state for account {}", account.getAddress());
override.getNonce().ifPresent(account::setNonce);
if (override.getBalance().isPresent()) {
account.setBalance(override.getBalance().get());
}
override.getCode().ifPresent(n -> account.setCode(Bytes.fromHexString(n)));
override
.getStateDiff()
.ifPresent(
d ->
d.forEach(
(key, value) ->
account.setStorageValue(
UInt256.fromHexString(key), UInt256.fromHexString(value))));
}
private long calculateSimulationGasCap( private long calculateSimulationGasCap(
final long userProvidedGasLimit, final long blockGasLimit) { final long userProvidedGasLimit, final long blockGasLimit) {
final long simulationGasCap; final long simulationGasCap;

@ -14,6 +14,8 @@
*/ */
package org.hyperledger.besu.ethereum.trie.diffbased.bonsai.cache; package org.hyperledger.besu.ethereum.trie.diffbased.bonsai.cache;
import static org.hyperledger.besu.metrics.BesuMetricCategory.BLOCKCHAIN;
import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.datatypes.StorageSlotKey; import org.hyperledger.besu.datatypes.StorageSlotKey;
@ -22,9 +24,7 @@ import org.hyperledger.besu.ethereum.trie.MerkleTrieException;
import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.storage.BonsaiWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.storage.BonsaiWorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.trie.diffbased.common.StorageSubscriber; import org.hyperledger.besu.ethereum.trie.diffbased.common.StorageSubscriber;
import org.hyperledger.besu.ethereum.trie.patricia.StoredMerklePatriciaTrie; import org.hyperledger.besu.ethereum.trie.patricia.StoredMerklePatriciaTrie;
import org.hyperledger.besu.metrics.BesuMetricCategory;
import org.hyperledger.besu.metrics.ObservableMetricsSystem; import org.hyperledger.besu.metrics.ObservableMetricsSystem;
import org.hyperledger.besu.metrics.prometheus.PrometheusMetricsSystem;
import java.util.Optional; import java.util.Optional;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
@ -33,7 +33,6 @@ import java.util.function.Function;
import com.google.common.annotations.VisibleForTesting; import com.google.common.annotations.VisibleForTesting;
import com.google.common.cache.Cache; import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheBuilder;
import io.prometheus.client.guava.cache.CacheMetricsCollector;
import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32; import org.apache.tuweni.bytes.Bytes32;
@ -47,12 +46,8 @@ public class BonsaiCachedMerkleTrieLoader implements StorageSubscriber {
CacheBuilder.newBuilder().recordStats().maximumSize(STORAGE_CACHE_SIZE).build(); CacheBuilder.newBuilder().recordStats().maximumSize(STORAGE_CACHE_SIZE).build();
public BonsaiCachedMerkleTrieLoader(final ObservableMetricsSystem metricsSystem) { public BonsaiCachedMerkleTrieLoader(final ObservableMetricsSystem metricsSystem) {
metricsSystem.createGuavaCacheCollector(BLOCKCHAIN, "accountsNodes", accountNodes);
CacheMetricsCollector cacheMetrics = new CacheMetricsCollector(); metricsSystem.createGuavaCacheCollector(BLOCKCHAIN, "storageNodes", storageNodes);
cacheMetrics.addCache("accountsNodes", accountNodes);
cacheMetrics.addCache("storageNodes", storageNodes);
if (metricsSystem instanceof PrometheusMetricsSystem prometheusMetricsSystem)
prometheusMetricsSystem.addCollector(BesuMetricCategory.BLOCKCHAIN, () -> cacheMetrics);
} }
public void preLoadAccount( public void preLoadAccount(

@ -0,0 +1,147 @@
/*
* Copyright contributors to Besu.
*
* 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.ethereum.util;
import org.hyperledger.besu.datatypes.Wei;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
// similar to AccountDiff
// BUT
// there are more fields that need to be added
// stateDiff
// movePrecompileToAddress
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonDeserialize(builder = AccountOverride.Builder.class)
public class AccountOverride {
private static final Logger LOG = LoggerFactory.getLogger(AccountOverride.class);
private final Optional<Wei> balance;
private final Optional<Long> nonce;
private final Optional<String> code;
private final Optional<Map<String, String>> stateDiff;
private AccountOverride(
final Optional<Wei> balance,
final Optional<Long> nonce,
final Optional<String> code,
final Optional<Map<String, String>> stateDiff) {
this.balance = balance;
this.nonce = nonce;
this.code = code;
this.stateDiff = stateDiff;
}
public Optional<Wei> getBalance() {
return balance;
}
public Optional<Long> getNonce() {
return nonce;
}
public Optional<String> getCode() {
return code;
}
public Optional<Map<String, String>> getStateDiff() {
return stateDiff;
}
public static class Builder {
private Optional<Wei> balance = Optional.empty();
private Optional<Long> nonce = Optional.empty();
private Optional<String> code = Optional.empty();
private Optional<Map<String, String>> stateDiff = Optional.empty();
/** Default constructor. */
public Builder() {}
public Builder withBalance(final Wei balance) {
this.balance = Optional.ofNullable(balance);
return this;
}
public Builder withNonce(final Long nonce) {
this.nonce = Optional.ofNullable(nonce);
return this;
}
public Builder withCode(final String code) {
this.code = Optional.ofNullable(code);
return this;
}
public Builder withStateDiff(final Map<String, String> stateDiff) {
this.stateDiff = Optional.ofNullable(stateDiff);
return this;
}
public AccountOverride build() {
return new AccountOverride(balance, nonce, code, stateDiff);
}
}
@JsonAnySetter
public void withUnknownProperties(final String key, final Object value) {
LOG.debug(
"unknown property - {} with value - {} and type - {} caught during serialization",
key,
value,
value != null ? value.getClass() : "NULL");
}
@Override
public boolean equals(final Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
final AccountOverride accountOverride = (AccountOverride) o;
return balance.equals(accountOverride.balance)
&& nonce.equals(accountOverride.nonce)
&& code.equals(accountOverride.code)
&& stateDiff.equals(accountOverride.stateDiff);
}
@Override
public int hashCode() {
return Objects.hash(balance, nonce, code, stateDiff);
}
@Override
public String toString() {
return "AccountOverride{"
+ "balance="
+ balance
+ ", nonce="
+ nonce
+ ", code="
+ code
+ ", stateDiff="
+ stateDiff
+ '}';
}
}

@ -0,0 +1,27 @@
/*
* Copyright contributors to Besu.
*
* 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.ethereum.util;
import org.hyperledger.besu.datatypes.Address;
import java.util.HashMap;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
@JsonIgnoreProperties(ignoreUnknown = true)
public class AccountOverrideMap extends HashMap<Address, AccountOverride> {
public AccountOverrideMap() {}
}

@ -21,7 +21,6 @@ import static org.hyperledger.besu.ethereum.core.InMemoryKeyValueStorageProvider
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import org.hyperledger.besu.config.GenesisConfigFile; import org.hyperledger.besu.config.GenesisConfigFile;
import org.hyperledger.besu.ethereum.ConsensusContext;
import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.ProtocolContext;
import org.hyperledger.besu.ethereum.chain.BadBlockManager; import org.hyperledger.besu.ethereum.chain.BadBlockManager;
import org.hyperledger.besu.ethereum.chain.Blockchain; import org.hyperledger.besu.ethereum.chain.Blockchain;
@ -161,15 +160,7 @@ public class BlockchainSetupUtil {
private static ProtocolContext mainnetProtocolContextProvider( private static ProtocolContext mainnetProtocolContextProvider(
final MutableBlockchain blockchain, final WorldStateArchive worldStateArchive) { final MutableBlockchain blockchain, final WorldStateArchive worldStateArchive) {
return new ProtocolContext( return new ProtocolContext(
blockchain, blockchain, worldStateArchive, new ConsensusContextFixture(), new BadBlockManager());
worldStateArchive,
new ConsensusContext() {
@Override
public <C extends ConsensusContext> C as(final Class<C> klass) {
return null;
}
},
new BadBlockManager());
} }
private static BlockchainSetupUtil create( private static BlockchainSetupUtil create(

@ -0,0 +1,24 @@
/*
* Copyright contributors to Besu.
*
* 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.ethereum.core;
import org.hyperledger.besu.ethereum.ConsensusContext;
public class ConsensusContextFixture implements ConsensusContext {
@Override
public <C extends ConsensusContext> C as(final Class<C> klass) {
return klass.cast(this);
}
}

@ -76,7 +76,8 @@ public class ExecutionContextTestFixture {
else this.stateArchive = createInMemoryWorldStateArchive(); else this.stateArchive = createInMemoryWorldStateArchive();
this.protocolSchedule = protocolSchedule; this.protocolSchedule = protocolSchedule;
this.protocolContext = this.protocolContext =
new ProtocolContext(blockchain, stateArchive, null, new BadBlockManager()); new ProtocolContext(
blockchain, stateArchive, new ConsensusContextFixture(), new BadBlockManager());
genesisState.writeStateTo(stateArchive.getMutable()); genesisState.writeStateTo(stateArchive.getMutable());
} }

@ -20,6 +20,7 @@ import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import org.hyperledger.besu.crypto.SECPSignature; import org.hyperledger.besu.crypto.SECPSignature;
@ -47,17 +48,21 @@ import org.hyperledger.besu.ethereum.mainnet.blockhash.BlockHashProcessor;
import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket; import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket;
import org.hyperledger.besu.ethereum.processing.TransactionProcessingResult; import org.hyperledger.besu.ethereum.processing.TransactionProcessingResult;
import org.hyperledger.besu.ethereum.processing.TransactionProcessingResult.Status; import org.hyperledger.besu.ethereum.processing.TransactionProcessingResult.Status;
import org.hyperledger.besu.ethereum.util.AccountOverride;
import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive;
import org.hyperledger.besu.evm.account.Account; import org.hyperledger.besu.evm.account.Account;
import org.hyperledger.besu.evm.account.MutableAccount;
import org.hyperledger.besu.evm.tracing.OperationTracer; import org.hyperledger.besu.evm.tracing.OperationTracer;
import org.hyperledger.besu.evm.worldstate.WorldUpdater; import org.hyperledger.besu.evm.worldstate.WorldUpdater;
import java.math.BigInteger; import java.math.BigInteger;
import java.util.Map;
import java.util.Optional; import java.util.Optional;
import com.google.common.base.Supplier; import com.google.common.base.Supplier;
import com.google.common.base.Suppliers; import com.google.common.base.Suppliers;
import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.units.bigints.UInt256;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.extension.ExtendWith;
@ -100,6 +105,42 @@ public class TransactionSimulatorTest {
new TransactionSimulator(blockchain, worldStateArchive, protocolSchedule, GAS_CAP); new TransactionSimulator(blockchain, worldStateArchive, protocolSchedule, GAS_CAP);
} }
@Test
public void testOverrides_whenNoOverrides_noUpdates() {
MutableAccount mutableAccount = mock(MutableAccount.class);
when(mutableAccount.getAddress()).thenReturn(DEFAULT_FROM); // called from logging
AccountOverride.Builder builder = new AccountOverride.Builder();
AccountOverride override = builder.build();
transactionSimulator.applyOverrides(mutableAccount, override);
verify(mutableAccount).getAddress();
verifyNoMoreInteractions(mutableAccount);
}
@Test
public void testOverrides_whenBalanceOverrides_balanceIsUpdated() {
MutableAccount mutableAccount = mock(MutableAccount.class);
when(mutableAccount.getAddress()).thenReturn(DEFAULT_FROM);
AccountOverride.Builder builder = new AccountOverride.Builder().withBalance(Wei.of(99));
AccountOverride override = builder.build();
transactionSimulator.applyOverrides(mutableAccount, override);
verify(mutableAccount).setBalance(eq(Wei.of(99)));
}
@Test
public void testOverrides_whenStateDiffOverrides_stateIsUpdated() {
MutableAccount mutableAccount = mock(MutableAccount.class);
when(mutableAccount.getAddress()).thenReturn(DEFAULT_FROM);
final String storageKey = "0x01a2";
final String storageValue = "0x00ff";
AccountOverride.Builder builder =
new AccountOverride.Builder().withStateDiff(Map.of(storageKey, storageValue));
AccountOverride override = builder.build();
transactionSimulator.applyOverrides(mutableAccount, override);
verify(mutableAccount)
.setStorageValue(
eq(UInt256.fromHexString(storageKey)), eq(UInt256.fromHexString(storageValue)));
}
@Test @Test
public void shouldReturnEmptyWhenBlockDoesNotExist() { public void shouldReturnEmptyWhenBlockDoesNotExist() {
when(blockchain.getBlockHeader(eq(1L))).thenReturn(Optional.empty()); when(blockchain.getBlockHeader(eq(1L))).thenReturn(Optional.empty());

@ -30,6 +30,7 @@ import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.BlockProcessingResult; import org.hyperledger.besu.ethereum.BlockProcessingResult;
import org.hyperledger.besu.ethereum.ConsensusContext;
import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.ProtocolContext;
import org.hyperledger.besu.ethereum.blockcreation.AbstractBlockCreator; import org.hyperledger.besu.ethereum.blockcreation.AbstractBlockCreator;
import org.hyperledger.besu.ethereum.chain.BadBlockManager; import org.hyperledger.besu.ethereum.chain.BadBlockManager;
@ -172,7 +173,9 @@ public abstract class AbstractIsolationTests {
throwingWorldStateHealerSupplier()); throwingWorldStateHealerSupplier());
var ws = archive.getMutable(); var ws = archive.getMutable();
genesisState.writeStateTo(ws); genesisState.writeStateTo(ws);
protocolContext = new ProtocolContext(blockchain, archive, null, new BadBlockManager()); protocolContext =
new ProtocolContext(
blockchain, archive, mock(ConsensusContext.class), new BadBlockManager());
ethContext = mock(EthContext.class, RETURNS_DEEP_STUBS); ethContext = mock(EthContext.class, RETURNS_DEEP_STUBS);
when(ethContext.getEthPeers().subscribeConnect(any())).thenReturn(1L); when(ethContext.getEthPeers().subscribeConnect(any())).thenReturn(1L);
transactionPool = transactionPool =

@ -0,0 +1,188 @@
/*
* Copyright contributors to Besu.
*
* 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.ethereum.util;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext;
import java.util.Optional;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.Test;
public class AccountOverrideParameterTest {
private static final String ADDRESS_HEX1 = "0xd9c9cd5f6779558b6e0ed4e6acf6b1947e7fa1f3";
private static final String ADDRESS_HEX2 = "0xd5E23607D5d73ff2293152f464C3caB005f87696";
private static final String STORAGE_KEY =
"0x1cf7945003fc5b59d2f6736f0704557aa805c4f2844084ccd1173b8d56946962";
private static final String STORAGE_VALUE =
"0x000000000000000000000000000000000000000000000000000000110ed03bf7";
private static final String CODE_STRING =
"0xdbf4257000000000000000000000000000000000000000000000000000000000";
@Test
public void jsonDeserializesCorrectly() throws Exception {
final String json =
"{\"jsonrpc\":\"2.0\",\"method\":\"eth_call\",\"params\":[{"
+ "\"from\":\"0x0\", \"to\": \"0x0\"}, "
+ "\"latest\","
+ "{\""
+ ADDRESS_HEX1
+ "\":"
+ "{"
+ "\"balance\": \"0x01\","
+ "\"nonce\": 88"
+ "}}],\"id\":1}";
final JsonRpcRequestContext request = new JsonRpcRequestContext(readJsonAsJsonRpcRequest(json));
final AccountOverrideMap accountOverrideParam =
request.getRequiredParameter(2, AccountOverrideMap.class);
final AccountOverride accountOverride =
accountOverrideParam.get(Address.fromHexString(ADDRESS_HEX1));
assertThat(accountOverride.getNonce()).isEqualTo(Optional.of(88L));
assertThat(accountOverride.getBalance()).isEqualTo(Optional.of(Wei.of(1)));
assertFalse(accountOverride.getStateDiff().isPresent());
}
@Test
public void jsonWithCodeDeserializesCorrectly() throws Exception {
final String json =
"{\"jsonrpc\":\"2.0\",\"method\":\"eth_call\",\"params\":[{"
+ "\"from\":\"0x0\", \"to\": \"0x0\"}, "
+ "\"latest\","
+ "{\""
+ ADDRESS_HEX1
+ "\":"
+ "{"
+ "\"balance\": \"0x01\","
+ "\"code\": \""
+ CODE_STRING
+ "\""
+ "}}],\"id\":1}";
final JsonRpcRequestContext request = new JsonRpcRequestContext(readJsonAsJsonRpcRequest(json));
final AccountOverrideMap accountOverrideParam =
request.getRequiredParameter(2, AccountOverrideMap.class);
final AccountOverride accountOverride =
accountOverrideParam.get(Address.fromHexString(ADDRESS_HEX1));
assertFalse(accountOverride.getNonce().isPresent());
assertThat(accountOverride.getBalance()).isEqualTo(Optional.of(Wei.of(1)));
assertThat(accountOverride.getCode()).isEqualTo(Optional.of(CODE_STRING));
assertFalse(accountOverride.getStateDiff().isPresent());
}
@Test
public void jsonWithStorageOverridesDeserializesCorrectly() throws Exception {
final String json =
"{\"jsonrpc\":\"2.0\",\"method\":\"eth_call\",\"params\":[{"
+ "\"from\":\"0x0\", \"to\": \"0x0\"}, "
+ "\"latest\","
+ "{\""
+ ADDRESS_HEX1
+ "\":"
+ "{"
+ "\"balance\": \"0x01\","
+ "\"nonce\": 88,"
+ "\"stateDiff\": {"
+ "\""
+ STORAGE_KEY
+ "\": \""
+ STORAGE_VALUE
+ "\""
+ "}}}],\"id\":1}";
final JsonRpcRequestContext request = new JsonRpcRequestContext(readJsonAsJsonRpcRequest(json));
final AccountOverrideMap accountOverrideParam =
request.getRequiredParameter(2, AccountOverrideMap.class);
assertThat(accountOverrideParam.size()).isEqualTo(1);
final AccountOverride accountOverride =
accountOverrideParam.get(Address.fromHexString(ADDRESS_HEX1));
assertThat(accountOverride.getNonce()).isEqualTo(Optional.of(88L));
assertTrue(accountOverride.getStateDiff().isPresent());
assertThat(accountOverride.getStateDiff().get().get(STORAGE_KEY)).isEqualTo(STORAGE_VALUE);
}
@Test
public void jsonWithMultipleAccountOverridesDeserializesCorrectly() throws Exception {
final String json =
"{\"jsonrpc\":\"2.0\",\"method\":\"eth_call\",\"params\":[{"
+ "\"from\":\"0x0\", \"to\": \"0x0\"}, "
+ "\"latest\","
+ "{\""
+ ADDRESS_HEX1
+ "\":"
+ "{"
+ "\"balance\": \"0x01\","
+ "\"nonce\": 88,"
+ "\"stateDiff\": {"
+ "\""
+ STORAGE_KEY
+ "\": \""
+ STORAGE_VALUE
+ "\""
+ "}},"
+ "\""
+ ADDRESS_HEX2
+ "\":"
+ "{"
+ "\"balance\": \"0xFF\","
+ "\"nonce\": 99,"
+ "\"stateDiff\": {"
+ "\""
+ STORAGE_KEY
+ "\": \""
+ STORAGE_VALUE
+ "\""
+ "}}}],\"id\":1}";
final JsonRpcRequestContext request = new JsonRpcRequestContext(readJsonAsJsonRpcRequest(json));
final AccountOverrideMap accountOverrideParam =
request.getRequiredParameter(2, AccountOverrideMap.class);
assertThat(accountOverrideParam.size()).isEqualTo(2);
final AccountOverride accountOverride1 =
accountOverrideParam.get(Address.fromHexString(ADDRESS_HEX1));
assertThat(accountOverride1.getNonce()).isEqualTo(Optional.of(88L));
assertThat(accountOverride1.getBalance()).isEqualTo(Optional.of(Wei.fromHexString("0x01")));
assertTrue(accountOverride1.getStateDiff().isPresent());
assertThat(accountOverride1.getStateDiff().get().get(STORAGE_KEY)).isEqualTo(STORAGE_VALUE);
final AccountOverride accountOverride2 =
accountOverrideParam.get(Address.fromHexString(ADDRESS_HEX2));
assertThat(accountOverride2.getNonce()).isEqualTo(Optional.of(99L));
assertThat(accountOverride2.getBalance()).isEqualTo(Optional.of(Wei.fromHexString("0xFF")));
assertTrue(accountOverride2.getStateDiff().isPresent());
assertThat(accountOverride2.getStateDiff().get().get(STORAGE_KEY)).isEqualTo(STORAGE_VALUE);
}
private JsonRpcRequest readJsonAsJsonRpcRequest(final String json) throws java.io.IOException {
return new ObjectMapper().readValue(json, JsonRpcRequest.class);
}
}

@ -18,6 +18,7 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import org.hyperledger.besu.ethereum.ConsensusContext;
import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.ProtocolContext;
import org.hyperledger.besu.ethereum.chain.BadBlockManager; import org.hyperledger.besu.ethereum.chain.BadBlockManager;
import org.hyperledger.besu.ethereum.chain.Blockchain; import org.hyperledger.besu.ethereum.chain.Blockchain;
@ -78,7 +79,8 @@ public class FullSyncTargetManagerTest {
final ProtocolSchedule protocolSchedule = ProtocolScheduleFixture.MAINNET; final ProtocolSchedule protocolSchedule = ProtocolScheduleFixture.MAINNET;
final ProtocolContext protocolContext = final ProtocolContext protocolContext =
new ProtocolContext(localBlockchain, localWorldState, null, new BadBlockManager()); new ProtocolContext(
localBlockchain, localWorldState, mock(ConsensusContext.class), new BadBlockManager());
ethProtocolManager = ethProtocolManager =
EthProtocolManagerTestUtil.create( EthProtocolManagerTestUtil.create(
protocolSchedule, protocolSchedule,

@ -19,6 +19,7 @@ import static org.hyperledger.besu.ethereum.core.InMemoryKeyValueStorageProvider
import static org.hyperledger.besu.ethereum.core.InMemoryKeyValueStorageProvider.createInMemoryWorldStateArchive; import static org.hyperledger.besu.ethereum.core.InMemoryKeyValueStorageProvider.createInMemoryWorldStateArchive;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import org.hyperledger.besu.ethereum.ConsensusContext;
import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.ProtocolContext;
import org.hyperledger.besu.ethereum.chain.BadBlockManager; import org.hyperledger.besu.ethereum.chain.BadBlockManager;
import org.hyperledger.besu.ethereum.chain.MutableBlockchain; import org.hyperledger.besu.ethereum.chain.MutableBlockchain;
@ -165,7 +166,11 @@ public class DetermineCommonAncestorTaskParameterizedTest {
final EthContext ethContext = ethProtocolManager.ethContext(); final EthContext ethContext = ethProtocolManager.ethContext();
final ProtocolContext protocolContext = final ProtocolContext protocolContext =
new ProtocolContext(localBlockchain, worldStateArchive, null, new BadBlockManager()); new ProtocolContext(
localBlockchain,
worldStateArchive,
mock(ConsensusContext.class),
new BadBlockManager());
final EthTask<BlockHeader> task = final EthTask<BlockHeader> task =
DetermineCommonAncestorTask.create( DetermineCommonAncestorTask.create(

@ -27,6 +27,7 @@ import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times; import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import org.hyperledger.besu.ethereum.ConsensusContext;
import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.ProtocolContext;
import org.hyperledger.besu.ethereum.chain.BadBlockManager; import org.hyperledger.besu.ethereum.chain.BadBlockManager;
import org.hyperledger.besu.ethereum.chain.Blockchain; import org.hyperledger.besu.ethereum.chain.Blockchain;
@ -100,7 +101,11 @@ public class DetermineCommonAncestorTaskTest {
EthProtocolConfiguration.defaultConfig()); EthProtocolConfiguration.defaultConfig());
ethContext = ethProtocolManager.ethContext(); ethContext = ethProtocolManager.ethContext();
protocolContext = protocolContext =
new ProtocolContext(localBlockchain, worldStateArchive, null, new BadBlockManager()); new ProtocolContext(
localBlockchain,
worldStateArchive,
mock(ConsensusContext.class),
new BadBlockManager());
peerTaskExecutor = Mockito.mock(PeerTaskExecutor.class); peerTaskExecutor = Mockito.mock(PeerTaskExecutor.class);
} }

@ -27,6 +27,7 @@ import org.hyperledger.besu.config.GenesisConfigFile;
import org.hyperledger.besu.crypto.KeyPair; import org.hyperledger.besu.crypto.KeyPair;
import org.hyperledger.besu.cryptoservices.NodeKey; import org.hyperledger.besu.cryptoservices.NodeKey;
import org.hyperledger.besu.cryptoservices.NodeKeyUtils; import org.hyperledger.besu.cryptoservices.NodeKeyUtils;
import org.hyperledger.besu.ethereum.ConsensusContext;
import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.ProtocolContext;
import org.hyperledger.besu.ethereum.chain.BadBlockManager; import org.hyperledger.besu.ethereum.chain.BadBlockManager;
import org.hyperledger.besu.ethereum.chain.GenesisState; import org.hyperledger.besu.ethereum.chain.GenesisState;
@ -135,7 +136,8 @@ public class TestNode implements Closeable {
final WorldStateArchive worldStateArchive = createInMemoryWorldStateArchive(); final WorldStateArchive worldStateArchive = createInMemoryWorldStateArchive();
genesisState.writeStateTo(worldStateArchive.getMutable()); genesisState.writeStateTo(worldStateArchive.getMutable());
final ProtocolContext protocolContext = final ProtocolContext protocolContext =
new ProtocolContext(blockchain, worldStateArchive, null, new BadBlockManager()); new ProtocolContext(
blockchain, worldStateArchive, mock(ConsensusContext.class), new BadBlockManager());
final SyncState syncState = mock(SyncState.class); final SyncState syncState = mock(SyncState.class);
final SynchronizerConfiguration syncConfig = mock(SynchronizerConfiguration.class); final SynchronizerConfiguration syncConfig = mock(SynchronizerConfiguration.class);

@ -43,7 +43,6 @@ dependencies {
implementation 'com.google.guava:guava' implementation 'com.google.guava:guava'
implementation 'dnsjava:dnsjava' implementation 'dnsjava:dnsjava'
implementation 'io.netty:netty-transport-native-unix-common' implementation 'io.netty:netty-transport-native-unix-common'
implementation 'io.prometheus:simpleclient'
implementation 'io.vertx:vertx-core' implementation 'io.vertx:vertx-core'
implementation 'io.tmio:tuweni-bytes' implementation 'io.tmio:tuweni-bytes'

@ -27,6 +27,7 @@ import org.hyperledger.besu.ethereum.core.Block;
import org.hyperledger.besu.ethereum.core.BlockBody; import org.hyperledger.besu.ethereum.core.BlockBody;
import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.core.BlockHeaderFunctions; import org.hyperledger.besu.ethereum.core.BlockHeaderFunctions;
import org.hyperledger.besu.ethereum.core.ConsensusContextFixture;
import org.hyperledger.besu.ethereum.core.Difficulty; import org.hyperledger.besu.ethereum.core.Difficulty;
import org.hyperledger.besu.ethereum.core.InMemoryKeyValueStorageProvider; import org.hyperledger.besu.ethereum.core.InMemoryKeyValueStorageProvider;
import org.hyperledger.besu.ethereum.core.MutableWorldState; import org.hyperledger.besu.ethereum.core.MutableWorldState;
@ -108,7 +109,11 @@ public class BlockchainReferenceTestCaseSpec {
this.blockchain = buildBlockchain(genesisBlockHeader); this.blockchain = buildBlockchain(genesisBlockHeader);
this.sealEngine = sealEngine; this.sealEngine = sealEngine;
this.protocolContext = this.protocolContext =
new ProtocolContext(this.blockchain, this.worldStateArchive, null, new BadBlockManager()); new ProtocolContext(
this.blockchain,
this.worldStateArchive,
new ConsensusContextFixture(),
new BadBlockManager());
} }
public String getNetwork() { public String getNetwork() {

@ -57,6 +57,7 @@ dependencies {
implementation 'io.prometheus:simpleclient' implementation 'io.prometheus:simpleclient'
implementation 'io.prometheus:simpleclient_common' implementation 'io.prometheus:simpleclient_common'
implementation 'io.prometheus:simpleclient_guava'
implementation 'io.prometheus:simpleclient_hotspot' implementation 'io.prometheus:simpleclient_hotspot'
implementation 'io.prometheus:simpleclient_pushgateway' implementation 'io.prometheus:simpleclient_pushgateway'
implementation 'io.vertx:vertx-core' implementation 'io.vertx:vertx-core'

@ -17,42 +17,25 @@ package org.hyperledger.besu.metrics;
import org.hyperledger.besu.plugin.services.MetricsSystem; import org.hyperledger.besu.plugin.services.MetricsSystem;
import org.hyperledger.besu.plugin.services.metrics.MetricCategory; import org.hyperledger.besu.plugin.services.metrics.MetricCategory;
import java.util.Set;
import java.util.stream.Stream; import java.util.stream.Stream;
/** The interface Observable metrics system. */ /** The observable metrics system is used to inspect metrics for debug reasons */
public interface ObservableMetricsSystem extends MetricsSystem { public interface ObservableMetricsSystem extends MetricsSystem {
/** /**
* Stream observations. * Stream observations by category
* *
* @param category the category * @param category the category
* @return the stream * @return the observations stream
*/ */
Stream<Observation> streamObservations(MetricCategory category); Stream<Observation> streamObservations(MetricCategory category);
/** /**
* Stream observations. * Stream observations
* *
* @return the stream * @return the observations stream
*/ */
Stream<Observation> streamObservations(); Stream<Observation> streamObservations();
/** /** Unregister all the collectors and perform other cleanup tasks */
* Provides an immutable view into the metric categories enabled for metric collection. void shutdown();
*
* @return the set of enabled metric categories.
*/
Set<MetricCategory> getEnabledCategories();
/**
* Checks if a particular category of metrics is enabled.
*
* @param category the category to check
* @return true if the category is enabled, false otherwise
*/
default boolean isCategoryEnabled(final MetricCategory category) {
return getEnabledCategories().stream()
.anyMatch(metricCategory -> metricCategory.getName().equals(category.getName()));
}
} }

@ -17,6 +17,7 @@ package org.hyperledger.besu.metrics.noop;
import org.hyperledger.besu.metrics.ObservableMetricsSystem; import org.hyperledger.besu.metrics.ObservableMetricsSystem;
import org.hyperledger.besu.metrics.Observation; import org.hyperledger.besu.metrics.Observation;
import org.hyperledger.besu.plugin.services.metrics.Counter; import org.hyperledger.besu.plugin.services.metrics.Counter;
import org.hyperledger.besu.plugin.services.metrics.ExternalSummary;
import org.hyperledger.besu.plugin.services.metrics.LabelledGauge; import org.hyperledger.besu.plugin.services.metrics.LabelledGauge;
import org.hyperledger.besu.plugin.services.metrics.LabelledMetric; import org.hyperledger.besu.plugin.services.metrics.LabelledMetric;
import org.hyperledger.besu.plugin.services.metrics.MetricCategory; import org.hyperledger.besu.plugin.services.metrics.MetricCategory;
@ -27,9 +28,11 @@ import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.function.DoubleSupplier; import java.util.function.DoubleSupplier;
import java.util.function.Supplier;
import java.util.stream.Stream; import java.util.stream.Stream;
import com.google.common.base.Preconditions; import com.google.common.base.Preconditions;
import com.google.common.cache.Cache;
/** The NoOp metrics system. */ /** The NoOp metrics system. */
public class NoOpMetricsSystem implements ObservableMetricsSystem { public class NoOpMetricsSystem implements ObservableMetricsSystem {
@ -113,6 +116,13 @@ public class NoOpMetricsSystem implements ObservableMetricsSystem {
return getOperationTimerLabelledMetric(labelNames.length); return getOperationTimerLabelledMetric(labelNames.length);
} }
@Override
public void trackExternalSummary(
final MetricCategory category,
final String name,
final String help,
final Supplier<ExternalSummary> summarySupplier) {}
@Override @Override
public LabelledMetric<OperationTimer> createLabelledTimer( public LabelledMetric<OperationTimer> createLabelledTimer(
final MetricCategory category, final MetricCategory category,
@ -144,6 +154,10 @@ public class NoOpMetricsSystem implements ObservableMetricsSystem {
final String help, final String help,
final DoubleSupplier valueSupplier) {} final DoubleSupplier valueSupplier) {}
@Override
public void createGuavaCacheCollector(
final MetricCategory category, final String name, final Cache<?, ?> cache) {}
@Override @Override
public LabelledGauge createLabelledGauge( public LabelledGauge createLabelledGauge(
final MetricCategory category, final MetricCategory category,
@ -187,6 +201,9 @@ public class NoOpMetricsSystem implements ObservableMetricsSystem {
return Collections.emptySet(); return Collections.emptySet();
} }
@Override
public void shutdown() {}
/** /**
* The Label counting NoOp metric. * The Label counting NoOp metric.
* *

@ -20,6 +20,7 @@ import org.hyperledger.besu.metrics.Observation;
import org.hyperledger.besu.metrics.StandardMetricCategory; import org.hyperledger.besu.metrics.StandardMetricCategory;
import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem;
import org.hyperledger.besu.plugin.services.metrics.Counter; import org.hyperledger.besu.plugin.services.metrics.Counter;
import org.hyperledger.besu.plugin.services.metrics.ExternalSummary;
import org.hyperledger.besu.plugin.services.metrics.LabelledGauge; import org.hyperledger.besu.plugin.services.metrics.LabelledGauge;
import org.hyperledger.besu.plugin.services.metrics.LabelledMetric; import org.hyperledger.besu.plugin.services.metrics.LabelledMetric;
import org.hyperledger.besu.plugin.services.metrics.MetricCategory; import org.hyperledger.besu.plugin.services.metrics.MetricCategory;
@ -40,9 +41,11 @@ import java.util.Set;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.function.DoubleSupplier; import java.util.function.DoubleSupplier;
import java.util.function.Supplier;
import java.util.stream.Stream; import java.util.stream.Stream;
import javax.inject.Singleton; import javax.inject.Singleton;
import com.google.common.cache.Cache;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.common.Attributes;
@ -242,6 +245,13 @@ public class OpenTelemetrySystem implements ObservableMetricsSystem {
return createLabelledTimer(category, name, help, labelNames); return createLabelledTimer(category, name, help, labelNames);
} }
@Override
public void trackExternalSummary(
final MetricCategory category,
final String name,
final String help,
final Supplier<ExternalSummary> summarySupplier) {}
@Override @Override
public LabelledMetric<OperationTimer> createLabelledTimer( public LabelledMetric<OperationTimer> createLabelledTimer(
final MetricCategory category, final MetricCategory category,
@ -277,6 +287,10 @@ public class OpenTelemetrySystem implements ObservableMetricsSystem {
} }
} }
@Override
public void createGuavaCacheCollector(
final MetricCategory category, final String name, final Cache<?, ?> cache) {}
@Override @Override
public LabelledGauge createLabelledGauge( public LabelledGauge createLabelledGauge(
final MetricCategory category, final MetricCategory category,
@ -376,6 +390,7 @@ public class OpenTelemetrySystem implements ObservableMetricsSystem {
} }
/** Shuts down the OpenTelemetry exporters, blocking until they have completed orderly. */ /** Shuts down the OpenTelemetry exporters, blocking until they have completed orderly. */
@Override
public void shutdown() { public void shutdown() {
final CompletableResultCode result = final CompletableResultCode result =
CompletableResultCode.ofAll( CompletableResultCode.ofAll(

@ -18,6 +18,7 @@ import org.hyperledger.besu.metrics.ObservableMetricsSystem;
import org.hyperledger.besu.metrics.Observation; import org.hyperledger.besu.metrics.Observation;
import org.hyperledger.besu.metrics.StandardMetricCategory; import org.hyperledger.besu.metrics.StandardMetricCategory;
import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem;
import org.hyperledger.besu.plugin.services.metrics.ExternalSummary;
import org.hyperledger.besu.plugin.services.metrics.LabelledGauge; import org.hyperledger.besu.plugin.services.metrics.LabelledGauge;
import org.hyperledger.besu.plugin.services.metrics.LabelledMetric; import org.hyperledger.besu.plugin.services.metrics.LabelledMetric;
import org.hyperledger.besu.plugin.services.metrics.MetricCategory; import org.hyperledger.besu.plugin.services.metrics.MetricCategory;
@ -34,6 +35,7 @@ import java.util.function.DoubleSupplier;
import java.util.function.Supplier; import java.util.function.Supplier;
import java.util.stream.Stream; import java.util.stream.Stream;
import com.google.common.cache.Cache;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import io.prometheus.client.Collector; import io.prometheus.client.Collector;
import io.prometheus.client.Collector.MetricFamilySamples; import io.prometheus.client.Collector.MetricFamilySamples;
@ -42,6 +44,7 @@ import io.prometheus.client.CollectorRegistry;
import io.prometheus.client.Counter; import io.prometheus.client.Counter;
import io.prometheus.client.Histogram; import io.prometheus.client.Histogram;
import io.prometheus.client.Summary; import io.prometheus.client.Summary;
import io.prometheus.client.guava.cache.CacheMetricsCollector;
import io.prometheus.client.hotspot.BufferPoolsExports; import io.prometheus.client.hotspot.BufferPoolsExports;
import io.prometheus.client.hotspot.ClassLoadingExports; import io.prometheus.client.hotspot.ClassLoadingExports;
import io.prometheus.client.hotspot.GarbageCollectorExports; import io.prometheus.client.hotspot.GarbageCollectorExports;
@ -52,6 +55,7 @@ import io.vertx.core.impl.ConcurrentHashSet;
/** The Prometheus metrics system. */ /** The Prometheus metrics system. */
public class PrometheusMetricsSystem implements ObservableMetricsSystem { public class PrometheusMetricsSystem implements ObservableMetricsSystem {
private static final List<String> EXTERNAL_SUMMARY_LABELS = List.of("quantile");
private final Map<MetricCategory, Collection<Collector>> collectors = new ConcurrentHashMap<>(); private final Map<MetricCategory, Collection<Collector>> collectors = new ConcurrentHashMap<>();
private final CollectorRegistry registry = new CollectorRegistry(true); private final CollectorRegistry registry = new CollectorRegistry(true);
@ -60,6 +64,9 @@ public class PrometheusMetricsSystem implements ObservableMetricsSystem {
private final Map<String, LabelledMetric<OperationTimer>> cachedTimers = private final Map<String, LabelledMetric<OperationTimer>> cachedTimers =
new ConcurrentHashMap<>(); new ConcurrentHashMap<>();
private final Set<String> totalSuffixedCounters = new ConcurrentHashSet<>(); private final Set<String> totalSuffixedCounters = new ConcurrentHashSet<>();
private final Map<MetricCategory, CacheMetricsCollector> guavaCacheCollectors =
new ConcurrentHashMap<>();
private final Set<String> guavaCacheNames = new ConcurrentHashSet<>();
private final Set<MetricCategory> enabledCategories; private final Set<MetricCategory> enabledCategories;
private final boolean timersEnabled; private final boolean timersEnabled;
@ -78,12 +85,16 @@ public class PrometheusMetricsSystem implements ObservableMetricsSystem {
/** Init. */ /** Init. */
public void init() { public void init() {
addCollector(StandardMetricCategory.PROCESS, StandardExports::new); if (isCategoryEnabled(StandardMetricCategory.PROCESS)) {
addCollector(StandardMetricCategory.JVM, MemoryPoolsExports::new); registerCollector(StandardMetricCategory.PROCESS, new StandardExports());
addCollector(StandardMetricCategory.JVM, BufferPoolsExports::new); }
addCollector(StandardMetricCategory.JVM, GarbageCollectorExports::new); if (isCategoryEnabled(StandardMetricCategory.JVM)) {
addCollector(StandardMetricCategory.JVM, ThreadExports::new); registerCollector(StandardMetricCategory.JVM, new MemoryPoolsExports());
addCollector(StandardMetricCategory.JVM, ClassLoadingExports::new); registerCollector(StandardMetricCategory.JVM, new BufferPoolsExports());
registerCollector(StandardMetricCategory.JVM, new GarbageCollectorExports());
registerCollector(StandardMetricCategory.JVM, new ThreadExports());
registerCollector(StandardMetricCategory.JVM, new ClassLoadingExports());
}
} }
@Override @Override
@ -103,7 +114,7 @@ public class PrometheusMetricsSystem implements ObservableMetricsSystem {
(k) -> { (k) -> {
if (isCategoryEnabled(category)) { if (isCategoryEnabled(category)) {
final Counter counter = Counter.build(metricName, help).labelNames(labelNames).create(); final Counter counter = Counter.build(metricName, help).labelNames(labelNames).create();
addCollectorUnchecked(category, counter); registerCollector(category, counter);
return new PrometheusCounter(counter); return new PrometheusCounter(counter);
} else { } else {
return NoOpMetricsSystem.getCounterLabelledMetric(labelNames.length); return NoOpMetricsSystem.getCounterLabelledMetric(labelNames.length);
@ -132,7 +143,7 @@ public class PrometheusMetricsSystem implements ObservableMetricsSystem {
.quantile(1.0, 0) .quantile(1.0, 0)
.labelNames(labelNames) .labelNames(labelNames)
.create(); .create();
addCollectorUnchecked(category, summary); registerCollector(category, summary);
return new PrometheusTimer(summary); return new PrometheusTimer(summary);
} else { } else {
return NoOpMetricsSystem.getOperationTimerLabelledMetric(labelNames.length); return NoOpMetricsSystem.getOperationTimerLabelledMetric(labelNames.length);
@ -153,7 +164,7 @@ public class PrometheusMetricsSystem implements ObservableMetricsSystem {
if (timersEnabled && isCategoryEnabled(category)) { if (timersEnabled && isCategoryEnabled(category)) {
final Histogram histogram = final Histogram histogram =
Histogram.build(metricName, help).labelNames(labelNames).buckets(1D).create(); Histogram.build(metricName, help).labelNames(labelNames).buckets(1D).create();
addCollectorUnchecked(category, histogram); registerCollector(category, histogram);
return new PrometheusSimpleTimer(histogram); return new PrometheusSimpleTimer(histogram);
} else { } else {
return NoOpMetricsSystem.getOperationTimerLabelledMetric(labelNames.length); return NoOpMetricsSystem.getOperationTimerLabelledMetric(labelNames.length);
@ -170,7 +181,61 @@ public class PrometheusMetricsSystem implements ObservableMetricsSystem {
final String metricName = convertToPrometheusName(category, name); final String metricName = convertToPrometheusName(category, name);
if (isCategoryEnabled(category)) { if (isCategoryEnabled(category)) {
final Collector collector = new CurrentValueCollector(metricName, help, valueSupplier); final Collector collector = new CurrentValueCollector(metricName, help, valueSupplier);
addCollectorUnchecked(category, collector); registerCollector(category, collector);
}
}
@Override
public void trackExternalSummary(
final MetricCategory category,
final String name,
final String help,
final Supplier<ExternalSummary> summarySupplier) {
if (isCategoryEnabled(category)) {
final var externalSummaryCollector =
new Collector() {
@Override
public List<MetricFamilySamples> collect() {
final var externalSummary = summarySupplier.get();
final var quantileValues =
externalSummary.quantiles().stream()
.map(
quantile ->
new Sample(
name,
EXTERNAL_SUMMARY_LABELS,
List.of(Double.toString(quantile.quantile())),
quantile.value()))
.toList();
return List.of(
new MetricFamilySamples(
name, Type.SUMMARY, "RocksDB histogram for " + name, quantileValues));
}
};
registerCollector(category, externalSummaryCollector);
}
}
@Override
public void createGuavaCacheCollector(
final MetricCategory category, final String name, final Cache<?, ?> cache) {
if (isCategoryEnabled(category)) {
if (guavaCacheNames.contains(name)) {
throw new IllegalStateException("Cache already registered: " + name);
}
guavaCacheNames.add(name);
final var guavaCacheCollector =
guavaCacheCollectors.computeIfAbsent(
category,
unused -> {
final var cmc = new CacheMetricsCollector();
registerCollector(category, cmc);
return cmc;
});
guavaCacheCollector.addCache(name, cache);
} }
} }
@ -183,46 +248,33 @@ public class PrometheusMetricsSystem implements ObservableMetricsSystem {
final String metricName = convertToPrometheusName(category, name); final String metricName = convertToPrometheusName(category, name);
if (isCategoryEnabled(category)) { if (isCategoryEnabled(category)) {
final PrometheusGauge gauge = new PrometheusGauge(metricName, help, List.of(labelNames)); final PrometheusGauge gauge = new PrometheusGauge(metricName, help, List.of(labelNames));
addCollectorUnchecked(category, gauge); registerCollector(category, gauge);
return gauge; return gauge;
} }
return NoOpMetricsSystem.getLabelledGauge(labelNames.length); return NoOpMetricsSystem.getLabelledGauge(labelNames.length);
} }
/** private void registerCollector(final MetricCategory category, final Collector collector) {
* Add collector. final Collection<Collector> categoryCollectors =
*
* @param category the category
* @param metricSupplier the metric supplier
*/
public void addCollector(
final MetricCategory category, final Supplier<Collector> metricSupplier) {
if (isCategoryEnabled(category)) {
addCollectorUnchecked(category, metricSupplier.get());
}
}
private void addCollectorUnchecked(final MetricCategory category, final Collector metric) {
final Collection<Collector> metrics =
this.collectors.computeIfAbsent( this.collectors.computeIfAbsent(
category, key -> Collections.newSetFromMap(new ConcurrentHashMap<>())); category, key -> Collections.newSetFromMap(new ConcurrentHashMap<>()));
final List<String> newSamples = final List<String> newSamples =
metric.collect().stream().map(metricFamilySamples -> metricFamilySamples.name).toList(); collector.collect().stream().map(metricFamilySamples -> metricFamilySamples.name).toList();
metrics.stream() categoryCollectors.stream()
.filter( .filter(
collector -> c ->
collector.collect().stream() c.collect().stream()
.anyMatch(metricFamilySamples -> newSamples.contains(metricFamilySamples.name))) .anyMatch(metricFamilySamples -> newSamples.contains(metricFamilySamples.name)))
.findFirst() .findFirst()
.ifPresent( .ifPresent(
collector -> { c -> {
metrics.remove(collector); categoryCollectors.remove(c);
registry.unregister(collector); registry.unregister(c);
}); });
metrics.add(metric.register(registry)); categoryCollectors.add(collector.register(registry));
} }
@Override @Override
@ -237,6 +289,16 @@ public class PrometheusMetricsSystem implements ObservableMetricsSystem {
return collectors.keySet().stream().flatMap(this::streamObservations); return collectors.keySet().stream().flatMap(this::streamObservations);
} }
@Override
public void shutdown() {
registry.clear();
collectors.clear();
cachedCounters.clear();
cachedTimers.clear();
guavaCacheCollectors.clear();
guavaCacheNames.clear();
}
private Stream<Observation> convertSamplesToObservations( private Stream<Observation> convertSamplesToObservations(
final MetricCategory category, final MetricFamilySamples familySamples) { final MetricCategory category, final MetricFamilySamples familySamples) {
return familySamples.samples.stream() return familySamples.samples.stream()

@ -18,6 +18,7 @@ import static java.util.Arrays.asList;
import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem;
import org.hyperledger.besu.plugin.services.metrics.Counter; import org.hyperledger.besu.plugin.services.metrics.Counter;
import org.hyperledger.besu.plugin.services.metrics.ExternalSummary;
import org.hyperledger.besu.plugin.services.metrics.LabelledGauge; import org.hyperledger.besu.plugin.services.metrics.LabelledGauge;
import org.hyperledger.besu.plugin.services.metrics.LabelledMetric; import org.hyperledger.besu.plugin.services.metrics.LabelledMetric;
import org.hyperledger.besu.plugin.services.metrics.MetricCategory; import org.hyperledger.besu.plugin.services.metrics.MetricCategory;
@ -29,8 +30,11 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.function.DoubleSupplier; import java.util.function.DoubleSupplier;
import java.util.function.Supplier;
import java.util.stream.Stream; import java.util.stream.Stream;
import com.google.common.cache.Cache;
public class StubMetricsSystem implements ObservableMetricsSystem { public class StubMetricsSystem implements ObservableMetricsSystem {
private final Map<String, StubLabelledCounter> counters = new HashMap<>(); private final Map<String, StubLabelledCounter> counters = new HashMap<>();
@ -84,6 +88,13 @@ public class StubMetricsSystem implements ObservableMetricsSystem {
return labelValues -> NoOpMetricsSystem.NO_OP_OPERATION_TIMER; return labelValues -> NoOpMetricsSystem.NO_OP_OPERATION_TIMER;
} }
@Override
public void trackExternalSummary(
final MetricCategory category,
final String name,
final String help,
final Supplier<ExternalSummary> summarySupplier) {}
@Override @Override
public void createGauge( public void createGauge(
final MetricCategory category, final MetricCategory category,
@ -93,6 +104,10 @@ public class StubMetricsSystem implements ObservableMetricsSystem {
gauges.put(name, valueSupplier); gauges.put(name, valueSupplier);
} }
@Override
public void createGuavaCacheCollector(
final MetricCategory category, final String name, final Cache<?, ?> cache) {}
public double getGaugeValue(final String name) { public double getGaugeValue(final String name) {
final DoubleSupplier gauge = gauges.get(name); final DoubleSupplier gauge = gauges.get(name);
if (gauge == null) { if (gauge == null) {
@ -116,6 +131,12 @@ public class StubMetricsSystem implements ObservableMetricsSystem {
return Collections.emptySet(); return Collections.emptySet();
} }
@Override
public void shutdown() {
counters.clear();
gauges.clear();
}
public static class StubLabelledCounter implements LabelledMetric<Counter> { public static class StubLabelledCounter implements LabelledMetric<Counter> {
private final Map<List<String>, StubCounter> metrics = new HashMap<>(); private final Map<List<String>, StubCounter> metrics = new HashMap<>();

@ -40,7 +40,5 @@ dependencies {
implementation project(':metrics:core') implementation project(':metrics:core')
implementation project(':plugin-api') implementation project(':plugin-api')
implementation 'com.google.guava:guava'
implementation 'io.prometheus:simpleclient'
implementation 'org.rocksdb:rocksdbjni' implementation 'org.rocksdb:rocksdbjni'
} }

@ -16,15 +16,14 @@ package org.hyperledger.besu.metrics.rocksdb;
import static org.hyperledger.besu.metrics.BesuMetricCategory.KVSTORE_ROCKSDB_STATS; import static org.hyperledger.besu.metrics.BesuMetricCategory.KVSTORE_ROCKSDB_STATS;
import org.hyperledger.besu.metrics.prometheus.PrometheusMetricsSystem; import org.hyperledger.besu.plugin.services.MetricsSystem;
import org.hyperledger.besu.plugin.services.metrics.ExternalSummary;
import org.hyperledger.besu.plugin.services.metrics.ExternalSummary.Quantile;
import org.hyperledger.besu.plugin.services.metrics.MetricCategory; import org.hyperledger.besu.plugin.services.metrics.MetricCategory;
import java.util.Arrays;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import io.prometheus.client.Collector;
import org.rocksdb.HistogramData; import org.rocksdb.HistogramData;
import org.rocksdb.HistogramType; import org.rocksdb.HistogramType;
import org.rocksdb.Statistics; import org.rocksdb.Statistics;
@ -32,22 +31,9 @@ import org.rocksdb.TickerType;
/** The Rocks db stats. */ /** The Rocks db stats. */
public class RocksDBStats { public class RocksDBStats {
/** The constant TICKER_TYPES. */
/** The Labels. */
static final List<String> LABELS = Collections.singletonList("quantile");
/** The Label 50. */
static final List<String> LABEL_50 = Collections.singletonList("0.5");
/** The Label 95. */
static final List<String> LABEL_95 = Collections.singletonList("0.95");
/** The Label 99. */
static final List<String> LABEL_99 = Collections.singletonList("0.99");
/** The constant TICKERS. */
// Tickers - RocksDB equivalent of counters // Tickers - RocksDB equivalent of counters
static final TickerType[] TICKERS = { static final TickerType[] TICKER_TYPES = {
TickerType.BLOCK_CACHE_ADD, TickerType.BLOCK_CACHE_ADD,
TickerType.BLOCK_CACHE_HIT, TickerType.BLOCK_CACHE_HIT,
TickerType.BLOCK_CACHE_ADD_FAILURES, TickerType.BLOCK_CACHE_ADD_FAILURES,
@ -133,9 +119,9 @@ public class RocksDBStats {
TickerType.NUMBER_MULTIGET_KEYS_FOUND, TickerType.NUMBER_MULTIGET_KEYS_FOUND,
}; };
/** The constant HISTOGRAMS. */ /** The constant HISTOGRAM_TYPES. */
// Histograms - treated as prometheus summaries // Histograms - treated as prometheus summaries
static final HistogramType[] HISTOGRAMS = { static final HistogramType[] HISTOGRAM_TYPES = {
HistogramType.DB_GET, HistogramType.DB_GET,
HistogramType.DB_WRITE, HistogramType.DB_WRITE,
HistogramType.COMPACTION_TIME, HistogramType.COMPACTION_TIME,
@ -175,47 +161,40 @@ public class RocksDBStats {
* @param category the category * @param category the category
*/ */
public static void registerRocksDBMetrics( public static void registerRocksDBMetrics(
final Statistics stats, final Statistics stats, final MetricsSystem metricsSystem, final MetricCategory category) {
final PrometheusMetricsSystem metricsSystem,
final MetricCategory category) { for (final var tickerType : TICKER_TYPES) {
if (!metricsSystem.isCategoryEnabled(category)) { final String promCounterName = tickerType.name().toLowerCase(Locale.ROOT);
return;
}
for (final TickerType ticker : TICKERS) {
final String promCounterName = ticker.name().toLowerCase(Locale.ROOT);
metricsSystem.createLongGauge( metricsSystem.createLongGauge(
category, category,
promCounterName, promCounterName,
"RocksDB reported statistics for " + ticker.name(), "RocksDB reported statistics for " + tickerType.name(),
() -> stats.getTickerCount(ticker)); () -> stats.getTickerCount(tickerType));
} }
for (final HistogramType histogram : HISTOGRAMS) { for (final var histogramType : HISTOGRAM_TYPES) {
metricsSystem.addCollector(category, () -> histogramToCollector(stats, histogram));
metricsSystem.trackExternalSummary(
KVSTORE_ROCKSDB_STATS,
KVSTORE_ROCKSDB_STATS.getName() + "_" + histogramType.name().toLowerCase(Locale.ROOT),
"RocksDB histogram for " + histogramType.name(),
() -> provideExternalSummary(stats, histogramType));
} }
} }
private static Collector histogramToCollector( private static ExternalSummary provideExternalSummary(
final Statistics stats, final HistogramType histogram) { final Statistics stats, final HistogramType histogramType) {
return new Collector() {
final String metricName =
KVSTORE_ROCKSDB_STATS.getName() + "_" + histogram.name().toLowerCase(Locale.ROOT);
@Override final HistogramData data = stats.getHistogramData(histogramType);
public List<MetricFamilySamples> collect() {
final HistogramData data = stats.getHistogramData(histogram); return new ExternalSummary(
return Collections.singletonList( data.getCount(),
new MetricFamilySamples( data.getSum(),
metricName, List.of(
Type.SUMMARY, new Quantile(0.0, data.getMin()),
"RocksDB histogram for " + metricName, new Quantile(0.5, data.getMedian()),
Arrays.asList( new Quantile(0.95, data.getPercentile95()),
new MetricFamilySamples.Sample(metricName, LABELS, LABEL_50, data.getMedian()), new Quantile(0.99, data.getPercentile99()),
new MetricFamilySamples.Sample( new Quantile(1.0, data.getMax())));
metricName, LABELS, LABEL_95, data.getPercentile95()),
new MetricFamilySamples.Sample(
metricName, LABELS, LABEL_99, data.getPercentile99()))));
}
};
} }
} }

@ -71,7 +71,7 @@ Calculated : ${currentHash}
tasks.register('checkAPIChanges', FileStateChecker) { tasks.register('checkAPIChanges', FileStateChecker) {
description = "Checks that the API for the Plugin-API project does not change without deliberate thought" description = "Checks that the API for the Plugin-API project does not change without deliberate thought"
files = sourceSets.main.allJava.files files = sourceSets.main.allJava.files
knownHash = '8rPIE3fYl48RPRQXxYhMk559e/r+wHSKU9bGSJmruKQ=' knownHash = 'aYWbsgPoKTGDgq9d4QUBvQEaZYbKNJGMiBufzyKnusA='
} }
check.dependsOn('checkAPIChanges') check.dependsOn('checkAPIChanges')

@ -15,14 +15,19 @@
package org.hyperledger.besu.plugin.services; package org.hyperledger.besu.plugin.services;
import org.hyperledger.besu.plugin.services.metrics.Counter; import org.hyperledger.besu.plugin.services.metrics.Counter;
import org.hyperledger.besu.plugin.services.metrics.ExternalSummary;
import org.hyperledger.besu.plugin.services.metrics.LabelledGauge; import org.hyperledger.besu.plugin.services.metrics.LabelledGauge;
import org.hyperledger.besu.plugin.services.metrics.LabelledMetric; import org.hyperledger.besu.plugin.services.metrics.LabelledMetric;
import org.hyperledger.besu.plugin.services.metrics.MetricCategory; import org.hyperledger.besu.plugin.services.metrics.MetricCategory;
import org.hyperledger.besu.plugin.services.metrics.OperationTimer; import org.hyperledger.besu.plugin.services.metrics.OperationTimer;
import java.util.Set;
import java.util.function.DoubleSupplier; import java.util.function.DoubleSupplier;
import java.util.function.IntSupplier; import java.util.function.IntSupplier;
import java.util.function.LongSupplier; import java.util.function.LongSupplier;
import java.util.function.Supplier;
import com.google.common.cache.Cache;
/** An interface for creating various Metrics components. */ /** An interface for creating various Metrics components. */
public interface MetricsSystem extends BesuService { public interface MetricsSystem extends BesuService {
@ -159,4 +164,45 @@ public interface MetricsSystem extends BesuService {
final LongSupplier valueSupplier) { final LongSupplier valueSupplier) {
createGauge(category, name, help, () -> (double) valueSupplier.getAsLong()); createGauge(category, name, help, () -> (double) valueSupplier.getAsLong());
} }
/**
* Track a summary that is computed externally to this metric system. Useful when existing
* libraries calculate the summary data on their own, and we want to export that summary via the
* configured metric system. A notable example are RocksDB statistics.
*
* @param category The {@link MetricCategory} this external summary is assigned to.
* @param name A name for the metric.
* @param help A human readable description of the metric.
* @param summarySupplier A supplier to retrieve the summary data when needed.
*/
void trackExternalSummary(
MetricCategory category, String name, String help, Supplier<ExternalSummary> summarySupplier);
/**
* Collect metrics from Guava cache.
*
* @param category The {@link MetricCategory} this Guava cache is assigned to.
* @param name the name to identify this Guava cache, must be unique.
* @param cache the Guava cache
*/
void createGuavaCacheCollector(MetricCategory category, String name, Cache<?, ?> cache);
/**
* Provides an immutable view into the metric categories enabled for metric collection.
*
* @return the set of enabled metric categories.
*/
Set<MetricCategory> getEnabledCategories();
/**
* Checks if a particular category of metrics is enabled.
*
* @param category the category to check
* @return true if the category is enabled, false otherwise
*/
default boolean isCategoryEnabled(final MetricCategory category) {
return getEnabledCategories().stream()
.map(MetricCategory::getName)
.anyMatch(category.getName()::equals);
}
} }

@ -0,0 +1,36 @@
/*
* Copyright contributors to Besu.
*
* 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.metrics;
import java.util.List;
/**
* Record of summary data the is kept outside the metric system. Useful when existing libraries
* calculate the summary data on their own, and we want to export that summary via the configured
* metric system. A notable example are RocksDB statistics.
*
* @param count the number of observations
* @param sum the sum of all the observations
* @param quantiles a list of quantiles with values
*/
public record ExternalSummary(long count, double sum, List<Quantile> quantiles) {
/**
* Represent a single quantile and its value
*
* @param quantile the quantile
* @param value the value
*/
public record Quantile(double quantile, double value) {}
}

@ -46,7 +46,6 @@ dependencies {
implementation 'com.google.guava:guava' implementation 'com.google.guava:guava'
implementation 'info.picocli:picocli' implementation 'info.picocli:picocli'
implementation 'io.opentelemetry:opentelemetry-api' implementation 'io.opentelemetry:opentelemetry-api'
implementation 'io.prometheus:simpleclient'
implementation 'io.tmio:tuweni-bytes' implementation 'io.tmio:tuweni-bytes'
implementation 'org.rocksdb:rocksdbjni' implementation 'org.rocksdb:rocksdbjni'
implementation project(path: ':ethereum:core') implementation project(path: ':ethereum:core')

@ -15,7 +15,6 @@
package org.hyperledger.besu.plugin.services.storage.rocksdb; package org.hyperledger.besu.plugin.services.storage.rocksdb;
import org.hyperledger.besu.metrics.BesuMetricCategory; import org.hyperledger.besu.metrics.BesuMetricCategory;
import org.hyperledger.besu.metrics.prometheus.PrometheusMetricsSystem;
import org.hyperledger.besu.metrics.rocksdb.RocksDBStats; import org.hyperledger.besu.metrics.rocksdb.RocksDBStats;
import org.hyperledger.besu.plugin.services.MetricsSystem; import org.hyperledger.besu.plugin.services.MetricsSystem;
import org.hyperledger.besu.plugin.services.metrics.Counter; import org.hyperledger.besu.plugin.services.metrics.Counter;
@ -107,10 +106,7 @@ public class RocksDBMetricsFactory {
"database") "database")
.labels(rocksDbConfiguration.getLabel()); .labels(rocksDbConfiguration.getLabel());
if (metricsSystem instanceof PrometheusMetricsSystem) { RocksDBStats.registerRocksDBMetrics(stats, metricsSystem, statsDbMetricCategory);
RocksDBStats.registerRocksDBMetrics(
stats, (PrometheusMetricsSystem) metricsSystem, statsDbMetricCategory);
}
metricsSystem.createLongGauge( metricsSystem.createLongGauge(
rocksDbMetricCategory, rocksDbMetricCategory,

Loading…
Cancel
Save