diff --git a/CHANGELOG.md b/CHANGELOG.md index f0c28640f..286d3ecb9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,24 @@ # Changelog ## Unreleased +### Breaking Changes +### Upcoming Breaking Changes +- `MetricSystem::createLabelledGauge` is deprecated and will be removed in a future release, replace it with `MetricSystem::createLabelledSuppliedGauge` +- k8s (KUBERNETES) Nat method is now deprecated and will be removed in a future release. Use docker or none instead. +- `--Xsnapsync-synchronizer-flat-db-healing-enabled` is deprecated, use `--Xbonsai-full-flat-db-enabled` instead. +- `--Xbonsai-limit-trie-logs-enabled` is deprecated, use `--bonsai-limit-trie-logs-enabled` instead. +- `--Xbonsai-trie-log-pruning-enabled` is deprecated, use `--bonsai-limit-trie-logs-enabled` instead. +- `--Xbonsai-trie-logs-pruning-window-size` is deprecated, use `--bonsai-trie-logs-pruning-window-size` instead. +- Sunsetting features - for more context on the reasoning behind the deprecation of these features, including alternative options, read [this blog post](https://www.lfdecentralizedtrust.org/blog/sunsetting-tessera-and-simplifying-hyperledger-besu) + - Tessera privacy + - Smart-contract-based (onchain) permissioning + - Proof of Work consensus + - Fast Sync +### Additions and Improvements +### Bug fixes + +## 25.2.0 + ### Breaking Changes - `rpc-gas-cap` default value has changed from 0 (unlimited) to 50M. If you require `rpc-gas-cap` greater than 50M, you'll need to set that explicitly. [#8251](https://github.com/hyperledger/besu/issues/8251) ### Upcoming Breaking Changes @@ -28,6 +46,7 @@ ### Bug fixes - Fix the simulation of txs with a future nonce [#8215](https://github.com/hyperledger/besu/pull/8215) +- Bump to besu-native 1.1.2 for ubuntu 20.04 native support[#8264](https://github.com/hyperledger/besu/pull/8264) ## 25.1.0 diff --git a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/account/Account.java b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/account/Account.java index 6cdd53fbe..1251d0864 100644 --- a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/account/Account.java +++ b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/account/Account.java @@ -78,7 +78,7 @@ public class Account { return new Account(eth, name, SIGNATURE_ALGORITHM.get().generateKeyPair()); } - static Account fromPrivateKey( + public static Account fromPrivateKey( final EthTransactions eth, final String name, final String privateKey) { return new Account( eth, diff --git a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/BesuNode.java b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/BesuNode.java index 3f18a5431..0724ee51a 100644 --- a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/BesuNode.java +++ b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/BesuNode.java @@ -35,6 +35,7 @@ import org.hyperledger.besu.ethereum.p2p.config.NetworkingConfiguration; import org.hyperledger.besu.ethereum.permissioning.PermissioningConfiguration; import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration; import org.hyperledger.besu.metrics.prometheus.MetricsConfiguration; +import org.hyperledger.besu.plugin.services.storage.KeyValueStorageFactory; import org.hyperledger.besu.tests.acceptance.dsl.condition.Condition; import org.hyperledger.besu.tests.acceptance.dsl.node.configuration.NodeConfiguration; import org.hyperledger.besu.tests.acceptance.dsl.node.configuration.genesis.GenesisConfigurationProvider; @@ -133,6 +134,7 @@ public class BesuNode implements NodeConfiguration, RunnableNode, AutoCloseable private Optional exitCode = Optional.empty(); private final boolean isStrictTxReplayProtectionEnabled; private final Map environment; + private final Optional storageFactory; public BesuNode( final String name, @@ -169,7 +171,8 @@ public class BesuNode implements NodeConfiguration, RunnableNode, AutoCloseable final List runCommand, final Optional keyPair, final boolean isStrictTxReplayProtectionEnabled, - final Map environment) + final Map environment, + final Optional maybeStorageFactory) throws IOException { this.homeDirectory = dataPath.orElseGet(BesuNode::createTmpDataDirectory); this.isStrictTxReplayProtectionEnabled = isStrictTxReplayProtectionEnabled; @@ -211,6 +214,7 @@ public class BesuNode implements NodeConfiguration, RunnableNode, AutoCloseable this.secp256k1Native = secp256k1Native; this.altbn128Native = altbn128Native; this.runCommand = runCommand; + this.storageFactory = maybeStorageFactory; plugins.forEach( pluginName -> { try { @@ -836,4 +840,8 @@ public class BesuNode implements NodeConfiguration, RunnableNode, AutoCloseable public ApiConfiguration getApiConfiguration() { return apiConfiguration; } + + public Optional getStorageFactory() { + return storageFactory; + } } diff --git a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/ThreadBesuNodeRunner.java b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/ThreadBesuNodeRunner.java index b21ff884c..865326e91 100644 --- a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/ThreadBesuNodeRunner.java +++ b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/ThreadBesuNodeRunner.java @@ -75,6 +75,7 @@ import org.hyperledger.besu.plugin.services.TransactionSelectionService; import org.hyperledger.besu.plugin.services.TransactionSimulationService; import org.hyperledger.besu.plugin.services.metrics.MetricCategoryRegistry; import org.hyperledger.besu.plugin.services.mining.MiningService; +import org.hyperledger.besu.plugin.services.storage.KeyValueStorageFactory; import org.hyperledger.besu.plugin.services.storage.rocksdb.RocksDBPlugin; import org.hyperledger.besu.plugin.services.transactionpool.TransactionPoolService; import org.hyperledger.besu.services.BesuConfigurationImpl; @@ -283,6 +284,7 @@ public class ThreadBesuNodeRunner implements BesuNodeRunner { } @Module + @SuppressWarnings("CloseableProvides") static class BesuNodeProviderModule { private final BesuNode toProvide; @@ -413,6 +415,13 @@ public class ThreadBesuNodeRunner implements BesuNodeRunner { return retval; } + @Provides + KeyValueStorageFactory provideKeyValueStorageFactory() { + return toProvide + .getStorageFactory() + .orElse(new InMemoryStoragePlugin.InMemoryKeyValueStorageFactory("memory")); + } + @Provides @Singleton MetricCategoryRegistryImpl provideMetricCategoryRegistry() { @@ -565,14 +574,16 @@ public class ThreadBesuNodeRunner implements BesuNodeRunner { @Provides public KeyValueStorageProvider provideKeyValueStorageProvider( - final BesuConfiguration commonPluginConfiguration, final MetricsSystem metricsSystem) { + final BesuConfiguration commonPluginConfiguration, + final MetricsSystem metricsSystem, + final KeyValueStorageFactory keyValueStorageFactory) { final StorageServiceImpl storageService = new StorageServiceImpl(); - storageService.registerKeyValueStorage( - new InMemoryStoragePlugin.InMemoryKeyValueStorageFactory("memory")); + final KeyValueStorageFactory storageFactory = keyValueStorageFactory; + storageService.registerKeyValueStorage(storageFactory); final KeyValueStorageProvider storageProvider = new KeyValueStorageProviderBuilder() - .withStorageFactory(storageService.getByName("memory").get()) + .withStorageFactory(storageFactory) .withCommonConfiguration(commonPluginConfiguration) .withMetricsSystem(metricsSystem) .build(); diff --git a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/configuration/BesuNodeConfiguration.java b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/configuration/BesuNodeConfiguration.java index f6a8cfb57..9ec9ae340 100644 --- a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/configuration/BesuNodeConfiguration.java +++ b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/configuration/BesuNodeConfiguration.java @@ -28,6 +28,7 @@ import org.hyperledger.besu.ethereum.p2p.config.NetworkingConfiguration; import org.hyperledger.besu.ethereum.permissioning.PermissioningConfiguration; import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration; import org.hyperledger.besu.metrics.prometheus.MetricsConfiguration; +import org.hyperledger.besu.plugin.services.storage.KeyValueStorageFactory; import org.hyperledger.besu.tests.acceptance.dsl.node.configuration.genesis.GenesisConfigurationProvider; import java.nio.file.Path; @@ -72,6 +73,7 @@ public class BesuNodeConfiguration { private final Optional keyPair; private final boolean strictTxReplayProtectionEnabled; private final Map environment; + private final Optional storageFactory; BesuNodeConfiguration( final String name, @@ -108,7 +110,8 @@ public class BesuNodeConfiguration { final List runCommand, final Optional keyPair, final boolean strictTxReplayProtectionEnabled, - final Map environment) { + final Map environment, + final Optional storageFactory) { this.name = name; this.miningConfiguration = miningConfiguration; this.transactionPoolConfiguration = transactionPoolConfiguration; @@ -144,6 +147,7 @@ public class BesuNodeConfiguration { this.keyPair = keyPair; this.strictTxReplayProtectionEnabled = strictTxReplayProtectionEnabled; this.environment = environment; + this.storageFactory = storageFactory; } public String getName() { @@ -285,4 +289,8 @@ public class BesuNodeConfiguration { public Map getEnvironment() { return environment; } + + public Optional storageImplementation() { + return storageFactory; + } } diff --git a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/configuration/BesuNodeConfigurationBuilder.java b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/configuration/BesuNodeConfigurationBuilder.java index f7342a4c8..1222f73b6 100644 --- a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/configuration/BesuNodeConfigurationBuilder.java +++ b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/configuration/BesuNodeConfigurationBuilder.java @@ -38,6 +38,7 @@ import org.hyperledger.besu.ethereum.p2p.config.NetworkingConfiguration; import org.hyperledger.besu.ethereum.permissioning.PermissioningConfiguration; import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration; import org.hyperledger.besu.metrics.prometheus.MetricsConfiguration; +import org.hyperledger.besu.plugin.services.storage.KeyValueStorageFactory; import org.hyperledger.besu.tests.acceptance.dsl.node.configuration.genesis.GenesisConfigurationProvider; import java.io.File; @@ -95,6 +96,7 @@ public class BesuNodeConfigurationBuilder { private Optional keyPair = Optional.empty(); private Boolean strictTxReplayProtectionEnabled = false; private Map environment = new HashMap<>(); + private Optional storageImplementation = Optional.empty(); public BesuNodeConfigurationBuilder() { // Check connections more frequently during acceptance tests to cut down on @@ -459,6 +461,12 @@ public class BesuNodeConfigurationBuilder { return this; } + public BesuNodeConfigurationBuilder storageImplementation( + final KeyValueStorageFactory storageFactory) { + this.storageImplementation = Optional.of(storageFactory); + return this; + } + public BesuNodeConfiguration build() { return new BesuNodeConfiguration( name, @@ -495,6 +503,7 @@ public class BesuNodeConfigurationBuilder { runCommand, keyPair, strictTxReplayProtectionEnabled, - environment); + environment, + storageImplementation); } } diff --git a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/configuration/BesuNodeFactory.java b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/configuration/BesuNodeFactory.java index 3708bcc1a..9974adf6f 100644 --- a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/configuration/BesuNodeFactory.java +++ b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/configuration/BesuNodeFactory.java @@ -83,7 +83,8 @@ public class BesuNodeFactory { config.getRunCommand(), config.getKeyPair(), config.isStrictTxReplayProtectionEnabled(), - config.getEnvironment()); + config.getEnvironment(), + config.storageImplementation()); } public BesuNode createMinerNode( diff --git a/acceptance-tests/tests/build.gradle b/acceptance-tests/tests/build.gradle index b6c388172..126dcb070 100644 --- a/acceptance-tests/tests/build.gradle +++ b/acceptance-tests/tests/build.gradle @@ -52,6 +52,7 @@ dependencies { testImplementation project(':privacy-contracts') testImplementation project(':testutil') testImplementation project(':util') + implementation project(':plugins:rocksdb') testImplementation 'commons-io:commons-io' testImplementation 'io.grpc:grpc-all' diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/bftsoak/BftMiningSoakTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/bftsoak/BftMiningSoakTest.java index 9098fcbb7..7d19a5be0 100644 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/bftsoak/BftMiningSoakTest.java +++ b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/bftsoak/BftMiningSoakTest.java @@ -95,7 +95,7 @@ public class BftMiningSoakTest extends ParameterizedBftTestBase { } catch (RuntimeException e) { assertThat(e.getMessage()) .contains( - "Revert reason: 'Transaction processing could not be completed due to an exception'"); + "Revert reason: 'Transaction processing could not be completed due to an exception (Invalid opcode: 0x5f)'"); } // Should initially be set to 0 diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/bootstrap/ClusterThreadNodeRunnerAcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/bootstrap/ClusterThreadNodeRunnerAcceptanceTest.java index 39cc5ad26..e13fbc2f1 100644 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/bootstrap/ClusterThreadNodeRunnerAcceptanceTest.java +++ b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/bootstrap/ClusterThreadNodeRunnerAcceptanceTest.java @@ -14,7 +14,13 @@ */ package org.hyperledger.besu.tests.acceptance.bootstrap; +import org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier; +import org.hyperledger.besu.plugin.services.storage.KeyValueStorageFactory; +import org.hyperledger.besu.plugin.services.storage.rocksdb.RocksDBKeyValueStorageFactory; +import org.hyperledger.besu.plugin.services.storage.rocksdb.RocksDBMetricsFactory; +import org.hyperledger.besu.plugin.services.storage.rocksdb.configuration.RocksDBCLIOptions; import org.hyperledger.besu.tests.acceptance.dsl.AcceptanceTestBase; +import org.hyperledger.besu.tests.acceptance.dsl.account.Account; import org.hyperledger.besu.tests.acceptance.dsl.node.BesuNode; import org.hyperledger.besu.tests.acceptance.dsl.node.BesuNodeRunner; import org.hyperledger.besu.tests.acceptance.dsl.node.Node; @@ -23,12 +29,14 @@ import org.hyperledger.besu.tests.acceptance.dsl.node.cluster.Cluster; import org.hyperledger.besu.tests.acceptance.dsl.node.cluster.ClusterConfiguration; import org.hyperledger.besu.tests.acceptance.dsl.node.cluster.ClusterConfigurationBuilder; +import java.util.List; + import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; public class ClusterThreadNodeRunnerAcceptanceTest extends AcceptanceTestBase { - private Node fullNode; + private Node miner; private Cluster noDiscoveryCluster; @BeforeEach @@ -38,14 +46,37 @@ public class ClusterThreadNodeRunnerAcceptanceTest extends AcceptanceTestBase { final BesuNodeRunner besuNodeRunner = new ThreadBesuNodeRunner(); noDiscoveryCluster = new Cluster(clusterConfiguration, net, besuNodeRunner); final BesuNode noDiscoveryNode = besu.createNodeWithNoDiscovery("noDiscovery"); - fullNode = besu.createArchiveNode("archive"); - noDiscoveryCluster.start(noDiscoveryNode, fullNode); + miner = + besu.createMinerNode( + "miner", + (builder) -> { + KeyValueStorageFactory persistentStorageFactory = + new RocksDBKeyValueStorageFactory( + RocksDBCLIOptions.create()::toDomainObject, + List.of(KeyValueSegmentIdentifier.values()), + RocksDBMetricsFactory.PUBLIC_ROCKS_DB_METRICS); + builder.storageImplementation(persistentStorageFactory); + return builder; + }); + noDiscoveryCluster.start(noDiscoveryNode, miner); } @Test public void shouldVerifySomething() { // we don't care what verifies, just that it gets to the point something can verify - fullNode.verify(net.awaitPeerCount(0)); + miner.verify(net.awaitPeerCount(0)); + } + + @Test + void shouldMineTransactionsEvenAfterRestart() { + final Account recipient = accounts.createAccount("account1"); + miner.execute(accountTransactions.createTransfer(recipient, 2)); + miner.verify(recipient.balanceEquals(2)); + + noDiscoveryCluster.stop(); + noDiscoveryCluster.start(miner); + // Checking that state is retained after restart + miner.verify(recipient.balanceEquals(2)); } @Override diff --git a/besu/src/main/java/org/hyperledger/besu/controller/MergeBesuControllerBuilder.java b/besu/src/main/java/org/hyperledger/besu/controller/MergeBesuControllerBuilder.java index 2352f9d39..cf99308f3 100644 --- a/besu/src/main/java/org/hyperledger/besu/controller/MergeBesuControllerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/controller/MergeBesuControllerBuilder.java @@ -59,6 +59,7 @@ import org.slf4j.LoggerFactory; public class MergeBesuControllerBuilder extends BesuControllerBuilder { private final AtomicReference syncState = new AtomicReference<>(); private static final Logger LOG = LoggerFactory.getLogger(MergeBesuControllerBuilder.class); + private final PostMergeContext postMergeContext = new PostMergeContext(); /** Default constructor. */ public MergeBesuControllerBuilder() {} @@ -198,7 +199,7 @@ public class MergeBesuControllerBuilder extends BesuControllerBuilder { && blockchain.getGenesisBlockHeader().getDifficulty().isZero(); final MergeContext mergeContext = - PostMergeContext.get() + postMergeContext .setSyncState(syncState.get()) .setTerminalTotalDifficulty( genesisConfigOptions @@ -261,7 +262,16 @@ public class MergeBesuControllerBuilder extends BesuControllerBuilder { @Override public BesuController build() { final BesuController controller = super.build(); - PostMergeContext.get().setSyncState(controller.getSyncState()); + postMergeContext.setSyncState(syncState.get()); return controller; } + + /** + * Gets post merge context. + * + * @return the post merge context + */ + public PostMergeContext getPostMergeContext() { + return postMergeContext; + } } diff --git a/besu/src/main/java/org/hyperledger/besu/controller/QbftBesuControllerBuilder.java b/besu/src/main/java/org/hyperledger/besu/controller/QbftBesuControllerBuilder.java index 8a0324560..4675f2021 100644 --- a/besu/src/main/java/org/hyperledger/besu/controller/QbftBesuControllerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/controller/QbftBesuControllerBuilder.java @@ -23,6 +23,7 @@ import org.hyperledger.besu.config.QbftFork; import org.hyperledger.besu.consensus.common.BftValidatorOverrides; import org.hyperledger.besu.consensus.common.EpochManager; import org.hyperledger.besu.consensus.common.ForksSchedule; +import org.hyperledger.besu.consensus.common.bft.BftBlockHashing; import org.hyperledger.besu.consensus.common.bft.BftBlockInterface; import org.hyperledger.besu.consensus.common.bft.BftContext; import org.hyperledger.besu.consensus.common.bft.BftEventQueue; @@ -46,13 +47,18 @@ import org.hyperledger.besu.consensus.common.validator.blockbased.BlockValidator import org.hyperledger.besu.consensus.qbft.QbftExtraDataCodec; import org.hyperledger.besu.consensus.qbft.QbftForksSchedulesFactory; import org.hyperledger.besu.consensus.qbft.QbftProtocolScheduleBuilder; +import org.hyperledger.besu.consensus.qbft.adaptor.BftEventHandlerAdaptor; import org.hyperledger.besu.consensus.qbft.adaptor.BlockUtil; import org.hyperledger.besu.consensus.qbft.adaptor.QbftBlockCodecAdaptor; import org.hyperledger.besu.consensus.qbft.adaptor.QbftBlockCreatorFactoryAdaptor; +import org.hyperledger.besu.consensus.qbft.adaptor.QbftBlockHashingAdaptor; import org.hyperledger.besu.consensus.qbft.adaptor.QbftBlockInterfaceAdaptor; +import org.hyperledger.besu.consensus.qbft.adaptor.QbftBlockchainAdaptor; import org.hyperledger.besu.consensus.qbft.adaptor.QbftExtraDataProviderAdaptor; import org.hyperledger.besu.consensus.qbft.adaptor.QbftFinalStateImpl; import org.hyperledger.besu.consensus.qbft.adaptor.QbftProtocolScheduleAdaptor; +import org.hyperledger.besu.consensus.qbft.adaptor.QbftValidatorModeTransitionLoggerAdaptor; +import org.hyperledger.besu.consensus.qbft.adaptor.QbftValidatorProviderAdaptor; import org.hyperledger.besu.consensus.qbft.blockcreation.QbftBlockCreatorFactory; import org.hyperledger.besu.consensus.qbft.core.network.QbftGossip; import org.hyperledger.besu.consensus.qbft.core.payload.MessageFactory; @@ -62,16 +68,18 @@ import org.hyperledger.besu.consensus.qbft.core.statemachine.QbftRoundFactory; import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockCodec; import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockInterface; import org.hyperledger.besu.consensus.qbft.core.types.QbftContext; +import org.hyperledger.besu.consensus.qbft.core.types.QbftEventHandler; import org.hyperledger.besu.consensus.qbft.core.types.QbftFinalState; import org.hyperledger.besu.consensus.qbft.core.types.QbftMinedBlockObserver; import org.hyperledger.besu.consensus.qbft.core.types.QbftProtocolSchedule; +import org.hyperledger.besu.consensus.qbft.core.types.QbftValidatorProvider; import org.hyperledger.besu.consensus.qbft.core.validation.MessageValidatorFactory; -import org.hyperledger.besu.consensus.qbft.core.validator.ValidatorModeTransitionLogger; import org.hyperledger.besu.consensus.qbft.jsonrpc.QbftJsonRpcMethods; import org.hyperledger.besu.consensus.qbft.protocol.Istanbul100SubProtocol; import org.hyperledger.besu.consensus.qbft.validator.ForkingValidatorProvider; import org.hyperledger.besu.consensus.qbft.validator.TransactionValidatorProvider; import org.hyperledger.besu.consensus.qbft.validator.ValidatorContractController; +import org.hyperledger.besu.consensus.qbft.validator.ValidatorModeTransitionLogger; import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.api.jsonrpc.methods.JsonRpcMethods; @@ -209,9 +217,11 @@ public class QbftBesuControllerBuilder extends BesuControllerBuilder { final ValidatorProvider validatorProvider = protocolContext.getConsensusContext(BftContext.class).getValidatorProvider(); + final QbftValidatorProvider qbftValidatorProvider = + new QbftValidatorProviderAdaptor(validatorProvider); final QbftBlockInterface qbftBlockInterface = new QbftBlockInterfaceAdaptor(bftBlockInterface); - final QbftContext qbftContext = new QbftContext(validatorProvider, qbftBlockInterface); + final QbftContext qbftContext = new QbftContext(qbftValidatorProvider, qbftBlockInterface); final ProtocolContext qbftProtocolContext = new ProtocolContext( blockchain, @@ -267,27 +277,31 @@ public class QbftBesuControllerBuilder extends BesuControllerBuilder { final MessageFactory messageFactory = new MessageFactory(nodeKey, blockEncoder); + QbftRoundFactory qbftRoundFactory = + new QbftRoundFactory( + finalState, + qbftProtocolContext, + qbftProtocolSchedule, + minedBlockObservers, + messageValidatorFactory, + messageFactory, + qbftExtraDataCodec, + new QbftExtraDataProviderAdaptor(qbftExtraDataCodec), + new QbftBlockHashingAdaptor(new BftBlockHashing(qbftExtraDataCodec))); QbftBlockHeightManagerFactory qbftBlockHeightManagerFactory = new QbftBlockHeightManagerFactory( finalState, - new QbftRoundFactory( - finalState, - qbftProtocolContext, - qbftProtocolSchedule, - minedBlockObservers, - messageValidatorFactory, - messageFactory, - qbftExtraDataCodec, - new QbftExtraDataProviderAdaptor(qbftExtraDataCodec)), + qbftRoundFactory, messageValidatorFactory, messageFactory, - new ValidatorModeTransitionLogger(qbftForksSchedule)); + new QbftValidatorModeTransitionLoggerAdaptor( + new ValidatorModeTransitionLogger(qbftForksSchedule))); qbftBlockHeightManagerFactory.isEarlyRoundChangeEnabled(isEarlyRoundChangeEnabled); - final BftEventHandler qbftController = + final QbftEventHandler qbftController = new QbftController( - blockchain, + new QbftBlockchainAdaptor(blockchain), finalState, qbftBlockHeightManagerFactory, gossiper, @@ -295,14 +309,15 @@ public class QbftBesuControllerBuilder extends BesuControllerBuilder { futureMessageBuffer, new EthSynchronizerUpdater(ethProtocolManager.ethContext().getEthPeers()), blockEncoder); + final BftEventHandler bftEventHandler = new BftEventHandlerAdaptor(qbftController); - final EventMultiplexer eventMultiplexer = new EventMultiplexer(qbftController); + final EventMultiplexer eventMultiplexer = new EventMultiplexer(bftEventHandler); final BftProcessor bftProcessor = new BftProcessor(bftEventQueue, eventMultiplexer); final MiningCoordinator miningCoordinator = new BftMiningCoordinator( bftExecutors, - qbftController, + bftEventHandler, bftProcessor, blockCreatorFactory, blockchain, diff --git a/besu/src/main/java/org/hyperledger/besu/controller/TransitionBesuControllerBuilder.java b/besu/src/main/java/org/hyperledger/besu/controller/TransitionBesuControllerBuilder.java index 9d37f594e..de5eb638e 100644 --- a/besu/src/main/java/org/hyperledger/besu/controller/TransitionBesuControllerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/controller/TransitionBesuControllerBuilder.java @@ -147,7 +147,8 @@ public class TransitionBesuControllerBuilder extends BesuControllerBuilder { transitionMiningConfiguration, syncState, transitionBackwardsSyncContext, - ethProtocolManager.ethContext().getScheduler())); + ethProtocolManager.ethContext().getScheduler()), + mergeBesuControllerBuilder.getPostMergeContext()); initTransitionWatcher(protocolContext, composedCoordinator); return composedCoordinator; } @@ -185,7 +186,7 @@ public class TransitionBesuControllerBuilder extends BesuControllerBuilder { new TransitionProtocolSchedule( preMergeBesuControllerBuilder.createProtocolSchedule(), mergeBesuControllerBuilder.createProtocolSchedule(), - PostMergeContext.get()); + mergeBesuControllerBuilder.getPostMergeContext()); return transitionProtocolSchedule; } @@ -255,7 +256,7 @@ public class TransitionBesuControllerBuilder extends BesuControllerBuilder { private void initTransitionWatcher( final ProtocolContext protocolContext, final TransitionCoordinator composedCoordinator) { - PostMergeContext postMergeContext = protocolContext.getConsensusContext(PostMergeContext.class); + PostMergeContext postMergeContext = mergeBesuControllerBuilder.getPostMergeContext(); postMergeContext.observeNewIsPostMergeState( (isPoS, priorState, difficultyStoppedAt) -> { if (isPoS) { @@ -290,7 +291,7 @@ public class TransitionBesuControllerBuilder extends BesuControllerBuilder { @Override public BesuController build() { final BesuController controller = super.build(); - PostMergeContext.get().setSyncState(controller.getSyncState()); + mergeBesuControllerBuilder.getPostMergeContext().setSyncState(controller.getSyncState()); return controller; } diff --git a/besu/src/test/java/org/hyperledger/besu/ForkIdsNetworkConfigTest.java b/besu/src/test/java/org/hyperledger/besu/ForkIdsNetworkConfigTest.java index 86ba68812..d0de1e71d 100644 --- a/besu/src/test/java/org/hyperledger/besu/ForkIdsNetworkConfigTest.java +++ b/besu/src/test/java/org/hyperledger/besu/ForkIdsNetworkConfigTest.java @@ -54,6 +54,7 @@ import org.mockito.junit.jupiter.MockitoExtension; @ExtendWith(MockitoExtension.class) public class ForkIdsNetworkConfigTest { + private static final PostMergeContext postMergeContext = new PostMergeContext(); public static Collection parameters() { return List.of( @@ -63,18 +64,18 @@ public class ForkIdsNetworkConfigTest { new ForkId(Bytes.ofUnsignedInt(0xfe3366e7L), 1735371L), new ForkId(Bytes.ofUnsignedInt(0xb96cbd13L), 1677557088L), new ForkId(Bytes.ofUnsignedInt(0xf7f9bc08L), 1706655072L), - new ForkId(Bytes.ofUnsignedInt(0x88cf81d9L), 1739980128L), - new ForkId(Bytes.ofUnsignedInt(0xbafd09c3L), 0L), - new ForkId(Bytes.ofUnsignedInt(0xbafd09c3L), 0L)) + new ForkId(Bytes.ofUnsignedInt(0x88cf81d9L), 1741159776L), + new ForkId(Bytes.ofUnsignedInt(0xed88b5fdL), 0L), + new ForkId(Bytes.ofUnsignedInt(0xed88b5fdL), 0L)) }, new Object[] { NetworkName.HOLESKY, List.of( new ForkId(Bytes.ofUnsignedInt(0xc61a6098L), 1696000704L), new ForkId(Bytes.ofUnsignedInt(0xfd4f016bL), 1707305664L), - new ForkId(Bytes.ofUnsignedInt(0x9b192ad0L), 1739352768L), - new ForkId(Bytes.ofUnsignedInt(0xf818a0d6L), 0L), - new ForkId(Bytes.ofUnsignedInt(0xf818a0d6L), 0L)) + new ForkId(Bytes.ofUnsignedInt(0x9b192ad0L), 1740434112L), + new ForkId(Bytes.ofUnsignedInt(0xdfbd9bedL), 0L), + new ForkId(Bytes.ofUnsignedInt(0xdfbd9bedL), 0L)) }, new Object[] { NetworkName.MAINNET, @@ -203,10 +204,10 @@ public class ForkIdsNetworkConfigTest { public MilestoneStreamingTransitionProtocolSchedule( final MilestoneStreamingProtocolSchedule preMergeProtocolSchedule, final MilestoneStreamingProtocolSchedule postMergeProtocolSchedule) { - super(preMergeProtocolSchedule, postMergeProtocolSchedule, PostMergeContext.get()); + super(preMergeProtocolSchedule, postMergeProtocolSchedule, postMergeContext); transitionUtils = new TransitionUtils<>( - preMergeProtocolSchedule, postMergeProtocolSchedule, PostMergeContext.get()); + preMergeProtocolSchedule, postMergeProtocolSchedule, postMergeContext); } public Stream streamMilestoneBlocks() { diff --git a/config/src/main/resources/holesky.json b/config/src/main/resources/holesky.json index effcd9a83..1253da5f8 100644 --- a/config/src/main/resources/holesky.json +++ b/config/src/main/resources/holesky.json @@ -15,7 +15,7 @@ "terminalTotalDifficulty": 0, "shanghaiTime": 1696000704, "cancunTime": 1707305664, - "pragueTime": 1739352768, + "pragueTime": 1740434112, "blobSchedule": { "cancun": { "target": 3, diff --git a/config/src/main/resources/sepolia.json b/config/src/main/resources/sepolia.json index c8de6240e..f30b7c36d 100644 --- a/config/src/main/resources/sepolia.json +++ b/config/src/main/resources/sepolia.json @@ -15,7 +15,7 @@ "terminalTotalDifficulty": 17000000000000000, "shanghaiTime": 1677557088, "cancunTime": 1706655072, - "pragueTime": 1739980128, + "pragueTime": 1741159776, "blobSchedule": { "cancun": { "target": 3, diff --git a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/BlockTimer.java b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/BlockTimer.java index 8b98a2dde..91f3c394d 100644 --- a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/BlockTimer.java +++ b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/BlockTimer.java @@ -17,12 +17,12 @@ package org.hyperledger.besu.consensus.common.bft; import org.hyperledger.besu.config.BftConfigOptions; import org.hyperledger.besu.consensus.common.ForksSchedule; import org.hyperledger.besu.consensus.common.bft.events.BlockTimerExpiry; -import org.hyperledger.besu.ethereum.core.BlockHeader; import java.time.Clock; import java.util.Optional; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; +import java.util.function.Supplier; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -81,10 +81,10 @@ public class BlockTimer { * Starts a timer for the supplied round cancelling any previously active block timer * * @param round The round identifier which this timer is tracking - * @param chainHeadHeader The header of the chain head + * @param headerTimestamp The timestamp from the of the chain head header */ public synchronized void startTimer( - final ConsensusRoundIdentifier round, final BlockHeader chainHeadHeader) { + final ConsensusRoundIdentifier round, final Supplier headerTimestamp) { cancelTimer(); final long expiryTime; @@ -104,7 +104,7 @@ public class BlockTimer { final int currentBlockPeriodSeconds = forksSchedule.getFork(round.getSequenceNumber()).getValue().getBlockPeriodSeconds(); final long minimumTimeBetweenBlocksMillis = currentBlockPeriodSeconds * 1000L; - expiryTime = chainHeadHeader.getTimestamp() * 1_000 + minimumTimeBetweenBlocksMillis; + expiryTime = headerTimestamp.get() * 1_000 + minimumTimeBetweenBlocksMillis; } setBlockTimes(round); @@ -115,14 +115,14 @@ public class BlockTimer { /** * Checks if the empty block timer is expired * - * @param chainHeadHeader The header of the chain head + * @param headerTimestamp Function to get the chain head timestamp * @param currentTimeInMillis The current time * @return a boolean value */ public synchronized boolean checkEmptyBlockExpired( - final BlockHeader chainHeadHeader, final long currentTimeInMillis) { + final Supplier headerTimestamp, final long currentTimeInMillis) { final long emptyBlockPeriodExpiryTime = - (chainHeadHeader.getTimestamp() + emptyBlockPeriodSeconds) * 1000; + (headerTimestamp.get() + emptyBlockPeriodSeconds) * 1000; if (currentTimeInMillis > emptyBlockPeriodExpiryTime) { LOG.debug("Empty Block expired"); @@ -136,15 +136,15 @@ public class BlockTimer { * Resets the empty block timer * * @param roundIdentifier The current round identifier - * @param chainHeadHeader The header of the chain head + * @param headerTimestamp Function to get timestamp from the header of the chain head * @param currentTimeInMillis The current time */ public void resetTimerForEmptyBlock( final ConsensusRoundIdentifier roundIdentifier, - final BlockHeader chainHeadHeader, + final Supplier headerTimestamp, final long currentTimeInMillis) { final long emptyBlockPeriodExpiryTime = - (chainHeadHeader.getTimestamp() + emptyBlockPeriodSeconds) * 1000; + (headerTimestamp.get() + emptyBlockPeriodSeconds) * 1000; final long nextBlockPeriodExpiryTime = currentTimeInMillis + blockPeriodSeconds * 1000; startTimer(roundIdentifier, Math.min(emptyBlockPeriodExpiryTime, nextBlockPeriodExpiryTime)); diff --git a/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/bft/BlockTimerTest.java b/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/bft/BlockTimerTest.java index 7521e5eb3..da8a739aa 100644 --- a/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/bft/BlockTimerTest.java +++ b/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/bft/BlockTimerTest.java @@ -102,7 +102,7 @@ public class BlockTimerTest { bftExecutors.scheduleTask(any(Runnable.class), anyLong(), any())) .thenReturn(mockedFuture); - timer.startTimer(round, header); + timer.startTimer(round, header::getTimestamp); verify(bftExecutors) .scheduleTask(any(Runnable.class), eq(EXPECTED_DELAY), eq(TimeUnit.MILLISECONDS)); } @@ -136,7 +136,7 @@ public class BlockTimerTest { final BftEventQueue eventQueue = new BftEventQueue(1000); final BlockTimer timer = new BlockTimer(eventQueue, mockForksSchedule, bftExecutors, mockClock); - timer.startTimer(round, header); + timer.startTimer(round, header::getTimestamp); // Verify that the event will not be added to the queue immediately assertThat(eventQueue.isEmpty()).isTrue(); @@ -182,7 +182,7 @@ public class BlockTimerTest { final ConsensusRoundIdentifier round = new ConsensusRoundIdentifier(0xFEDBCA9876543210L, 0x12345678); - timer.startTimer(round, header); + timer.startTimer(round, header::getTimestamp); verify(bftExecutors, never()).scheduleTask(any(Runnable.class), anyLong(), any()); final ArgumentCaptor bftEventCaptor = ArgumentCaptor.forClass(BftEvent.class); @@ -218,7 +218,7 @@ public class BlockTimerTest { final ConsensusRoundIdentifier round = new ConsensusRoundIdentifier(0xFEDBCA9876543210L, 0x12345678); - timer.startTimer(round, header); + timer.startTimer(round, header::getTimestamp); verify(bftExecutors, never()).scheduleTask(any(Runnable.class), anyLong(), any()); final ArgumentCaptor bftEventCaptor = ArgumentCaptor.forClass(BftEvent.class); @@ -258,9 +258,9 @@ public class BlockTimerTest { Mockito.>when( bftExecutors.scheduleTask(any(Runnable.class), anyLong(), eq(TimeUnit.MILLISECONDS))) .thenReturn(mockedFuture); - timer.startTimer(round, header); + timer.startTimer(round, header::getTimestamp); verify(mockedFuture, times(0)).cancel(false); - timer.startTimer(round, header); + timer.startTimer(round, header::getTimestamp); verify(mockedFuture, times(1)).cancel(false); } @@ -292,7 +292,7 @@ public class BlockTimerTest { Mockito.>when( bftExecutors.scheduleTask(any(Runnable.class), anyLong(), eq(TimeUnit.MILLISECONDS))) .thenReturn(mockedFuture); - timer.startTimer(round, header); + timer.startTimer(round, header::getTimestamp); when(mockedFuture.isDone()).thenReturn(false); assertThat(timer.isRunning()).isTrue(); when(mockedFuture.isDone()).thenReturn(true); @@ -322,7 +322,7 @@ public class BlockTimerTest { MINIMAL_TIME_BETWEEN_EMPTY_BLOCKS_SECONDS))); final BlockTimer timer = new BlockTimer(mockQueue, mockForksSchedule, bftExecutors, mockClock); - timer.startTimer(round, header); + timer.startTimer(round, header::getTimestamp); assertThat(timer.getBlockPeriodSeconds()).isEqualTo(MINIMAL_TIME_BETWEEN_BLOCKS_SECONDS); assertThat(timer.getEmptyBlockPeriodSeconds()) diff --git a/consensus/ibft/src/main/java/org/hyperledger/besu/consensus/ibft/statemachine/IbftBlockHeightManager.java b/consensus/ibft/src/main/java/org/hyperledger/besu/consensus/ibft/statemachine/IbftBlockHeightManager.java index 64dd67bc7..8db52ad12 100644 --- a/consensus/ibft/src/main/java/org/hyperledger/besu/consensus/ibft/statemachine/IbftBlockHeightManager.java +++ b/consensus/ibft/src/main/java/org/hyperledger/besu/consensus/ibft/statemachine/IbftBlockHeightManager.java @@ -117,7 +117,7 @@ public class IbftBlockHeightManager implements BaseIbftBlockHeightManager { currentRound = roundFactory.createNewRound(parentHeader, 0); if (finalState.isLocalNodeProposerForRound(currentRound.getRoundIdentifier())) { - blockTimer.startTimer(currentRound.getRoundIdentifier(), parentHeader); + blockTimer.startTimer(currentRound.getRoundIdentifier(), parentHeader::getTimestamp); } } diff --git a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/PostMergeContext.java b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/PostMergeContext.java index 1d7e4b76c..b080cb64a 100644 --- a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/PostMergeContext.java +++ b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/PostMergeContext.java @@ -28,7 +28,6 @@ import java.util.Optional; import java.util.concurrent.atomic.AtomicReference; import java.util.stream.Stream; -import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.EvictingQueue; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -40,7 +39,6 @@ public class PostMergeContext implements MergeContext { /** The Max blocks in progress. */ static final int MAX_BLOCKS_IN_PROGRESS = 12; - private static final AtomicReference singleton = new AtomicReference<>(); private final AtomicReference syncState; private final AtomicReference terminalTotalDifficulty; // initial postMerge state is indeterminate until it is set: @@ -62,8 +60,7 @@ public class PostMergeContext implements MergeContext { private boolean isPostMergeAtGenesis; /** Instantiates a new Post merge context. */ - @VisibleForTesting - PostMergeContext() { + public PostMergeContext() { this(Difficulty.ZERO); } @@ -72,24 +69,11 @@ public class PostMergeContext implements MergeContext { * * @param difficulty the difficulty */ - @VisibleForTesting - PostMergeContext(final Difficulty difficulty) { + private PostMergeContext(final Difficulty difficulty) { this.terminalTotalDifficulty = new AtomicReference<>(difficulty); this.syncState = new AtomicReference<>(); } - /** - * Get post merge context. - * - * @return the post merge context - */ - public static PostMergeContext get() { - if (singleton.get() == null) { - singleton.compareAndSet(null, new PostMergeContext()); - } - return singleton.get(); - } - @Override public C as(final Class klass) { return klass.cast(this); diff --git a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/TransitionProtocolSchedule.java b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/TransitionProtocolSchedule.java index 44fd5f8ed..78b3e5f35 100644 --- a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/TransitionProtocolSchedule.java +++ b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/TransitionProtocolSchedule.java @@ -14,21 +14,16 @@ */ package org.hyperledger.besu.consensus.merge; -import org.hyperledger.besu.config.GenesisConfigOptions; import org.hyperledger.besu.datatypes.HardforkId; import org.hyperledger.besu.ethereum.ProtocolContext; -import org.hyperledger.besu.ethereum.chain.BadBlockManager; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.Difficulty; -import org.hyperledger.besu.ethereum.core.MiningConfiguration; import org.hyperledger.besu.ethereum.core.PermissionTransactionFilter; import org.hyperledger.besu.ethereum.core.ProcessableBlockHeader; -import org.hyperledger.besu.ethereum.mainnet.MainnetProtocolSchedule; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec; import org.hyperledger.besu.ethereum.mainnet.ScheduledProtocolSpec; import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; -import org.hyperledger.besu.plugin.services.MetricsSystem; import java.math.BigInteger; import java.util.Optional; @@ -60,41 +55,6 @@ public class TransitionProtocolSchedule implements ProtocolSchedule { new TransitionUtils<>(preMergeProtocolSchedule, postMergeProtocolSchedule, mergeContext); } - /** - * Create a Proof-of-Stake protocol schedule from a config object - * - * @param genesisConfigOptions {@link GenesisConfigOptions} containing the config options for the - * milestone starting points - * @param miningConfiguration the mining parameters - * @param badBlockManager the cache to use to keep invalid blocks - * @param isParallelTxProcessingEnabled indicates whether parallel transaction is enabled. - * @return an initialised TransitionProtocolSchedule using post-merge defaults - */ - public static TransitionProtocolSchedule fromConfig( - final GenesisConfigOptions genesisConfigOptions, - final MiningConfiguration miningConfiguration, - final BadBlockManager badBlockManager, - final boolean isParallelTxProcessingEnabled, - final MetricsSystem metricsSystem) { - ProtocolSchedule preMergeProtocolSchedule = - MainnetProtocolSchedule.fromConfig( - genesisConfigOptions, - miningConfiguration, - badBlockManager, - isParallelTxProcessingEnabled, - metricsSystem); - ProtocolSchedule postMergeProtocolSchedule = - MergeProtocolSchedule.create( - genesisConfigOptions, - false, - miningConfiguration, - badBlockManager, - isParallelTxProcessingEnabled, - metricsSystem); - return new TransitionProtocolSchedule( - preMergeProtocolSchedule, postMergeProtocolSchedule, PostMergeContext.get()); - } - /** * Gets pre merge schedule. * diff --git a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/TransitionCoordinator.java b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/TransitionCoordinator.java index 681c6f334..a7d426435 100644 --- a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/TransitionCoordinator.java +++ b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/TransitionCoordinator.java @@ -47,10 +47,13 @@ public class TransitionCoordinator extends TransitionUtils * * @param miningCoordinator the mining coordinator * @param mergeCoordinator the merge coordinator + * @param postMergeContext the post merge context */ public TransitionCoordinator( - final MiningCoordinator miningCoordinator, final MiningCoordinator mergeCoordinator) { - super(miningCoordinator, mergeCoordinator, PostMergeContext.get()); + final MiningCoordinator miningCoordinator, + final MiningCoordinator mergeCoordinator, + final PostMergeContext postMergeContext) { + super(miningCoordinator, mergeCoordinator, postMergeContext); this.miningCoordinator = miningCoordinator; this.mergeCoordinator = (MergeMiningCoordinator) mergeCoordinator; } diff --git a/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeReorgTest.java b/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeReorgTest.java index 250ba9434..0feb2077e 100644 --- a/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeReorgTest.java +++ b/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeReorgTest.java @@ -67,7 +67,7 @@ public class MergeReorgTest implements MergeGenesisConfigHelper { private MergeCoordinator coordinator; - private final MergeContext mergeContext = PostMergeContext.get(); + private final MergeContext mergeContext = new PostMergeContext(); private final ProtocolSchedule mockProtocolSchedule = getMergeProtocolSchedule(); private final GenesisState genesisState = GenesisState.fromConfig(getPowGenesisConfig(), mockProtocolSchedule); diff --git a/consensus/qbft-core/src/integration-test/java/org/hyperledger/besu/consensus/qbft/core/support/IntegrationTestHelpers.java b/consensus/qbft-core/src/integration-test/java/org/hyperledger/besu/consensus/qbft/core/support/IntegrationTestHelpers.java index dd618c84f..c50dbd695 100644 --- a/consensus/qbft-core/src/integration-test/java/org/hyperledger/besu/consensus/qbft/core/support/IntegrationTestHelpers.java +++ b/consensus/qbft-core/src/integration-test/java/org/hyperledger/besu/consensus/qbft/core/support/IntegrationTestHelpers.java @@ -19,13 +19,17 @@ import org.hyperledger.besu.consensus.common.bft.BftBlockInterface; import org.hyperledger.besu.consensus.common.bft.ConsensusRoundIdentifier; import org.hyperledger.besu.consensus.common.bft.payload.SignedData; import org.hyperledger.besu.consensus.qbft.QbftExtraDataCodec; +import org.hyperledger.besu.consensus.qbft.adaptor.QbftBlockHashingAdaptor; import org.hyperledger.besu.consensus.qbft.adaptor.QbftBlockInterfaceAdaptor; +import org.hyperledger.besu.consensus.qbft.adaptor.QbftExtraDataProviderAdaptor; import org.hyperledger.besu.consensus.qbft.core.payload.CommitPayload; import org.hyperledger.besu.consensus.qbft.core.payload.MessageFactory; import org.hyperledger.besu.consensus.qbft.core.statemachine.PreparedCertificate; import org.hyperledger.besu.consensus.qbft.core.types.QbftBlock; import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockCodec; +import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockHashing; import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockInterface; +import org.hyperledger.besu.consensus.qbft.core.types.QbftExtraDataProvider; import org.hyperledger.besu.consensus.qbft.core.types.QbftHashMode; import org.hyperledger.besu.crypto.SECPSignature; import org.hyperledger.besu.cryptoservices.NodeKey; @@ -42,10 +46,14 @@ public class IntegrationTestHelpers { final QbftBlock commitBlock = createCommitBlockFromProposalBlock(block, roundId.getRoundNumber()); + final QbftBlockHashing blockHashing = + new QbftBlockHashingAdaptor(new BftBlockHashing(qbftExtraDataEncoder)); + final QbftExtraDataProvider extraDataProvider = + new QbftExtraDataProviderAdaptor(qbftExtraDataEncoder); final SECPSignature commitSeal = nodeKey.sign( - new BftBlockHashing(qbftExtraDataEncoder) - .calculateDataHashForCommittedSeal(commitBlock.getHeader())); + blockHashing.calculateDataHashForCommittedSeal( + commitBlock.getHeader(), extraDataProvider.getExtraData(commitBlock.getHeader()))); final MessageFactory messageFactory = new MessageFactory(nodeKey, blockEncoder); diff --git a/consensus/qbft-core/src/integration-test/java/org/hyperledger/besu/consensus/qbft/core/support/TestContext.java b/consensus/qbft-core/src/integration-test/java/org/hyperledger/besu/consensus/qbft/core/support/TestContext.java index bffb6977d..9ef56fa1d 100644 --- a/consensus/qbft-core/src/integration-test/java/org/hyperledger/besu/consensus/qbft/core/support/TestContext.java +++ b/consensus/qbft-core/src/integration-test/java/org/hyperledger/besu/consensus/qbft/core/support/TestContext.java @@ -22,14 +22,20 @@ import org.hyperledger.besu.consensus.common.bft.ConsensusRoundIdentifier; import org.hyperledger.besu.consensus.common.bft.EventMultiplexer; import org.hyperledger.besu.consensus.common.bft.blockcreation.ProposerSelector; import org.hyperledger.besu.consensus.common.bft.inttest.NodeParams; -import org.hyperledger.besu.consensus.common.bft.statemachine.BftEventHandler; import org.hyperledger.besu.consensus.common.validator.ValidatorProvider; import org.hyperledger.besu.consensus.qbft.adaptor.BlockUtil; import org.hyperledger.besu.consensus.qbft.adaptor.QbftBlockAdaptor; +import org.hyperledger.besu.consensus.qbft.adaptor.QbftBlockHeaderAdaptor; +import org.hyperledger.besu.consensus.qbft.adaptor.QbftBlockchainAdaptor; +import org.hyperledger.besu.consensus.qbft.adaptor.QbftValidatorProviderAdaptor; import org.hyperledger.besu.consensus.qbft.core.payload.MessageFactory; import org.hyperledger.besu.consensus.qbft.core.types.QbftBlock; import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockCodec; +import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockHeader; +import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockchain; +import org.hyperledger.besu.consensus.qbft.core.types.QbftEventHandler; import org.hyperledger.besu.consensus.qbft.core.types.QbftFinalState; +import org.hyperledger.besu.consensus.qbft.core.types.QbftValidatorProvider; import org.hyperledger.besu.crypto.SECPSignature; import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.ethereum.chain.MutableBlockchain; @@ -57,7 +63,7 @@ public class TestContext { private final Map remotePeers; private final MutableBlockchain blockchain; private final BftExecutors bftExecutors; - private final BftEventHandler controller; + private final QbftEventHandler controller; private final QbftFinalState finalState; private final EventMultiplexer eventMultiplexer; private final MessageFactory messageFactory; @@ -70,7 +76,7 @@ public class TestContext { final Map remotePeers, final MutableBlockchain blockchain, final BftExecutors bftExecutors, - final BftEventHandler controller, + final QbftEventHandler controller, final QbftFinalState finalState, final EventMultiplexer eventMultiplexer, final MessageFactory messageFactory, @@ -96,11 +102,11 @@ public class TestContext { controller.start(); } - public MutableBlockchain getBlockchain() { - return blockchain; + public QbftBlockchain getBlockchain() { + return new QbftBlockchainAdaptor(blockchain); } - public BftEventHandler getController() { + public QbftEventHandler getController() { return controller; } @@ -129,25 +135,30 @@ public class TestContext { public QbftBlock createBlockForProposalFromChainHead( final long timestamp, final Address proposer) { // this implies that EVERY block will have this node as the proposer :/ - return createBlockForProposal(blockchain.getChainHeadHeader(), timestamp, proposer, 0); + return createBlockForProposal( + new QbftBlockHeaderAdaptor(blockchain.getChainHeadHeader()), timestamp, proposer, 0); } public QbftBlock createBlockForProposalFromChainHead( final long timestamp, final Address proposer, final int roundNumber) { // this implies that EVERY block will have this node as the proposer :/ return createBlockForProposal( - blockchain.getChainHeadHeader(), timestamp, proposer, roundNumber); + new QbftBlockHeaderAdaptor(blockchain.getChainHeadHeader()), + timestamp, + proposer, + roundNumber); } public QbftBlock createBlockForProposal( - final BlockHeader parent, + final QbftBlockHeader parent, final long timestamp, final Address proposer, final int roundNumber) { final QbftBlock block = finalState.getBlockCreatorFactory().create(roundNumber).createBlock(timestamp, parent); - final BlockHeaderBuilder headerBuilder = BlockHeaderBuilder.fromHeader(block.getHeader()); + final BlockHeaderBuilder headerBuilder = + BlockHeaderBuilder.fromHeader(BlockUtil.toBesuBlockHeader(block.getHeader())); headerBuilder .coinbase(proposer) .blockHeaderFunctions(BftBlockHeaderFunctions.forCommittedSeal(bftExtraDataCodec)); @@ -158,7 +169,7 @@ public class TestContext { } public QbftBlock createBlockForProposal( - final BlockHeader parent, final long timestamp, final Address proposer) { + final QbftBlockHeader parent, final long timestamp, final Address proposer) { return createBlockForProposal(parent, timestamp, proposer, 0); } @@ -192,12 +203,16 @@ public class TestContext { return blockchain.getChainHeadBlockNumber(); } - public ValidatorProvider getValidatorProvider() { - return validatorProvider; + public QbftValidatorProvider getValidatorProvider() { + return new QbftValidatorProviderAdaptor(validatorProvider); } public void appendBlock(final QbftBlock signedCurrentHeightBlock) { blockchain.appendBlock( BlockUtil.toBesuBlock(signedCurrentHeightBlock), Collections.emptyList()); } + + public QbftBlockHeader getBlockHeader(final int blockNumber) { + return new QbftBlockHeaderAdaptor(blockchain.getBlockHeader(blockNumber).get()); + } } diff --git a/consensus/qbft-core/src/integration-test/java/org/hyperledger/besu/consensus/qbft/core/support/TestContextBuilder.java b/consensus/qbft-core/src/integration-test/java/org/hyperledger/besu/consensus/qbft/core/support/TestContextBuilder.java index 2b30d9625..cc7c1c5cf 100644 --- a/consensus/qbft-core/src/integration-test/java/org/hyperledger/besu/consensus/qbft/core/support/TestContextBuilder.java +++ b/consensus/qbft-core/src/integration-test/java/org/hyperledger/besu/consensus/qbft/core/support/TestContextBuilder.java @@ -32,6 +32,7 @@ import org.hyperledger.besu.config.StubGenesisConfigOptions; import org.hyperledger.besu.consensus.common.BftValidatorOverrides; import org.hyperledger.besu.consensus.common.EpochManager; import org.hyperledger.besu.consensus.common.ForksSchedule; +import org.hyperledger.besu.consensus.common.bft.BftBlockHashing; import org.hyperledger.besu.consensus.common.bft.BftBlockHeaderFunctions; import org.hyperledger.besu.consensus.common.bft.BftBlockInterface; import org.hyperledger.besu.consensus.common.bft.BftContext; @@ -54,7 +55,6 @@ import org.hyperledger.besu.consensus.common.bft.inttest.NodeParams; import org.hyperledger.besu.consensus.common.bft.inttest.StubValidatorMulticaster; import org.hyperledger.besu.consensus.common.bft.inttest.StubbedSynchronizerUpdater; import org.hyperledger.besu.consensus.common.bft.inttest.TestTransitions; -import org.hyperledger.besu.consensus.common.bft.statemachine.BftEventHandler; import org.hyperledger.besu.consensus.common.bft.statemachine.FutureMessageBuffer; import org.hyperledger.besu.consensus.common.validator.ValidatorProvider; import org.hyperledger.besu.consensus.common.validator.blockbased.BlockValidatorProvider; @@ -62,12 +62,17 @@ import org.hyperledger.besu.consensus.qbft.MutableQbftConfigOptions; import org.hyperledger.besu.consensus.qbft.QbftExtraDataCodec; import org.hyperledger.besu.consensus.qbft.QbftForksSchedulesFactory; import org.hyperledger.besu.consensus.qbft.QbftProtocolScheduleBuilder; +import org.hyperledger.besu.consensus.qbft.adaptor.BftEventHandlerAdaptor; import org.hyperledger.besu.consensus.qbft.adaptor.QbftBlockCodecAdaptor; import org.hyperledger.besu.consensus.qbft.adaptor.QbftBlockCreatorFactoryAdaptor; +import org.hyperledger.besu.consensus.qbft.adaptor.QbftBlockHashingAdaptor; import org.hyperledger.besu.consensus.qbft.adaptor.QbftBlockInterfaceAdaptor; +import org.hyperledger.besu.consensus.qbft.adaptor.QbftBlockchainAdaptor; import org.hyperledger.besu.consensus.qbft.adaptor.QbftExtraDataProviderAdaptor; import org.hyperledger.besu.consensus.qbft.adaptor.QbftFinalStateImpl; import org.hyperledger.besu.consensus.qbft.adaptor.QbftProtocolScheduleAdaptor; +import org.hyperledger.besu.consensus.qbft.adaptor.QbftValidatorModeTransitionLoggerAdaptor; +import org.hyperledger.besu.consensus.qbft.adaptor.QbftValidatorProviderAdaptor; import org.hyperledger.besu.consensus.qbft.blockcreation.QbftBlockCreatorFactory; import org.hyperledger.besu.consensus.qbft.core.network.QbftGossip; import org.hyperledger.besu.consensus.qbft.core.payload.MessageFactory; @@ -75,16 +80,19 @@ import org.hyperledger.besu.consensus.qbft.core.statemachine.QbftBlockHeightMana import org.hyperledger.besu.consensus.qbft.core.statemachine.QbftController; import org.hyperledger.besu.consensus.qbft.core.statemachine.QbftRoundFactory; import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockCodec; +import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockHashing; import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockInterface; import org.hyperledger.besu.consensus.qbft.core.types.QbftContext; +import org.hyperledger.besu.consensus.qbft.core.types.QbftEventHandler; import org.hyperledger.besu.consensus.qbft.core.types.QbftExtraDataProvider; import org.hyperledger.besu.consensus.qbft.core.types.QbftFinalState; import org.hyperledger.besu.consensus.qbft.core.types.QbftMinedBlockObserver; +import org.hyperledger.besu.consensus.qbft.core.types.QbftValidatorProvider; import org.hyperledger.besu.consensus.qbft.core.validation.MessageValidatorFactory; -import org.hyperledger.besu.consensus.qbft.core.validator.ValidatorModeTransitionLogger; import org.hyperledger.besu.consensus.qbft.validator.ForkingValidatorProvider; import org.hyperledger.besu.consensus.qbft.validator.TransactionValidatorProvider; import org.hyperledger.besu.consensus.qbft.validator.ValidatorContractController; +import org.hyperledger.besu.consensus.qbft.validator.ValidatorModeTransitionLogger; import org.hyperledger.besu.cryptoservices.NodeKey; import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Hash; @@ -148,7 +156,7 @@ public class TestContextBuilder { "UnusedVariable") // false positive https://github.com/google/error-prone/issues/2713 private record ControllerAndState( BftExecutors bftExecutors, - BftEventHandler eventHandler, + QbftEventHandler eventHandler, QbftFinalState finalState, EventMultiplexer eventMultiplexer, MessageFactory messageFactory, @@ -470,6 +478,8 @@ public class TestContextBuilder { final ValidatorProvider validatorProvider = new ForkingValidatorProvider( blockChain, forksSchedule, blockValidatorProvider, transactionValidatorProvider); + final QbftValidatorProvider qbftValidatorProvider = + new QbftValidatorProviderAdaptor(validatorProvider); final ProtocolContext bftProtocolContext = new ProtocolContext( @@ -481,7 +491,7 @@ public class TestContextBuilder { new ProtocolContext( blockChain, worldStateArchive, - new QbftContext(validatorProvider, qbftBlockInterface), + new QbftContext(qbftValidatorProvider, qbftBlockInterface), new BadBlockManager()); final TransactionPoolConfiguration poolConf = @@ -555,10 +565,15 @@ public class TestContextBuilder { blockChain.getChainHeadBlockNumber()); final QbftExtraDataProvider qbftExtraDataProvider = new QbftExtraDataProviderAdaptor(BFT_EXTRA_DATA_ENCODER); + final QbftBlockHashing blockHashing = + new QbftBlockHashingAdaptor(new BftBlockHashing(BFT_EXTRA_DATA_ENCODER)); + final QbftValidatorModeTransitionLoggerAdaptor validatorModeTransitionLogger = + new QbftValidatorModeTransitionLoggerAdaptor( + new ValidatorModeTransitionLogger(forksSchedule)); final QbftController qbftController = new QbftController( - blockChain, + new QbftBlockchainAdaptor(blockChain), finalState, new QbftBlockHeightManagerFactory( finalState, @@ -570,17 +585,19 @@ public class TestContextBuilder { messageValidatorFactory, messageFactory, BFT_EXTRA_DATA_ENCODER, - qbftExtraDataProvider), + qbftExtraDataProvider, + blockHashing), messageValidatorFactory, messageFactory, - new ValidatorModeTransitionLogger(forksSchedule)), + validatorModeTransitionLogger), gossiper, duplicateMessageTracker, futureMessageBuffer, synchronizerUpdater, blockEncoder); - final EventMultiplexer eventMultiplexer = new EventMultiplexer(qbftController); + final EventMultiplexer eventMultiplexer = + new EventMultiplexer(new BftEventHandlerAdaptor(qbftController)); //////////////////////////// END QBFT BesuController //////////////////////////// return new ControllerAndState( diff --git a/consensus/qbft-core/src/integration-test/java/org/hyperledger/besu/consensus/qbft/core/test/FutureHeightTest.java b/consensus/qbft-core/src/integration-test/java/org/hyperledger/besu/consensus/qbft/core/test/FutureHeightTest.java index d53db14b5..88e30c47c 100644 --- a/consensus/qbft-core/src/integration-test/java/org/hyperledger/besu/consensus/qbft/core/test/FutureHeightTest.java +++ b/consensus/qbft-core/src/integration-test/java/org/hyperledger/besu/consensus/qbft/core/test/FutureHeightTest.java @@ -19,7 +19,6 @@ import static org.hyperledger.besu.consensus.qbft.core.support.IntegrationTestHe import org.hyperledger.besu.consensus.common.bft.BftExtraDataCodec; import org.hyperledger.besu.consensus.common.bft.ConsensusRoundIdentifier; -import org.hyperledger.besu.consensus.common.bft.events.NewChainHead; import org.hyperledger.besu.consensus.qbft.QbftExtraDataCodec; import org.hyperledger.besu.consensus.qbft.core.messagewrappers.Commit; import org.hyperledger.besu.consensus.qbft.core.messagewrappers.Prepare; @@ -28,6 +27,7 @@ import org.hyperledger.besu.consensus.qbft.core.support.RoundSpecificPeers; import org.hyperledger.besu.consensus.qbft.core.support.TestContext; import org.hyperledger.besu.consensus.qbft.core.support.TestContextBuilder; import org.hyperledger.besu.consensus.qbft.core.types.QbftBlock; +import org.hyperledger.besu.consensus.qbft.core.types.QbftNewChainHead; import java.time.Clock; import java.time.Instant; @@ -94,7 +94,7 @@ public class FutureHeightTest { assertThat(context.getCurrentChainHeight()).isEqualTo(1); context .getController() - .handleNewBlockEvent(new NewChainHead(signedCurrentHeightBlock.getHeader())); + .handleNewBlockEvent(new QbftNewChainHead(signedCurrentHeightBlock.getHeader())); final Prepare expectedPrepareMessage = localNodeMessageFactory.createPrepare(futureHeightRoundId, futureHeightBlock.getHash()); @@ -132,7 +132,7 @@ public class FutureHeightTest { assertThat(context.getCurrentChainHeight()).isEqualTo(1); context .getController() - .handleNewBlockEvent(new NewChainHead(signedCurrentHeightBlock.getHeader())); + .handleNewBlockEvent(new QbftNewChainHead(signedCurrentHeightBlock.getHeader())); // Inject prepares and commits from all peers for the 'previous' round (i.e. the height // from before the block arrived). @@ -156,7 +156,7 @@ public class FutureHeightTest { context .getController() - .handleNewBlockEvent(new NewChainHead(context.getBlockchain().getChainHeadHeader())); + .handleNewBlockEvent(new QbftNewChainHead(context.getBlockchain().getChainHeadHeader())); // Should only require 1 more prepare to close it out peers.getNonProposing(1).injectPrepare(roundId, currentHeightBlock.getHash()); @@ -201,7 +201,7 @@ public class FutureHeightTest { assertThat(context.getCurrentChainHeight()).isEqualTo(1); context .getController() - .handleNewBlockEvent(new NewChainHead(signedCurrentHeightBlock.getHeader())); + .handleNewBlockEvent(new QbftNewChainHead(signedCurrentHeightBlock.getHeader())); peers.verifyNoMessagesReceived(); peers.getProposer().injectProposal(nextHeightRoundId, nextHeightBlock); @@ -221,7 +221,7 @@ public class FutureHeightTest { assertThat(context.getCurrentChainHeight()).isEqualTo(2); context .getController() - .handleNewBlockEvent(new NewChainHead(signedNextHeightBlock.getHeader())); + .handleNewBlockEvent(new QbftNewChainHead(signedNextHeightBlock.getHeader())); final Prepare expectedFuturePrepareMessage = localNodeMessageFactory.createPrepare(futureHeightRoundId, futureHeightBlock.getHash()); diff --git a/consensus/qbft-core/src/integration-test/java/org/hyperledger/besu/consensus/qbft/core/test/GossipTest.java b/consensus/qbft-core/src/integration-test/java/org/hyperledger/besu/consensus/qbft/core/test/GossipTest.java index a95ecb98a..f4c0e9398 100644 --- a/consensus/qbft-core/src/integration-test/java/org/hyperledger/besu/consensus/qbft/core/test/GossipTest.java +++ b/consensus/qbft-core/src/integration-test/java/org/hyperledger/besu/consensus/qbft/core/test/GossipTest.java @@ -17,7 +17,6 @@ package org.hyperledger.besu.consensus.qbft.core.test; import static java.util.Collections.emptyList; import org.hyperledger.besu.consensus.common.bft.ConsensusRoundIdentifier; -import org.hyperledger.besu.consensus.common.bft.events.NewChainHead; import org.hyperledger.besu.consensus.qbft.QbftExtraDataCodec; import org.hyperledger.besu.consensus.qbft.core.messagedata.ProposalMessageData; import org.hyperledger.besu.consensus.qbft.core.messagewrappers.Commit; @@ -30,6 +29,7 @@ import org.hyperledger.besu.consensus.qbft.core.support.TestContext; import org.hyperledger.besu.consensus.qbft.core.support.TestContextBuilder; import org.hyperledger.besu.consensus.qbft.core.support.ValidatorPeer; import org.hyperledger.besu.consensus.qbft.core.types.QbftBlock; +import org.hyperledger.besu.consensus.qbft.core.types.QbftNewChainHead; import org.hyperledger.besu.cryptoservices.NodeKeyUtils; import java.time.Clock; @@ -170,7 +170,7 @@ public class GossipTest { context.appendBlock(signedCurrentHeightBlock); context .getController() - .handleNewBlockEvent(new NewChainHead(signedCurrentHeightBlock.getHeader())); + .handleNewBlockEvent(new QbftNewChainHead(signedCurrentHeightBlock.getHeader())); peers.verifyMessagesReceivedNonProposing(futurePrepare); } diff --git a/consensus/qbft-core/src/integration-test/java/org/hyperledger/besu/consensus/qbft/core/test/LocalNodeIsProposerTest.java b/consensus/qbft-core/src/integration-test/java/org/hyperledger/besu/consensus/qbft/core/test/LocalNodeIsProposerTest.java index 2999d1a38..c8625021b 100644 --- a/consensus/qbft-core/src/integration-test/java/org/hyperledger/besu/consensus/qbft/core/test/LocalNodeIsProposerTest.java +++ b/consensus/qbft-core/src/integration-test/java/org/hyperledger/besu/consensus/qbft/core/test/LocalNodeIsProposerTest.java @@ -19,7 +19,6 @@ import static org.hyperledger.besu.consensus.qbft.core.support.IntegrationTestHe import org.hyperledger.besu.consensus.common.bft.ConsensusRoundIdentifier; import org.hyperledger.besu.consensus.common.bft.events.BlockTimerExpiry; -import org.hyperledger.besu.consensus.common.bft.events.NewChainHead; import org.hyperledger.besu.consensus.common.bft.events.RoundExpiry; import org.hyperledger.besu.consensus.qbft.core.messagewrappers.Commit; import org.hyperledger.besu.consensus.qbft.core.messagewrappers.Prepare; @@ -29,6 +28,7 @@ import org.hyperledger.besu.consensus.qbft.core.support.RoundSpecificPeers; import org.hyperledger.besu.consensus.qbft.core.support.TestContext; import org.hyperledger.besu.consensus.qbft.core.support.TestContextBuilder; import org.hyperledger.besu.consensus.qbft.core.types.QbftBlock; +import org.hyperledger.besu.consensus.qbft.core.types.QbftNewChainHead; import java.time.Clock; import java.time.Instant; @@ -138,7 +138,7 @@ public class LocalNodeIsProposerTest { context .getController() - .handleNewBlockEvent(new NewChainHead(expectedProposedBlock.getHeader())); + .handleNewBlockEvent(new QbftNewChainHead(expectedProposedBlock.getHeader())); peers.verifyNoMessagesReceived(); } diff --git a/consensus/qbft-core/src/integration-test/java/org/hyperledger/besu/consensus/qbft/core/test/TransitionsTest.java b/consensus/qbft-core/src/integration-test/java/org/hyperledger/besu/consensus/qbft/core/test/TransitionsTest.java index 1c57e532b..512b3d481 100644 --- a/consensus/qbft-core/src/integration-test/java/org/hyperledger/besu/consensus/qbft/core/test/TransitionsTest.java +++ b/consensus/qbft-core/src/integration-test/java/org/hyperledger/besu/consensus/qbft/core/test/TransitionsTest.java @@ -20,10 +20,10 @@ import org.hyperledger.besu.config.BftFork; import org.hyperledger.besu.config.JsonUtil; import org.hyperledger.besu.config.QbftFork; import org.hyperledger.besu.consensus.common.bft.BftEventQueue; -import org.hyperledger.besu.consensus.common.bft.events.NewChainHead; import org.hyperledger.besu.consensus.qbft.core.support.TestContext; import org.hyperledger.besu.consensus.qbft.core.support.TestContextBuilder; -import org.hyperledger.besu.ethereum.core.BlockHeader; +import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockHeader; +import org.hyperledger.besu.consensus.qbft.core.types.QbftNewChainHead; import org.hyperledger.besu.testutil.TestClock; import java.time.Instant; @@ -63,13 +63,13 @@ public class TransitionsTest { context .getController() - .handleNewBlockEvent(new NewChainHead(context.getBlockchain().getChainHeadHeader())); + .handleNewBlockEvent(new QbftNewChainHead(context.getBlockchain().getChainHeadHeader())); clock.stepMillis(20_000); context.getEventMultiplexer().handleBftEvent(bftEventQueue.poll(1, TimeUnit.SECONDS)); - final BlockHeader genesisBlock = context.getBlockchain().getBlockHeader(0).get(); - final BlockHeader blockHeader1 = context.getBlockchain().getBlockHeader(1).get(); - final BlockHeader blockHeader2 = context.getBlockchain().getBlockHeader(2).get(); + final QbftBlockHeader genesisBlock = context.getBlockHeader(0); + final QbftBlockHeader blockHeader1 = context.getBlockHeader(1); + final QbftBlockHeader blockHeader2 = context.getBlockHeader(2); assertThat(blockHeader1.getTimestamp()).isEqualTo(genesisBlock.getTimestamp() + 10); assertThat(blockHeader2.getTimestamp()).isEqualTo(blockHeader1.getTimestamp() + 20); diff --git a/consensus/qbft-core/src/integration-test/java/org/hyperledger/besu/consensus/qbft/core/test/ValidatorContractTest.java b/consensus/qbft-core/src/integration-test/java/org/hyperledger/besu/consensus/qbft/core/test/ValidatorContractTest.java index 6e3f4a389..926523118 100644 --- a/consensus/qbft-core/src/integration-test/java/org/hyperledger/besu/consensus/qbft/core/test/ValidatorContractTest.java +++ b/consensus/qbft-core/src/integration-test/java/org/hyperledger/besu/consensus/qbft/core/test/ValidatorContractTest.java @@ -23,18 +23,20 @@ import org.hyperledger.besu.config.QbftFork; import org.hyperledger.besu.config.QbftFork.VALIDATOR_SELECTION_MODE; import org.hyperledger.besu.consensus.common.bft.ConsensusRoundIdentifier; import org.hyperledger.besu.consensus.common.bft.events.BlockTimerExpiry; -import org.hyperledger.besu.consensus.common.bft.events.NewChainHead; import org.hyperledger.besu.consensus.common.bft.inttest.NodeParams; -import org.hyperledger.besu.consensus.common.validator.ValidatorProvider; import org.hyperledger.besu.consensus.qbft.QbftExtraDataCodec; +import org.hyperledger.besu.consensus.qbft.adaptor.QbftExtraDataProviderAdaptor; import org.hyperledger.besu.consensus.qbft.core.support.RoundSpecificPeers; import org.hyperledger.besu.consensus.qbft.core.support.TestContext; import org.hyperledger.besu.consensus.qbft.core.support.TestContextBuilder; import org.hyperledger.besu.consensus.qbft.core.support.ValidatorPeer; import org.hyperledger.besu.consensus.qbft.core.types.QbftBlock; +import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockHeader; +import org.hyperledger.besu.consensus.qbft.core.types.QbftExtraDataProvider; +import org.hyperledger.besu.consensus.qbft.core.types.QbftNewChainHead; +import org.hyperledger.besu.consensus.qbft.core.types.QbftValidatorProvider; import org.hyperledger.besu.cryptoservices.NodeKeyUtils; import org.hyperledger.besu.datatypes.Address; -import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.testutil.TestClock; import java.time.Instant; @@ -66,7 +68,8 @@ public class ValidatorContractTest { private TestClock clock; - private final QbftExtraDataCodec extraDataCodec = new QbftExtraDataCodec(); + private final QbftExtraDataProvider extraDataProvider = + new QbftExtraDataProviderAdaptor(new QbftExtraDataCodec()); @BeforeEach public void setup() { @@ -87,9 +90,9 @@ public class ValidatorContractTest { createNewBlockAsProposer(context, 1); - final ValidatorProvider validatorProvider = context.getValidatorProvider(); - final BlockHeader genesisBlock = context.getBlockchain().getBlockHeader(0).get(); - final BlockHeader block1 = context.getBlockchain().getBlockHeader(1).get(); + final QbftValidatorProvider validatorProvider = context.getValidatorProvider(); + final QbftBlockHeader genesisBlock = context.getBlockHeader(0); + final QbftBlockHeader block1 = context.getBlockHeader(1); assertThat(validatorProvider.getValidatorsForBlock(genesisBlock)).containsExactly(NODE_ADDRESS); assertThat(validatorProvider.getValidatorsForBlock(block1)).containsExactly(NODE_ADDRESS); } @@ -109,9 +112,9 @@ public class ValidatorContractTest { createNewBlockAsProposer(context, 1); - final ValidatorProvider validatorProvider = context.getValidatorProvider(); - final BlockHeader genesisBlock = context.getBlockchain().getBlockHeader(0).get(); - final BlockHeader block1 = context.getBlockchain().getBlockHeader(1).get(); + final QbftValidatorProvider validatorProvider = context.getValidatorProvider(); + final QbftBlockHeader genesisBlock = context.getBlockHeader(0); + final QbftBlockHeader block1 = context.getBlockHeader(1); assertThat(validatorProvider.getValidatorsForBlock(genesisBlock)).containsExactly(NODE_ADDRESS); assertThat(validatorProvider.getValidatorsForBlock(block1)).containsExactly(NODE_ADDRESS); } @@ -133,9 +136,9 @@ public class ValidatorContractTest { createNewBlockAsProposer(context, 1); - final ValidatorProvider validatorProvider = context.getValidatorProvider(); - final BlockHeader genesisBlock = context.getBlockchain().getBlockHeader(0).get(); - final BlockHeader block1 = context.getBlockchain().getBlockHeader(1).get(); + final QbftValidatorProvider validatorProvider = context.getValidatorProvider(); + final QbftBlockHeader genesisBlock = context.getBlockHeader(0); + final QbftBlockHeader block1 = context.getBlockHeader(1); assertThat(validatorProvider.getValidatorsForBlock(genesisBlock)).containsExactly(NODE_ADDRESS); assertThat(validatorProvider.getValidatorsForBlock(block1)).containsExactly(NODE_ADDRESS); } @@ -160,9 +163,9 @@ public class ValidatorContractTest { context, 1, 266L); // 10s ahead of genesis timestamp in genesis_validator_contract_shanghai.json - final ValidatorProvider validatorProvider = context.getValidatorProvider(); - final BlockHeader genesisBlock = context.getBlockchain().getBlockHeader(0).get(); - final BlockHeader block1 = context.getBlockchain().getBlockHeader(1).get(); + final QbftValidatorProvider validatorProvider = context.getValidatorProvider(); + final QbftBlockHeader genesisBlock = context.getBlockHeader(0); + final QbftBlockHeader block1 = context.getBlockHeader(1); assertThat(validatorProvider.getValidatorsForBlock(genesisBlock)).containsExactly(NODE_ADDRESS); assertThat(validatorProvider.getValidatorsForBlock(block1)).containsExactly(NODE_ADDRESS); } @@ -184,9 +187,9 @@ public class ValidatorContractTest { createNewBlockAsProposer(context, 1); - final ValidatorProvider validatorProvider = context.getValidatorProvider(); - final BlockHeader genesisBlock = context.getBlockchain().getBlockHeader(0).get(); - final BlockHeader block1 = context.getBlockchain().getBlockHeader(1).get(); + final QbftValidatorProvider validatorProvider = context.getValidatorProvider(); + final QbftBlockHeader genesisBlock = context.getBlockHeader(0); + final QbftBlockHeader block1 = context.getBlockHeader(1); assertThat(validatorProvider.getValidatorsForBlock(genesisBlock)).containsExactly(NODE_ADDRESS); assertThat(validatorProvider.getValidatorsForBlock(block1)).containsExactly(NODE_ADDRESS); } @@ -211,9 +214,9 @@ public class ValidatorContractTest { context, 1, 266L); // 10s ahead of genesis timestamp in genesis_validator_contract_shanghai.json - final ValidatorProvider validatorProvider = context.getValidatorProvider(); - final BlockHeader genesisBlock = context.getBlockchain().getBlockHeader(0).get(); - final BlockHeader block1 = context.getBlockchain().getBlockHeader(1).get(); + final QbftValidatorProvider validatorProvider = context.getValidatorProvider(); + final QbftBlockHeader genesisBlock = context.getBlockHeader(0); + final QbftBlockHeader block1 = context.getBlockHeader(1); assertThat(validatorProvider.getValidatorsForBlock(genesisBlock)).containsExactly(NODE_ADDRESS); assertThat(validatorProvider.getValidatorsForBlock(block1)).containsExactly(NODE_ADDRESS); } @@ -244,17 +247,18 @@ public class ValidatorContractTest { remotePeerProposesNewBlock(context, 1L); - final ValidatorProvider validatorProvider = context.getValidatorProvider(); - final BlockHeader genesisBlock = context.getBlockchain().getBlockHeader(0).get(); - final BlockHeader block1 = context.getBlockchain().getBlockHeader(1).get(); + final QbftValidatorProvider validatorProvider = context.getValidatorProvider(); + final QbftBlockHeader genesisBlock = context.getBlockHeader(0); + final QbftBlockHeader block1 = context.getBlockHeader(1); assertThat(validatorProvider.getValidatorsForBlock(genesisBlock)).isEqualTo(block0Addresses); - assertThat(extraDataCodec.decode(genesisBlock).getValidators()).containsExactly(NODE_ADDRESS); + assertThat(extraDataProvider.getExtraData(genesisBlock).getValidators()) + .containsExactly(NODE_ADDRESS); // contract block extra data cannot contain validators or vote assertThat(validatorProvider.getValidatorsForBlock(block1)).isEqualTo(block1Addresses); - assertThat(extraDataCodec.decode(block1).getValidators()).isEmpty(); - assertThat(extraDataCodec.decode(block1).getVote()).isEmpty(); + assertThat(extraDataProvider.getExtraData(block1).getValidators()).isEmpty(); + assertThat(extraDataProvider.getExtraData(block1).getVote()).isEmpty(); } @Test @@ -282,19 +286,19 @@ public class ValidatorContractTest { remotePeerProposesNewBlock(context, 1L); - final ValidatorProvider validatorProvider = context.getValidatorProvider(); - final BlockHeader genesisBlock = context.getBlockchain().getBlockHeader(0).get(); - final BlockHeader block1 = context.getBlockchain().getBlockHeader(1).get(); + final QbftValidatorProvider validatorProvider = context.getValidatorProvider(); + final QbftBlockHeader genesisBlock = context.getBlockHeader(0); + final QbftBlockHeader block1 = context.getBlockHeader(1); // contract block extra data cannot contain validators or vote assertThat(validatorProvider.getValidatorsForBlock(genesisBlock)).isEqualTo(block0Addresses); - assertThat(extraDataCodec.decode(genesisBlock).getValidators()).isEmpty(); - assertThat(extraDataCodec.decode(genesisBlock).getVote()).isEmpty(); + assertThat(extraDataProvider.getExtraData(genesisBlock).getValidators()).isEmpty(); + assertThat(extraDataProvider.getExtraData(genesisBlock).getVote()).isEmpty(); // contract block extra data cannot contain validators or vote assertThat(validatorProvider.getValidatorsForBlock(block1)).isEqualTo(block1Addresses); - assertThat(extraDataCodec.decode(block1).getValidators()).isEmpty(); - assertThat(extraDataCodec.decode(block1).getVote()).isEmpty(); + assertThat(extraDataProvider.getExtraData(block1).getValidators()).isEmpty(); + assertThat(extraDataProvider.getExtraData(block1).getVote()).isEmpty(); } @Test @@ -325,24 +329,24 @@ public class ValidatorContractTest { clock.step(TestContextBuilder.BLOCK_TIMER_SEC, SECONDS); remotePeerProposesNewBlock(context, 2L); - final ValidatorProvider validatorProvider = context.getValidatorProvider(); - final BlockHeader genesisBlock = context.getBlockchain().getBlockHeader(0).get(); - final BlockHeader block1 = context.getBlockchain().getBlockHeader(1).get(); - final BlockHeader block2 = context.getBlockchain().getBlockHeader(2).get(); + final QbftValidatorProvider validatorProvider = context.getValidatorProvider(); + final QbftBlockHeader genesisBlock = context.getBlockHeader(0); + final QbftBlockHeader block1 = context.getBlockHeader(1); + final QbftBlockHeader block2 = context.getBlockHeader(2); // contract block extra data cannot contain validators or vote assertThat(validatorProvider.getValidatorsForBlock(genesisBlock)).isEqualTo(block0Addresses); - assertThat(extraDataCodec.decode(genesisBlock).getValidators()).isEmpty(); - assertThat(extraDataCodec.decode(genesisBlock).getVote()).isEmpty(); + assertThat(extraDataProvider.getExtraData(genesisBlock).getValidators()).isEmpty(); + assertThat(extraDataProvider.getExtraData(genesisBlock).getVote()).isEmpty(); // uses overridden validators assertThat(validatorProvider.getValidatorsForBlock(block1)).isEqualTo(block1Addresses); - assertThat(extraDataCodec.decode(block1).getValidators()) + assertThat(extraDataProvider.getExtraData(block1).getValidators()) .containsExactly(NODE_2_ADDRESS, NODE_ADDRESS); // uses cached validators assertThat(validatorProvider.getValidatorsForBlock(block2)).isEqualTo(block1Addresses); - assertThat(extraDataCodec.decode(block2).getValidators()) + assertThat(extraDataProvider.getExtraData(block2).getValidators()) .containsExactly(NODE_2_ADDRESS, NODE_ADDRESS); } @@ -381,28 +385,29 @@ public class ValidatorContractTest { clock.step(TestContextBuilder.BLOCK_TIMER_SEC, SECONDS); remotePeerProposesNewBlock(context, 3L); - final ValidatorProvider validatorProvider = context.getValidatorProvider(); - final BlockHeader genesisBlock = context.getBlockchain().getBlockHeader(0).get(); - final BlockHeader block1 = context.getBlockchain().getBlockHeader(1).get(); - final BlockHeader block2 = context.getBlockchain().getBlockHeader(2).get(); - final BlockHeader block3 = context.getBlockchain().getBlockHeader(3).get(); + final QbftValidatorProvider validatorProvider = context.getValidatorProvider(); + final QbftBlockHeader genesisBlock = context.getBlockHeader(0); + final QbftBlockHeader block1 = context.getBlockHeader(1); + final QbftBlockHeader block2 = context.getBlockHeader(2); + final QbftBlockHeader block3 = context.getBlockHeader(3); assertThat(validatorProvider.getValidatorsForBlock(genesisBlock)).isEqualTo(block0Addresses); - assertThat(extraDataCodec.decode(genesisBlock).getValidators()).containsExactly(NODE_ADDRESS); + assertThat(extraDataProvider.getExtraData(genesisBlock).getValidators()) + .containsExactly(NODE_ADDRESS); // contract block extra data cannot contain validators or vote assertThat(validatorProvider.getValidatorsForBlock(block1)).isEqualTo(block1Addresses); - assertThat(extraDataCodec.decode(block1).getValidators()).isEmpty(); - assertThat(extraDataCodec.decode(block1).getVote()).isEmpty(); + assertThat(extraDataProvider.getExtraData(block1).getValidators()).isEmpty(); + assertThat(extraDataProvider.getExtraData(block1).getVote()).isEmpty(); // uses overridden validators assertThat(validatorProvider.getValidatorsForBlock(block2)).isEqualTo(block1Addresses); - assertThat(extraDataCodec.decode(block2).getValidators()) + assertThat(extraDataProvider.getExtraData(block2).getValidators()) .containsExactly(NODE_2_ADDRESS, NODE_ADDRESS); // uses cached validators assertThat(validatorProvider.getValidatorsForBlock(block3)).isEqualTo(block1Addresses); - assertThat(extraDataCodec.decode(block3).getValidators()) + assertThat(extraDataProvider.getExtraData(block3).getValidators()) .containsExactly(NODE_2_ADDRESS, NODE_ADDRESS); } @@ -438,23 +443,24 @@ public class ValidatorContractTest { clock.step(TestContextBuilder.BLOCK_TIMER_SEC, SECONDS); remotePeerProposesNewBlock(context, 2L); - final ValidatorProvider validatorProvider = context.getValidatorProvider(); - final BlockHeader genesisBlock = context.getBlockchain().getBlockHeader(0).get(); - final BlockHeader block1 = context.getBlockchain().getBlockHeader(1).get(); - final BlockHeader block2 = context.getBlockchain().getBlockHeader(2).get(); + final QbftValidatorProvider validatorProvider = context.getValidatorProvider(); + final QbftBlockHeader genesisBlock = context.getBlockHeader(0); + final QbftBlockHeader block1 = context.getBlockHeader(1); + final QbftBlockHeader block2 = context.getBlockHeader(2); // contract block extra data cannot contain validators or vote assertThat(validatorProvider.getValidatorsForBlock(genesisBlock)).isEqualTo(block0Addresses); - assertThat(extraDataCodec.decode(genesisBlock).getValidators()).isEmpty(); - assertThat(extraDataCodec.decode(genesisBlock).getVote()).isEmpty(); + assertThat(extraDataProvider.getExtraData(genesisBlock).getValidators()).isEmpty(); + assertThat(extraDataProvider.getExtraData(genesisBlock).getVote()).isEmpty(); assertThat(validatorProvider.getValidatorsForBlock(block1)).isEqualTo(block1Addresses); - assertThat(extraDataCodec.decode(block1).getValidators()).containsExactly(NODE_2_ADDRESS); + assertThat(extraDataProvider.getExtraData(block1).getValidators()) + .containsExactly(NODE_2_ADDRESS); // contract block extra data cannot contain validators or vote assertThat(validatorProvider.getValidatorsForBlock(block2)).isEqualTo(block2Addresses); - assertThat(extraDataCodec.decode(block2).getValidators()).isEmpty(); - assertThat(extraDataCodec.decode(block2).getVote()).isEmpty(); + assertThat(extraDataProvider.getExtraData(block2).getValidators()).isEmpty(); + assertThat(extraDataProvider.getExtraData(block2).getVote()).isEmpty(); } private void createNewBlockAsProposer(final TestContext context, final long blockNumber) { @@ -472,7 +478,7 @@ public class ValidatorContractTest { assertThat(context.getCurrentChainHeight()).isEqualTo(blockNumber); context .getController() - .handleNewBlockEvent(new NewChainHead(context.getBlockchain().getChainHeadHeader())); + .handleNewBlockEvent(new QbftNewChainHead(context.getBlockchain().getChainHeadHeader())); } private void createNewBlockAsProposerFixedTime( @@ -490,7 +496,7 @@ public class ValidatorContractTest { assertThat(context.getCurrentChainHeight()).isEqualTo(blockNumber); context .getController() - .handleNewBlockEvent(new NewChainHead(context.getBlockchain().getChainHeadHeader())); + .handleNewBlockEvent(new QbftNewChainHead(context.getBlockchain().getChainHeadHeader())); } private void remotePeerProposesNewBlock(final TestContext context, final long blockNumber) { @@ -507,7 +513,7 @@ public class ValidatorContractTest { context .getController() - .handleNewBlockEvent(new NewChainHead(context.getBlockchain().getChainHeadHeader())); + .handleNewBlockEvent(new QbftNewChainHead(context.getBlockchain().getChainHeadHeader())); } private QbftFork createContractFork(final long block, final Address contractAddress) { diff --git a/consensus/qbft-core/src/integration-test/java/org/hyperledger/besu/consensus/qbft/core/test/round/QbftRoundIntegrationTest.java b/consensus/qbft-core/src/integration-test/java/org/hyperledger/besu/consensus/qbft/core/test/round/QbftRoundIntegrationTest.java index 2ce73c58a..4f8c23696 100644 --- a/consensus/qbft-core/src/integration-test/java/org/hyperledger/besu/consensus/qbft/core/test/round/QbftRoundIntegrationTest.java +++ b/consensus/qbft-core/src/integration-test/java/org/hyperledger/besu/consensus/qbft/core/test/round/QbftRoundIntegrationTest.java @@ -30,6 +30,7 @@ import org.hyperledger.besu.consensus.common.bft.RoundTimer; import org.hyperledger.besu.consensus.common.bft.inttest.StubValidatorMulticaster; import org.hyperledger.besu.consensus.qbft.QbftExtraDataCodec; import org.hyperledger.besu.consensus.qbft.adaptor.QbftBlockAdaptor; +import org.hyperledger.besu.consensus.qbft.adaptor.QbftBlockHeaderAdaptor; import org.hyperledger.besu.consensus.qbft.adaptor.QbftBlockInterfaceAdaptor; import org.hyperledger.besu.consensus.qbft.core.network.QbftMessageTransmitter; import org.hyperledger.besu.consensus.qbft.core.payload.MessageFactory; @@ -38,6 +39,8 @@ import org.hyperledger.besu.consensus.qbft.core.statemachine.RoundState; import org.hyperledger.besu.consensus.qbft.core.types.QbftBlock; import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockCodec; import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockCreator; +import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockHashing; +import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockHeader; import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockImporter; import org.hyperledger.besu.consensus.qbft.core.types.QbftContext; import org.hyperledger.besu.consensus.qbft.core.types.QbftExtraDataProvider; @@ -97,9 +100,10 @@ public class QbftRoundIntegrationTest { private MessageFactory throwingMessageFactory; private QbftMessageTransmitter transmitter; @Mock private StubValidatorMulticaster multicaster; - @Mock private BlockHeader parentHeader; + @Mock private QbftBlockHeader parentHeader; @Mock private QbftBlockCodec blockEncoder; @Mock private QbftExtraDataProvider qbftExtraDataProvider; + @Mock private QbftBlockHashing blockHashing; private QbftBlock proposedBlock; @@ -129,8 +133,9 @@ public class QbftRoundIntegrationTest { headerTestFixture.number(1); final BlockHeader header = headerTestFixture.buildHeader(); final Block block = new Block(header, new BlockBody(emptyList(), emptyList())); + final QbftBlockHeader qbftBlockHeader = new QbftBlockHeaderAdaptor(header); proposedBlock = new QbftBlockAdaptor(block); - when(qbftExtraDataProvider.getExtraData(header)).thenReturn(proposedExtraData); + when(qbftExtraDataProvider.getExtraData(qbftBlockHeader)).thenReturn(proposedExtraData); when(protocolSchedule.getByBlockHeader(any())).thenReturn(protocolSpec); when(protocolSpec.getBlockImporter()).thenReturn(blockImporter); @@ -163,6 +168,7 @@ public class QbftRoundIntegrationTest { roundTimer, bftExtraDataCodec, qbftExtraDataProvider, + blockHashing, parentHeader); round.handleProposalMessage( @@ -203,6 +209,7 @@ public class QbftRoundIntegrationTest { roundTimer, bftExtraDataCodec, qbftExtraDataProvider, + blockHashing, parentHeader); // inject a block first, then a prepare on it. diff --git a/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/statemachine/BaseQbftBlockHeightManager.java b/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/statemachine/BaseQbftBlockHeightManager.java index b426263c2..7c5cd3f33 100644 --- a/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/statemachine/BaseQbftBlockHeightManager.java +++ b/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/statemachine/BaseQbftBlockHeightManager.java @@ -14,14 +14,43 @@ */ package org.hyperledger.besu.consensus.qbft.core.statemachine; -import org.hyperledger.besu.consensus.common.bft.statemachine.BaseBlockHeightManager; +import org.hyperledger.besu.consensus.common.bft.ConsensusRoundIdentifier; +import org.hyperledger.besu.consensus.common.bft.events.RoundExpiry; import org.hyperledger.besu.consensus.qbft.core.messagewrappers.Commit; import org.hyperledger.besu.consensus.qbft.core.messagewrappers.Prepare; import org.hyperledger.besu.consensus.qbft.core.messagewrappers.Proposal; import org.hyperledger.besu.consensus.qbft.core.messagewrappers.RoundChange; +import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockHeader; /** The interface Base qbft block height manager. */ -public interface BaseQbftBlockHeightManager extends BaseBlockHeightManager { +public interface BaseQbftBlockHeightManager { + /** + * Handle block timer expiry. + * + * @param roundIdentifier the round identifier + */ + void handleBlockTimerExpiry(ConsensusRoundIdentifier roundIdentifier); + + /** + * Round expired. + * + * @param expire the expiry + */ + void roundExpired(RoundExpiry expire); + + /** + * Gets chain height. + * + * @return the chain height + */ + long getChainHeight(); + + /** + * Gets parent block header. + * + * @return the parent block header + */ + QbftBlockHeader getParentBlockHeader(); /** * Handle proposal payload. diff --git a/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/statemachine/NoOpBlockHeightManager.java b/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/statemachine/NoOpBlockHeightManager.java index 4ad83333d..37d05efe0 100644 --- a/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/statemachine/NoOpBlockHeightManager.java +++ b/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/statemachine/NoOpBlockHeightManager.java @@ -20,19 +20,19 @@ import org.hyperledger.besu.consensus.qbft.core.messagewrappers.Commit; import org.hyperledger.besu.consensus.qbft.core.messagewrappers.Prepare; import org.hyperledger.besu.consensus.qbft.core.messagewrappers.Proposal; import org.hyperledger.besu.consensus.qbft.core.messagewrappers.RoundChange; -import org.hyperledger.besu.ethereum.core.BlockHeader; +import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockHeader; /** The type NoOp block height manager. */ public class NoOpBlockHeightManager implements BaseQbftBlockHeightManager { - private final BlockHeader parentHeader; + private final QbftBlockHeader parentHeader; /** * Instantiates a new NoOp block height manager. * * @param parentHeader the parent header */ - public NoOpBlockHeightManager(final BlockHeader parentHeader) { + public NoOpBlockHeightManager(final QbftBlockHeader parentHeader) { this.parentHeader = parentHeader; } @@ -60,7 +60,7 @@ public class NoOpBlockHeightManager implements BaseQbftBlockHeightManager { } @Override - public BlockHeader getParentBlockHeader() { + public QbftBlockHeader getParentBlockHeader() { return parentHeader; } } diff --git a/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/statemachine/QbftBlockHeightManager.java b/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/statemachine/QbftBlockHeightManager.java index c8afaac10..a74b9c6d3 100644 --- a/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/statemachine/QbftBlockHeightManager.java +++ b/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/statemachine/QbftBlockHeightManager.java @@ -25,11 +25,11 @@ import org.hyperledger.besu.consensus.qbft.core.messagewrappers.RoundChange; import org.hyperledger.besu.consensus.qbft.core.network.QbftMessageTransmitter; import org.hyperledger.besu.consensus.qbft.core.payload.MessageFactory; import org.hyperledger.besu.consensus.qbft.core.types.QbftBlock; +import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockHeader; import org.hyperledger.besu.consensus.qbft.core.types.QbftFinalState; import org.hyperledger.besu.consensus.qbft.core.validation.FutureRoundProposalMessageValidator; import org.hyperledger.besu.consensus.qbft.core.validation.MessageValidatorFactory; import org.hyperledger.besu.datatypes.Address; -import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.plugin.services.securitymodule.SecurityModuleException; import java.time.Clock; @@ -57,7 +57,7 @@ public class QbftBlockHeightManager implements BaseQbftBlockHeightManager { private final QbftRoundFactory roundFactory; private final RoundChangeManager roundChangeManager; - private final BlockHeader parentHeader; + private final QbftBlockHeader parentHeader; private final QbftMessageTransmitter transmitter; private final MessageFactory messageFactory; private final Map futureRoundStateBuffer = Maps.newHashMap(); @@ -82,7 +82,7 @@ public class QbftBlockHeightManager implements BaseQbftBlockHeightManager { * @param messageFactory the message factory */ public QbftBlockHeightManager( - final BlockHeader parentHeader, + final QbftBlockHeader parentHeader, final QbftFinalState finalState, final RoundChangeManager roundChangeManager, final QbftRoundFactory qbftRoundFactory, @@ -113,7 +113,7 @@ public class QbftBlockHeightManager implements BaseQbftBlockHeightManager { final ConsensusRoundIdentifier roundIdentifier = new ConsensusRoundIdentifier(nextBlockHeight, 0); - finalState.getBlockTimer().startTimer(roundIdentifier, parentHeader); + finalState.getBlockTimer().startTimer(roundIdentifier, parentHeader::getTimestamp); } /** @@ -130,7 +130,7 @@ public class QbftBlockHeightManager implements BaseQbftBlockHeightManager { * @param isEarlyRoundChangeEnabled enable round change when f+1 RC messages are received */ public QbftBlockHeightManager( - final BlockHeader parentHeader, + final QbftBlockHeader parentHeader, final QbftFinalState finalState, final RoundChangeManager roundChangeManager, final QbftRoundFactory qbftRoundFactory, @@ -199,7 +199,9 @@ public class QbftBlockHeightManager implements BaseQbftBlockHeightManager { // handle the block times period final long currentTimeInMillis = finalState.getClock().millis(); boolean emptyBlockExpired = - finalState.getBlockTimer().checkEmptyBlockExpired(parentHeader, currentTimeInMillis); + finalState + .getBlockTimer() + .checkEmptyBlockExpired(parentHeader::getTimestamp, currentTimeInMillis); if (emptyBlockExpired) { LOG.trace( "Block has no transactions and this node is a proposer so it will send a proposal: " @@ -211,7 +213,8 @@ public class QbftBlockHeightManager implements BaseQbftBlockHeightManager { + roundIdentifier); finalState .getBlockTimer() - .resetTimerForEmptyBlock(roundIdentifier, parentHeader, currentTimeInMillis); + .resetTimerForEmptyBlock( + roundIdentifier, parentHeader::getTimestamp, currentTimeInMillis); finalState.getRoundTimer().cancelTimer(); currentRound = Optional.empty(); } @@ -452,7 +455,7 @@ public class QbftBlockHeightManager implements BaseQbftBlockHeightManager { } @Override - public BlockHeader getParentBlockHeader() { + public QbftBlockHeader getParentBlockHeader() { return parentHeader; } diff --git a/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/statemachine/QbftBlockHeightManagerFactory.java b/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/statemachine/QbftBlockHeightManagerFactory.java index 0d3607b50..cc957513d 100644 --- a/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/statemachine/QbftBlockHeightManagerFactory.java +++ b/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/statemachine/QbftBlockHeightManagerFactory.java @@ -16,10 +16,10 @@ package org.hyperledger.besu.consensus.qbft.core.statemachine; import org.hyperledger.besu.consensus.common.bft.BftHelpers; import org.hyperledger.besu.consensus.qbft.core.payload.MessageFactory; +import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockHeader; import org.hyperledger.besu.consensus.qbft.core.types.QbftFinalState; +import org.hyperledger.besu.consensus.qbft.core.types.QbftValidatorModeTransitionLogger; import org.hyperledger.besu.consensus.qbft.core.validation.MessageValidatorFactory; -import org.hyperledger.besu.consensus.qbft.core.validator.ValidatorModeTransitionLogger; -import org.hyperledger.besu.ethereum.core.BlockHeader; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -33,7 +33,7 @@ public class QbftBlockHeightManagerFactory { private final QbftFinalState finalState; private final MessageValidatorFactory messageValidatorFactory; private final MessageFactory messageFactory; - private final ValidatorModeTransitionLogger validatorModeTransitionLogger; + private final QbftValidatorModeTransitionLogger validatorModeTransitionLogger; private boolean isEarlyRoundChangeEnabled = false; /** @@ -50,7 +50,7 @@ public class QbftBlockHeightManagerFactory { final QbftRoundFactory roundFactory, final MessageValidatorFactory messageValidatorFactory, final MessageFactory messageFactory, - final ValidatorModeTransitionLogger validatorModeTransitionLogger) { + final QbftValidatorModeTransitionLogger validatorModeTransitionLogger) { this.roundFactory = roundFactory; this.finalState = finalState; this.messageValidatorFactory = messageValidatorFactory; @@ -64,7 +64,7 @@ public class QbftBlockHeightManagerFactory { * @param parentHeader the parent header * @return the base qbft block height manager */ - public BaseQbftBlockHeightManager create(final BlockHeader parentHeader) { + public BaseQbftBlockHeightManager create(final QbftBlockHeader parentHeader) { validatorModeTransitionLogger.logTransitionChange(parentHeader); if (finalState.isLocalNodeValidator()) { @@ -85,11 +85,13 @@ public class QbftBlockHeightManagerFactory { this.isEarlyRoundChangeEnabled = isEarlyRoundChangeEnabled; } - private BaseQbftBlockHeightManager createNoOpBlockHeightManager(final BlockHeader parentHeader) { + private BaseQbftBlockHeightManager createNoOpBlockHeightManager( + final QbftBlockHeader parentHeader) { return new NoOpBlockHeightManager(parentHeader); } - private BaseQbftBlockHeightManager createFullBlockHeightManager(final BlockHeader parentHeader) { + private BaseQbftBlockHeightManager createFullBlockHeightManager( + final QbftBlockHeader parentHeader) { QbftBlockHeightManager qbftBlockHeightManager; RoundChangeManager roundChangeManager; diff --git a/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/statemachine/QbftController.java b/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/statemachine/QbftController.java index 91a112aa3..c2fdaaf70 100644 --- a/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/statemachine/QbftController.java +++ b/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/statemachine/QbftController.java @@ -20,11 +20,9 @@ import org.hyperledger.besu.consensus.common.bft.MessageTracker; import org.hyperledger.besu.consensus.common.bft.SynchronizerUpdater; import org.hyperledger.besu.consensus.common.bft.events.BftReceivedMessageEvent; import org.hyperledger.besu.consensus.common.bft.events.BlockTimerExpiry; -import org.hyperledger.besu.consensus.common.bft.events.NewChainHead; import org.hyperledger.besu.consensus.common.bft.events.RoundExpiry; import org.hyperledger.besu.consensus.common.bft.messagewrappers.BftMessage; import org.hyperledger.besu.consensus.common.bft.payload.Authored; -import org.hyperledger.besu.consensus.common.bft.statemachine.BftEventHandler; import org.hyperledger.besu.consensus.common.bft.statemachine.FutureMessageBuffer; import org.hyperledger.besu.consensus.qbft.core.messagedata.CommitMessageData; import org.hyperledger.besu.consensus.qbft.core.messagedata.PrepareMessageData; @@ -32,9 +30,11 @@ import org.hyperledger.besu.consensus.qbft.core.messagedata.ProposalMessageData; import org.hyperledger.besu.consensus.qbft.core.messagedata.QbftV1; import org.hyperledger.besu.consensus.qbft.core.messagedata.RoundChangeMessageData; import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockCodec; +import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockHeader; +import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockchain; +import org.hyperledger.besu.consensus.qbft.core.types.QbftEventHandler; import org.hyperledger.besu.consensus.qbft.core.types.QbftFinalState; -import org.hyperledger.besu.ethereum.chain.Blockchain; -import org.hyperledger.besu.ethereum.core.BlockHeader; +import org.hyperledger.besu.consensus.qbft.core.types.QbftNewChainHead; import org.hyperledger.besu.ethereum.p2p.rlpx.wire.Message; import org.hyperledger.besu.ethereum.p2p.rlpx.wire.MessageData; @@ -45,10 +45,10 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** The Qbft controller. */ -public class QbftController implements BftEventHandler { +public class QbftController implements QbftEventHandler { private static final Logger LOG = LoggerFactory.getLogger(QbftController.class); - private final Blockchain blockchain; + private final QbftBlockchain blockchain; private final QbftFinalState finalState; private final FutureMessageBuffer futureMessageBuffer; private final Gossiper gossiper; @@ -72,7 +72,7 @@ public class QbftController implements BftEventHandler { * @param blockEncoder the block encoder */ public QbftController( - final Blockchain blockchain, + final QbftBlockchain blockchain, final QbftFinalState finalState, final QbftBlockHeightManagerFactory qbftBlockHeightManagerFactory, final Gossiper gossiper, @@ -131,7 +131,7 @@ public class QbftController implements BftEventHandler { } } - private void createNewHeightManager(final BlockHeader parentHeader) { + private void createNewHeightManager(final QbftBlockHeader parentHeader) { currentHeightManager = qbftBlockHeightManagerFactory.create(parentHeader); } @@ -187,9 +187,9 @@ public class QbftController implements BftEventHandler { } @Override - public void handleNewBlockEvent(final NewChainHead newChainHead) { - final BlockHeader newBlockHeader = newChainHead.getNewChainHeadHeader(); - final BlockHeader currentMiningParent = getCurrentHeightManager().getParentBlockHeader(); + public void handleNewBlockEvent(final QbftNewChainHead newChainHead) { + final QbftBlockHeader newBlockHeader = newChainHead.newChainHeadHeader(); + final QbftBlockHeader currentMiningParent = getCurrentHeightManager().getParentBlockHeader(); LOG.debug( "New chain head detected (block number={})," + " currently mining on top of {}.", newBlockHeader.getNumber(), @@ -251,7 +251,7 @@ public class QbftController implements BftEventHandler { } } - private void startNewHeightManager(final BlockHeader parentHeader) { + private void startNewHeightManager(final QbftBlockHeader parentHeader) { createNewHeightManager(parentHeader); final long newChainHeight = getCurrentHeightManager().getChainHeight(); futureMessageBuffer.retrieveMessagesForHeight(newChainHeight).forEach(this::handleMessage); diff --git a/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/statemachine/QbftRound.java b/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/statemachine/QbftRound.java index 20d5e80f5..37b098448 100644 --- a/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/statemachine/QbftRound.java +++ b/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/statemachine/QbftRound.java @@ -16,7 +16,6 @@ package org.hyperledger.besu.consensus.qbft.core.statemachine; import static java.util.Collections.emptyList; -import org.hyperledger.besu.consensus.common.bft.BftBlockHashing; import org.hyperledger.besu.consensus.common.bft.BftExtraData; import org.hyperledger.besu.consensus.common.bft.BftExtraDataCodec; import org.hyperledger.besu.consensus.common.bft.ConsensusRoundIdentifier; @@ -31,6 +30,8 @@ import org.hyperledger.besu.consensus.qbft.core.payload.PreparePayload; import org.hyperledger.besu.consensus.qbft.core.payload.RoundChangePayload; import org.hyperledger.besu.consensus.qbft.core.types.QbftBlock; import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockCreator; +import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockHashing; +import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockHeader; import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockImporter; import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockInterface; import org.hyperledger.besu.consensus.qbft.core.types.QbftContext; @@ -42,7 +43,6 @@ import org.hyperledger.besu.crypto.SECPSignature; import org.hyperledger.besu.cryptoservices.NodeKey; import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.ethereum.ProtocolContext; -import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.plugin.services.securitymodule.SecurityModuleException; import org.hyperledger.besu.util.Subscribers; @@ -81,7 +81,8 @@ public class QbftRound { /** The Bft extra data provider */ protected final QbftExtraDataProvider qbftExtraDataProvider; - private final BlockHeader parentHeader; + private final QbftBlockHashing blockHashing; + private final QbftBlockHeader parentHeader; /** * Instantiates a new Qbft round. @@ -97,6 +98,7 @@ public class QbftRound { * @param roundTimer the round timer * @param bftExtraDataCodec the bft extra data codec * @param qbftExtraDataProvider the qbft extra data provider + * @param blockHashing the block hashing * @param parentHeader the parent header */ public QbftRound( @@ -111,7 +113,8 @@ public class QbftRound { final RoundTimer roundTimer, final BftExtraDataCodec bftExtraDataCodec, final QbftExtraDataProvider qbftExtraDataProvider, - final BlockHeader parentHeader) { + final QbftBlockHashing blockHashing, + final QbftBlockHeader parentHeader) { this.roundState = roundState; this.blockCreator = blockCreator; this.protocolContext = protocolContext; @@ -122,6 +125,7 @@ public class QbftRound { this.transmitter = transmitter; this.bftExtraDataCodec = bftExtraDataCodec; this.qbftExtraDataProvider = qbftExtraDataProvider; + this.blockHashing = blockHashing; this.parentHeader = parentHeader; roundTimer.startTimer(getRoundIdentifier()); } @@ -166,7 +170,7 @@ public class QbftRound { "Sending proposal from PreparedCertificate. round={}", roundState.getRoundIdentifier()); QbftBlock preparedBlock = bestPreparedCertificate.get().getBlock(); final QbftBlockInterface bftBlockInterface = - protocolContext.getConsensusContext(QbftContext.class).getBlockInterface(); + protocolContext.getConsensusContext(QbftContext.class).blockInterface(); blockToPublish = bftBlockInterface.replaceRoundInBlock( preparedBlock, @@ -391,17 +395,16 @@ public class QbftRound { private SECPSignature createCommitSeal(final QbftBlock block) { final QbftBlock commitBlock = createCommitBlock(block); - final BlockHeader proposedHeader = commitBlock.getHeader(); + final QbftBlockHeader proposedHeader = commitBlock.getHeader(); final BftExtraData extraData = qbftExtraDataProvider.getExtraData(proposedHeader); final Hash commitHash = - new BftBlockHashing(bftExtraDataCodec) - .calculateDataHashForCommittedSeal(proposedHeader, extraData); + blockHashing.calculateDataHashForCommittedSeal(proposedHeader, extraData); return nodeKey.sign(commitHash); } private QbftBlock createCommitBlock(final QbftBlock block) { final QbftBlockInterface bftBlockInterface = - protocolContext.getConsensusContext(QbftContext.class).getBlockInterface(); + protocolContext.getConsensusContext(QbftContext.class).blockInterface(); return bftBlockInterface.replaceRoundInBlock( block, getRoundIdentifier().getRoundNumber(), QbftHashMode.COMMITTED_SEAL); } diff --git a/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/statemachine/QbftRoundFactory.java b/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/statemachine/QbftRoundFactory.java index a09b1dd5a..fd3f627df 100644 --- a/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/statemachine/QbftRoundFactory.java +++ b/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/statemachine/QbftRoundFactory.java @@ -20,13 +20,14 @@ import org.hyperledger.besu.consensus.qbft.core.network.QbftMessageTransmitter; import org.hyperledger.besu.consensus.qbft.core.payload.MessageFactory; import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockCreator; import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockCreatorFactory; +import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockHashing; +import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockHeader; import org.hyperledger.besu.consensus.qbft.core.types.QbftExtraDataProvider; import org.hyperledger.besu.consensus.qbft.core.types.QbftFinalState; import org.hyperledger.besu.consensus.qbft.core.types.QbftMinedBlockObserver; import org.hyperledger.besu.consensus.qbft.core.types.QbftProtocolSchedule; import org.hyperledger.besu.consensus.qbft.core.validation.MessageValidatorFactory; import org.hyperledger.besu.ethereum.ProtocolContext; -import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.util.Subscribers; /** The Qbft round factory. */ @@ -41,6 +42,7 @@ public class QbftRoundFactory { private final MessageFactory messageFactory; private final BftExtraDataCodec bftExtraDataCodec; private final QbftExtraDataProvider qbftExtraDataProvider; + private final QbftBlockHashing blockHashing; /** * Instantiates a new Qbft round factory. @@ -53,6 +55,7 @@ public class QbftRoundFactory { * @param messageFactory the message factory * @param bftExtraDataCodec the bft extra data codec * @param qbftExtraDataProvider the bft extra data codec + * @param blockHashing the block hashing */ public QbftRoundFactory( final QbftFinalState finalState, @@ -62,7 +65,8 @@ public class QbftRoundFactory { final MessageValidatorFactory messageValidatorFactory, final MessageFactory messageFactory, final BftExtraDataCodec bftExtraDataCodec, - final QbftExtraDataProvider qbftExtraDataProvider) { + final QbftExtraDataProvider qbftExtraDataProvider, + final QbftBlockHashing blockHashing) { this.finalState = finalState; this.blockCreatorFactory = finalState.getBlockCreatorFactory(); this.protocolContext = protocolContext; @@ -72,6 +76,7 @@ public class QbftRoundFactory { this.messageFactory = messageFactory; this.bftExtraDataCodec = bftExtraDataCodec; this.qbftExtraDataProvider = qbftExtraDataProvider; + this.blockHashing = blockHashing; } /** @@ -81,7 +86,7 @@ public class QbftRoundFactory { * @param round the round * @return the qbft round */ - public QbftRound createNewRound(final BlockHeader parentHeader, final int round) { + public QbftRound createNewRound(final QbftBlockHeader parentHeader, final int round) { long nextBlockHeight = parentHeader.getNumber() + 1; final ConsensusRoundIdentifier roundIdentifier = new ConsensusRoundIdentifier(nextBlockHeight, round); @@ -103,7 +108,7 @@ public class QbftRoundFactory { * @return the qbft round */ public QbftRound createNewRoundWithState( - final BlockHeader parentHeader, final RoundState roundState) { + final QbftBlockHeader parentHeader, final RoundState roundState) { final QbftBlockCreator blockCreator = blockCreatorFactory.create(roundState.getRoundIdentifier().getRoundNumber()); @@ -123,6 +128,7 @@ public class QbftRoundFactory { finalState.getRoundTimer(), bftExtraDataCodec, qbftExtraDataProvider, + blockHashing, parentHeader); } } diff --git a/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/types/QbftBlock.java b/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/types/QbftBlock.java index 30a97ea00..d2c607d3d 100644 --- a/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/types/QbftBlock.java +++ b/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/types/QbftBlock.java @@ -15,7 +15,6 @@ package org.hyperledger.besu.consensus.qbft.core.types; import org.hyperledger.besu.datatypes.Hash; -import org.hyperledger.besu.ethereum.core.BlockHeader; /** Represents a block in the context of the QBFT consensus mechanism. */ public interface QbftBlock { @@ -25,7 +24,7 @@ public interface QbftBlock { * * @return the block header. */ - BlockHeader getHeader(); + QbftBlockHeader getHeader(); /** * Whether the block is considered empty, generally this means that the block has no transactions. diff --git a/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/types/QbftBlockCreator.java b/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/types/QbftBlockCreator.java index ad01cac60..80c06b021 100644 --- a/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/types/QbftBlockCreator.java +++ b/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/types/QbftBlockCreator.java @@ -15,7 +15,6 @@ package org.hyperledger.besu.consensus.qbft.core.types; import org.hyperledger.besu.crypto.SECPSignature; -import org.hyperledger.besu.ethereum.core.BlockHeader; import java.util.Collection; @@ -29,7 +28,7 @@ public interface QbftBlockCreator { * @param parentHeader the parent header * @return the block */ - QbftBlock createBlock(long headerTimeStampSeconds, BlockHeader parentHeader); + QbftBlock createBlock(long headerTimeStampSeconds, QbftBlockHeader parentHeader); /** * Create sealed block. diff --git a/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/types/QbftBlockHashing.java b/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/types/QbftBlockHashing.java new file mode 100644 index 000000000..c4dc04641 --- /dev/null +++ b/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/types/QbftBlockHashing.java @@ -0,0 +1,34 @@ +/* + * 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.consensus.qbft.core.types; + +import org.hyperledger.besu.consensus.common.bft.BftExtraData; +import org.hyperledger.besu.datatypes.Hash; + +/** Provides hashing for QBFT block headers. */ +public interface QbftBlockHashing { + + /** + * Constructs a hash of the block header suitable for signing as a committed seal. The extra data + * in the hash uses an empty list for the committed seals. + * + * @param header The header for which a proposer seal is to be calculated (with or without extra + * data) + * @param extraData The extra data block which is to be inserted to the header once seal is + * calculated + * @return the hash of the header including the validator and proposer seal in the extra data + */ + Hash calculateDataHashForCommittedSeal(QbftBlockHeader header, BftExtraData extraData); +} diff --git a/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/types/QbftBlockHeader.java b/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/types/QbftBlockHeader.java new file mode 100644 index 000000000..e3bf30e3a --- /dev/null +++ b/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/types/QbftBlockHeader.java @@ -0,0 +1,50 @@ +/* + * 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.consensus.qbft.core.types; + +import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.datatypes.Hash; + +/** Represents a block header in the context of the QBFT consensus mechanism. */ +public interface QbftBlockHeader { + + /** + * Returns the block number of the block. + * + * @return the block number. + */ + long getNumber(); + + /** + * Returns the timestamp of the block. + * + * @return the timestamp. + */ + long getTimestamp(); + + /** + * Returns the coinbase of the block. + * + * @return the coinbase. + */ + Address getCoinbase(); + + /** + * Returns the hash of the block. + * + * @return the hash. + */ + Hash getHash(); +} diff --git a/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/types/QbftBlockchain.java b/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/types/QbftBlockchain.java new file mode 100644 index 000000000..5047784ce --- /dev/null +++ b/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/types/QbftBlockchain.java @@ -0,0 +1,32 @@ +/* + * 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.consensus.qbft.core.types; + +/** Minimal QBFT interface for reading data from the blockchain. */ +public interface QbftBlockchain { + /** + * Returns the chain head header. + * + * @return the header. + */ + QbftBlockHeader getChainHeadHeader(); + + /** + * Returns the chain head block number. + * + * @return the block number. + */ + long getChainHeadBlockNumber(); +} diff --git a/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/types/QbftContext.java b/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/types/QbftContext.java index e87017df6..77b1fc7e0 100644 --- a/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/types/QbftContext.java +++ b/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/types/QbftContext.java @@ -14,33 +14,25 @@ */ package org.hyperledger.besu.consensus.qbft.core.types; -import org.hyperledger.besu.consensus.common.validator.ValidatorProvider; import org.hyperledger.besu.ethereum.ConsensusContext; -/** Holds the QBFT specific mutable state. */ -public class QbftContext implements ConsensusContext { - - private final ValidatorProvider validatorProvider; - private final QbftBlockInterface blockInterface; - - /** - * Instantiates a new Bft context. - * - * @param validatorProvider the validator provider - * @param blockInterface the block interface - */ - public QbftContext( - final ValidatorProvider validatorProvider, final QbftBlockInterface blockInterface) { - this.validatorProvider = validatorProvider; - this.blockInterface = blockInterface; - } +/** + * Holds the QBFT specific mutable state. + * + * @param validatorProvider the validator provider + * @param blockInterface the block interface + */ +public record QbftContext( + QbftValidatorProvider validatorProvider, QbftBlockInterface blockInterface) + implements ConsensusContext { /** * Gets validator provider. * * @return the validator provider */ - public ValidatorProvider getValidatorProvider() { + @Override + public QbftValidatorProvider validatorProvider() { return validatorProvider; } @@ -49,7 +41,8 @@ public class QbftContext implements ConsensusContext { * * @return the block interface */ - public QbftBlockInterface getBlockInterface() { + @Override + public QbftBlockInterface blockInterface() { return blockInterface; } diff --git a/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/types/QbftEventHandler.java b/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/types/QbftEventHandler.java new file mode 100644 index 000000000..c90a484d8 --- /dev/null +++ b/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/types/QbftEventHandler.java @@ -0,0 +1,54 @@ +/* + * 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.consensus.qbft.core.types; + +import org.hyperledger.besu.consensus.common.bft.events.BftReceivedMessageEvent; +import org.hyperledger.besu.consensus.common.bft.events.BlockTimerExpiry; +import org.hyperledger.besu.consensus.common.bft.events.RoundExpiry; + +/** The interface QBFT event handler. */ +public interface QbftEventHandler { + + /** Start. */ + void start(); + + /** + * Handle errorMessage event. + * + * @param msg the msg + */ + void handleMessageEvent(BftReceivedMessageEvent msg); + + /** + * Handle new block event. + * + * @param newChainHead the new chain head + */ + void handleNewBlockEvent(QbftNewChainHead newChainHead); + + /** + * Handle block timer expiry. + * + * @param blockTimerExpiry the block timer expiry + */ + void handleBlockTimerExpiry(BlockTimerExpiry blockTimerExpiry); + + /** + * Handle round expiry. + * + * @param roundExpiry the round expiry + */ + void handleRoundExpiry(RoundExpiry roundExpiry); +} diff --git a/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/types/QbftExtraDataProvider.java b/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/types/QbftExtraDataProvider.java index 013ebb13b..7671a1f82 100644 --- a/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/types/QbftExtraDataProvider.java +++ b/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/types/QbftExtraDataProvider.java @@ -15,7 +15,6 @@ package org.hyperledger.besu.consensus.qbft.core.types; import org.hyperledger.besu.consensus.common.bft.BftExtraData; -import org.hyperledger.besu.ethereum.core.BlockHeader; /** Provides the extra data for a block. */ public interface QbftExtraDataProvider { @@ -26,5 +25,5 @@ public interface QbftExtraDataProvider { * @param header the block header to retrieve the extra data from * @return the extra data */ - BftExtraData getExtraData(BlockHeader header); + BftExtraData getExtraData(QbftBlockHeader header); } diff --git a/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/types/QbftNewChainHead.java b/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/types/QbftNewChainHead.java new file mode 100644 index 000000000..4db3adbce --- /dev/null +++ b/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/types/QbftNewChainHead.java @@ -0,0 +1,41 @@ +/* + * 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.consensus.qbft.core.types; + +import org.hyperledger.besu.consensus.common.bft.events.BftEvent; +import org.hyperledger.besu.consensus.common.bft.events.BftEvents; + +/** + * Event indicating that new chain head has been received + * + * @param newChainHeadHeader the new chain head header + */ +public record QbftNewChainHead(QbftBlockHeader newChainHeadHeader) implements BftEvent { + + @Override + public BftEvents.Type getType() { + return BftEvents.Type.NEW_CHAIN_HEAD; + } + + /** + * Gets new chain head header. + * + * @return the new chain head header + */ + @Override + public QbftBlockHeader newChainHeadHeader() { + return newChainHeadHeader; + } +} diff --git a/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/types/QbftProtocolSchedule.java b/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/types/QbftProtocolSchedule.java index 9dbc75e4c..f3016cd0a 100644 --- a/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/types/QbftProtocolSchedule.java +++ b/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/types/QbftProtocolSchedule.java @@ -14,8 +14,6 @@ */ package org.hyperledger.besu.consensus.qbft.core.types; -import org.hyperledger.besu.ethereum.core.BlockHeader; - /** * Provides the ability to select the appropriate QbftProtocolSpec containing the validation and * import for the supplied block header. @@ -28,5 +26,5 @@ public interface QbftProtocolSchedule { * @param header The block header to select the appropriate QbftProtocolSpec for * @return The QbftProtocolSpec for the supplied block header */ - QbftProtocolSpec getByBlockHeader(BlockHeader header); + QbftProtocolSpec getByBlockHeader(QbftBlockHeader header); } diff --git a/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/types/QbftValidatorModeTransitionLogger.java b/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/types/QbftValidatorModeTransitionLogger.java new file mode 100644 index 000000000..e16ceb8f7 --- /dev/null +++ b/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/types/QbftValidatorModeTransitionLogger.java @@ -0,0 +1,26 @@ +/* + * 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.consensus.qbft.core.types; + +/** Provides logging for QBFT transition changes */ +public interface QbftValidatorModeTransitionLogger { + + /** + * Logs the transition change + * + * @param parentHeader the parent header + */ + void logTransitionChange(QbftBlockHeader parentHeader); +} diff --git a/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/types/QbftValidatorProvider.java b/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/types/QbftValidatorProvider.java new file mode 100644 index 000000000..4109a9f03 --- /dev/null +++ b/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/types/QbftValidatorProvider.java @@ -0,0 +1,82 @@ +/* + * 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.consensus.qbft.core.types; + +import org.hyperledger.besu.consensus.common.validator.VoteProvider; +import org.hyperledger.besu.cryptoservices.NodeKey; +import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.ethereum.core.Util; + +import java.util.Collection; +import java.util.Optional; + +/** The interface Validator provider. */ +public interface QbftValidatorProvider { + + /** + * Gets validators at head. + * + * @return the validators at head + */ + Collection
getValidatorsAtHead(); + + /** + * Gets validators after block. + * + * @param header the header + * @return the validators after block + */ + Collection
getValidatorsAfterBlock(QbftBlockHeader header); + + /** + * Gets validators for block. + * + * @param header the header + * @return the validators for block + */ + Collection
getValidatorsForBlock(QbftBlockHeader header); + + /** + * Gets vote provider at head. + * + * @return the vote provider at head + */ + Optional getVoteProviderAtHead(); + + /** + * Gets vote provider after block. + * + * @param header the header + * @return the vote provider after block + */ + /* + * ForkingValidatorProvider has a specific implementation but we don't want the client code to + * know it's using a ForkingValidatorProvider. ForkingValidatorProvider's voteProvider can be + * different per block. Other ValidatorProviders yield the same voteProvider at every block. + */ + default Optional getVoteProviderAfterBlock(final QbftBlockHeader header) { + return getVoteProviderAtHead(); + } + + /** + * Determines if this node is a validator + * + * @param nodekey our node key + * @return true if this node is a validator + */ + default boolean nodeIsValidator(final NodeKey nodekey) { + return this.getValidatorsAtHead().contains(Util.publicKeyToAddress(nodekey.getPublicKey())); + } +} diff --git a/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/validation/FutureRoundProposalMessageValidator.java b/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/validation/FutureRoundProposalMessageValidator.java index dd585c26f..6402eece5 100644 --- a/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/validation/FutureRoundProposalMessageValidator.java +++ b/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/validation/FutureRoundProposalMessageValidator.java @@ -16,14 +16,14 @@ package org.hyperledger.besu.consensus.qbft.core.validation; import org.hyperledger.besu.consensus.common.bft.ConsensusRoundIdentifier; import org.hyperledger.besu.consensus.qbft.core.messagewrappers.Proposal; -import org.hyperledger.besu.ethereum.core.BlockHeader; +import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockHeader; /** The Future round proposal message validator. */ public class FutureRoundProposalMessageValidator { private final MessageValidatorFactory messageValidatorFactory; private final long chainHeight; - private final BlockHeader parentHeader; + private final QbftBlockHeader parentHeader; /** * Instantiates a new Future round proposal message validator. @@ -35,7 +35,7 @@ public class FutureRoundProposalMessageValidator { public FutureRoundProposalMessageValidator( final MessageValidatorFactory messageValidatorFactory, final long chainHeight, - final BlockHeader parentHeader) { + final QbftBlockHeader parentHeader) { this.messageValidatorFactory = messageValidatorFactory; this.chainHeight = chainHeight; this.parentHeader = parentHeader; diff --git a/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/validation/MessageValidatorFactory.java b/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/validation/MessageValidatorFactory.java index d34c99ba5..db09a88c5 100644 --- a/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/validation/MessageValidatorFactory.java +++ b/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/validation/MessageValidatorFactory.java @@ -17,13 +17,13 @@ package org.hyperledger.besu.consensus.qbft.core.validation; import org.hyperledger.besu.consensus.common.bft.BftHelpers; import org.hyperledger.besu.consensus.common.bft.ConsensusRoundIdentifier; import org.hyperledger.besu.consensus.common.bft.blockcreation.ProposerSelector; +import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockHeader; import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockInterface; import org.hyperledger.besu.consensus.qbft.core.types.QbftContext; import org.hyperledger.besu.consensus.qbft.core.types.QbftProtocolSchedule; import org.hyperledger.besu.consensus.qbft.core.validation.MessageValidator.SubsequentMessageValidator; import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.ethereum.ProtocolContext; -import org.hyperledger.besu.ethereum.core.BlockHeader; import java.util.Collection; @@ -58,10 +58,10 @@ public class MessageValidatorFactory { * @return the list of validators */ public static Collection
getValidatorsAfterBlock( - final ProtocolContext protocolContext, final BlockHeader parentHeader) { + final ProtocolContext protocolContext, final QbftBlockHeader parentHeader) { return protocolContext .getConsensusContext(QbftContext.class) - .getValidatorProvider() + .validatorProvider() .getValidatorsAfterBlock(parentHeader); } @@ -73,10 +73,10 @@ public class MessageValidatorFactory { * @return the list of validators */ public static Collection
getValidatorsForBlock( - final ProtocolContext protocolContext, final BlockHeader parentHeader) { + final ProtocolContext protocolContext, final QbftBlockHeader parentHeader) { return protocolContext .getConsensusContext(QbftContext.class) - .getValidatorProvider() + .validatorProvider() .getValidatorsForBlock(parentHeader); } @@ -88,7 +88,7 @@ public class MessageValidatorFactory { * @return the round change message validator */ public RoundChangeMessageValidator createRoundChangeMessageValidator( - final long chainHeight, final BlockHeader parentHeader) { + final long chainHeight, final QbftBlockHeader parentHeader) { final Collection
validatorsForHeight = getValidatorsAfterBlock(protocolContext, parentHeader); @@ -112,7 +112,7 @@ public class MessageValidatorFactory { * @return the message validator */ public MessageValidator createMessageValidator( - final ConsensusRoundIdentifier roundIdentifier, final BlockHeader parentHeader) { + final ConsensusRoundIdentifier roundIdentifier, final QbftBlockHeader parentHeader) { final Collection
validatorsForHeight = getValidatorsAfterBlock(protocolContext, parentHeader); @@ -126,7 +126,7 @@ public class MessageValidatorFactory { proposerSelector.selectProposerForRound(roundIdentifier)); final QbftBlockInterface blockInterface = - protocolContext.getConsensusContext(QbftContext.class).getBlockInterface(); + protocolContext.getConsensusContext(QbftContext.class).blockInterface(); return new MessageValidator( block -> new SubsequentMessageValidator( @@ -142,7 +142,7 @@ public class MessageValidatorFactory { * @return the future round proposal message validator */ public FutureRoundProposalMessageValidator createFutureRoundProposalMessageValidator( - final long chainHeight, final BlockHeader parentHeader) { + final long chainHeight, final QbftBlockHeader parentHeader) { return new FutureRoundProposalMessageValidator(this, chainHeight, parentHeader); } } diff --git a/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/validation/ProposalValidator.java b/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/validation/ProposalValidator.java index 7811a384e..84912409c 100644 --- a/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/validation/ProposalValidator.java +++ b/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/validation/ProposalValidator.java @@ -144,7 +144,7 @@ public class ProposalValidator { // Need to check that if we substitute the LatestPrepareCert round number into the supplied // block that we get the SAME hash as PreparedCert. final QbftBlockInterface bftBlockInterface = - protocolContext.getConsensusContext(QbftContext.class).getBlockInterface(); + protocolContext.getConsensusContext(QbftContext.class).blockInterface(); final QbftBlock currentBlockWithOldRound = bftBlockInterface.replaceRoundInBlock( proposal.getBlock(), metadata.getPreparedRound(), QbftHashMode.COMMITTED_SEAL); diff --git a/consensus/qbft-core/src/test/java/org/hyperledger/besu/consensus/qbft/core/QbftBlockTestFixture.java b/consensus/qbft-core/src/test/java/org/hyperledger/besu/consensus/qbft/core/QbftBlockTestFixture.java index 2402f52b9..4536e7b1b 100644 --- a/consensus/qbft-core/src/test/java/org/hyperledger/besu/consensus/qbft/core/QbftBlockTestFixture.java +++ b/consensus/qbft-core/src/test/java/org/hyperledger/besu/consensus/qbft/core/QbftBlockTestFixture.java @@ -15,15 +15,15 @@ package org.hyperledger.besu.consensus.qbft.core; import org.hyperledger.besu.consensus.qbft.core.types.QbftBlock; -import org.hyperledger.besu.ethereum.core.BlockDataGenerator; -import org.hyperledger.besu.ethereum.core.BlockHeader; +import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockHeader; +import org.hyperledger.besu.consensus.qbft.core.validation.QbftBlockHeaderTestFixture; public class QbftBlockTestFixture { - private BlockHeader blockHeader = new BlockDataGenerator().header(); + private QbftBlockHeader blockHeader = new QbftBlockHeaderTestFixture().buildHeader(); private boolean isEmpty = true; - public QbftBlockTestFixture blockHeader(final BlockHeader blockHeader) { + public QbftBlockTestFixture blockHeader(final QbftBlockHeader blockHeader) { this.blockHeader = blockHeader; return this; } @@ -40,7 +40,7 @@ public class QbftBlockTestFixture { class TestQbftBlock implements QbftBlock { @Override - public BlockHeader getHeader() { + public QbftBlockHeader getHeader() { return blockHeader; } diff --git a/consensus/qbft-core/src/test/java/org/hyperledger/besu/consensus/qbft/core/QbftContextBuilder.java b/consensus/qbft-core/src/test/java/org/hyperledger/besu/consensus/qbft/core/QbftContextBuilder.java index a2be4e1e3..978c6fa81 100644 --- a/consensus/qbft-core/src/test/java/org/hyperledger/besu/consensus/qbft/core/QbftContextBuilder.java +++ b/consensus/qbft-core/src/test/java/org/hyperledger/besu/consensus/qbft/core/QbftContextBuilder.java @@ -19,9 +19,9 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import static org.mockito.Mockito.withSettings; -import org.hyperledger.besu.consensus.common.validator.ValidatorProvider; import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockInterface; import org.hyperledger.besu.consensus.qbft.core.types.QbftContext; +import org.hyperledger.besu.consensus.qbft.core.types.QbftValidatorProvider; import org.hyperledger.besu.datatypes.Address; import java.util.Collection; @@ -35,11 +35,11 @@ public class QbftContextBuilder { final Collection
validators, final QbftBlockInterface bftBlockInterface) { final T bftContext = mock(contextClazz, withSettings().strictness(Strictness.LENIENT)); - final ValidatorProvider mockValidatorProvider = - mock(ValidatorProvider.class, withSettings().strictness(Strictness.LENIENT)); - when(bftContext.getValidatorProvider()).thenReturn(mockValidatorProvider); + final QbftValidatorProvider mockValidatorProvider = + mock(QbftValidatorProvider.class, withSettings().strictness(Strictness.LENIENT)); + when(bftContext.validatorProvider()).thenReturn(mockValidatorProvider); when(mockValidatorProvider.getValidatorsAfterBlock(any())).thenReturn(validators); - when(bftContext.getBlockInterface()).thenReturn(bftBlockInterface); + when(bftContext.blockInterface()).thenReturn(bftBlockInterface); when(bftContext.as(any())).thenReturn(bftContext); return bftContext; diff --git a/consensus/qbft-core/src/test/java/org/hyperledger/besu/consensus/qbft/core/statemachine/QbftBlockHeightManagerTest.java b/consensus/qbft-core/src/test/java/org/hyperledger/besu/consensus/qbft/core/statemachine/QbftBlockHeightManagerTest.java index ec1953f0a..4c10eada0 100644 --- a/consensus/qbft-core/src/test/java/org/hyperledger/besu/consensus/qbft/core/statemachine/QbftBlockHeightManagerTest.java +++ b/consensus/qbft-core/src/test/java/org/hyperledger/besu/consensus/qbft/core/statemachine/QbftBlockHeightManagerTest.java @@ -37,7 +37,6 @@ import org.hyperledger.besu.consensus.common.bft.ConsensusRoundIdentifier; import org.hyperledger.besu.consensus.common.bft.RoundTimer; import org.hyperledger.besu.consensus.common.bft.events.RoundExpiry; import org.hyperledger.besu.consensus.common.bft.network.ValidatorMulticaster; -import org.hyperledger.besu.consensus.common.validator.ValidatorProvider; import org.hyperledger.besu.consensus.qbft.core.QbftBlockTestFixture; import org.hyperledger.besu.consensus.qbft.core.messagedata.RoundChangeMessageData; import org.hyperledger.besu.consensus.qbft.core.messagewrappers.Commit; @@ -49,6 +48,8 @@ import org.hyperledger.besu.consensus.qbft.core.payload.MessageFactory; import org.hyperledger.besu.consensus.qbft.core.types.QbftBlock; import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockCodec; import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockCreator; +import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockHashing; +import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockHeader; import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockImporter; import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockInterface; import org.hyperledger.besu.consensus.qbft.core.types.QbftContext; @@ -56,9 +57,11 @@ import org.hyperledger.besu.consensus.qbft.core.types.QbftExtraDataProvider; import org.hyperledger.besu.consensus.qbft.core.types.QbftFinalState; import org.hyperledger.besu.consensus.qbft.core.types.QbftProtocolSchedule; import org.hyperledger.besu.consensus.qbft.core.types.QbftProtocolSpec; +import org.hyperledger.besu.consensus.qbft.core.types.QbftValidatorProvider; import org.hyperledger.besu.consensus.qbft.core.validation.FutureRoundProposalMessageValidator; import org.hyperledger.besu.consensus.qbft.core.validation.MessageValidator; import org.hyperledger.besu.consensus.qbft.core.validation.MessageValidatorFactory; +import org.hyperledger.besu.consensus.qbft.core.validation.QbftBlockHeaderTestFixture; import org.hyperledger.besu.consensus.qbft.core.validation.RoundChangeMessageValidator; import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; import org.hyperledger.besu.cryptoservices.NodeKey; @@ -66,8 +69,6 @@ import org.hyperledger.besu.cryptoservices.NodeKeyUtils; import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.ethereum.ProtocolContext; -import org.hyperledger.besu.ethereum.core.BlockHeader; -import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; import org.hyperledger.besu.ethereum.core.Util; import org.hyperledger.besu.ethereum.p2p.rlpx.wire.MessageData; import org.hyperledger.besu.util.Subscribers; @@ -95,7 +96,7 @@ import org.mockito.quality.Strictness; public class QbftBlockHeightManagerTest { private final NodeKey nodeKey = NodeKeyUtils.generate(); - private final BlockHeaderTestFixture headerTestFixture = new BlockHeaderTestFixture(); + private final QbftBlockHeaderTestFixture headerTestFixture = new QbftBlockHeaderTestFixture(); private MessageFactory messageFactory; @Mock private QbftFinalState finalState; @@ -111,14 +112,15 @@ public class QbftBlockHeightManagerTest { @Mock private ValidatorMulticaster validatorMulticaster; @Mock private ProtocolContext protocolContext; @Mock private QbftProtocolSchedule protocolSchedule; - @Mock private BlockHeader parentHeader; + @Mock private QbftBlockHeader parentHeader; @Mock private BftExtraDataCodec bftExtraDataCodec; @Mock private QbftBlockCodec blockEncoder; @Mock private QbftExtraDataProvider qbftExtraDataProvider; @Mock private QbftBlockInterface blockInterface; - @Mock private ValidatorProvider validatorProvider; + @Mock private QbftValidatorProvider validatorProvider; @Mock private QbftProtocolSpec protocolSpec; @Mock private QbftBlockImporter blockImporter; + @Mock private QbftBlockHashing blockHashing; @Captor private ArgumentCaptor sentMessageArgCaptor; @@ -176,6 +178,7 @@ public class QbftBlockHeightManagerTest { roundTimer, bftExtraDataCodec, qbftExtraDataProvider, + blockHashing, parentHeader); }); @@ -195,6 +198,7 @@ public class QbftBlockHeightManagerTest { roundTimer, bftExtraDataCodec, qbftExtraDataProvider, + blockHashing, parentHeader); }); @@ -406,6 +410,7 @@ public class QbftBlockHeightManagerTest { when(finalState.getQuorum()).thenReturn(1); when(blockInterface.replaceRoundInBlock(eq(createdBlock), eq(2), any())) .thenReturn(createdBlock); + when(blockHashing.calculateDataHashForCommittedSeal(any(), any())).thenReturn(Hash.ZERO); when(blockCreator.createSealedBlock(any(), any(), anyInt(), any())).thenReturn(createdBlock); when(protocolSchedule.getByBlockHeader(any())).thenReturn(protocolSpec); when(protocolSpec.getBlockImporter()).thenReturn(blockImporter); @@ -456,6 +461,7 @@ public class QbftBlockHeightManagerTest { when(blockTimer.checkEmptyBlockExpired(any(), eq(0L))).thenReturn(true); when(blockInterface.replaceRoundInBlock(eq(createdBlock), eq(0), any())) .thenReturn(createdBlock); + when(blockHashing.calculateDataHashForCommittedSeal(any(), any())).thenReturn(Hash.ZERO); when(blockCreator.createSealedBlock(any(), any(), anyInt(), any())).thenReturn(createdBlock); when(protocolSchedule.getByBlockHeader(any())).thenReturn(protocolSpec); when(protocolSpec.getBlockImporter()).thenReturn(blockImporter); diff --git a/consensus/qbft-core/src/test/java/org/hyperledger/besu/consensus/qbft/core/statemachine/QbftControllerTest.java b/consensus/qbft-core/src/test/java/org/hyperledger/besu/consensus/qbft/core/statemachine/QbftControllerTest.java index 79d17a815..75cd3d024 100644 --- a/consensus/qbft-core/src/test/java/org/hyperledger/besu/consensus/qbft/core/statemachine/QbftControllerTest.java +++ b/consensus/qbft-core/src/test/java/org/hyperledger/besu/consensus/qbft/core/statemachine/QbftControllerTest.java @@ -30,7 +30,6 @@ import org.hyperledger.besu.consensus.common.bft.EthSynchronizerUpdater; import org.hyperledger.besu.consensus.common.bft.MessageTracker; import org.hyperledger.besu.consensus.common.bft.events.BftReceivedMessageEvent; import org.hyperledger.besu.consensus.common.bft.events.BlockTimerExpiry; -import org.hyperledger.besu.consensus.common.bft.events.NewChainHead; import org.hyperledger.besu.consensus.common.bft.events.RoundExpiry; import org.hyperledger.besu.consensus.common.bft.statemachine.FutureMessageBuffer; import org.hyperledger.besu.consensus.qbft.core.messagedata.CommitMessageData; @@ -44,11 +43,12 @@ import org.hyperledger.besu.consensus.qbft.core.messagewrappers.Proposal; import org.hyperledger.besu.consensus.qbft.core.messagewrappers.RoundChange; import org.hyperledger.besu.consensus.qbft.core.network.QbftGossip; import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockCodec; +import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockHeader; +import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockchain; import org.hyperledger.besu.consensus.qbft.core.types.QbftFinalState; +import org.hyperledger.besu.consensus.qbft.core.types.QbftNewChainHead; import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Hash; -import org.hyperledger.besu.ethereum.chain.Blockchain; -import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.p2p.rlpx.wire.DefaultMessage; import org.hyperledger.besu.ethereum.p2p.rlpx.wire.Message; @@ -67,11 +67,11 @@ import org.mockito.quality.Strictness; @ExtendWith(MockitoExtension.class) @MockitoSettings(strictness = Strictness.LENIENT) public class QbftControllerTest { - @Mock private Blockchain blockChain; + @Mock private QbftBlockchain blockChain; @Mock private QbftFinalState qbftFinalState; @Mock private QbftBlockHeightManagerFactory blockHeightManagerFactory; - @Mock private BlockHeader chainHeadBlockHeader; - @Mock private BlockHeader nextBlock; + @Mock private QbftBlockHeader chainHeadBlockHeader; + @Mock private QbftBlockHeader nextBlock; @Mock private BaseQbftBlockHeightManager blockHeightManager; @Mock private Proposal proposal; @@ -187,7 +187,7 @@ public class QbftControllerTest { constructQbftController(); qbftController.start(); - final NewChainHead newChainHead = new NewChainHead(nextBlock); + final QbftNewChainHead newChainHead = new QbftNewChainHead(nextBlock); qbftController.handleNewBlockEvent(newChainHead); verify(blockHeightManagerFactory).create(nextBlock); @@ -210,11 +210,11 @@ public class QbftControllerTest { long chainHeadHeight = 4; when(nextBlock.getNumber()).thenReturn(chainHeadHeight); when(nextBlock.getHash()).thenReturn(Hash.ZERO); - final NewChainHead sameHeightBlock = new NewChainHead(nextBlock); + final QbftNewChainHead sameHeightBlock = new QbftNewChainHead(nextBlock); qbftController.handleNewBlockEvent(sameHeightBlock); when(nextBlock.getNumber()).thenReturn(chainHeadHeight - 1); - final NewChainHead priorBlock = new NewChainHead(nextBlock); + final QbftNewChainHead priorBlock = new QbftNewChainHead(nextBlock); qbftController.handleNewBlockEvent(priorBlock); verify(blockHeightManagerFactory, times(2)).create(any()); // 2 blocks created } diff --git a/consensus/qbft-core/src/test/java/org/hyperledger/besu/consensus/qbft/core/statemachine/QbftRoundTest.java b/consensus/qbft-core/src/test/java/org/hyperledger/besu/consensus/qbft/core/statemachine/QbftRoundTest.java index 7b92636c2..4492b622f 100644 --- a/consensus/qbft-core/src/test/java/org/hyperledger/besu/consensus/qbft/core/statemachine/QbftRoundTest.java +++ b/consensus/qbft-core/src/test/java/org/hyperledger/besu/consensus/qbft/core/statemachine/QbftRoundTest.java @@ -42,6 +42,8 @@ import org.hyperledger.besu.consensus.qbft.core.payload.PreparePayload; import org.hyperledger.besu.consensus.qbft.core.types.QbftBlock; import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockCodec; import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockCreator; +import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockHashing; +import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockHeader; import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockImporter; import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockInterface; import org.hyperledger.besu.consensus.qbft.core.types.QbftContext; @@ -51,15 +53,15 @@ import org.hyperledger.besu.consensus.qbft.core.types.QbftMinedBlockObserver; import org.hyperledger.besu.consensus.qbft.core.types.QbftProtocolSchedule; import org.hyperledger.besu.consensus.qbft.core.types.QbftProtocolSpec; import org.hyperledger.besu.consensus.qbft.core.validation.MessageValidator; +import org.hyperledger.besu.consensus.qbft.core.validation.QbftBlockHeaderTestFixture; import org.hyperledger.besu.crypto.SECPSignature; import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; import org.hyperledger.besu.cryptoservices.NodeKey; import org.hyperledger.besu.cryptoservices.NodeKeyUtils; +import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.chain.BadBlockManager; import org.hyperledger.besu.ethereum.chain.MutableBlockchain; -import org.hyperledger.besu.ethereum.core.BlockHeader; -import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; import org.hyperledger.besu.plugin.services.securitymodule.SecurityModuleException; import org.hyperledger.besu.util.Subscribers; @@ -102,11 +104,12 @@ public class QbftRoundTest { @Mock private RoundTimer roundTimer; @Mock private QbftProtocolSpec protocolSpec; @Mock private QbftBlockImporter blockImporter; - @Mock private org.hyperledger.besu.ethereum.core.BlockHeader parentHeader; + @Mock private QbftBlockHeader parentHeader; @Mock private BftExtraDataCodec bftExtraDataCodec; @Mock private QbftBlockInterface blockInteface; @Mock private QbftBlockCodec blockEncoder; @Mock private QbftExtraDataProvider qbftExtraDataProvider; + @Mock private QbftBlockHashing blockHashing; @Captor private ArgumentCaptor blockCaptor; @@ -132,7 +135,7 @@ public class QbftRoundTest { when(messageValidator.validatePrepare(any())).thenReturn(true); when(messageValidator.validateCommit(any())).thenReturn(true); - final BlockHeader header = new BlockHeaderTestFixture().number(1).buildHeader(); + final QbftBlockHeader header = new QbftBlockHeaderTestFixture().number(1).buildHeader(); proposedBlock = new QbftBlockTestFixture().blockHeader(header).build(); @@ -168,6 +171,7 @@ public class QbftRoundTest { roundTimer, bftExtraDataCodec, qbftExtraDataProvider, + blockHashing, parentHeader); verify(roundTimer, times(1)).startTimer(roundIdentifier); } @@ -188,6 +192,7 @@ public class QbftRoundTest { roundTimer, bftExtraDataCodec, qbftExtraDataProvider, + blockHashing, parentHeader); when(blockInteface.replaceRoundInBlock(eq(proposedBlock), eq(0), any())) @@ -202,7 +207,7 @@ public class QbftRoundTest { @Test public void aProposalWithAnewBlockIsSentUponReceptionOfARoundChangeWithNoCertificate() { - final BlockHeader header = new BlockHeaderTestFixture().number(0).buildHeader(); + final QbftBlockHeader header = new QbftBlockHeaderTestFixture().number(0).buildHeader(); final QbftBlock commitBlock = new QbftBlockTestFixture().blockHeader(header).build(); when(blockInteface.replaceRoundInBlock(proposedBlock, 0, QbftHashMode.COMMITTED_SEAL)) @@ -222,6 +227,7 @@ public class QbftRoundTest { roundTimer, bftExtraDataCodec, qbftExtraDataProvider, + blockHashing, parentHeader); round.startRoundWith(new RoundChangeArtifacts(emptyList(), Optional.empty()), 15); @@ -234,11 +240,11 @@ public class QbftRoundTest { public void aProposalMessageWithTheSameBlockIsSentUponReceptionOfARoundChangeWithCertificate() { final QbftBlock publishBlock = new QbftBlockTestFixture() - .blockHeader(new BlockHeaderTestFixture().number(0).buildHeader()) + .blockHeader(new QbftBlockHeaderTestFixture().number(0).buildHeader()) .build(); final QbftBlock commitBlock = new QbftBlockTestFixture() - .blockHeader(new BlockHeaderTestFixture().number(0).buildHeader()) + .blockHeader(new QbftBlockHeaderTestFixture().number(0).buildHeader()) .build(); when(blockInteface.replaceRoundInBlock(proposedBlock, 0, QbftHashMode.COMMITTED_SEAL)) .thenReturn(publishBlock); @@ -260,6 +266,7 @@ public class QbftRoundTest { roundTimer, bftExtraDataCodec, qbftExtraDataProvider, + blockHashing, parentHeader); final SignedData preparedPayload = @@ -294,7 +301,7 @@ public class QbftRoundTest { public void creatingNewBlockFromEmptyPreparedCertificateUpdatesInternalState() { final QbftBlock commitBlock = new QbftBlockTestFixture() - .blockHeader(new BlockHeaderTestFixture().number(0).buildHeader()) + .blockHeader(new QbftBlockHeaderTestFixture().number(0).buildHeader()) .build(); when(blockInteface.replaceRoundInBlock(proposedBlock, 0, QbftHashMode.COMMITTED_SEAL)) .thenReturn(commitBlock); @@ -313,6 +320,7 @@ public class QbftRoundTest { roundTimer, bftExtraDataCodec, qbftExtraDataProvider, + blockHashing, parentHeader); final RoundChange roundChange = @@ -356,12 +364,14 @@ public class QbftRoundTest { roundTimer, bftExtraDataCodec, qbftExtraDataProvider, + blockHashing, parentHeader); when(blockInteface.replaceRoundInBlock(proposedBlock, 0, QbftHashMode.COMMITTED_SEAL)) .thenReturn(proposedBlock); when(blockCreator.createSealedBlock(eq(qbftExtraDataProvider), eq(proposedBlock), eq(0), any())) .thenReturn(proposedBlock); + when(blockHashing.calculateDataHashForCommittedSeal(any(), any())).thenReturn(Hash.ZERO); round.handleCommitMessage( messageFactory.createCommit(roundIdentifier, proposedBlock.getHash(), remoteCommitSeal)); @@ -390,12 +400,14 @@ public class QbftRoundTest { roundTimer, bftExtraDataCodec, qbftExtraDataProvider, + blockHashing, parentHeader); when(blockInteface.replaceRoundInBlock(eq(proposedBlock), eq(0), any())) .thenReturn(proposedBlock); when(blockCreator.createSealedBlock(eq(qbftExtraDataProvider), eq(proposedBlock), eq(0), any())) .thenReturn(proposedBlock); + when(blockHashing.calculateDataHashForCommittedSeal(any(), any())).thenReturn(Hash.ZERO); round.handleCommitMessage( messageFactory.createCommit(roundIdentifier, proposedBlock.getHash(), remoteCommitSeal)); @@ -428,6 +440,7 @@ public class QbftRoundTest { roundTimer, bftExtraDataCodec, qbftExtraDataProvider, + blockHashing, parentHeader); when(blockInteface.replaceRoundInBlock(eq(proposedBlock), eq(0), any())) diff --git a/consensus/qbft-core/src/test/java/org/hyperledger/besu/consensus/qbft/core/validation/ProposalPayloadValidatorTest.java b/consensus/qbft-core/src/test/java/org/hyperledger/besu/consensus/qbft/core/validation/ProposalPayloadValidatorTest.java index 3a020a3d6..be4921e02 100644 --- a/consensus/qbft-core/src/test/java/org/hyperledger/besu/consensus/qbft/core/validation/ProposalPayloadValidatorTest.java +++ b/consensus/qbft-core/src/test/java/org/hyperledger/besu/consensus/qbft/core/validation/ProposalPayloadValidatorTest.java @@ -27,12 +27,11 @@ import org.hyperledger.besu.consensus.qbft.core.messagewrappers.Proposal; import org.hyperledger.besu.consensus.qbft.core.payload.MessageFactory; import org.hyperledger.besu.consensus.qbft.core.types.QbftBlock; import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockCodec; +import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockHeader; import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockValidator; import org.hyperledger.besu.cryptoservices.NodeKey; import org.hyperledger.besu.cryptoservices.NodeKeyUtils; import org.hyperledger.besu.datatypes.Address; -import org.hyperledger.besu.ethereum.core.BlockHeader; -import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; import org.hyperledger.besu.ethereum.core.Util; import java.util.Optional; @@ -68,8 +67,8 @@ public class ProposalPayloadValidatorTest { public void validationPassesWhenProposerAndRoundMatchAndBlockIsValid() { final ProposalPayloadValidator payloadValidator = new ProposalPayloadValidator(expectedProposer, roundIdentifier, blockValidator); - final BlockHeader header = - new BlockHeaderTestFixture().number(roundIdentifier.getSequenceNumber()).buildHeader(); + final QbftBlockHeader header = + new QbftBlockHeaderTestFixture().number(roundIdentifier.getSequenceNumber()).buildHeader(); final QbftBlock block = new QbftBlockTestFixture().blockHeader(header).build(); final Proposal proposal = messageFactory.createProposal(roundIdentifier, block, emptyList(), emptyList()); @@ -85,8 +84,8 @@ public class ProposalPayloadValidatorTest { final ProposalPayloadValidator payloadValidator = new ProposalPayloadValidator(expectedProposer, roundIdentifier, blockValidator); - final BlockHeader header = - new BlockHeaderTestFixture().number(roundIdentifier.getSequenceNumber()).buildHeader(); + final QbftBlockHeader header = + new QbftBlockHeaderTestFixture().number(roundIdentifier.getSequenceNumber()).buildHeader(); final QbftBlock block = new QbftBlockTestFixture().blockHeader(header).build(); final Proposal proposal = messageFactory.createProposal(roundIdentifier, block, emptyList(), emptyList()); @@ -104,8 +103,8 @@ public class ProposalPayloadValidatorTest { final ProposalPayloadValidator payloadValidator = new ProposalPayloadValidator(expectedProposer, roundIdentifier, blockValidator); - final BlockHeader header = - new BlockHeaderTestFixture().number(roundIdentifier.getSequenceNumber()).buildHeader(); + final QbftBlockHeader header = + new QbftBlockHeaderTestFixture().number(roundIdentifier.getSequenceNumber()).buildHeader(); final QbftBlock block = new QbftBlockTestFixture().blockHeader(header).build(); final Proposal proposal = messageFactory.createProposal(roundIdentifier, block, emptyList(), emptyList()); @@ -120,8 +119,8 @@ public class ProposalPayloadValidatorTest { public void validationFailsWhenExpectedProposerDoesNotMatchPayloadsAuthor() { final ProposalPayloadValidator payloadValidator = new ProposalPayloadValidator(Address.fromHexString("0x1"), roundIdentifier, blockValidator); - final BlockHeader header = - new BlockHeaderTestFixture().number(roundIdentifier.getSequenceNumber()).buildHeader(); + final QbftBlockHeader header = + new QbftBlockHeaderTestFixture().number(roundIdentifier.getSequenceNumber()).buildHeader(); final QbftBlock block = new QbftBlockTestFixture().blockHeader(header).build(); final Proposal proposal = messageFactory.createProposal(roundIdentifier, block, emptyList(), emptyList()); @@ -135,8 +134,8 @@ public class ProposalPayloadValidatorTest { final ProposalPayloadValidator payloadValidator = new ProposalPayloadValidator(expectedProposer, roundIdentifier, blockValidator); - final BlockHeader header = - new BlockHeaderTestFixture().number(roundIdentifier.getSequenceNumber()).buildHeader(); + final QbftBlockHeader header = + new QbftBlockHeaderTestFixture().number(roundIdentifier.getSequenceNumber()).buildHeader(); final QbftBlock block = new QbftBlockTestFixture().blockHeader(header).build(); final Proposal proposal = messageFactory.createProposal( @@ -154,8 +153,8 @@ public class ProposalPayloadValidatorTest { final ProposalPayloadValidator payloadValidator = new ProposalPayloadValidator(expectedProposer, roundIdentifier, blockValidator); - final BlockHeader header = - new BlockHeaderTestFixture().number(roundIdentifier.getSequenceNumber()).buildHeader(); + final QbftBlockHeader header = + new QbftBlockHeaderTestFixture().number(roundIdentifier.getSequenceNumber()).buildHeader(); final QbftBlock block = new QbftBlockTestFixture().blockHeader(header).build(); final Proposal proposal = messageFactory.createProposal( @@ -172,8 +171,10 @@ public class ProposalPayloadValidatorTest { public void validationFailsForBlockWithIncorrectHeight() { final ProposalPayloadValidator payloadValidator = new ProposalPayloadValidator(expectedProposer, roundIdentifier, blockValidator); - final BlockHeader header = - new BlockHeaderTestFixture().number(roundIdentifier.getSequenceNumber() + 1).buildHeader(); + final QbftBlockHeader header = + new QbftBlockHeaderTestFixture() + .number(roundIdentifier.getSequenceNumber() + 1) + .buildHeader(); final QbftBlock block = new QbftBlockTestFixture().blockHeader(header).build(); final Proposal proposal = messageFactory.createProposal(roundIdentifier, block, emptyList(), emptyList()); diff --git a/consensus/qbft-core/src/test/java/org/hyperledger/besu/consensus/qbft/core/validation/ProposalValidatorTest.java b/consensus/qbft-core/src/test/java/org/hyperledger/besu/consensus/qbft/core/validation/ProposalValidatorTest.java index 570b4fabb..27ccb63c5 100644 --- a/consensus/qbft-core/src/test/java/org/hyperledger/besu/consensus/qbft/core/validation/ProposalValidatorTest.java +++ b/consensus/qbft-core/src/test/java/org/hyperledger/besu/consensus/qbft/core/validation/ProposalValidatorTest.java @@ -27,7 +27,6 @@ import org.hyperledger.besu.consensus.common.bft.BftHelpers; import org.hyperledger.besu.consensus.common.bft.ConsensusRoundHelpers; import org.hyperledger.besu.consensus.common.bft.ConsensusRoundIdentifier; import org.hyperledger.besu.consensus.common.bft.payload.SignedData; -import org.hyperledger.besu.consensus.common.validator.ValidatorProvider; import org.hyperledger.besu.consensus.qbft.core.QbftBlockTestFixture; import org.hyperledger.besu.consensus.qbft.core.messagewrappers.Prepare; import org.hyperledger.besu.consensus.qbft.core.messagewrappers.Proposal; @@ -37,16 +36,16 @@ import org.hyperledger.besu.consensus.qbft.core.payload.PreparedRoundMetadata; import org.hyperledger.besu.consensus.qbft.core.payload.RoundChangePayload; import org.hyperledger.besu.consensus.qbft.core.types.QbftBlock; import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockCodec; +import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockHeader; import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockInterface; import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockValidator; import org.hyperledger.besu.consensus.qbft.core.types.QbftContext; import org.hyperledger.besu.consensus.qbft.core.types.QbftHashMode; import org.hyperledger.besu.consensus.qbft.core.types.QbftProtocolSchedule; import org.hyperledger.besu.consensus.qbft.core.types.QbftProtocolSpec; +import org.hyperledger.besu.consensus.qbft.core.types.QbftValidatorProvider; import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.ethereum.ProtocolContext; -import org.hyperledger.besu.ethereum.core.BlockHeader; -import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; import java.util.HashMap; import java.util.List; @@ -89,7 +88,7 @@ public class ProposalValidatorTest { @Mock private QbftProtocolSpec protocolSpec; @Mock private QbftBlockCodec blockEncoder; @Mock private QbftBlockInterface blockInterface; - @Mock private ValidatorProvider validatorProvider; + @Mock private QbftValidatorProvider validatorProvider; @Mock private ProtocolContext protocolContext; private QbftNodeList validators; @@ -115,8 +114,8 @@ public class ProposalValidatorTest { private RoundSpecificItems createRoundSpecificItems(final int roundNumber) { final ConsensusRoundIdentifier roundIdentifier = new ConsensusRoundIdentifier(1, roundNumber); - final BlockHeader blockHeader = - new BlockHeaderTestFixture() + final QbftBlockHeader blockHeader = + new QbftBlockHeaderTestFixture() .number(roundIdentifier.getSequenceNumber()) .coinbase(validators.getNodeAddresses().getFirst()) .buildHeader(); diff --git a/consensus/qbft-core/src/test/java/org/hyperledger/besu/consensus/qbft/core/validation/QbftBlockHeaderTestFixture.java b/consensus/qbft-core/src/test/java/org/hyperledger/besu/consensus/qbft/core/validation/QbftBlockHeaderTestFixture.java new file mode 100644 index 000000000..8451c039c --- /dev/null +++ b/consensus/qbft-core/src/test/java/org/hyperledger/besu/consensus/qbft/core/validation/QbftBlockHeaderTestFixture.java @@ -0,0 +1,71 @@ +/* + * 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.consensus.qbft.core.validation; + +import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockHeader; +import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.datatypes.Hash; + +public class QbftBlockHeaderTestFixture { + + private long number = 0; + private long timestamp = 0; + private Hash hash = Hash.EMPTY; + private Address coinbase = Address.ZERO; + + public QbftBlockHeaderTestFixture number(final long number) { + this.number = number; + return this; + } + + public QbftBlockHeaderTestFixture timestamp(final long timestamp) { + this.timestamp = timestamp; + return this; + } + + public QbftBlockHeaderTestFixture hash(final Hash hash) { + this.hash = hash; + return this; + } + + public QbftBlockHeaderTestFixture coinbase(final Address coinbase) { + this.coinbase = coinbase; + return this; + } + + public QbftBlockHeader buildHeader() { + return new QbftBlockHeader() { + @Override + public long getNumber() { + return number; + } + + @Override + public long getTimestamp() { + return timestamp; + } + + @Override + public Hash getHash() { + return hash; + } + + @Override + public Address getCoinbase() { + return coinbase; + } + }; + } +} diff --git a/consensus/qbft-core/src/test/java/org/hyperledger/besu/consensus/qbft/core/validation/RoundChangeMessageValidatorTest.java b/consensus/qbft-core/src/test/java/org/hyperledger/besu/consensus/qbft/core/validation/RoundChangeMessageValidatorTest.java index cb2c13ed0..18f33a482 100644 --- a/consensus/qbft-core/src/test/java/org/hyperledger/besu/consensus/qbft/core/validation/RoundChangeMessageValidatorTest.java +++ b/consensus/qbft-core/src/test/java/org/hyperledger/besu/consensus/qbft/core/validation/RoundChangeMessageValidatorTest.java @@ -34,14 +34,13 @@ import org.hyperledger.besu.consensus.qbft.core.payload.RoundChangePayload; import org.hyperledger.besu.consensus.qbft.core.statemachine.PreparedCertificate; import org.hyperledger.besu.consensus.qbft.core.types.QbftBlock; import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockCodec; +import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockHeader; import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockValidator; import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockValidator.ValidationResult; import org.hyperledger.besu.consensus.qbft.core.types.QbftProtocolSchedule; import org.hyperledger.besu.consensus.qbft.core.types.QbftProtocolSpec; import org.hyperledger.besu.crypto.SECPSignature; import org.hyperledger.besu.datatypes.Hash; -import org.hyperledger.besu.ethereum.core.BlockHeader; -import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; import java.util.Optional; import java.util.stream.Collectors; @@ -109,8 +108,8 @@ public class RoundChangeMessageValidatorTest { validators.getNodeAddresses(), protocolSchedule); - final BlockHeader header = - new BlockHeaderTestFixture().number(roundIdentifier.getSequenceNumber()).buildHeader(); + final QbftBlockHeader header = + new QbftBlockHeaderTestFixture().number(roundIdentifier.getSequenceNumber()).buildHeader(); final QbftBlock block = new QbftBlockTestFixture().blockHeader(header).build(); final PreparedCertificate prepCert = createPreparedCertificate( @@ -134,8 +133,8 @@ public class RoundChangeMessageValidatorTest { validators.getNodeAddresses(), protocolSchedule); - final BlockHeader header = - new BlockHeaderTestFixture().number(roundIdentifier.getSequenceNumber()).buildHeader(); + final QbftBlockHeader header = + new QbftBlockHeaderTestFixture().number(roundIdentifier.getSequenceNumber()).buildHeader(); final QbftBlock block = new QbftBlockTestFixture().blockHeader(header).build(); final PreparedCertificate prepCert = createPreparedCertificate( @@ -161,8 +160,8 @@ public class RoundChangeMessageValidatorTest { validators.getNodeAddresses(), protocolSchedule); - final BlockHeader header = - new BlockHeaderTestFixture().number(roundIdentifier.getSequenceNumber()).buildHeader(); + final QbftBlockHeader header = + new QbftBlockHeaderTestFixture().number(roundIdentifier.getSequenceNumber()).buildHeader(); final QbftBlock block = new QbftBlockTestFixture().blockHeader(header).build(); final PreparedCertificate prepCert = createPreparedCertificate( @@ -202,8 +201,8 @@ public class RoundChangeMessageValidatorTest { validators.getNodeAddresses(), protocolSchedule); - final BlockHeader header = - new BlockHeaderTestFixture().number(roundIdentifier.getSequenceNumber()).buildHeader(); + final QbftBlockHeader header = + new QbftBlockHeaderTestFixture().number(roundIdentifier.getSequenceNumber()).buildHeader(); final QbftBlock block = new QbftBlockTestFixture().blockHeader(header).build(); final PreparedCertificate prepCert = createPreparedCertificate( @@ -229,8 +228,8 @@ public class RoundChangeMessageValidatorTest { final QbftNode nonValidator = QbftNode.create(blockEncoder); - final BlockHeader header = - new BlockHeaderTestFixture().number(roundIdentifier.getSequenceNumber()).buildHeader(); + final QbftBlockHeader header = + new QbftBlockHeaderTestFixture().number(roundIdentifier.getSequenceNumber()).buildHeader(); final QbftBlock block = new QbftBlockTestFixture().blockHeader(header).build(); final PreparedCertificate prepCert = createPreparedCertificate( @@ -254,8 +253,8 @@ public class RoundChangeMessageValidatorTest { validators.getNodeAddresses(), protocolSchedule); - final BlockHeader header = - new BlockHeaderTestFixture().number(roundIdentifier.getSequenceNumber()).buildHeader(); + final QbftBlockHeader header = + new QbftBlockHeaderTestFixture().number(roundIdentifier.getSequenceNumber()).buildHeader(); final QbftBlock block = new QbftBlockTestFixture().blockHeader(header).build(); final PreparedCertificate prepCert = new PreparedCertificate( @@ -287,8 +286,8 @@ public class RoundChangeMessageValidatorTest { validators.getNodeAddresses(), protocolSchedule); - final BlockHeader header = - new BlockHeaderTestFixture().number(roundIdentifier.getSequenceNumber()).buildHeader(); + final QbftBlockHeader header = + new QbftBlockHeaderTestFixture().number(roundIdentifier.getSequenceNumber()).buildHeader(); final QbftBlock block = new QbftBlockTestFixture().blockHeader(header).build(); final PreparedCertificate prepCert = new PreparedCertificate( @@ -322,8 +321,8 @@ public class RoundChangeMessageValidatorTest { validators.getNodeAddresses(), protocolSchedule); - final BlockHeader header = - new BlockHeaderTestFixture().number(roundIdentifier.getSequenceNumber()).buildHeader(); + final QbftBlockHeader header = + new QbftBlockHeaderTestFixture().number(roundIdentifier.getSequenceNumber()).buildHeader(); final QbftBlock block = new QbftBlockTestFixture().blockHeader(header).build(); final PreparedCertificate prepCert = new PreparedCertificate( @@ -357,8 +356,8 @@ public class RoundChangeMessageValidatorTest { validators.getNodeAddresses(), protocolSchedule); - final BlockHeader header = - new BlockHeaderTestFixture().number(roundIdentifier.getSequenceNumber()).buildHeader(); + final QbftBlockHeader header = + new QbftBlockHeaderTestFixture().number(roundIdentifier.getSequenceNumber()).buildHeader(); final QbftBlock block = new QbftBlockTestFixture().blockHeader(header).build(); final PreparedCertificate prepCert = createPreparedCertificate( @@ -387,8 +386,8 @@ public class RoundChangeMessageValidatorTest { validators.getNodeAddresses(), protocolSchedule); - final BlockHeader header = - new BlockHeaderTestFixture().number(roundIdentifier.getSequenceNumber()).buildHeader(); + final QbftBlockHeader header = + new QbftBlockHeaderTestFixture().number(roundIdentifier.getSequenceNumber()).buildHeader(); final QbftBlock block = new QbftBlockTestFixture().blockHeader(header).build(); final RoundChangePayload payload = new RoundChangePayload(targetRound, Optional.empty()); @@ -415,8 +414,8 @@ public class RoundChangeMessageValidatorTest { validators.getNodeAddresses(), protocolSchedule); - final BlockHeader header = - new BlockHeaderTestFixture().number(roundIdentifier.getSequenceNumber()).buildHeader(); + final QbftBlockHeader header = + new QbftBlockHeaderTestFixture().number(roundIdentifier.getSequenceNumber()).buildHeader(); final QbftBlock block = new QbftBlockTestFixture().blockHeader(header).build(); final RoundChangePayload payload = diff --git a/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/adaptor/BftEventHandlerAdaptor.java b/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/adaptor/BftEventHandlerAdaptor.java new file mode 100644 index 000000000..955fe45ce --- /dev/null +++ b/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/adaptor/BftEventHandlerAdaptor.java @@ -0,0 +1,65 @@ +/* + * 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.consensus.qbft.adaptor; + +import org.hyperledger.besu.consensus.common.bft.events.BftReceivedMessageEvent; +import org.hyperledger.besu.consensus.common.bft.events.BlockTimerExpiry; +import org.hyperledger.besu.consensus.common.bft.events.NewChainHead; +import org.hyperledger.besu.consensus.common.bft.events.RoundExpiry; +import org.hyperledger.besu.consensus.common.bft.statemachine.BftEventHandler; +import org.hyperledger.besu.consensus.qbft.core.types.QbftEventHandler; +import org.hyperledger.besu.consensus.qbft.core.types.QbftNewChainHead; +import org.hyperledger.besu.ethereum.core.BlockHeader; + +/** Adaptor class to allow a {@link QbftEventHandler} to be used as a {@link BftEventHandler}. */ +public class BftEventHandlerAdaptor implements BftEventHandler { + private final QbftEventHandler qbftEventHandler; + + /** + * Create a new instance of the adaptor. + * + * @param qbftEventHandler The {@link QbftEventHandler} to adapt. + */ + public BftEventHandlerAdaptor(final QbftEventHandler qbftEventHandler) { + this.qbftEventHandler = qbftEventHandler; + } + + @Override + public void start() { + qbftEventHandler.start(); + } + + @Override + public void handleMessageEvent(final BftReceivedMessageEvent msg) { + qbftEventHandler.handleMessageEvent(msg); + } + + @Override + public void handleNewBlockEvent(final NewChainHead newChainHead) { + BlockHeader besuNewChainHeadHeader = newChainHead.getNewChainHeadHeader(); + var qbftChainHead = new QbftNewChainHead(new QbftBlockHeaderAdaptor(besuNewChainHeadHeader)); + qbftEventHandler.handleNewBlockEvent(qbftChainHead); + } + + @Override + public void handleBlockTimerExpiry(final BlockTimerExpiry blockTimerExpiry) { + qbftEventHandler.handleBlockTimerExpiry(blockTimerExpiry); + } + + @Override + public void handleRoundExpiry(final RoundExpiry roundExpiry) { + qbftEventHandler.handleRoundExpiry(roundExpiry); + } +} diff --git a/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/adaptor/BlockUtil.java b/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/adaptor/BlockUtil.java index 1c8eccb06..dfd596f9d 100644 --- a/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/adaptor/BlockUtil.java +++ b/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/adaptor/BlockUtil.java @@ -15,7 +15,9 @@ package org.hyperledger.besu.consensus.qbft.adaptor; import org.hyperledger.besu.consensus.qbft.core.types.QbftBlock; +import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockHeader; import org.hyperledger.besu.ethereum.core.Block; +import org.hyperledger.besu.ethereum.core.BlockHeader; /** Utility class to convert between Besu and QBFT blocks. */ public class BlockUtil { @@ -36,4 +38,18 @@ public class BlockUtil { throw new IllegalArgumentException("Unsupported block type"); } } + + /** + * Convert a QBFT block header to a Besu block header. + * + * @param header the QBFT block header + * @return the Besu block header + */ + public static BlockHeader toBesuBlockHeader(final QbftBlockHeader header) { + if (header instanceof QbftBlockHeaderAdaptor) { + return ((QbftBlockHeaderAdaptor) header).getBesuBlockHeader(); + } else { + throw new IllegalArgumentException("Unsupported block header type"); + } + } } diff --git a/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/adaptor/QbftBlockAdaptor.java b/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/adaptor/QbftBlockAdaptor.java index b36bcd577..55469a5ed 100644 --- a/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/adaptor/QbftBlockAdaptor.java +++ b/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/adaptor/QbftBlockAdaptor.java @@ -15,35 +15,36 @@ package org.hyperledger.besu.consensus.qbft.adaptor; import org.hyperledger.besu.consensus.qbft.core.types.QbftBlock; +import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockHeader; +import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.ethereum.core.Block; -import org.hyperledger.besu.ethereum.core.BlockHeader; import java.util.Objects; /** Adaptor class to allow a {@link Block} to be used as a {@link QbftBlock}. */ public class QbftBlockAdaptor implements QbftBlock { - private final BlockHeader header; - private final Block block; + private final Block besuBlock; + private final QbftBlockHeader qbftBlockHeader; /** * Constructs a QbftBlock from a Besu Block. * - * @param block the Besu Block + * @param besuBlock the Besu Block */ - public QbftBlockAdaptor(final Block block) { - this.block = block; - this.header = block.getHeader(); + public QbftBlockAdaptor(final Block besuBlock) { + this.besuBlock = besuBlock; + this.qbftBlockHeader = new QbftBlockHeaderAdaptor(besuBlock.getHeader()); } @Override - public BlockHeader getHeader() { - return header; + public QbftBlockHeader getHeader() { + return qbftBlockHeader; } @Override public boolean isEmpty() { - return block.getBody().getTransactions().isEmpty(); + return besuBlock.getHeader().getTransactionsRoot().equals(Hash.EMPTY_TRIE_HASH); } /** @@ -53,17 +54,18 @@ public class QbftBlockAdaptor implements QbftBlock { * @return the Besu Block */ public Block getBesuBlock() { - return block; + return besuBlock; } @Override public boolean equals(final Object o) { if (!(o instanceof QbftBlockAdaptor qbftBlock)) return false; - return Objects.equals(header, qbftBlock.header) && Objects.equals(block, qbftBlock.block); + return Objects.equals(besuBlock, qbftBlock.besuBlock) + && Objects.equals(qbftBlockHeader, qbftBlock.qbftBlockHeader); } @Override public int hashCode() { - return Objects.hash(header, block); + return Objects.hash(besuBlock, qbftBlockHeader); } } diff --git a/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/adaptor/QbftBlockCreatorAdaptor.java b/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/adaptor/QbftBlockCreatorAdaptor.java index ab94d7307..7fed70f58 100644 --- a/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/adaptor/QbftBlockCreatorAdaptor.java +++ b/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/adaptor/QbftBlockCreatorAdaptor.java @@ -19,6 +19,7 @@ import org.hyperledger.besu.consensus.common.bft.BftExtraData; import org.hyperledger.besu.consensus.common.bft.BftExtraDataCodec; import org.hyperledger.besu.consensus.qbft.core.types.QbftBlock; import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockCreator; +import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockHeader; import org.hyperledger.besu.consensus.qbft.core.types.QbftExtraDataProvider; import org.hyperledger.besu.crypto.SECPSignature; import org.hyperledger.besu.ethereum.blockcreation.BlockCreator; @@ -47,8 +48,11 @@ public class QbftBlockCreatorAdaptor implements QbftBlockCreator { } @Override - public QbftBlock createBlock(final long headerTimeStampSeconds, final BlockHeader parentHeader) { - var blockResult = besuBlockCreator.createBlock(headerTimeStampSeconds, parentHeader); + public QbftBlock createBlock( + final long headerTimeStampSeconds, final QbftBlockHeader parentHeader) { + var blockResult = + besuBlockCreator.createBlock( + headerTimeStampSeconds, BlockUtil.toBesuBlockHeader(parentHeader)); return new QbftBlockAdaptor(blockResult.getBlock()); } @@ -59,8 +63,8 @@ public class QbftBlockCreatorAdaptor implements QbftBlockCreator { final int roundNumber, final Collection commitSeals) { final Block besuBlock = BlockUtil.toBesuBlock(block); - final BlockHeader initialBesuHeader = besuBlock.getHeader(); - final BftExtraData initialExtraData = bftQbftExtraDataProvider.getExtraData(initialBesuHeader); + final QbftBlockHeader initialHeader = block.getHeader(); + final BftExtraData initialExtraData = bftQbftExtraDataProvider.getExtraData(initialHeader); final BftExtraData sealedExtraData = new BftExtraData( @@ -71,7 +75,7 @@ public class QbftBlockCreatorAdaptor implements QbftBlockCreator { initialExtraData.getValidators()); final BlockHeader sealedHeader = - BlockHeaderBuilder.fromHeader(initialBesuHeader) + BlockHeaderBuilder.fromHeader(BlockUtil.toBesuBlockHeader(initialHeader)) .extraData(bftExtraDataCodec.encode(sealedExtraData)) .blockHeaderFunctions(BftBlockHeaderFunctions.forOnchainBlock(bftExtraDataCodec)) .buildBlockHeader(); diff --git a/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/adaptor/QbftBlockHashingAdaptor.java b/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/adaptor/QbftBlockHashingAdaptor.java new file mode 100644 index 000000000..f71ca8bf4 --- /dev/null +++ b/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/adaptor/QbftBlockHashingAdaptor.java @@ -0,0 +1,42 @@ +/* + * 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.consensus.qbft.adaptor; + +import org.hyperledger.besu.consensus.common.bft.BftBlockHashing; +import org.hyperledger.besu.consensus.common.bft.BftExtraData; +import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockHashing; +import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockHeader; +import org.hyperledger.besu.datatypes.Hash; + +/** Adaptor to allow a {linkBftBlockHashing} to be used as a {@link QbftBlockHashing}. */ +public class QbftBlockHashingAdaptor implements QbftBlockHashing { + private final BftBlockHashing bftBlockHashing; + + /** + * Construct a new Qbft BlockHasher + * + * @param bftBlockHashing the BFT BlockHashing + */ + public QbftBlockHashingAdaptor(final BftBlockHashing bftBlockHashing) { + this.bftBlockHashing = bftBlockHashing; + } + + @Override + public Hash calculateDataHashForCommittedSeal( + final QbftBlockHeader header, final BftExtraData extraData) { + return bftBlockHashing.calculateDataHashForCommittedSeal( + BlockUtil.toBesuBlockHeader(header), extraData); + } +} diff --git a/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/adaptor/QbftBlockHeaderAdaptor.java b/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/adaptor/QbftBlockHeaderAdaptor.java new file mode 100644 index 000000000..da9c08915 --- /dev/null +++ b/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/adaptor/QbftBlockHeaderAdaptor.java @@ -0,0 +1,77 @@ +/* + * 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.consensus.qbft.adaptor; + +import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockHeader; +import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.ethereum.core.BlockHeader; + +import java.util.Objects; + +/** Adaptor class to allow a {@link BlockHeader} to be used as a {@link QbftBlockHeader}. */ +public class QbftBlockHeaderAdaptor implements QbftBlockHeader { + + private final BlockHeader blockHeader; + + /** + * Construct a new QbftBlockHeader + * + * @param blockHeader the Besu block header + */ + public QbftBlockHeaderAdaptor(final BlockHeader blockHeader) { + this.blockHeader = blockHeader; + } + + @Override + public long getNumber() { + return blockHeader.getNumber(); + } + + @Override + public long getTimestamp() { + return blockHeader.getTimestamp(); + } + + @Override + public Address getCoinbase() { + return blockHeader.getCoinbase(); + } + + @Override + public Hash getHash() { + return blockHeader.getHash(); + } + + /** + * Returns the Besu block header. + * + * @return the Besu block header. + */ + public BlockHeader getBesuBlockHeader() { + return blockHeader; + } + + @Override + public boolean equals(final Object o) { + if (!(o instanceof QbftBlockHeaderAdaptor that)) return false; + return Objects.equals(blockHeader, that.blockHeader); + } + + @Override + public int hashCode() { + return Objects.hashCode(blockHeader); + } +} diff --git a/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/adaptor/QbftBlockchainAdaptor.java b/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/adaptor/QbftBlockchainAdaptor.java new file mode 100644 index 000000000..fa01732a9 --- /dev/null +++ b/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/adaptor/QbftBlockchainAdaptor.java @@ -0,0 +1,45 @@ +/* + * 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.consensus.qbft.adaptor; + +import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockHeader; +import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockchain; +import org.hyperledger.besu.ethereum.chain.Blockchain; +import org.hyperledger.besu.ethereum.core.BlockHeader; + +/** Adaptor class to allow a {@link Blockchain} to be used as a {@link QbftBlockchain}. */ +public class QbftBlockchainAdaptor implements QbftBlockchain { + private final Blockchain blockchain; + + /** + * Create a new instance of the adaptor. + * + * @param blockchain The {@link Blockchain} to adapt. + */ + public QbftBlockchainAdaptor(final Blockchain blockchain) { + this.blockchain = blockchain; + } + + @Override + public QbftBlockHeader getChainHeadHeader() { + BlockHeader chainHeadHeader = blockchain.getChainHeadHeader(); + return new QbftBlockHeaderAdaptor(chainHeadHeader); + } + + @Override + public long getChainHeadBlockNumber() { + return blockchain.getChainHeadBlockNumber(); + } +} diff --git a/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/adaptor/QbftExtraDataProviderAdaptor.java b/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/adaptor/QbftExtraDataProviderAdaptor.java index 05fbaa672..2386e3779 100644 --- a/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/adaptor/QbftExtraDataProviderAdaptor.java +++ b/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/adaptor/QbftExtraDataProviderAdaptor.java @@ -16,8 +16,8 @@ package org.hyperledger.besu.consensus.qbft.adaptor; import org.hyperledger.besu.consensus.common.bft.BftExtraData; import org.hyperledger.besu.consensus.common.bft.BftExtraDataCodec; +import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockHeader; import org.hyperledger.besu.consensus.qbft.core.types.QbftExtraDataProvider; -import org.hyperledger.besu.ethereum.core.BlockHeader; /** * Adaptor class to allow a {@link BftExtraDataCodec} to be used as a {@link QbftExtraDataProvider}. @@ -35,7 +35,7 @@ public class QbftExtraDataProviderAdaptor implements QbftExtraDataProvider { } @Override - public BftExtraData getExtraData(final BlockHeader header) { - return bftExtraDataCodec.decode(header); + public BftExtraData getExtraData(final QbftBlockHeader header) { + return bftExtraDataCodec.decode(BlockUtil.toBesuBlockHeader(header)); } } diff --git a/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/adaptor/QbftProtocolScheduleAdaptor.java b/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/adaptor/QbftProtocolScheduleAdaptor.java index 3d3484383..31e25809e 100644 --- a/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/adaptor/QbftProtocolScheduleAdaptor.java +++ b/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/adaptor/QbftProtocolScheduleAdaptor.java @@ -14,10 +14,10 @@ */ package org.hyperledger.besu.consensus.qbft.adaptor; +import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockHeader; import org.hyperledger.besu.consensus.qbft.core.types.QbftProtocolSchedule; import org.hyperledger.besu.consensus.qbft.core.types.QbftProtocolSpec; import org.hyperledger.besu.ethereum.ProtocolContext; -import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec; @@ -42,8 +42,9 @@ public class QbftProtocolScheduleAdaptor implements QbftProtocolSchedule { } @Override - public QbftProtocolSpec getByBlockHeader(final BlockHeader header) { - final ProtocolSpec protocolSpec = besuProtocolSchedule.getByBlockHeader(header); + public QbftProtocolSpec getByBlockHeader(final QbftBlockHeader header) { + final ProtocolSpec protocolSpec = + besuProtocolSchedule.getByBlockHeader(BlockUtil.toBesuBlockHeader(header)); return new QbftProtocolSpecAdaptor(protocolSpec, context); } } diff --git a/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/adaptor/QbftValidatorModeTransitionLoggerAdaptor.java b/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/adaptor/QbftValidatorModeTransitionLoggerAdaptor.java new file mode 100644 index 000000000..6c62ab94c --- /dev/null +++ b/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/adaptor/QbftValidatorModeTransitionLoggerAdaptor.java @@ -0,0 +1,43 @@ +/* + * 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.consensus.qbft.adaptor; + +import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockHeader; +import org.hyperledger.besu.consensus.qbft.core.types.QbftValidatorModeTransitionLogger; +import org.hyperledger.besu.consensus.qbft.validator.ValidatorModeTransitionLogger; + +/** + * Adaptor class to allow the {@link ValidatorModeTransitionLogger} to be used as a {@link + * QbftValidatorModeTransitionLogger}. + */ +public class QbftValidatorModeTransitionLoggerAdaptor implements QbftValidatorModeTransitionLogger { + + private final ValidatorModeTransitionLogger validatorModeTransitionLogger; + + /** + * Create a new instance of the adaptor. + * + * @param validatorModeTransitionLogger the {@link ValidatorModeTransitionLogger} to adapt. + */ + public QbftValidatorModeTransitionLoggerAdaptor( + final ValidatorModeTransitionLogger validatorModeTransitionLogger) { + this.validatorModeTransitionLogger = validatorModeTransitionLogger; + } + + @Override + public void logTransitionChange(final QbftBlockHeader parentHeader) { + validatorModeTransitionLogger.logTransitionChange(BlockUtil.toBesuBlockHeader(parentHeader)); + } +} diff --git a/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/adaptor/QbftValidatorProviderAdaptor.java b/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/adaptor/QbftValidatorProviderAdaptor.java new file mode 100644 index 000000000..80c147ad6 --- /dev/null +++ b/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/adaptor/QbftValidatorProviderAdaptor.java @@ -0,0 +1,62 @@ +/* + * 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.consensus.qbft.adaptor; + +import org.hyperledger.besu.consensus.common.validator.ValidatorProvider; +import org.hyperledger.besu.consensus.common.validator.VoteProvider; +import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockHeader; +import org.hyperledger.besu.consensus.qbft.core.types.QbftValidatorProvider; +import org.hyperledger.besu.datatypes.Address; + +import java.util.Collection; +import java.util.Optional; + +/** + * Adaptor class to allow the {@link ValidatorProvider} to be used as a {@link + * QbftValidatorProvider}. + */ +public class QbftValidatorProviderAdaptor implements QbftValidatorProvider { + + private final ValidatorProvider validatorProvider; + + /** + * Create a new instance of the adaptor. + * + * @param validatorProvider the {@link ValidatorProvider} to adapt. + */ + public QbftValidatorProviderAdaptor(final ValidatorProvider validatorProvider) { + this.validatorProvider = validatorProvider; + } + + @Override + public Collection
getValidatorsAtHead() { + return validatorProvider.getValidatorsAtHead(); + } + + @Override + public Collection
getValidatorsAfterBlock(final QbftBlockHeader header) { + return validatorProvider.getValidatorsAfterBlock(BlockUtil.toBesuBlockHeader(header)); + } + + @Override + public Collection
getValidatorsForBlock(final QbftBlockHeader header) { + return validatorProvider.getValidatorsForBlock(BlockUtil.toBesuBlockHeader(header)); + } + + @Override + public Optional getVoteProviderAtHead() { + return validatorProvider.getVoteProviderAtHead(); + } +} diff --git a/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/validator/ValidatorModeTransitionLogger.java b/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/validator/ValidatorModeTransitionLogger.java similarity index 98% rename from consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/validator/ValidatorModeTransitionLogger.java rename to consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/validator/ValidatorModeTransitionLogger.java index 8265959ef..83c18262c 100644 --- a/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/validator/ValidatorModeTransitionLogger.java +++ b/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/validator/ValidatorModeTransitionLogger.java @@ -12,7 +12,7 @@ * * SPDX-License-Identifier: Apache-2.0 */ -package org.hyperledger.besu.consensus.qbft.core.validator; +package org.hyperledger.besu.consensus.qbft.validator; import org.hyperledger.besu.config.QbftConfigOptions; import org.hyperledger.besu.consensus.common.ForkSpec; diff --git a/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/adaptor/BftEventHandlerAdaptorTest.java b/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/adaptor/BftEventHandlerAdaptorTest.java new file mode 100644 index 000000000..9ba5e484e --- /dev/null +++ b/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/adaptor/BftEventHandlerAdaptorTest.java @@ -0,0 +1,87 @@ +/* + * 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.consensus.qbft.adaptor; + +import static org.mockito.ArgumentMatchers.argThat; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import org.hyperledger.besu.consensus.common.bft.events.BftReceivedMessageEvent; +import org.hyperledger.besu.consensus.common.bft.events.BlockTimerExpiry; +import org.hyperledger.besu.consensus.common.bft.events.NewChainHead; +import org.hyperledger.besu.consensus.common.bft.events.RoundExpiry; +import org.hyperledger.besu.consensus.qbft.core.types.QbftEventHandler; +import org.hyperledger.besu.ethereum.core.BlockHeader; +import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +class BftEventHandlerAdaptorTest { + @Mock private QbftEventHandler qbftEventHandler; + @Mock private BftReceivedMessageEvent bftReceivedMessageEvent; + @Mock private BlockTimerExpiry blockTimerExpiry; + @Mock private RoundExpiry roundExpiry; + @Mock private NewChainHead newChainHead; + private BftEventHandlerAdaptor handler; + + @BeforeEach + void start() { + handler = new BftEventHandlerAdaptor(qbftEventHandler); + } + + @Test + void startDelegatesToQbftEventHandler() { + handler.start(); + verify(qbftEventHandler).start(); + } + + @Test + void handleMessageEventDelegatesToQbftEventHandler() { + handler.handleMessageEvent(bftReceivedMessageEvent); + verify(qbftEventHandler).handleMessageEvent(bftReceivedMessageEvent); + } + + @Test + void handleBlockTimerExpiryDelegatesToQbftEventHandler() { + handler.handleBlockTimerExpiry(blockTimerExpiry); + verify(qbftEventHandler).handleBlockTimerExpiry(blockTimerExpiry); + } + + @Test + void handleRoundExpiryDelegatesToQbftEventHandler() { + handler.handleRoundExpiry(roundExpiry); + verify(qbftEventHandler).handleRoundExpiry(roundExpiry); + } + + @Test + void handleNewBlockEventDelegatesToQbftEventHandler() { + BlockHeader header = new BlockHeaderTestFixture().buildHeader(); + when(newChainHead.getNewChainHeadHeader()).thenReturn(header); + + handler.handleNewBlockEvent(newChainHead); + verify(qbftEventHandler) + .handleNewBlockEvent( + argThat( + argument -> + ((QbftBlockHeaderAdaptor) argument.newChainHeadHeader()) + .getBesuBlockHeader() + .equals(header))); + } +} diff --git a/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/adaptor/QbftBlockCreatorAdaptorTest.java b/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/adaptor/QbftBlockCreatorAdaptorTest.java index fcd36fed9..1f093bb08 100644 --- a/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/adaptor/QbftBlockCreatorAdaptorTest.java +++ b/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/adaptor/QbftBlockCreatorAdaptorTest.java @@ -22,6 +22,7 @@ import org.hyperledger.besu.consensus.common.bft.BftExtraData; import org.hyperledger.besu.consensus.common.bft.Vote; import org.hyperledger.besu.consensus.qbft.QbftExtraDataCodec; import org.hyperledger.besu.consensus.qbft.core.types.QbftBlock; +import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockHeader; import org.hyperledger.besu.consensus.qbft.core.types.QbftExtraDataProvider; import org.hyperledger.besu.crypto.SECPSignature; import org.hyperledger.besu.datatypes.Address; @@ -44,14 +45,16 @@ import org.mockito.junit.jupiter.MockitoExtension; @ExtendWith(MockitoExtension.class) class QbftBlockCreatorAdaptorTest { @Mock private BlockCreator blockCreator; - @Mock private BlockHeader parentHeader; @Mock private Block besuBlock; @Mock private QbftExtraDataProvider qbftExtraDataProvider; private final QbftExtraDataCodec qbftExtraDataCodec = new QbftExtraDataCodec(); @Test void createsBlockUsingBesuBlockCreator() { - when(blockCreator.createBlock(10, parentHeader)) + BlockHeader besuParentHeader = new BlockHeaderTestFixture().buildHeader(); + QbftBlockHeader parentHeader = new QbftBlockHeaderAdaptor(besuParentHeader); + + when(blockCreator.createBlock(10, besuParentHeader)) .thenReturn(new BlockCreator.BlockCreationResult(besuBlock, null, null)); QbftBlockCreatorAdaptor qbftBlockCreator = @@ -73,13 +76,15 @@ class QbftBlockCreatorAdaptorTest { Block besuBlock = new Block(header, BlockBody.empty()); QbftBlock block = new QbftBlockAdaptor(besuBlock); SECPSignature seal = new SECPSignature(BigInteger.ONE, BigInteger.ONE, (byte) 1); - when(qbftExtraDataProvider.getExtraData(header)).thenReturn(bftExtraData); + when(qbftExtraDataProvider.getExtraData(new QbftBlockHeaderAdaptor(header))) + .thenReturn(bftExtraData); QbftBlockCreatorAdaptor qbftBlockCreator = new QbftBlockCreatorAdaptor(blockCreator, qbftExtraDataCodec); QbftBlock sealedBlock = qbftBlockCreator.createSealedBlock(qbftExtraDataProvider, block, 1, List.of(seal)); - BftExtraData sealedExtraData = qbftExtraDataCodec.decode(sealedBlock.getHeader()); + BftExtraData sealedExtraData = + qbftExtraDataCodec.decode(BlockUtil.toBesuBlockHeader(sealedBlock.getHeader())); assertThat(sealedExtraData.getVanityData()).isEqualTo(Bytes.wrap(new byte[32])); assertThat(sealedExtraData.getVote()).contains(Vote.authVote(Address.ZERO)); assertThat(sealedExtraData.getValidators()).isEqualTo(List.of(Address.ZERO)); diff --git a/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/adaptor/QbftBlockHashingAdaptorTest.java b/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/adaptor/QbftBlockHashingAdaptorTest.java new file mode 100644 index 000000000..d09140c3f --- /dev/null +++ b/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/adaptor/QbftBlockHashingAdaptorTest.java @@ -0,0 +1,54 @@ +/* + * 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.consensus.qbft.adaptor; + +import static java.util.Collections.emptyList; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.when; + +import org.hyperledger.besu.consensus.common.bft.BftBlockHashing; +import org.hyperledger.besu.consensus.common.bft.BftExtraData; +import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockHeader; +import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.ethereum.core.BlockHeader; +import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; + +import java.util.Optional; + +import org.apache.tuweni.bytes.Bytes; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +class QbftBlockHashingAdaptorTest { + @Mock private BftBlockHashing bftBlockHashing; + + @Test + void calculatesHashForCommittedSeal() { + BlockHeader header = new BlockHeaderTestFixture().buildHeader(); + QbftBlockHeader qbftBlockHeader = new QbftBlockHeaderAdaptor(header); + final BftExtraData bftExtraData = + new BftExtraData(Bytes.wrap(new byte[32]), emptyList(), Optional.empty(), 0, emptyList()); + when(bftBlockHashing.calculateDataHashForCommittedSeal(header, bftExtraData)) + .thenReturn(Hash.EMPTY); + + QbftBlockHashingAdaptor qbftBlockHashingAdaptor = new QbftBlockHashingAdaptor(bftBlockHashing); + Hash hash = + qbftBlockHashingAdaptor.calculateDataHashForCommittedSeal(qbftBlockHeader, bftExtraData); + assertThat(hash).isEqualTo(Hash.EMPTY); + } +} diff --git a/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/adaptor/QbftBlockHeaderAdaptorTest.java b/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/adaptor/QbftBlockHeaderAdaptorTest.java new file mode 100644 index 000000000..ee204d99f --- /dev/null +++ b/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/adaptor/QbftBlockHeaderAdaptorTest.java @@ -0,0 +1,43 @@ +/* + * 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.consensus.qbft.adaptor; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockHeader; +import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.ethereum.core.BlockHeader; +import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; + +import org.junit.jupiter.api.Test; + +class QbftBlockHeaderAdaptorTest { + + @Test + void adaptsBesuBlockHeader() { + BlockHeader header = + new BlockHeaderTestFixture() + .number(1) + .timestamp(1000L) + .coinbase(Address.ZERO) + .buildHeader(); + QbftBlockHeader qbftBlockHeader = new QbftBlockHeaderAdaptor(header); + + assertThat(qbftBlockHeader.getNumber()).isEqualTo(1); + assertThat(qbftBlockHeader.getTimestamp()).isEqualTo(1000L); + assertThat(qbftBlockHeader.getHash()).isEqualTo(header.getHash()); + assertThat(qbftBlockHeader.getCoinbase()).isEqualTo(Address.ZERO); + } +} diff --git a/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/adaptor/QbftBlockInterfaceAdaptorTest.java b/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/adaptor/QbftBlockInterfaceAdaptorTest.java index 462279dbc..110546c88 100644 --- a/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/adaptor/QbftBlockInterfaceAdaptorTest.java +++ b/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/adaptor/QbftBlockInterfaceAdaptorTest.java @@ -53,7 +53,8 @@ class QbftBlockInterfaceAdaptorTest { QbftBlockInterface qbftBlockInterface = new QbftBlockInterfaceAdaptor(bftBlockInterface); QbftBlock updatedBlock = qbftBlockInterface.replaceRoundInBlock(block, 1, QbftHashMode.COMMITTED_SEAL); - BftExtraData extraData = qbftExtraDataCodec.decode(updatedBlock.getHeader()); + BftExtraData extraData = + qbftExtraDataCodec.decode(BlockUtil.toBesuBlockHeader(updatedBlock.getHeader())); assertThat(extraData.getRound()).isEqualTo(1); } } diff --git a/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/adaptor/QbftBlockchainAdaptorTest.java b/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/adaptor/QbftBlockchainAdaptorTest.java new file mode 100644 index 000000000..aa0290070 --- /dev/null +++ b/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/adaptor/QbftBlockchainAdaptorTest.java @@ -0,0 +1,39 @@ +/* + * 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.consensus.qbft.adaptor; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import org.hyperledger.besu.ethereum.chain.Blockchain; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +class QbftBlockchainAdaptorTest { + @Mock private Blockchain blockchain; + + @Test + void returnsChainHeadBlockNumber() { + when(blockchain.getChainHeadBlockNumber()).thenReturn(1L); + long chainHeadBlockNumber = new QbftBlockchainAdaptor(blockchain).getChainHeadBlockNumber(); + assertThat(chainHeadBlockNumber).isEqualTo(1L); + verify(blockchain).getChainHeadBlockNumber(); + } +} diff --git a/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/adaptor/QbftExtraDataProviderAdaptorTest.java b/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/adaptor/QbftExtraDataProviderAdaptorTest.java index 654135b9f..3d1ba2c22 100644 --- a/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/adaptor/QbftExtraDataProviderAdaptorTest.java +++ b/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/adaptor/QbftExtraDataProviderAdaptorTest.java @@ -19,6 +19,7 @@ import static org.assertj.core.api.Assertions.assertThat; import org.hyperledger.besu.consensus.common.bft.BftExtraData; import org.hyperledger.besu.consensus.qbft.QbftExtraDataCodec; +import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockHeader; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; @@ -35,12 +36,13 @@ class QbftExtraDataProviderAdaptorTest { final BftExtraData bftExtraData = new BftExtraData(Bytes.wrap(new byte[32]), emptyList(), Optional.empty(), 0, emptyList()); final Bytes encoded = qbftExtraDataCodec.encode(bftExtraData); - final BlockHeader header = + final BlockHeader besuHeader = new BlockHeaderTestFixture().number(1).extraData(encoded).buildHeader(); + final QbftBlockHeader qbftHeader = new QbftBlockHeaderAdaptor(besuHeader); final QbftExtraDataProviderAdaptor qbftExtraDataProvider = new QbftExtraDataProviderAdaptor(new QbftExtraDataCodec()); - final BftExtraData retrievedExtraData = qbftExtraDataProvider.getExtraData(header); + final BftExtraData retrievedExtraData = qbftExtraDataProvider.getExtraData(qbftHeader); assertThat(retrievedExtraData).isEqualToComparingFieldByField(bftExtraData); } } diff --git a/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/adaptor/QbftProtocolScheduleAdaptorTest.java b/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/adaptor/QbftProtocolScheduleAdaptorTest.java index fe3babb31..2f994eb19 100644 --- a/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/adaptor/QbftProtocolScheduleAdaptorTest.java +++ b/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/adaptor/QbftProtocolScheduleAdaptorTest.java @@ -17,10 +17,12 @@ package org.hyperledger.besu.consensus.qbft.adaptor; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.when; +import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockHeader; import org.hyperledger.besu.consensus.qbft.core.types.QbftProtocolSchedule; import org.hyperledger.besu.consensus.qbft.core.types.QbftProtocolSpec; import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.core.BlockHeader; +import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec; @@ -34,15 +36,17 @@ class QbftProtocolScheduleAdaptorTest { @Mock private ProtocolSchedule besuProtocolSchedule; @Mock private ProtocolSpec besuProtocolSpec; @Mock private ProtocolContext besuProtocolContext; - @Mock private BlockHeader blockHeader; @Test void createsAProtocolSpecUsingBesuProtocolSpec() { - when(besuProtocolSchedule.getByBlockHeader(blockHeader)).thenReturn(besuProtocolSpec); + final BlockHeader besuHeader = new BlockHeaderTestFixture().number(1).buildHeader(); + final QbftBlockHeader qbftHeader = new QbftBlockHeaderAdaptor(besuHeader); + + when(besuProtocolSchedule.getByBlockHeader(besuHeader)).thenReturn(besuProtocolSpec); final QbftProtocolSchedule qbftProtocolSchedule = new QbftProtocolScheduleAdaptor(besuProtocolSchedule, besuProtocolContext); - final QbftProtocolSpec protocolSpec = qbftProtocolSchedule.getByBlockHeader(blockHeader); + final QbftProtocolSpec protocolSpec = qbftProtocolSchedule.getByBlockHeader(qbftHeader); assertThat(protocolSpec).hasFieldOrPropertyWithValue("besuProtocolSpec", besuProtocolSpec); } } diff --git a/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/adaptor/QbftValidatorModeTransitionLoggerAdaptorTest.java b/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/adaptor/QbftValidatorModeTransitionLoggerAdaptorTest.java new file mode 100644 index 000000000..7842877d7 --- /dev/null +++ b/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/adaptor/QbftValidatorModeTransitionLoggerAdaptorTest.java @@ -0,0 +1,41 @@ +/* + * 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.consensus.qbft.adaptor; + +import static org.mockito.Mockito.verify; + +import org.hyperledger.besu.consensus.qbft.validator.ValidatorModeTransitionLogger; +import org.hyperledger.besu.ethereum.core.BlockHeader; +import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +class QbftValidatorModeTransitionLoggerAdaptorTest { + @Mock private ValidatorModeTransitionLogger logger; + + @Test + void logTransitionChangeDelegatesToLogger() { + BlockHeader header = new BlockHeaderTestFixture().buildHeader(); + QbftBlockHeaderAdaptor qbftHeader = new QbftBlockHeaderAdaptor(header); + + var adaptor = new QbftValidatorModeTransitionLoggerAdaptor(logger); + adaptor.logTransitionChange(qbftHeader); + verify(logger).logTransitionChange(header); + } +} diff --git a/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/adaptor/QbftValidatorProviderAdaptorTest.java b/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/adaptor/QbftValidatorProviderAdaptorTest.java new file mode 100644 index 000000000..c3b6d6270 --- /dev/null +++ b/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/adaptor/QbftValidatorProviderAdaptorTest.java @@ -0,0 +1,87 @@ +/* + * 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.consensus.qbft.adaptor; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.when; + +import org.hyperledger.besu.consensus.common.validator.ValidatorProvider; +import org.hyperledger.besu.consensus.common.validator.VoteProvider; +import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockHeader; +import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.ethereum.core.BlockHeader; +import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; + +import java.util.List; +import java.util.Optional; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +class QbftValidatorProviderAdaptorTest { + @Mock private ValidatorProvider validatorProvider; + @Mock private VoteProvider voteProvider; + + @Test + void returnsValidatorsAtHead() { + List
validatorsAtHead = + List.of(Address.fromHexString("0x095e7baea6a6c7c4c2dfeb977efac326af552d87")); + when(validatorProvider.getValidatorsAtHead()).thenReturn(validatorsAtHead); + + QbftValidatorProviderAdaptor qbftValidatorProviderAdaptor = + new QbftValidatorProviderAdaptor(validatorProvider); + assertThat(qbftValidatorProviderAdaptor.getValidatorsAtHead()).isEqualTo(validatorsAtHead); + } + + @Test + void returnsValidatorsAfterBlock() { + BlockHeader header = new BlockHeaderTestFixture().buildHeader(); + QbftBlockHeader qbftBlockHeader = new QbftBlockHeaderAdaptor(header); + List
validatorsAfterBlock = + List.of(Address.fromHexString("0x095e7baea6a6c7c4c2dfeb977efac326af552d87")); + when(validatorProvider.getValidatorsAfterBlock(header)).thenReturn(validatorsAfterBlock); + + QbftValidatorProviderAdaptor qbftValidatorProviderAdaptor = + new QbftValidatorProviderAdaptor(validatorProvider); + assertThat(qbftValidatorProviderAdaptor.getValidatorsAfterBlock(qbftBlockHeader)) + .isEqualTo(validatorsAfterBlock); + } + + @Test + void returnsValidatorsForBlock() { + BlockHeader header = new BlockHeaderTestFixture().buildHeader(); + QbftBlockHeader qbftBlockHeader = new QbftBlockHeaderAdaptor(header); + List
validatorsForBlock = + List.of(Address.fromHexString("0x095e7baea6a6c7c4c2dfeb977efac326af552d87")); + when(validatorProvider.getValidatorsForBlock(header)).thenReturn(validatorsForBlock); + + QbftValidatorProviderAdaptor qbftValidatorProviderAdaptor = + new QbftValidatorProviderAdaptor(validatorProvider); + assertThat(qbftValidatorProviderAdaptor.getValidatorsForBlock(qbftBlockHeader)) + .isEqualTo(validatorsForBlock); + } + + @Test + void returnsVoteProviderAtHead() { + when(validatorProvider.getVoteProviderAtHead()).thenReturn(Optional.of(voteProvider)); + + QbftValidatorProviderAdaptor qbftValidatorProviderAdaptor = + new QbftValidatorProviderAdaptor(validatorProvider); + assertThat(qbftValidatorProviderAdaptor.getVoteProviderAtHead()).contains(voteProvider); + } +} diff --git a/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/validator/ValidatorModeTransitionLoggerTest.java b/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/validator/ValidatorModeTransitionLoggerTest.java index 1a531cb34..dabf26749 100644 --- a/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/validator/ValidatorModeTransitionLoggerTest.java +++ b/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/validator/ValidatorModeTransitionLoggerTest.java @@ -25,7 +25,6 @@ import org.hyperledger.besu.config.QbftConfigOptions; import org.hyperledger.besu.consensus.common.ForkSpec; import org.hyperledger.besu.consensus.common.ForksSchedule; import org.hyperledger.besu.consensus.qbft.MutableQbftConfigOptions; -import org.hyperledger.besu.consensus.qbft.core.validator.ValidatorModeTransitionLogger; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineForkchoiceUpdated.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineForkchoiceUpdated.java index 727677aa8..fd40f2262 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineForkchoiceUpdated.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineForkchoiceUpdated.java @@ -170,11 +170,6 @@ public abstract class AbstractEngineForkchoiceUpdated extends ExecutionEngineJso .log(); return maybeError.get(); } - ValidationResult forkValidationResult = - validateForkSupported(payloadAttributes.getTimestamp()); - if (!forkValidationResult.isValid()) { - return new JsonRpcErrorResponse(requestId, forkValidationResult); - } } final BlockHeader newHead = maybeNewHead.get(); diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineNewPayload.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineNewPayload.java index a4f267be9..6acf4e5a9 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineNewPayload.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineNewPayload.java @@ -153,6 +153,12 @@ public abstract class AbstractEngineNewPayload extends ExecutionEngineJsonRpcMet e); } + final ValidationResult forkValidationResult = + validateForkSupported(blockParam.getTimestamp()); + if (!forkValidationResult.isValid()) { + return new JsonRpcErrorResponse(reqId, forkValidationResult); + } + final ValidationResult parameterValidationResult = validateParameters( blockParam, @@ -163,12 +169,6 @@ public abstract class AbstractEngineNewPayload extends ExecutionEngineJsonRpcMet return new JsonRpcErrorResponse(reqId, parameterValidationResult); } - final ValidationResult forkValidationResult = - validateForkSupported(blockParam.getTimestamp()); - if (!forkValidationResult.isValid()) { - return new JsonRpcErrorResponse(reqId, forkValidationResult); - } - final Optional> maybeVersionedHashes; try { maybeVersionedHashes = extractVersionedHashes(maybeVersionedHashParam); diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineForkchoiceUpdatedV2.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineForkchoiceUpdatedV2.java index 1dedf2919..6ade5b6ad 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineForkchoiceUpdatedV2.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineForkchoiceUpdatedV2.java @@ -59,6 +59,12 @@ public class EngineForkchoiceUpdatedV2 extends AbstractEngineForkchoiceUpdated { return Optional.of(new JsonRpcErrorResponse(requestId, getInvalidPayloadAttributesError())); } + ValidationResult forkValidationResult = + validateForkSupported(payloadAttributes.getTimestamp()); + if (!forkValidationResult.isValid()) { + return Optional.of(new JsonRpcErrorResponse(requestId, forkValidationResult)); + } + return Optional.empty(); } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineForkchoiceUpdatedV3.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineForkchoiceUpdatedV3.java index c06b11932..55d76cfc9 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineForkchoiceUpdatedV3.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineForkchoiceUpdatedV3.java @@ -81,6 +81,7 @@ public class EngineForkchoiceUpdatedV3 extends AbstractEngineForkchoiceUpdated { @Override protected Optional isPayloadAttributesValid( final Object requestId, final EnginePayloadAttributesParameter payloadAttributes) { + if (payloadAttributes.getParentBeaconBlockRoot() == null) { LOG.error( "Parent beacon block root hash not present in payload attributes after cancun hardfork"); @@ -91,8 +92,10 @@ public class EngineForkchoiceUpdatedV3 extends AbstractEngineForkchoiceUpdated { return Optional.of(new JsonRpcErrorResponse(requestId, getInvalidPayloadAttributesError())); } - if (cancunMilestone.isEmpty() || payloadAttributes.getTimestamp() < cancunMilestone.get()) { - return Optional.of(new JsonRpcErrorResponse(requestId, RpcErrorType.UNSUPPORTED_FORK)); + ValidationResult forkValidationResult = + validateForkSupported(payloadAttributes.getTimestamp()); + if (!forkValidationResult.isValid()) { + return Optional.of(new JsonRpcErrorResponse(requestId, forkValidationResult)); } return Optional.empty(); diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadV3.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadV3.java index f0b026ef4..25e7ac487 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadV3.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadV3.java @@ -15,6 +15,7 @@ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine; import static org.hyperledger.besu.datatypes.HardforkId.MainnetHardforkId.CANCUN; +import static org.hyperledger.besu.datatypes.HardforkId.MainnetHardforkId.PRAGUE; import org.hyperledger.besu.consensus.merge.PayloadWrapper; import org.hyperledger.besu.consensus.merge.blockcreation.MergeMiningCoordinator; @@ -68,6 +69,11 @@ public class EngineGetPayloadV3 extends AbstractEngineGetPayload { @Override protected ValidationResult validateForkSupported(final long blockTimestamp) { - return ForkSupportHelper.validateForkSupported(CANCUN, cancunMilestone, blockTimestamp); + return ForkSupportHelper.validateForkSupported( + CANCUN, + cancunMilestone, + PRAGUE, + protocolSchedule.flatMap(s -> s.milestoneFor(PRAGUE)), + blockTimestamp); } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV3.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV3.java index beb566cfc..fe9cddad3 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV3.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV3.java @@ -15,6 +15,7 @@ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine; import static org.hyperledger.besu.datatypes.HardforkId.MainnetHardforkId.CANCUN; +import static org.hyperledger.besu.datatypes.HardforkId.MainnetHardforkId.PRAGUE; import org.hyperledger.besu.consensus.merge.blockcreation.MergeMiningCoordinator; import org.hyperledger.besu.ethereum.ProtocolContext; @@ -89,6 +90,11 @@ public class EngineNewPayloadV3 extends AbstractEngineNewPayload { @Override protected ValidationResult validateForkSupported(final long blockTimestamp) { - return ForkSupportHelper.validateForkSupported(CANCUN, cancunMilestone, blockTimestamp); + return ForkSupportHelper.validateForkSupported( + CANCUN, + cancunMilestone, + PRAGUE, + protocolSchedule.flatMap(s -> s.milestoneFor(PRAGUE)), + blockTimestamp); } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/ForkSupportHelper.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/ForkSupportHelper.java index c5a022f99..e8780f93d 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/ForkSupportHelper.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/ForkSupportHelper.java @@ -21,22 +21,54 @@ import org.hyperledger.besu.ethereum.mainnet.ValidationResult; import java.util.Optional; public class ForkSupportHelper { + public static ValidationResult validateForkSupported( final HardforkId firstSupportedHardforkId, - final Optional maybeForkMilestone, + final Optional maybeFirstSupportedForkMilestone, final long blockTimestamp) { - if (maybeForkMilestone.isEmpty()) { + + if (maybeFirstSupportedForkMilestone.isEmpty()) { return ValidationResult.invalid( RpcErrorType.UNSUPPORTED_FORK, "Configuration error, no schedule for " + firstSupportedHardforkId.name() + " fork set"); } - if (Long.compareUnsigned(blockTimestamp, maybeForkMilestone.get()) < 0) { + if (Long.compareUnsigned(blockTimestamp, maybeFirstSupportedForkMilestone.get()) < 0) { return ValidationResult.invalid( RpcErrorType.UNSUPPORTED_FORK, firstSupportedHardforkId.name() + " configured to start at timestamp: " - + maybeForkMilestone.get()); + + maybeFirstSupportedForkMilestone.get()); + } + + return ValidationResult.valid(); + } + + public static ValidationResult validateForkSupported( + final HardforkId firstSupportedHardforkId, + final Optional maybeFirstSupportedForkMilestone, + final HardforkId firstUnsupportedHardforkId, + final Optional maybeFirstUnsupportedMilestone, + final long blockTimestamp) { + + var result = + validateForkSupported( + firstSupportedHardforkId, maybeFirstSupportedForkMilestone, blockTimestamp); + + if (!result.isValid()) { + return result; + } + + if (maybeFirstUnsupportedMilestone.isPresent() + && Long.compareUnsigned(blockTimestamp, maybeFirstUnsupportedMilestone.get()) >= 0) { + return ValidationResult.invalid( + RpcErrorType.UNSUPPORTED_FORK, + "block timestamp " + + blockTimestamp + + " is after the first unsupported milestone: " + + firstUnsupportedHardforkId.name() + + " at timestamp " + + maybeFirstUnsupportedMilestone.get()); } return ValidationResult.valid(); diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/CodeDelegationResult.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/CodeDelegationResult.java new file mode 100644 index 000000000..a3945ae50 --- /dev/null +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/CodeDelegationResult.java @@ -0,0 +1,70 @@ +/* + * 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.api.jsonrpc.internal.results; + +import org.hyperledger.besu.datatypes.CodeDelegation; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import org.apache.tuweni.units.bigints.UInt256; + +@JsonPropertyOrder({"chainId", "address", "nonce", "yParity", "r", "s"}) +public class CodeDelegationResult { + private final String chainId; + private final String address; + private final String nonce; + private final String yParity; + private final String r; + private final String s; + + public CodeDelegationResult(final CodeDelegation codeDelegation) { + chainId = Quantity.create(UInt256.valueOf(codeDelegation.chainId())); + address = codeDelegation.address().toHexString(); + nonce = Quantity.create(codeDelegation.nonce()); + yParity = Quantity.create(codeDelegation.v()); + r = Quantity.create(codeDelegation.r()); + s = Quantity.create(codeDelegation.s()); + } + + @JsonProperty("chainId") + public String chainId() { + return chainId; + } + + @JsonProperty("address") + public String address() { + return address; + } + + @JsonProperty("nonce") + public String nonce() { + return nonce; + } + + @JsonProperty("yParity") + public String yParity() { + return yParity; + } + + @JsonProperty("r") + public String r() { + return r; + } + + @JsonProperty("s") + public String s() { + return s; + } +} diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/TransactionCompleteResult.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/TransactionCompleteResult.java index ce05b82cb..7f3febc60 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/TransactionCompleteResult.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/TransactionCompleteResult.java @@ -23,6 +23,7 @@ import org.hyperledger.besu.ethereum.api.query.TransactionWithMetadata; import org.hyperledger.besu.ethereum.core.Transaction; import java.util.List; +import java.util.Optional; import com.fasterxml.jackson.annotation.JsonGetter; import com.fasterxml.jackson.annotation.JsonInclude; @@ -94,7 +95,7 @@ public class TransactionCompleteResult implements TransactionResult { private final List versionedHashes; @JsonInclude(JsonInclude.Include.NON_NULL) - private final List authorizationList; + private final List authorizationList; public TransactionCompleteResult(final TransactionWithMetadata tx) { final Transaction transaction = tx.getTransaction(); @@ -140,7 +141,11 @@ public class TransactionCompleteResult implements TransactionResult { this.r = Quantity.create(transaction.getR()); this.s = Quantity.create(transaction.getS()); this.versionedHashes = transaction.getVersionedHashes().orElse(null); - this.authorizationList = transaction.getCodeDelegationList().orElse(null); + final Optional> codeDelegationList = transaction.getCodeDelegationList(); + this.authorizationList = + codeDelegationList + .map(cds -> cds.stream().map(CodeDelegationResult::new).toList()) + .orElse(null); } @JsonGetter(value = "accessList") @@ -256,7 +261,7 @@ public class TransactionCompleteResult implements TransactionResult { } @JsonGetter(value = "authorizationList") - public List getAuthorizationList() { + public List getAuthorizationList() { return authorizationList; } } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetTransactionByHashTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetTransactionByHashTest.java index 48350ff9d..18e5f89f7 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetTransactionByHashTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetTransactionByHashTest.java @@ -50,8 +50,9 @@ import org.mockito.junit.jupiter.MockitoExtension; @ExtendWith(MockitoExtension.class) class EthGetTransactionByHashTest { + // EIP-7702 Set Code Transaction private static final String VALID_TRANSACTION = - "0xf86d0485174876e800830222e0945aae326516b4f8fe08074b7e972e40a713048d62880de0b6b3a7640000801ba05d4e7998757264daab67df2ce6f7e7a0ae36910778a406ca73898c9899a32b9ea0674700d5c3d1d27f2e6b4469957dfd1a1c49bf92383d80717afc84eb05695d5b"; + "0xb8c404f8c1018080078307a12094a94f5374fce5edbc8e2a8697c15331677e6ebf0b8080c0f85cf85a809400000000000000000000000000000000000010008080a0dbcff17ff6c249f13b334fa86bcbaa1afd9f566ca9b06e4ea5fab9bdde9a9202a05c34c9d8af5b20e4a425fc1daf2d9d484576857eaf1629145b4686bac733868e01a0d61673cd58ffa5fc605c3215aa4647fa3afbea1d1f577e08402442992526d980a0063068ca818025c7b8493d0623cb70ef3a2ba4b3e2ae0af1146d1c9b065c0aff"; @Mock private BlockchainQueries blockchainQueries; private EthGetTransactionByHash method; diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineNewPayloadTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineNewPayloadTest.java index 97e775cdb..63c40ee46 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineNewPayloadTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineNewPayloadTest.java @@ -20,6 +20,7 @@ import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.Executi import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.ExecutionEngineJsonRpcMethod.EngineStatus.INVALID; import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.ExecutionEngineJsonRpcMethod.EngineStatus.SYNCING; import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.ExecutionEngineJsonRpcMethod.EngineStatus.VALID; +import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine.EngineTestSupport.fromErrorResp; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.lenient; import static org.mockito.Mockito.mock; @@ -43,7 +44,6 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.ExecutionEngin import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.EnginePayloadParameter; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.WithdrawalParameter; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.EnginePayloadStatusResult; @@ -429,14 +429,6 @@ public abstract class AbstractEngineNewPayloadTest extends AbstractScheduledApiT .get(); } - protected JsonRpcError fromErrorResp(final JsonRpcResponse resp) { - assertThat(resp.getType()).isEqualTo(RpcResponseType.ERROR); - return Optional.of(resp) - .map(JsonRpcErrorResponse.class::cast) - .map(JsonRpcErrorResponse::getError) - .get(); - } - protected BlockHeader createBlockHeader(final Optional> maybeWithdrawals) { return createBlockHeaderFixture(maybeWithdrawals).buildHeader(); } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractScheduledApiTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractScheduledApiTest.java index 46fe7d3b6..46e12cba8 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractScheduledApiTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractScheduledApiTest.java @@ -44,9 +44,9 @@ public class AbstractScheduledApiTest { protected final ScheduledProtocolSpec.Hardfork cancunHardfork = new ScheduledProtocolSpec.Hardfork("Cancun", 30); protected final ScheduledProtocolSpec.Hardfork pragueHardfork = - new ScheduledProtocolSpec.Hardfork("Prague", 40); + new ScheduledProtocolSpec.Hardfork("Prague", 50); protected final ScheduledProtocolSpec.Hardfork experimentalHardfork = - new ScheduledProtocolSpec.Hardfork("ExperimentalEips", 50); + new ScheduledProtocolSpec.Hardfork("ExperimentalEips", 70); @Mock protected DefaultProtocolSchedule protocolSchedule; diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetBlobsV1Test.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetBlobsV1Test.java index 29c7ae82e..3b017712f 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetBlobsV1Test.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetBlobsV1Test.java @@ -15,6 +15,7 @@ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine; import static org.assertj.core.api.Assertions.assertThat; +import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine.EngineTestSupport.fromErrorResp; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; @@ -32,7 +33,6 @@ import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; @@ -256,12 +256,4 @@ public class EngineGetBlobsV1Test { list.forEach(obj -> blobAndProofV1s.add((BlobAndProofV1) obj)); return blobAndProofV1s; } - - private RpcErrorType fromErrorResp(final JsonRpcResponse resp) { - assertThat(resp.getType()).isEqualTo(RpcResponseType.ERROR); - return Optional.of(resp) - .map(JsonRpcErrorResponse.class::cast) - .map(JsonRpcErrorResponse::getErrorType) - .get(); - } } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadBodiesByHashV1Test.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadBodiesByHashV1Test.java index f7752a797..f1eec5923 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadBodiesByHashV1Test.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadBodiesByHashV1Test.java @@ -15,6 +15,7 @@ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine; import static org.assertj.core.api.Assertions.assertThat; +import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine.EngineTestSupport.fromErrorResp; import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType.INVALID_RANGE_REQUEST_TOO_LARGE; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.spy; @@ -29,10 +30,8 @@ import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.BlockResultFactory; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.EngineGetPayloadBodiesResultV1; import org.hyperledger.besu.ethereum.chain.MutableBlockchain; @@ -259,12 +258,4 @@ public class EngineGetPayloadBodiesByHashV1Test { .map(EngineGetPayloadBodiesResultV1.class::cast) .get(); } - - private RpcErrorType fromErrorResp(final JsonRpcResponse resp) { - assertThat(resp.getType()).isEqualTo(RpcResponseType.ERROR); - return Optional.of(resp) - .map(JsonRpcErrorResponse.class::cast) - .map(JsonRpcErrorResponse::getErrorType) - .get(); - } } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadV3Test.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadV3Test.java index 1fe3b44d4..f656ac91a 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadV3Test.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadV3Test.java @@ -14,7 +14,10 @@ */ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine; +import static java.util.Collections.emptyList; import static org.assertj.core.api.Assertions.assertThat; +import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine.EngineTestSupport.fromErrorResp; +import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType.UNSUPPORTED_FORK; import static org.mockito.Mockito.lenient; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; @@ -30,7 +33,10 @@ import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.TransactionType; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.EngineGetPayloadResultV3; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.Quantity; import org.hyperledger.besu.ethereum.core.BlobTestFixture; @@ -86,6 +92,76 @@ public class EngineGetPayloadV3Test extends AbstractEngineGetPayloadTest { assertThat(method.getName()).isEqualTo("engine_getPayloadV3"); } + @Test + public void shouldReturnUnsupportedForkIfBlockTimestampIsBeforeCancunMilestone() { + BlockHeader shanghaiHeader = + new BlockHeaderTestFixture() + .prevRandao(Bytes32.random()) + .timestamp(cancunHardfork.milestone() - 1) + .excessBlobGas(BlobGas.of(10L)) + .buildHeader(); + + PayloadIdentifier shanghaiPid = + PayloadIdentifier.forPayloadParams( + Hash.ZERO, + cancunHardfork.milestone() - 1, + Bytes32.random(), + Address.fromHexString("0x42"), + Optional.empty(), + Optional.empty()); + + BlockWithReceipts shanghaiBlock = + new BlockWithReceipts( + new Block( + shanghaiHeader, new BlockBody(emptyList(), emptyList(), Optional.of(emptyList()))), + emptyList()); + PayloadWrapper payloadShanghai = + new PayloadWrapper(shanghaiPid, shanghaiBlock, Optional.empty()); + + when(mergeContext.retrievePayloadById(shanghaiPid)).thenReturn(Optional.of(payloadShanghai)); + + final var resp = resp(RpcMethod.ENGINE_GET_PAYLOAD_V3.getMethodName(), shanghaiPid); + + assertThat(resp).isInstanceOf(JsonRpcErrorResponse.class); + assertThat(((JsonRpcErrorResponse) resp).getErrorType()) + .isEqualTo(RpcErrorType.UNSUPPORTED_FORK); + } + + @Test + public void shouldReturnUnsupportedForkIfBlockTimestampIsAfterPragueMilestone() { + BlockHeader pragueHeader = + new BlockHeaderTestFixture() + .prevRandao(Bytes32.random()) + .timestamp(pragueHardfork.milestone()) + .excessBlobGas(BlobGas.of(10L)) + .buildHeader(); + + PayloadIdentifier postCancunPid = + PayloadIdentifier.forPayloadParams( + Hash.ZERO, + cancunHardfork.milestone(), + Bytes32.random(), + Address.fromHexString("0x42"), + Optional.empty(), + Optional.empty()); + + BlockWithReceipts pragueBlock = + new BlockWithReceipts( + new Block( + pragueHeader, new BlockBody(emptyList(), emptyList(), Optional.of(emptyList()))), + emptyList()); + PayloadWrapper payloadPostCancun = + new PayloadWrapper(postCancunPid, pragueBlock, Optional.empty()); + + when(mergeContext.retrievePayloadById(postCancunPid)) + .thenReturn(Optional.of(payloadPostCancun)); + + final var resp = resp(RpcMethod.ENGINE_GET_PAYLOAD_V3.getMethodName(), postCancunPid); + final JsonRpcError jsonRpcError = fromErrorResp(resp); + assertThat(jsonRpcError.getCode()).isEqualTo(UNSUPPORTED_FORK.getCode()); + verify(engineCallListener, times(1)).executionEngineCalled(); + } + @Override @Test public void shouldReturnBlockForKnownPayloadId() { diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadV4Test.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadV4Test.java index 4a241ce38..d706b42a4 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadV4Test.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadV4Test.java @@ -93,6 +93,15 @@ public class EngineGetPayloadV4Test extends AbstractEngineGetPayloadTest { assertThat(method.getName()).isEqualTo("engine_getPayloadV4"); } + @Test + public void shouldReturnUnsupportedForkIfBlockTimestampIsBeforePragueMilestone() { + final var resp = resp(RpcMethod.ENGINE_GET_PAYLOAD_V4.getMethodName(), mockPid); + + assertThat(resp).isInstanceOf(JsonRpcErrorResponse.class); + assertThat(((JsonRpcErrorResponse) resp).getErrorType()) + .isEqualTo(RpcErrorType.UNSUPPORTED_FORK); + } + @Override @Test public void shouldReturnBlockForKnownPayloadId() { @@ -220,15 +229,6 @@ public class EngineGetPayloadV4Test extends AbstractEngineGetPayloadTest { }); } - @Test - public void shouldReturnUnsupportedFork() { - final var resp = resp(RpcMethod.ENGINE_GET_PAYLOAD_V4.getMethodName(), mockPid); - - assertThat(resp).isInstanceOf(JsonRpcErrorResponse.class); - assertThat(((JsonRpcErrorResponse) resp).getErrorType()) - .isEqualTo(RpcErrorType.UNSUPPORTED_FORK); - } - @Override protected String getMethodName() { return RpcMethod.ENGINE_GET_PAYLOAD_V4.getMethodName(); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV2Test.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV2Test.java index 3632084ac..963bbf66e 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV2Test.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV2Test.java @@ -16,6 +16,7 @@ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine; import static org.assertj.core.api.Assertions.assertThat; import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.ExecutionEngineJsonRpcMethod.EngineStatus.INVALID; +import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine.EngineTestSupport.fromErrorResp; import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.WithdrawalParameterTestFixture.WITHDRAWAL_PARAM_1; import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType.INVALID_BLOB_GAS_USED_PARAMS; import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType.INVALID_PARAMS; @@ -34,12 +35,14 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.WithdrawalP import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.Withdrawal; +import org.hyperledger.besu.ethereum.mainnet.ScheduledProtocolSpec; import org.hyperledger.besu.ethereum.mainnet.WithdrawalsValidator; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import java.util.Collections; import java.util.List; import java.util.Optional; +import java.util.Set; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -52,6 +55,10 @@ import org.mockito.quality.Strictness; @MockitoSettings(strictness = Strictness.LENIENT) public class EngineNewPayloadV2Test extends AbstractEngineNewPayloadTest { + protected Set supportedHardforks() { + return Set.of(shanghaiHardfork); + } + public EngineNewPayloadV2Test() {} @Override @@ -177,7 +184,7 @@ public class EngineNewPayloadV2Test extends AbstractEngineNewPayloadTest { @Test public void shouldReturnUnsupportedForkIfBlockTimestampIsAfterCancunMilestone() { - // Cancun starte at timestamp 30 + // Cancun started at timestamp 30 final long blockTimestamp = 31L; BlockHeader blockHeader = createBlockHeaderFixture(Optional.of(Collections.emptyList())) diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV3Test.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV3Test.java index 2fb451248..cf3da05a1 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV3Test.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV3Test.java @@ -17,7 +17,9 @@ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine; import static java.util.Collections.emptyList; import static org.assertj.core.api.Assertions.assertThat; import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.ExecutionEngineJsonRpcMethod.EngineStatus.INVALID; +import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine.EngineTestSupport.fromErrorResp; import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType.INVALID_PARAMS; +import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType.UNSUPPORTED_FORK; import static org.mockito.Mockito.lenient; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; @@ -52,6 +54,7 @@ import org.hyperledger.besu.ethereum.core.encoding.EncodingContext; import org.hyperledger.besu.ethereum.core.encoding.TransactionEncoder; import org.hyperledger.besu.ethereum.mainnet.BodyValidation; import org.hyperledger.besu.ethereum.mainnet.CancunTargetingGasLimitCalculator; +import org.hyperledger.besu.ethereum.mainnet.ScheduledProtocolSpec; import org.hyperledger.besu.ethereum.mainnet.ValidationResult; import org.hyperledger.besu.evm.gascalculator.CancunGasCalculator; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; @@ -59,13 +62,14 @@ import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import java.math.BigInteger; import java.util.List; import java.util.Optional; +import java.util.Random; +import java.util.Set; import java.util.function.Supplier; import com.google.common.base.Suppliers; import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.junit.jupiter.MockitoExtension; @@ -78,6 +82,11 @@ public class EngineNewPayloadV3Test extends EngineNewPayloadV2Test { public EngineNewPayloadV3Test() {} + @Override + protected Set supportedHardforks() { + return Set.of(cancunHardfork); + } + @Override @Test public void shouldReturnExpectedMethodName() { @@ -104,6 +113,37 @@ public class EngineNewPayloadV3Test extends EngineNewPayloadV2Test { .thenReturn(mock(CancunTargetingGasLimitCalculator.class)); } + @Override + public void shouldReturnUnsupportedForkIfBlockTimestampIsAfterCancunMilestone() { + // only relevant for v2 + } + + @Test + public void shouldReturnUnsupportedForkIfBlockTimestampIsAfterPragueMilestone() { + final BlockHeader pragueHeader = + createBlockHeaderFixture(Optional.of(emptyList())) + .timestamp(pragueHardfork.milestone()) + .buildHeader(); + + var resp = resp(mockEnginePayload(pragueHeader, emptyList(), null)); + final JsonRpcError jsonRpcError = fromErrorResp(resp); + assertThat(jsonRpcError.getCode()).isEqualTo(UNSUPPORTED_FORK.getCode()); + verify(engineCallListener, times(1)).executionEngineCalled(); + } + + @Test + public void shouldReturnUnsupportedForkIfBlockTimestampIsBeforeCancunMilestone() { + final BlockHeader shanghaiHeader = + createBlockHeaderFixture(Optional.of(emptyList())) + .timestamp(cancunHardfork.milestone() - 1) + .buildHeader(); + + var resp = resp(mockEnginePayload(shanghaiHeader, emptyList(), null)); + final JsonRpcError jsonRpcError = fromErrorResp(resp); + assertThat(jsonRpcError.getCode()).isEqualTo(UNSUPPORTED_FORK.getCode()); + verify(engineCallListener, times(1)).executionEngineCalled(); + } + @Test public void shouldInvalidVersionedHash_whenShortVersionedHash() { final Bytes shortHash = Bytes.fromHexString("0x" + "69".repeat(31)); @@ -213,6 +253,7 @@ public class EngineNewPayloadV3Test extends EngineNewPayloadV2Test { // V3 must return error if null blobGasUsed BlockHeader blockHeader = createBlockHeaderFixture(Optional.of(emptyList())) + .timestamp(getTimestampForSupportedFork()) .excessBlobGas(BlobGas.MAX_BLOB_GAS) .blobGasUsed(null) .buildHeader(); @@ -231,6 +272,7 @@ public class EngineNewPayloadV3Test extends EngineNewPayloadV2Test { // V3 must return error if null excessBlobGas BlockHeader blockHeader = createBlockHeaderFixture(Optional.of(emptyList())) + .timestamp(getTimestampForSupportedFork()) .excessBlobGas(null) .blobGasUsed(100L) .buildHeader(); @@ -280,12 +322,6 @@ public class EngineNewPayloadV3Test extends EngineNewPayloadV2Test { .createTransaction(senderKeys); } - @Override - @Disabled - public void shouldReturnUnsupportedForkIfBlockTimestampIsAfterCancunMilestone() { - // only relevant for v2 - } - @Override protected JsonRpcResponse resp(final EnginePayloadParameter payload) { Object[] params = @@ -295,4 +331,9 @@ public class EngineNewPayloadV3Test extends EngineNewPayloadV2Test { return method.response( new JsonRpcRequestContext(new JsonRpcRequest("2.0", this.method.getName(), params))); } + + protected long getTimestampForSupportedFork() { + final int index = new Random().nextInt(supportedHardforks().size()); + return supportedHardforks().stream().toList().get(index).milestone(); + } } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV4Test.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV4Test.java index 8dc84418b..913add4f1 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV4Test.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV4Test.java @@ -17,7 +17,9 @@ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine; import static java.util.Collections.emptyList; import static org.assertj.core.api.Assertions.assertThat; import static org.hyperledger.besu.ethereum.api.graphql.internal.response.GraphQLError.INVALID_PARAMS; +import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine.EngineTestSupport.fromErrorResp; import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType.INVALID_EXECUTION_REQUESTS_PARAMS; +import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType.UNSUPPORTED_FORK; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.lenient; import static org.mockito.Mockito.mock; @@ -41,6 +43,7 @@ import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; import org.hyperledger.besu.ethereum.core.Request; import org.hyperledger.besu.ethereum.core.Withdrawal; import org.hyperledger.besu.ethereum.mainnet.BodyValidation; +import org.hyperledger.besu.ethereum.mainnet.ScheduledProtocolSpec; import org.hyperledger.besu.ethereum.mainnet.ValidationResult; import org.hyperledger.besu.ethereum.mainnet.requests.MainnetRequestsValidator; import org.hyperledger.besu.ethereum.mainnet.requests.ProhibitedRequestValidator; @@ -50,6 +53,7 @@ import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import java.util.Comparator; import java.util.List; import java.util.Optional; +import java.util.Set; import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; @@ -63,6 +67,11 @@ public class EngineNewPayloadV4Test extends EngineNewPayloadV3Test { public EngineNewPayloadV4Test() {} + @Override + protected Set supportedHardforks() { + return Set.of(pragueHardfork); + } + private static final List VALID_REQUESTS = List.of( new Request(RequestType.DEPOSIT, Bytes.of(1)), @@ -93,6 +102,22 @@ public class EngineNewPayloadV4Test extends EngineNewPayloadV3Test { assertThat(method.getName()).isEqualTo("engine_newPayloadV4"); } + @Override + public void shouldReturnUnsupportedForkIfBlockTimestampIsAfterPragueMilestone() { + // Only relevant for V3 + } + + @Test + public void shouldReturnUnsupportedForkIfBlockTimestampIsBeforePragueMilestone() { + final BlockHeader cancunHeader = createBlockHeaderFixtureForV3(Optional.empty()).buildHeader(); + + var resp = resp(mockEnginePayload(cancunHeader, emptyList())); + + final JsonRpcError jsonRpcError = fromErrorResp(resp); + assertThat(jsonRpcError.getCode()).isEqualTo(UNSUPPORTED_FORK.getCode()); + verify(engineCallListener, times(1)).executionEngineCalled(); + } + @Test public void shouldReturnInvalidIfRequestsIsNull_WhenRequestsAllowed() { var resp = @@ -173,6 +198,7 @@ public class EngineNewPayloadV4Test extends EngineNewPayloadV3Test { final Optional> maybeWithdrawals) { return createBlockHeaderFixtureForV3(maybeWithdrawals) .requestsHash(BodyValidation.requestsHash(VALID_REQUESTS)) + .timestamp(pragueHardfork.milestone()) .buildHeader(); } @@ -181,7 +207,7 @@ public class EngineNewPayloadV4Test extends EngineNewPayloadV3Test { BlockHeader parentBlockHeader = new BlockHeaderTestFixture() .baseFeePerGas(Wei.ONE) - .timestamp(pragueHardfork.milestone()) + .timestamp(pragueHardfork.milestone() - 2) // cancun parent .excessBlobGas(BlobGas.ZERO) .blobGasUsed(0L) .buildHeader(); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineTestSupport.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineTestSupport.java new file mode 100644 index 000000000..688d78aed --- /dev/null +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineTestSupport.java @@ -0,0 +1,35 @@ +/* + * 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.api.jsonrpc.internal.methods.engine; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; +import org.hyperledger.besu.plugin.services.rpc.RpcResponseType; + +import java.util.Optional; + +public class EngineTestSupport { + + static JsonRpcError fromErrorResp(final JsonRpcResponse resp) { + assertThat(resp.getType()).isEqualTo(RpcResponseType.ERROR); + return Optional.of(resp) + .map(JsonRpcErrorResponse.class::cast) + .map(JsonRpcErrorResponse::getError) + .get(); + } +} diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/feemarket/ExcessBlobGasCalculator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/feemarket/ExcessBlobGasCalculator.java index f6372097b..5f4d1f280 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/feemarket/ExcessBlobGasCalculator.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/feemarket/ExcessBlobGasCalculator.java @@ -24,7 +24,7 @@ public class ExcessBlobGasCalculator { * public class ExcessBlobGasCalculator { /** Calculates the excess blob gas for a parent block * header. * - * @param protocolSpec The protocol specification. + * @param protocolSpec The protocol specification of the current block. * @param parentHeader The parent block header. * @return The excess blob gas. */ diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/TransactionRLPDecoderTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/TransactionRLPDecoderTest.java index ba0b5d8e6..dc7782d38 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/TransactionRLPDecoderTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/TransactionRLPDecoderTest.java @@ -19,10 +19,13 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.hyperledger.besu.evm.account.Account.MAX_NONCE; import static org.junit.jupiter.api.Assumptions.assumeTrue; +import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.TransactionType; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.core.BlockDataGenerator; +import org.hyperledger.besu.ethereum.core.CodeDelegation; import org.hyperledger.besu.ethereum.core.Transaction; +import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput; import org.hyperledger.besu.ethereum.rlp.RLP; import org.hyperledger.besu.ethereum.rlp.RLPException; import org.hyperledger.besu.ethereum.rlp.RLPInput; @@ -44,6 +47,37 @@ class TransactionRLPDecoderTest { "0xb8a902f8a686796f6c6f7632800285012a05f20082753094000000000000000000000000000000000000aaaa8080f838f794000000000000000000000000000000000000aaaae1a0000000000000000000000000000000000000000000000000000000000000000001a00c1d69648e348fe26155b45de45004f0e4195f6352d8f0935bc93e98a3e2a862a060064e5b9765c0ac74223b0cf49635c59ae0faf82044fd17bcc68a549ade6f95"; private static final String NONCE_64_BIT_MAX_MINUS_2_TX_RLP = "0xf86788fffffffffffffffe0182520894095e7baea6a6c7c4c2dfeb977efac326af552d8780801ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a01fffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804"; + private static final String EIP7702_SET_CODE_TX_OPAQUE = + "0x04f8c1018080078307a12094a94f5374fce5edbc8e2a8697c15331677e6ebf0b8080c0f85cf85a809400000000000000000000000000000000000010008080a0dbcff17ff6c249f13b334fa86bcbaa1afd9f566ca9b06e4ea5fab9bdde9a9202a05c34c9d8af5b20e4a425fc1daf2d9d484576857eaf1629145b4686bac733868e01a0d61673cd58ffa5fc605c3215aa4647fa3afbea1d1f577e08402442992526d980a0063068ca818025c7b8493d0623cb70ef3a2ba4b3e2ae0af1146d1c9b065c0aff"; + + @Test + void decodeEIP7702SetCodeTransaction() { + final Transaction transaction = + TransactionDecoder.decodeOpaqueBytes( + Bytes.fromHexString(EIP7702_SET_CODE_TX_OPAQUE), EncodingContext.BLOCK_BODY); + final BytesValueRLPOutput rlpOut = new BytesValueRLPOutput(); + TransactionEncoder.encodeRLP(transaction, rlpOut, EncodingContext.BLOCK_BODY); + assertThat(rlpOut.encoded()) + .isEqualTo( + Bytes.fromHexString( + "0xb8c404f8c1018080078307a12094a94f5374fce5edbc8e2a8697c15331677e6ebf0b8080c0f85cf85a809400000000000000000000000000000000000010008080a0dbcff17ff6c249f13b334fa86bcbaa1afd9f566ca9b06e4ea5fab9bdde9a9202a05c34c9d8af5b20e4a425fc1daf2d9d484576857eaf1629145b4686bac733868e01a0d61673cd58ffa5fc605c3215aa4647fa3afbea1d1f577e08402442992526d980a0063068ca818025c7b8493d0623cb70ef3a2ba4b3e2ae0af1146d1c9b065c0aff")); + assertThat(transaction.getType()).isEqualTo(TransactionType.DELEGATE_CODE); + assertThat(transaction.getCodeDelegationList()).isPresent(); + assertThat(transaction.getCodeDelegationList().get().size()).isEqualTo(1); + var expectedCodeDelegation = + CodeDelegation.createCodeDelegation( + BigInteger.ZERO, + Address.fromHexString("0x1000"), + "0x0", + "0x0", + "0xdbcff17ff6c249f13b334fa86bcbaa1afd9f566ca9b06e4ea5fab9bdde9a9202", + "0x5c34c9d8af5b20e4a425fc1daf2d9d484576857eaf1629145b4686bac733868e"); + var actualCodeDelegation = transaction.getCodeDelegationList().get().getFirst(); + assertThat(actualCodeDelegation.chainId()).isEqualTo(expectedCodeDelegation.chainId()); + assertThat(actualCodeDelegation.address()).isEqualTo(expectedCodeDelegation.address()); + assertThat(actualCodeDelegation.nonce()).isEqualTo(expectedCodeDelegation.nonce()); + assertThat(actualCodeDelegation.signature()).isEqualTo(expectedCodeDelegation.signature()); + } @Test void decodeFrontierNominalCase() { diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index 2f44ded87..6cd992d18 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -5152,18 +5152,15 @@ - - - + + + - - + + - - - - - + + @@ -5174,74 +5171,59 @@ - - - + + + - - + + - - - - - + + - - - + + + - - + + - - - - - + + - - - + + + - - + + - - - - - + + - - - + + + - - + + - - - - - + + - - - + + + - - + + - - - - - + + diff --git a/platform/build.gradle b/platform/build.gradle index 8be1b4280..3be52256c 100644 --- a/platform/build.gradle +++ b/platform/build.gradle @@ -48,6 +48,7 @@ dependencies { api project(':consensus:ibft') api project(':consensus:merge') api project(':consensus:qbft') + api project(':consensus:qbft-core') api project(':crypto:algorithms') api project(':crypto:services') api project(':datatypes') @@ -137,12 +138,12 @@ dependencies { api 'org.hibernate.validator:hibernate-validator:8.0.1.Final' - api 'org.hyperledger.besu:arithmetic:1.1.1' - api 'org.hyperledger.besu:blake2bf:1.1.1' - api 'org.hyperledger.besu:gnark:1.1.1' - api 'org.hyperledger.besu:ipa-multipoint:1.1.1' - api 'org.hyperledger.besu:secp256k1:1.1.1' - api 'org.hyperledger.besu:secp256r1:1.1.1' + api 'org.hyperledger.besu:arithmetic:1.1.2' + api 'org.hyperledger.besu:blake2bf:1.1.2' + api 'org.hyperledger.besu:gnark:1.1.2' + api 'org.hyperledger.besu:ipa-multipoint:1.1.2' + api 'org.hyperledger.besu:secp256k1:1.1.2' + api 'org.hyperledger.besu:secp256r1:1.1.2' api 'org.hyperledger.besu:besu-errorprone-checks:1.0.0'