From 1a62d2a6c22e5fbd452cb39b29a6f66956c60990 Mon Sep 17 00:00:00 2001 From: Justin Florentine Date: Mon, 11 Jul 2022 13:34:39 -0400 Subject: [PATCH] 3943 stop blocks on finalized (#4058) * adds interfaces for tracking merge state and forchoices * after 2 finalizations from fcu, disconnect any peers sending new blocks, or connecting with td > ttd * tests for preventing pow peers from joining * refactored to separate out merge logic Signed-off-by: Justin Florentine --- .../controller/BesuControllerBuilder.java | 8 +- ...onsensusScheduleBesuControllerBuilder.java | 7 +- .../IbftLegacyBesuControllerBuilder.java | 4 +- .../MergeBesuControllerBuilder.java | 46 +++++++- .../TransitionBesuControllerBuilder.java | 5 +- .../protocol/Istanbul99ProtocolManager.java | 2 + .../merge/FinalizedBlockHashSupplier.java | 3 +- .../besu/consensus/merge/MergeContext.java | 16 +-- .../consensus/merge/PostMergeContext.java | 15 +-- .../consensus/merge/TransitionContext.java | 8 +- .../consensus/merge/PostMergeContextTest.java | 8 +- .../merge/ForkchoiceMessageListener.java | 29 +++++ .../consensus/merge/MergeStateHandler.java | 26 +++++ .../eth/manager/EthProtocolManager.java | 24 ++++- .../ethereum/eth/manager/MergePeerFilter.java | 102 ++++++++++++++++++ .../task/AbstractRetryingPeerTask.java | 2 +- .../eth/manager/task/WaitForPeersTask.java | 4 +- .../eth/manager/EthProtocolManagerTest.java | 83 +++++++++++--- .../manager/EthProtocolManagerTestUtil.java | 36 +++++++ .../ethereum/eth/transactions/TestNode.java | 2 + .../TransactionPoolFactoryTest.java | 1 + 21 files changed, 368 insertions(+), 63 deletions(-) create mode 100644 ethereum/eth/src/main/java/org/hyperledger/besu/consensus/merge/ForkchoiceMessageListener.java create mode 100644 ethereum/eth/src/main/java/org/hyperledger/besu/consensus/merge/MergeStateHandler.java create mode 100644 ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/MergePeerFilter.java diff --git a/besu/src/main/java/org/hyperledger/besu/controller/BesuControllerBuilder.java b/besu/src/main/java/org/hyperledger/besu/controller/BesuControllerBuilder.java index 2ba399ed82..f74c33db83 100644 --- a/besu/src/main/java/org/hyperledger/besu/controller/BesuControllerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/controller/BesuControllerBuilder.java @@ -49,6 +49,7 @@ import org.hyperledger.besu.ethereum.eth.manager.EthMessages; import org.hyperledger.besu.ethereum.eth.manager.EthPeers; import org.hyperledger.besu.ethereum.eth.manager.EthProtocolManager; import org.hyperledger.besu.ethereum.eth.manager.EthScheduler; +import org.hyperledger.besu.ethereum.eth.manager.MergePeerFilter; import org.hyperledger.besu.ethereum.eth.manager.snap.SnapProtocolManager; import org.hyperledger.besu.ethereum.eth.peervalidation.CheckpointBlocksPeerValidator; import org.hyperledger.besu.ethereum.eth.peervalidation.ClassicForkPeerValidator; @@ -401,7 +402,8 @@ public abstract class BesuControllerBuilder implements MiningParameterOverrides ethContext, ethMessages, scheduler, - peerValidators); + peerValidators, + Optional.empty()); final Optional maybeSnapProtocolManager = createSnapProtocolManager(peerValidators, ethPeers, snapMessages, worldStateArchive); @@ -559,7 +561,8 @@ public abstract class BesuControllerBuilder implements MiningParameterOverrides final EthContext ethContext, final EthMessages ethMessages, final EthScheduler scheduler, - final List peerValidators) { + final List peerValidators, + final Optional mergePeerFilter) { return new EthProtocolManager( protocolContext.getBlockchain(), networkId, @@ -570,6 +573,7 @@ public abstract class BesuControllerBuilder implements MiningParameterOverrides ethMessages, ethContext, peerValidators, + mergePeerFilter, fastSyncEnabled, scheduler, genesisConfig.getForks()); diff --git a/besu/src/main/java/org/hyperledger/besu/controller/ConsensusScheduleBesuControllerBuilder.java b/besu/src/main/java/org/hyperledger/besu/controller/ConsensusScheduleBesuControllerBuilder.java index 45f2119513..ecf42731f3 100644 --- a/besu/src/main/java/org/hyperledger/besu/controller/ConsensusScheduleBesuControllerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/controller/ConsensusScheduleBesuControllerBuilder.java @@ -46,6 +46,7 @@ import org.hyperledger.besu.ethereum.eth.manager.EthMessages; import org.hyperledger.besu.ethereum.eth.manager.EthPeers; import org.hyperledger.besu.ethereum.eth.manager.EthProtocolManager; import org.hyperledger.besu.ethereum.eth.manager.EthScheduler; +import org.hyperledger.besu.ethereum.eth.manager.MergePeerFilter; import org.hyperledger.besu.ethereum.eth.manager.snap.SnapProtocolManager; import org.hyperledger.besu.ethereum.eth.peervalidation.PeerValidator; import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration; @@ -232,7 +233,8 @@ public class ConsensusScheduleBesuControllerBuilder extends BesuControllerBuilde final EthContext ethContext, final EthMessages ethMessages, final EthScheduler scheduler, - final List peerValidators) { + final List peerValidators, + final Optional mergePeerFilter) { return besuControllerBuilderSchedule .get(0L) .createEthProtocolManager( @@ -244,7 +246,8 @@ public class ConsensusScheduleBesuControllerBuilder extends BesuControllerBuilde ethContext, ethMessages, scheduler, - peerValidators); + peerValidators, + mergePeerFilter); } @Override diff --git a/besu/src/main/java/org/hyperledger/besu/controller/IbftLegacyBesuControllerBuilder.java b/besu/src/main/java/org/hyperledger/besu/controller/IbftLegacyBesuControllerBuilder.java index e595411007..fe3e405f51 100644 --- a/besu/src/main/java/org/hyperledger/besu/controller/IbftLegacyBesuControllerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/controller/IbftLegacyBesuControllerBuilder.java @@ -36,6 +36,7 @@ import org.hyperledger.besu.ethereum.eth.manager.EthMessages; import org.hyperledger.besu.ethereum.eth.manager.EthPeers; import org.hyperledger.besu.ethereum.eth.manager.EthProtocolManager; import org.hyperledger.besu.ethereum.eth.manager.EthScheduler; +import org.hyperledger.besu.ethereum.eth.manager.MergePeerFilter; import org.hyperledger.besu.ethereum.eth.manager.snap.SnapProtocolManager; import org.hyperledger.besu.ethereum.eth.peervalidation.PeerValidator; import org.hyperledger.besu.ethereum.eth.sync.state.SyncState; @@ -125,7 +126,8 @@ public class IbftLegacyBesuControllerBuilder extends BesuControllerBuilder { final EthContext ethContext, final EthMessages ethMessages, final EthScheduler scheduler, - final List peerValidators) { + final List peerValidators, + final Optional mergePeerFilter) { LOG.info("Operating on IBFT-1.0 network."); return new Istanbul99ProtocolManager( protocolContext.getBlockchain(), 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 6519e2f31a..1876de302e 100644 --- a/besu/src/main/java/org/hyperledger/besu/controller/MergeBesuControllerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/controller/MergeBesuControllerBuilder.java @@ -25,7 +25,13 @@ import org.hyperledger.besu.ethereum.chain.Blockchain; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.Difficulty; import org.hyperledger.besu.ethereum.core.MiningParameters; +import org.hyperledger.besu.ethereum.eth.EthProtocolConfiguration; +import org.hyperledger.besu.ethereum.eth.manager.EthContext; +import org.hyperledger.besu.ethereum.eth.manager.EthMessages; +import org.hyperledger.besu.ethereum.eth.manager.EthPeers; import org.hyperledger.besu.ethereum.eth.manager.EthProtocolManager; +import org.hyperledger.besu.ethereum.eth.manager.EthScheduler; +import org.hyperledger.besu.ethereum.eth.manager.MergePeerFilter; import org.hyperledger.besu.ethereum.eth.peervalidation.PeerValidator; import org.hyperledger.besu.ethereum.eth.peervalidation.RequiredBlocksPeerValidator; import org.hyperledger.besu.ethereum.eth.sync.backwardsync.BackwardChain; @@ -62,7 +68,6 @@ public class MergeBesuControllerBuilder extends BesuControllerBuilder { transactionPool, miningParameters, syncState, - ethProtocolManager, new BackwardSyncContext( protocolContext, protocolSchedule, @@ -73,13 +78,50 @@ public class MergeBesuControllerBuilder extends BesuControllerBuilder { storageProvider, ScheduleBasedBlockHeaderFunctions.create(protocolSchedule)))); } + @Override + protected EthProtocolManager createEthProtocolManager( + final ProtocolContext protocolContext, + final boolean fastSyncEnabled, + final TransactionPool transactionPool, + final EthProtocolConfiguration ethereumWireProtocolConfiguration, + final EthPeers ethPeers, + final EthContext ethContext, + final EthMessages ethMessages, + final EthScheduler scheduler, + final List peerValidators, + final Optional mergePeerFilter) { + + if (mergePeerFilter.isPresent()) { + protocolContext + .getConsensusContext(MergeContext.class) + .observeNewIsPostMergeState(mergePeerFilter.get()); + protocolContext + .getConsensusContext(MergeContext.class) + .addNewForkchoiceMessageListener(mergePeerFilter.get()); + } + + EthProtocolManager ethProtocolManager = + super.createEthProtocolManager( + protocolContext, + fastSyncEnabled, + transactionPool, + ethereumWireProtocolConfiguration, + ethPeers, + ethContext, + ethMessages, + scheduler, + peerValidators, + mergePeerFilter); + + return ethProtocolManager; + } + protected MiningCoordinator createTransitionMiningCoordinator( final ProtocolSchedule protocolSchedule, final ProtocolContext protocolContext, final TransactionPool transactionPool, final MiningParameters miningParameters, final SyncState syncState, - final EthProtocolManager ethProtocolManager, final BackwardSyncContext backwardSyncContext) { this.syncState.set(syncState); 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 3e257cbc30..a859ee65e8 100644 --- a/besu/src/main/java/org/hyperledger/besu/controller/TransitionBesuControllerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/controller/TransitionBesuControllerBuilder.java @@ -114,7 +114,6 @@ public class TransitionBesuControllerBuilder extends BesuControllerBuilder { transactionPool, transitionMiningParameters, syncState, - ethProtocolManager, transitionBackwardsSyncContext)); initTransitionWatcher(protocolContext, composedCoordinator); return composedCoordinator; @@ -150,8 +149,8 @@ public class TransitionBesuControllerBuilder extends BesuControllerBuilder { PostMergeContext postMergeContext = protocolContext.getConsensusContext(PostMergeContext.class); postMergeContext.observeNewIsPostMergeState( - newIsPostMergeState -> { - if (newIsPostMergeState) { + (isPoS, difficultyStoppedAt) -> { + if (isPoS) { // if we transitioned to post-merge, stop and disable any mining composedCoordinator.getPreMergeObject().disable(); composedCoordinator.getPreMergeObject().stop(); diff --git a/consensus/ibftlegacy/src/main/java/org/hyperledger/besu/consensus/ibftlegacy/protocol/Istanbul99ProtocolManager.java b/consensus/ibftlegacy/src/main/java/org/hyperledger/besu/consensus/ibftlegacy/protocol/Istanbul99ProtocolManager.java index bf0a7a1799..d52cbef4b3 100644 --- a/consensus/ibftlegacy/src/main/java/org/hyperledger/besu/consensus/ibftlegacy/protocol/Istanbul99ProtocolManager.java +++ b/consensus/ibftlegacy/src/main/java/org/hyperledger/besu/consensus/ibftlegacy/protocol/Istanbul99ProtocolManager.java @@ -30,6 +30,7 @@ import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; import java.math.BigInteger; import java.util.List; +import java.util.Optional; /** This allows for interoperability with Quorum, but shouldn't be used otherwise. */ public class Istanbul99ProtocolManager extends EthProtocolManager { @@ -56,6 +57,7 @@ public class Istanbul99ProtocolManager extends EthProtocolManager { ethMessages, ethContext, peerValidators, + Optional.empty(), fastSyncEnabled, scheduler); } diff --git a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/FinalizedBlockHashSupplier.java b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/FinalizedBlockHashSupplier.java index 46d9172cab..7fe3317cc6 100644 --- a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/FinalizedBlockHashSupplier.java +++ b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/FinalizedBlockHashSupplier.java @@ -14,7 +14,6 @@ */ package org.hyperledger.besu.consensus.merge; -import org.hyperledger.besu.consensus.merge.MergeContext.NewForkchoiceMessageListener; import org.hyperledger.besu.datatypes.Hash; import java.util.Optional; @@ -24,7 +23,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class FinalizedBlockHashSupplier - implements Supplier>, NewForkchoiceMessageListener { + implements Supplier>, ForkchoiceMessageListener { private static final Logger LOG = LoggerFactory.getLogger(FinalizedBlockHashSupplier.class); private volatile Optional lastAnnouncedFinalizedBlockHash = Optional.empty(); diff --git a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/MergeContext.java b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/MergeContext.java index ba6af5b0dd..069c84ae4b 100644 --- a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/MergeContext.java +++ b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/MergeContext.java @@ -36,10 +36,9 @@ public interface MergeContext extends ConsensusContext { boolean isSyncing(); - void observeNewIsPostMergeState(final NewMergeStateCallback newMergeStateCallback); + void observeNewIsPostMergeState(final MergeStateHandler mergeStateHandler); - long addNewForkchoiceMessageListener( - final NewForkchoiceMessageListener newForkchoiceMessageListener); + long addNewForkchoiceMessageListener(final ForkchoiceMessageListener forkchoiceMessageListener); void removeNewForkchoiceMessageListener(final long subscriberId); @@ -67,15 +66,4 @@ public interface MergeContext extends ConsensusContext { final Hash headBlockHash, final Optional maybeFinalizedBlockHash, final Hash safeBlockHash); - - interface NewMergeStateCallback { - void onNewIsPostMergeState(final boolean newIsPostMergeState); - } - - interface NewForkchoiceMessageListener { - void onNewForkchoiceMessage( - final Hash headBlockHash, - final Optional maybeFinalizedBlockHash, - final Hash safeBlockHash); - } } 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 3babd1bf85..ab9b1cde60 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 @@ -41,9 +41,9 @@ public class PostMergeContext implements MergeContext { // initial postMerge state is indeterminate until it is set: private final AtomicReference> isPostMerge = new AtomicReference<>(Optional.empty()); - private final Subscribers newMergeStateCallbackSubscribers = + private final Subscribers newMergeStateCallbackSubscribers = Subscribers.create(); - private final Subscribers newForkchoiceMessageCallbackSubscribers = + private final Subscribers newForkchoiceMessageCallbackSubscribers = Subscribers.create(); private final EvictingQueue blocksInProgress = @@ -99,7 +99,8 @@ public class PostMergeContext implements MergeContext { if (oldState.isEmpty() || oldState.get() != newState) { newMergeStateCallbackSubscribers.forEach( - newMergeStateCallback -> newMergeStateCallback.onNewIsPostMergeState(newState)); + newMergeStateCallback -> + newMergeStateCallback.mergeStateChanged(newState, Optional.of(totalDifficulty))); } } @@ -123,14 +124,14 @@ public class PostMergeContext implements MergeContext { } @Override - public void observeNewIsPostMergeState(final NewMergeStateCallback newMergeStateCallback) { - newMergeStateCallbackSubscribers.subscribe(newMergeStateCallback); + public void observeNewIsPostMergeState(final MergeStateHandler mergeStateHandler) { + newMergeStateCallbackSubscribers.subscribe(mergeStateHandler); } @Override public long addNewForkchoiceMessageListener( - final NewForkchoiceMessageListener newForkchoiceMessageListener) { - return newForkchoiceMessageCallbackSubscribers.subscribe(newForkchoiceMessageListener); + final ForkchoiceMessageListener forkchoiceMessageListener) { + return newForkchoiceMessageCallbackSubscribers.subscribe(forkchoiceMessageListener); } @Override diff --git a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/TransitionContext.java b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/TransitionContext.java index 79cb554902..9a53186c11 100644 --- a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/TransitionContext.java +++ b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/TransitionContext.java @@ -68,14 +68,14 @@ public class TransitionContext implements MergeContext { } @Override - public void observeNewIsPostMergeState(final NewMergeStateCallback newMergeStateCallback) { - postMergeContext.observeNewIsPostMergeState(newMergeStateCallback); + public void observeNewIsPostMergeState(final MergeStateHandler mergeStateHandler) { + postMergeContext.observeNewIsPostMergeState(mergeStateHandler); } @Override public long addNewForkchoiceMessageListener( - final NewForkchoiceMessageListener newForkchoiceMessageListener) { - return postMergeContext.addNewForkchoiceMessageListener(newForkchoiceMessageListener); + final ForkchoiceMessageListener forkchoiceMessageListener) { + return postMergeContext.addNewForkchoiceMessageListener(forkchoiceMessageListener); } @Override diff --git a/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/PostMergeContextTest.java b/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/PostMergeContextTest.java index 4c548efc72..6505d6f2e6 100644 --- a/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/PostMergeContextTest.java +++ b/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/PostMergeContextTest.java @@ -22,7 +22,6 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoInteractions; import static org.mockito.Mockito.when; -import org.hyperledger.besu.consensus.merge.MergeContext.NewMergeStateCallback; import org.hyperledger.besu.consensus.merge.blockcreation.PayloadIdentifier; import org.hyperledger.besu.ethereum.core.Block; import org.hyperledger.besu.ethereum.core.BlockHeader; @@ -169,12 +168,13 @@ public class PostMergeContextTest { assertThat(postMergeContext.retrieveBlockById(evictedPayloadId)).isEmpty(); } - private static class MergeStateChangeCollector implements NewMergeStateCallback { + private static class MergeStateChangeCollector implements MergeStateHandler { final List stateChanges = new ArrayList<>(); @Override - public void onNewIsPostMergeState(final boolean newIsPostMergeState) { - stateChanges.add(newIsPostMergeState); + public void mergeStateChanged( + final boolean isPoS, final Optional difficultyStoppedAt) { + stateChanges.add(isPoS); } public void reset() { diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/consensus/merge/ForkchoiceMessageListener.java b/ethereum/eth/src/main/java/org/hyperledger/besu/consensus/merge/ForkchoiceMessageListener.java new file mode 100644 index 0000000000..0ebced15eb --- /dev/null +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/consensus/merge/ForkchoiceMessageListener.java @@ -0,0 +1,29 @@ +/* + * Copyright Hyperledger Besu Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +package org.hyperledger.besu.consensus.merge; + +import org.hyperledger.besu.datatypes.Hash; + +import java.util.Optional; + +public interface ForkchoiceMessageListener { + + void onNewForkchoiceMessage( + final Hash headBlockHash, + final Optional maybeFinalizedBlockHash, + final Hash safeBlockHash); +} diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/consensus/merge/MergeStateHandler.java b/ethereum/eth/src/main/java/org/hyperledger/besu/consensus/merge/MergeStateHandler.java new file mode 100644 index 0000000000..4dd8210ead --- /dev/null +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/consensus/merge/MergeStateHandler.java @@ -0,0 +1,26 @@ +/* + * Copyright Hyperledger Besu Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +package org.hyperledger.besu.consensus.merge; + +import org.hyperledger.besu.ethereum.core.Difficulty; + +import java.util.Optional; + +public interface MergeStateHandler { + + void mergeStateChanged(final boolean isPoS, final Optional difficultyStoppedAt); +} diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManager.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManager.java index d27037b663..c6a3d54f47 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManager.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManager.java @@ -73,6 +73,7 @@ public class EthProtocolManager implements ProtocolManager, MinedBlockObserver { private final List peerValidators; // The max size of messages (in bytes) private final int maxMessageSize; + private final Optional mergePeerFilter; public EthProtocolManager( final Blockchain blockchain, @@ -84,6 +85,7 @@ public class EthProtocolManager implements ProtocolManager, MinedBlockObserver { final EthMessages ethMessages, final EthContext ethContext, final List peerValidators, + final Optional mergePeerFilter, final boolean fastSyncEnabled, final EthScheduler scheduler, final ForkIdManager forkIdManager) { @@ -92,9 +94,9 @@ public class EthProtocolManager implements ProtocolManager, MinedBlockObserver { this.scheduler = scheduler; this.blockchain = blockchain; this.maxMessageSize = ethereumWireProtocolConfiguration.getMaxMessageSize(); - + this.mergePeerFilter = mergePeerFilter; this.shutdown = new CountDownLatch(1); - genesisHash = blockchain.getBlockHashByNumber(0L).get(); + this.genesisHash = blockchain.getBlockHashByNumber(0L).orElse(Hash.ZERO); this.forkIdManager = forkIdManager; @@ -131,6 +133,7 @@ public class EthProtocolManager implements ProtocolManager, MinedBlockObserver { final EthMessages ethMessages, final EthContext ethContext, final List peerValidators, + final Optional mergePeerFilter, final boolean fastSyncEnabled, final EthScheduler scheduler) { this( @@ -143,6 +146,7 @@ public class EthProtocolManager implements ProtocolManager, MinedBlockObserver { ethMessages, ethContext, peerValidators, + mergePeerFilter, fastSyncEnabled, scheduler, new ForkIdManager( @@ -161,6 +165,7 @@ public class EthProtocolManager implements ProtocolManager, MinedBlockObserver { final EthMessages ethMessages, final EthContext ethContext, final List peerValidators, + final Optional mergePeerFilter, final boolean fastSyncEnabled, final EthScheduler scheduler, final List forks) { @@ -174,6 +179,7 @@ public class EthProtocolManager implements ProtocolManager, MinedBlockObserver { ethMessages, ethContext, peerValidators, + mergePeerFilter, fastSyncEnabled, scheduler, new ForkIdManager( @@ -240,7 +246,7 @@ public class EthProtocolManager implements ProtocolManager, MinedBlockObserver { final EthPeer ethPeer = ethPeers.peer(message.getConnection()); if (ethPeer == null) { LOG.debug( - "Ignoring message received from unknown peer connection: " + message.getConnection()); + "Ignoring message received from unknown peer connection: {}", message.getConnection()); return; } @@ -271,6 +277,13 @@ public class EthProtocolManager implements ProtocolManager, MinedBlockObserver { return; } + if (this.mergePeerFilter.isPresent()) { + if (this.mergePeerFilter.get().disconnectIfGossipingBlocks(message, ethPeer)) { + handleDisconnect(ethPeer.getConnection(), DisconnectReason.SUBPROTOCOL_TRIGGERED, false); + return; + } + } + final EthMessage ethMessage = new EthMessage(ethPeer, messageData); if (!ethPeer.validateReceivedMessage(ethMessage, getSupportedProtocol())) { @@ -377,6 +390,11 @@ public class EthProtocolManager implements ProtocolManager, MinedBlockObserver { networkId, status.genesisHash()); peer.disconnect(DisconnectReason.SUBPROTOCOL_TRIGGERED); + } else if (mergePeerFilter.isPresent()) { + boolean disconnected = mergePeerFilter.get().disconnectIfPoW(status, peer); + if (disconnected) { + handleDisconnect(peer.getConnection(), DisconnectReason.SUBPROTOCOL_TRIGGERED, false); + } } else { LOG.debug("Received status message from {}: {}", peer, status); peer.registerStatusReceived( diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/MergePeerFilter.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/MergePeerFilter.java new file mode 100644 index 0000000000..884bf78253 --- /dev/null +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/MergePeerFilter.java @@ -0,0 +1,102 @@ +/* + * Copyright Hyperledger Besu Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +package org.hyperledger.besu.ethereum.eth.manager; + +import org.hyperledger.besu.consensus.merge.ForkchoiceMessageListener; +import org.hyperledger.besu.consensus.merge.MergeStateHandler; +import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.ethereum.core.Difficulty; +import org.hyperledger.besu.ethereum.eth.messages.EthPV62; +import org.hyperledger.besu.ethereum.eth.messages.StatusMessage; +import org.hyperledger.besu.ethereum.p2p.rlpx.wire.Message; +import org.hyperledger.besu.ethereum.p2p.rlpx.wire.messages.DisconnectMessage.DisconnectReason; + +import java.util.Optional; +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.locks.StampedLock; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class MergePeerFilter implements MergeStateHandler, ForkchoiceMessageListener { + + private Optional powTerminalDifficulty = Optional.of(Difficulty.MAX_VALUE); + private final StampedLock powTerminalDifficultyLock = new StampedLock(); + private Hash lastFinalized = Hash.ZERO; + private final AtomicLong numFinalizedSeen = new AtomicLong(0); + private static final Logger LOG = LoggerFactory.getLogger(MergePeerFilter.class); + + public boolean disconnectIfPoW(final StatusMessage status, final EthPeer peer) { + long lockStamp = this.powTerminalDifficultyLock.readLock(); + try { + if (this.powTerminalDifficulty.isPresent() + && status.totalDifficulty().greaterThan(this.powTerminalDifficulty.get())) { + LOG.debug( + "Disconnecting peer with difficulty {}, likely still on PoW chain", + status.totalDifficulty()); + peer.disconnect(DisconnectReason.SUBPROTOCOL_TRIGGERED); + return true; + } else { + return false; + } + } finally { + this.powTerminalDifficultyLock.unlockRead(lockStamp); + } + } + + public boolean disconnectIfGossipingBlocks(final Message message, final EthPeer peer) { + final int code = message.getData().getCode(); + if (isFinalized() && (code == EthPV62.NEW_BLOCK || code == EthPV62.NEW_BLOCK_HASHES)) { + LOG.debug("disconnecting peer for sending new blocks after transition to PoS"); + peer.disconnect(DisconnectReason.SUBPROTOCOL_TRIGGERED); + return true; + } else { + return false; + } + } + + private boolean isFinalized() { + return this.numFinalizedSeen.get() > 1; + } + + @Override + public void onNewForkchoiceMessage( + final Hash headBlockHash, + final Optional maybeFinalizedBlockHash, + final Hash safeBlockHash) { + if (maybeFinalizedBlockHash.isPresent() + && !maybeFinalizedBlockHash.get().equals(this.lastFinalized)) { + this.lastFinalized = maybeFinalizedBlockHash.get(); + this.numFinalizedSeen.getAndIncrement(); + LOG.debug("have seen {} finalized blocks", this.numFinalizedSeen); + } + } + + @Override + public void mergeStateChanged( + final boolean isPoS, final Optional difficultyStoppedAt) { + if (isPoS && difficultyStoppedAt.isPresent()) { + LOG.debug("terminal difficulty set to {}", difficultyStoppedAt.get().getValue()); + long lockStamp = this.powTerminalDifficultyLock.writeLock(); + try { + this.powTerminalDifficulty = difficultyStoppedAt; + } finally { + this.powTerminalDifficultyLock.unlockWrite(lockStamp); + } + } + } +} diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/task/AbstractRetryingPeerTask.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/task/AbstractRetryingPeerTask.java index 0e2d923ec1..5822ee367d 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/task/AbstractRetryingPeerTask.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/task/AbstractRetryingPeerTask.java @@ -113,7 +113,7 @@ public abstract class AbstractRetryingPeerTask extends AbstractEthTask { } if (cause instanceof NoAvailablePeersException) { - LOG.info( + LOG.debug( "No useful peer found, checking remaining current peers for usefulness: {}", ethContext.getEthPeers().peerCount()); // Wait for new peer to connect diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/task/WaitForPeersTask.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/task/WaitForPeersTask.java index 8bd6cd7164..6cfd3d719d 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/task/WaitForPeersTask.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/task/WaitForPeersTask.java @@ -60,11 +60,11 @@ public class WaitForPeersTask extends AbstractEthTask { (peer) -> { final int peerCount = ethPeers.peerCount(); if (peerCount >= targetPeerCount) { - LOG.info("Complete: {} peers connected.", targetPeerCount); + LOG.debug("Complete: {} peers connected.", targetPeerCount); // We hit our target result.complete(null); } else { - LOG.info( + LOG.debug( "Waiting for {} total peers to connect. {} peers currently connected.", targetPeerCount, peerCount); diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManagerTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManagerTest.java index 2fefaff37b..1f4eaaef17 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManagerTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManagerTest.java @@ -65,6 +65,7 @@ import org.hyperledger.besu.ethereum.p2p.rlpx.wire.Capability; import org.hyperledger.besu.ethereum.p2p.rlpx.wire.DefaultMessage; import org.hyperledger.besu.ethereum.p2p.rlpx.wire.MessageData; import org.hyperledger.besu.ethereum.p2p.rlpx.wire.RawMessage; +import org.hyperledger.besu.ethereum.p2p.rlpx.wire.messages.DisconnectMessage.DisconnectReason; import org.hyperledger.besu.ethereum.worldstate.DataStorageFormat; import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; @@ -77,6 +78,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.List; +import java.util.Optional; import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; @@ -219,6 +221,55 @@ public final class EthProtocolManagerTest { } } + @Test + public void disconnectNewPoWPeers() { + MergePeerFilter mergePeerFilter = new MergePeerFilter(); + try (final EthProtocolManager ethManager = + EthProtocolManagerTestUtil.create( + blockchain, + protocolContext.getWorldStateArchive(), + transactionPool, + EthProtocolConfiguration.defaultConfig(), + Optional.of(mergePeerFilter))) { + + final MockPeerConnection workPeer = setupPeer(ethManager, (cap, msg, conn) -> {}); + final MockPeerConnection stakePeer = setupPeer(ethManager, (cap, msg, conn) -> {}); + + final StatusMessage workPeerStatus = + StatusMessage.create( + EthProtocol.EthVersion.V63, + BigInteger.ONE, + blockchain.getChainHead().getTotalDifficulty().add(20), + blockchain.getChainHeadHash(), + blockchain.getBlockHeader(BlockHeader.GENESIS_BLOCK_NUMBER).get().getHash()); + + final StatusMessage stakePeerStatus = + StatusMessage.create( + EthProtocol.EthVersion.V63, + BigInteger.ONE, + blockchain.getChainHead().getTotalDifficulty(), + blockchain.getChainHeadHash(), + blockchain.getBlockHeader(BlockHeader.GENESIS_BLOCK_NUMBER).get().getHash()); + + ethManager.processMessage(EthProtocol.ETH63, new DefaultMessage(stakePeer, stakePeerStatus)); + + mergePeerFilter.mergeStateChanged( + true, Optional.of(blockchain.getChainHead().getTotalDifficulty())); + mergePeerFilter.onNewForkchoiceMessage( + Hash.EMPTY, Optional.of(Hash.hash(Bytes.of(1))), Hash.EMPTY); + mergePeerFilter.onNewForkchoiceMessage( + Hash.EMPTY, Optional.of(Hash.hash(Bytes.of(2))), Hash.EMPTY); + + ethManager.processMessage(EthProtocol.ETH63, new DefaultMessage(workPeer, workPeerStatus)); + assertThat(workPeer.isDisconnected()).isTrue(); + assertThat(workPeer.getDisconnectReason()).isPresent(); + assertThat(workPeer.getDisconnectReason()) + .get() + .isEqualTo(DisconnectReason.SUBPROTOCOL_TRIGGERED); + assertThat(stakePeer.isDisconnected()).isFalse(); + } + } + @Test public void doNotDisconnectOnLargeMessageWithinLimits() { try (final EthProtocolManager ethManager = @@ -311,7 +362,7 @@ public final class EthProtocolManagerTest { final BlockHeadersMessage headersMsg = BlockHeadersMessage.readFrom(message); final List headers = Lists.newArrayList(headersMsg.getHeaders(protocolSchedule)); - assertThat(headers.size()).isEqualTo(blockCount); + assertThat(headers).hasSize(blockCount); for (int i = 0; i < blockCount; i++) { assertThat(headers.get(i).getNumber()).isEqualTo(startBlock + i); } @@ -350,7 +401,7 @@ public final class EthProtocolManagerTest { final BlockHeadersMessage headersMsg = BlockHeadersMessage.readFrom(message); final List headers = Lists.newArrayList(headersMsg.getHeaders(protocolSchedule)); - assertThat(headers.size()).isEqualTo(limit); + assertThat(headers).hasSize(limit); for (int i = 0; i < limit; i++) { assertThat(headers.get(i).getNumber()).isEqualTo(startBlock + i); } @@ -386,7 +437,7 @@ public final class EthProtocolManagerTest { final BlockHeadersMessage headersMsg = BlockHeadersMessage.readFrom(message); final List headers = Lists.newArrayList(headersMsg.getHeaders(protocolSchedule)); - assertThat(headers.size()).isEqualTo(blockCount); + assertThat(headers).hasSize(blockCount); for (int i = 0; i < blockCount; i++) { assertThat(headers.get(i).getNumber()).isEqualTo(endBlock - i); } @@ -424,7 +475,7 @@ public final class EthProtocolManagerTest { final BlockHeadersMessage headersMsg = BlockHeadersMessage.readFrom(message); final List headers = Lists.newArrayList(headersMsg.getHeaders(protocolSchedule)); - assertThat(headers.size()).isEqualTo(blockCount); + assertThat(headers).hasSize(blockCount); for (int i = 0; i < blockCount; i++) { assertThat(headers.get(i).getNumber()).isEqualTo(startBlock + i * (skip + 1)); } @@ -463,7 +514,7 @@ public final class EthProtocolManagerTest { final BlockHeadersMessage headersMsg = BlockHeadersMessage.readFrom(message); final List headers = Lists.newArrayList(headersMsg.getHeaders(protocolSchedule)); - assertThat(headers.size()).isEqualTo(blockCount); + assertThat(headers).hasSize(blockCount); for (int i = 0; i < blockCount; i++) { assertThat(headers.get(i).getNumber()).isEqualTo(endBlock - i * (skip + 1)); } @@ -522,7 +573,7 @@ public final class EthProtocolManagerTest { final BlockHeadersMessage headersMsg = BlockHeadersMessage.readFrom(message); final List headers = Lists.newArrayList(headersMsg.getHeaders(protocolSchedule)); - assertThat(headers.size()).isEqualTo(2); + assertThat(headers).hasSize(2); for (int i = 0; i < 2; i++) { assertThat(headers.get(i).getNumber()).isEqualTo(startBlock + i); } @@ -559,7 +610,7 @@ public final class EthProtocolManagerTest { final BlockHeadersMessage headersMsg = BlockHeadersMessage.readFrom(message); final List headers = Lists.newArrayList(headersMsg.getHeaders(protocolSchedule)); - assertThat(headers.size()).isEqualTo(0); + assertThat(headers).isEmpty(); done.complete(null); }; final PeerConnection peer = setupPeer(ethManager, onSend); @@ -603,7 +654,7 @@ public final class EthProtocolManagerTest { final BlockBodiesMessage blocksMessage = BlockBodiesMessage.readFrom(message); final List bodies = Lists.newArrayList(blocksMessage.bodies(protocolSchedule)); - assertThat(bodies.size()).isEqualTo(blockCount); + assertThat(bodies).hasSize(blockCount); for (int i = 0; i < blockCount; i++) { assertThat(expectedBlocks[i].getBody()).isEqualTo(bodies.get(i)); } @@ -654,7 +705,7 @@ public final class EthProtocolManagerTest { final BlockBodiesMessage blocksMessage = BlockBodiesMessage.readFrom(message); final List bodies = Lists.newArrayList(blocksMessage.bodies(protocolSchedule)); - assertThat(bodies.size()).isEqualTo(limit); + assertThat(bodies).hasSize(limit); for (int i = 0; i < limit; i++) { assertThat(expectedBlocks[i].getBody()).isEqualTo(bodies.get(i)); } @@ -698,7 +749,7 @@ public final class EthProtocolManagerTest { final BlockBodiesMessage blocksMessage = BlockBodiesMessage.readFrom(message); final List bodies = Lists.newArrayList(blocksMessage.bodies(protocolSchedule)); - assertThat(bodies.size()).isEqualTo(1); + assertThat(bodies).hasSize(1); assertThat(expectedBlock.getBody()).isEqualTo(bodies.get(0)); done.complete(null); }; @@ -743,7 +794,7 @@ public final class EthProtocolManagerTest { final ReceiptsMessage receiptsMessage = ReceiptsMessage.readFrom(message); final List> receipts = Lists.newArrayList(receiptsMessage.receipts()); - assertThat(receipts.size()).isEqualTo(blockCount); + assertThat(receipts).hasSize(blockCount); for (int i = 0; i < blockCount; i++) { assertThat(expectedReceipts.get(i)).isEqualTo(receipts.get(i)); } @@ -793,7 +844,7 @@ public final class EthProtocolManagerTest { final ReceiptsMessage receiptsMessage = ReceiptsMessage.readFrom(message); final List> receipts = Lists.newArrayList(receiptsMessage.receipts()); - assertThat(receipts.size()).isEqualTo(limit); + assertThat(receipts).hasSize(limit); for (int i = 0; i < limit; i++) { assertThat(expectedReceipts.get(i)).isEqualTo(receipts.get(i)); } @@ -837,7 +888,7 @@ public final class EthProtocolManagerTest { final ReceiptsMessage receiptsMessage = ReceiptsMessage.readFrom(message); final List> receipts = Lists.newArrayList(receiptsMessage.receipts()); - assertThat(receipts.size()).isEqualTo(1); + assertThat(receipts).hasSize(1); assertThat(expectedReceipts).isEqualTo(receipts.get(0)); done.complete(null); }; @@ -885,7 +936,7 @@ public final class EthProtocolManagerTest { assertThat(message.getCode()).isEqualTo(EthPV63.NODE_DATA); final NodeDataMessage receiptsMessage = NodeDataMessage.readFrom(message); final List nodeData = receiptsMessage.nodeData(); - assertThat(nodeData.size()).isEqualTo(blockCount); + assertThat(nodeData).hasSize(blockCount); for (int i = 0; i < blockCount; i++) { assertThat(expectedResults.get(i)).isEqualTo(nodeData.get(i)); } @@ -952,7 +1003,7 @@ public final class EthProtocolManagerTest { assertThat(msg.totalDifficulty(protocolSchdeule)).isEqualTo(expectedTotalDifficulty); } - assertThat(receivingPeerCaptor.getAllValues().containsAll(peers)).isTrue(); + assertThat(receivingPeerCaptor.getAllValues()).containsAll(peers); } } @@ -994,7 +1045,7 @@ public final class EthProtocolManagerTest { final BlockHeadersMessage headersMsg = BlockHeadersMessage.readFrom(message); final List headers = Lists.newArrayList(headersMsg.getHeaders(protocolSchedule)); - assertThat(headers.size()).isEqualTo(receivedBlockCount); + assertThat(headers).hasSize(receivedBlockCount); for (int i = 0; i < receivedBlockCount; i++) { assertThat(headers.get(i).getNumber()).isEqualTo(receivedBlockCount - 1 - i); } diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManagerTestUtil.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManagerTestUtil.java index 39e4a711da..6a3c546c01 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManagerTestUtil.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManagerTestUtil.java @@ -40,6 +40,7 @@ import org.hyperledger.besu.testutil.TestClock; import java.math.BigInteger; import java.util.Collections; +import java.util.Optional; import java.util.OptionalLong; public class EthProtocolManagerTestUtil { @@ -58,6 +59,40 @@ public class EthProtocolManagerTestUtil { ethereumWireProtocolConfiguration); } + public static EthProtocolManager create( + final Blockchain blockchain, + final WorldStateArchive worldStateArchive, + final TransactionPool transactionPool, + final EthProtocolConfiguration ethereumWireProtocolConfiguration, + final Optional mergePeerFilter) { + + EthPeers peers = + new EthPeers( + EthProtocol.NAME, + TestClock.fixed(), + new NoOpMetricsSystem(), + 25, + EthProtocolConfiguration.DEFAULT_MAX_MESSAGE_SIZE); + EthMessages messages = new EthMessages(); + EthScheduler ethScheduler = new DeterministicEthScheduler(TimeoutPolicy.NEVER_TIMEOUT); + EthContext ethContext = new EthContext(peers, messages, ethScheduler); + + return new EthProtocolManager( + blockchain, + BigInteger.ONE, + worldStateArchive, + transactionPool, + ethereumWireProtocolConfiguration, + peers, + messages, + ethContext, + Collections.emptyList(), + mergePeerFilter, + false, + ethScheduler, + new ForkIdManager(blockchain, Collections.emptyList(), false)); + } + public static EthProtocolManager create( final Blockchain blockchain, final EthScheduler ethScheduler, @@ -101,6 +136,7 @@ public class EthProtocolManagerTestUtil { ethMessages, ethContext, Collections.emptyList(), + Optional.empty(), false, ethScheduler, forkIdManager); diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TestNode.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TestNode.java index 39d4837fbb..b7726d4c18 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TestNode.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TestNode.java @@ -67,6 +67,7 @@ import java.math.BigInteger; import java.util.Collections; import java.util.HashMap; import java.util.Map; +import java.util.Optional; import java.util.concurrent.CompletableFuture; import io.vertx.core.Vertx; @@ -157,6 +158,7 @@ public class TestNode implements Closeable { ethMessages, ethContext, Collections.emptyList(), + Optional.empty(), false, scheduler); diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPoolFactoryTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPoolFactoryTest.java index ceb2202a54..b47080abcc 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPoolFactoryTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPoolFactoryTest.java @@ -115,6 +115,7 @@ public class TransactionPoolFactoryTest { mock(EthMessages.class), ethContext, Collections.emptyList(), + Optional.empty(), true, mock(EthScheduler.class), mock(ForkIdManager.class));