diff --git a/consensus/ibft/src/integration-test/java/tech/pegasys/pantheon/consensus/ibft/support/RoundSpecificPeers.java b/consensus/ibft/src/integration-test/java/tech/pegasys/pantheon/consensus/ibft/support/RoundSpecificPeers.java index 671160d98d..6cf725cec0 100644 --- a/consensus/ibft/src/integration-test/java/tech/pegasys/pantheon/consensus/ibft/support/RoundSpecificPeers.java +++ b/consensus/ibft/src/integration-test/java/tech/pegasys/pantheon/consensus/ibft/support/RoundSpecificPeers.java @@ -37,6 +37,7 @@ import java.util.Collection; import java.util.List; import java.util.Optional; +import java.util.function.Consumer; import java.util.stream.Collectors; import com.google.common.collect.ImmutableList; @@ -124,6 +125,10 @@ public void commitForNonProposing(final ConsensusRoundIdentifier roundId, final nonProposingPeers.forEach(peer -> peer.injectCommit(roundId, hash)); } + public void forNonProposing(final Consumer assertion) { + nonProposingPeers.forEach(assertion); + } + public Collection> createSignedPreparePayloadOfNonProposing( final ConsensusRoundIdentifier preparedRound, final Hash hash) { return nonProposingPeers.stream() diff --git a/consensus/ibft/src/integration-test/java/tech/pegasys/pantheon/consensus/ibft/support/StubbedSynchronizerUpdater.java b/consensus/ibft/src/integration-test/java/tech/pegasys/pantheon/consensus/ibft/support/StubbedSynchronizerUpdater.java new file mode 100644 index 0000000000..a88e0c66f4 --- /dev/null +++ b/consensus/ibft/src/integration-test/java/tech/pegasys/pantheon/consensus/ibft/support/StubbedSynchronizerUpdater.java @@ -0,0 +1,39 @@ +/* + * Copyright 2019 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. + */ +package tech.pegasys.pantheon.consensus.ibft.support; + +import static java.util.function.Function.identity; + +import tech.pegasys.pantheon.consensus.ibft.SynchronizerUpdater; +import tech.pegasys.pantheon.ethereum.p2p.api.PeerConnection; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.stream.Collectors; + +public class StubbedSynchronizerUpdater implements SynchronizerUpdater { + + private Map validatorNodes = new HashMap<>(); + + @Override + public void updatePeerChainState( + final long knownBlockNumber, final PeerConnection peerConnection) { + validatorNodes.get(peerConnection).updateEstimatedChainHeight(knownBlockNumber); + } + + public void addNetworkPeers(final Collection nodes) { + validatorNodes.putAll( + nodes.stream().collect(Collectors.toMap(ValidatorPeer::getPeerConnection, identity()))); + } +} diff --git a/consensus/ibft/src/integration-test/java/tech/pegasys/pantheon/consensus/ibft/support/TestContextBuilder.java b/consensus/ibft/src/integration-test/java/tech/pegasys/pantheon/consensus/ibft/support/TestContextBuilder.java index 3e46fe78dc..dfae9f6187 100644 --- a/consensus/ibft/src/integration-test/java/tech/pegasys/pantheon/consensus/ibft/support/TestContextBuilder.java +++ b/consensus/ibft/src/integration-test/java/tech/pegasys/pantheon/consensus/ibft/support/TestContextBuilder.java @@ -35,6 +35,7 @@ import tech.pegasys.pantheon.consensus.ibft.IbftHelpers; import tech.pegasys.pantheon.consensus.ibft.IbftProtocolSchedule; import tech.pegasys.pantheon.consensus.ibft.RoundTimer; +import tech.pegasys.pantheon.consensus.ibft.SynchronizerUpdater; import tech.pegasys.pantheon.consensus.ibft.UniqueMessageMulticaster; import tech.pegasys.pantheon.consensus.ibft.blockcreation.IbftBlockCreatorFactory; import tech.pegasys.pantheon.consensus.ibft.blockcreation.ProposerSelector; @@ -164,9 +165,17 @@ public TestContext build() { final Gossiper gossiper = useGossip ? new IbftGossip(uniqueMulticaster) : mock(Gossiper.class); + final StubbedSynchronizerUpdater synchronizerUpdater = new StubbedSynchronizerUpdater(); + final ControllerAndState controllerAndState = createControllerAndFinalState( - blockChain, multicaster, nodeKeys, clock, ibftEventQueue, gossiper); + blockChain, + multicaster, + nodeKeys, + clock, + ibftEventQueue, + gossiper, + synchronizerUpdater); // Add each networkNode to the Multicaster (such that each can receive msgs from local node). // NOTE: the remotePeers needs to be ordered based on Address (as this is used to determine @@ -187,6 +196,7 @@ public TestContext build() { LinkedHashMap::new)); multicaster.addNetworkPeers(remotePeers.values()); + synchronizerUpdater.addNetworkPeers(remotePeers.values()); return new TestContext( remotePeers, @@ -227,7 +237,8 @@ private static ControllerAndState createControllerAndFinalState( final KeyPair nodeKeys, final Clock clock, final IbftEventQueue ibftEventQueue, - final Gossiper gossiper) { + final Gossiper gossiper, + final SynchronizerUpdater synchronizerUpdater) { final WorldStateArchive worldStateArchive = createInMemoryWorldStateArchive(); @@ -312,7 +323,8 @@ private static ControllerAndState createControllerAndFinalState( messageValidatorFactory), messageValidatorFactory), gossiper, - DUPLICATE_MESSAGE_LIMIT); + DUPLICATE_MESSAGE_LIMIT, + synchronizerUpdater); final EventMultiplexer eventMultiplexer = new EventMultiplexer(ibftController); //////////////////////////// END IBFT PantheonController //////////////////////////// diff --git a/consensus/ibft/src/integration-test/java/tech/pegasys/pantheon/consensus/ibft/support/ValidatorPeer.java b/consensus/ibft/src/integration-test/java/tech/pegasys/pantheon/consensus/ibft/support/ValidatorPeer.java index 03d1e29c8b..b178f20f72 100644 --- a/consensus/ibft/src/integration-test/java/tech/pegasys/pantheon/consensus/ibft/support/ValidatorPeer.java +++ b/consensus/ibft/src/integration-test/java/tech/pegasys/pantheon/consensus/ibft/support/ValidatorPeer.java @@ -12,6 +12,8 @@ */ package tech.pegasys.pantheon.consensus.ibft.support; +import static org.assertj.core.api.Assertions.assertThat; + import tech.pegasys.pantheon.consensus.ibft.ConsensusRoundIdentifier; import tech.pegasys.pantheon.consensus.ibft.EventMultiplexer; import tech.pegasys.pantheon.consensus.ibft.ibftevent.IbftEvents; @@ -53,6 +55,7 @@ public class ValidatorPeer { private final List receivedMessages = Lists.newArrayList(); private final EventMultiplexer localEventMultiplexer; + private long estimatedChainHeight = 0; public ValidatorPeer( final NodeParams nodeParams, @@ -74,6 +77,10 @@ public KeyPair getNodeKeys() { return nodeKeys; } + public PeerConnection getPeerConnection() { + return peerConnection; + } + public Proposal injectProposal(final ConsensusRoundIdentifier rId, final Block block) { final Proposal payload = messageFactory.createProposal(rId, block, Optional.empty()); @@ -147,4 +154,12 @@ public MessageFactory getMessageFactory() { public KeyPair getNodeKeyPair() { return nodeKeys; } + + public void updateEstimatedChainHeight(final long estimatedChainHeight) { + this.estimatedChainHeight = estimatedChainHeight; + } + + public void verifyEstimatedChainHeightEquals(final long expectedChainHeight) { + assertThat(estimatedChainHeight).isEqualTo(expectedChainHeight); + } } diff --git a/consensus/ibft/src/integration-test/java/tech/pegasys/pantheon/consensus/ibft/tests/FutureHeightTest.java b/consensus/ibft/src/integration-test/java/tech/pegasys/pantheon/consensus/ibft/tests/FutureHeightTest.java index 24982190b4..d02d30f823 100644 --- a/consensus/ibft/src/integration-test/java/tech/pegasys/pantheon/consensus/ibft/tests/FutureHeightTest.java +++ b/consensus/ibft/src/integration-test/java/tech/pegasys/pantheon/consensus/ibft/tests/FutureHeightTest.java @@ -74,8 +74,17 @@ public void messagesForFutureHeightAreBufferedUntilChainHeightCatchesUp() { peers.getProposer().injectProposal(futureHeightRoundId, futureHeightBlock); peers.verifyNoMessagesReceived(); + // verify that we have incremented the estimated height of the proposer. + peers + .getProposer() + .verifyEstimatedChainHeightEquals(futureHeightBlock.getHeader().getNumber() - 1); + // Inject prepares and commits from all peers peers.prepareForNonProposing(futureHeightRoundId, futureHeightBlock.getHash()); + peers.forNonProposing( + peer -> + peer.verifyEstimatedChainHeightEquals(futureHeightBlock.getHeader().getNumber() - 1)); + peers.commitForNonProposing(futureHeightRoundId, futureHeightBlock.getHash()); peers.verifyNoMessagesReceived(); diff --git a/consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/EthSynchronizerUpdater.java b/consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/EthSynchronizerUpdater.java new file mode 100644 index 0000000000..022f22f4cf --- /dev/null +++ b/consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/EthSynchronizerUpdater.java @@ -0,0 +1,42 @@ +/* + * Copyright 2019 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. + */ +package tech.pegasys.pantheon.consensus.ibft; + +import static org.apache.logging.log4j.LogManager.getLogger; + +import tech.pegasys.pantheon.ethereum.eth.manager.EthPeer; +import tech.pegasys.pantheon.ethereum.eth.manager.EthPeers; +import tech.pegasys.pantheon.ethereum.p2p.api.PeerConnection; + +import org.apache.logging.log4j.Logger; + +public class EthSynchronizerUpdater implements SynchronizerUpdater { + + private static final Logger LOG = getLogger(); + private final EthPeers ethPeers; + + public EthSynchronizerUpdater(final EthPeers ethPeers) { + this.ethPeers = ethPeers; + } + + @Override + public void updatePeerChainState( + final long knownBlockNumber, final PeerConnection peerConnection) { + final EthPeer ethPeer = ethPeers.peer(peerConnection); + if (ethPeer == null) { + LOG.debug("Received message from a peer with no corresponding EthPeer."); + return; + } + ethPeer.chainState().updateHeightEstimate(knownBlockNumber); + } +} diff --git a/consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/SynchronizerUpdater.java b/consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/SynchronizerUpdater.java new file mode 100644 index 0000000000..aa8ebe39d6 --- /dev/null +++ b/consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/SynchronizerUpdater.java @@ -0,0 +1,20 @@ +/* + * Copyright 2019 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. + */ +package tech.pegasys.pantheon.consensus.ibft; + +import tech.pegasys.pantheon.ethereum.p2p.api.PeerConnection; + +public interface SynchronizerUpdater { + + void updatePeerChainState(long knownBlockNumber, PeerConnection peerConnection); +} diff --git a/consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/statemachine/IbftController.java b/consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/statemachine/IbftController.java index 6433ce38fd..c9a7786227 100644 --- a/consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/statemachine/IbftController.java +++ b/consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/statemachine/IbftController.java @@ -17,6 +17,7 @@ import tech.pegasys.pantheon.consensus.ibft.ConsensusRoundIdentifier; import tech.pegasys.pantheon.consensus.ibft.Gossiper; import tech.pegasys.pantheon.consensus.ibft.MessageTracker; +import tech.pegasys.pantheon.consensus.ibft.SynchronizerUpdater; import tech.pegasys.pantheon.consensus.ibft.ibftevent.BlockTimerExpiry; import tech.pegasys.pantheon.consensus.ibft.ibftevent.IbftReceivedMessageEvent; import tech.pegasys.pantheon.consensus.ibft.ibftevent.NewChainHead; @@ -44,6 +45,7 @@ import org.apache.logging.log4j.Logger; public class IbftController { + private static final Logger LOG = LogManager.getLogger(); private final Blockchain blockchain; private final IbftFinalState ibftFinalState; @@ -52,20 +54,23 @@ public class IbftController { private BlockHeightManager currentHeightManager; private final Gossiper gossiper; private final MessageTracker duplicateMessageTracker; + private final SynchronizerUpdater sychronizerUpdater; public IbftController( final Blockchain blockchain, final IbftFinalState ibftFinalState, final IbftBlockHeightManagerFactory ibftBlockHeightManagerFactory, final Gossiper gossiper, - final int duplicateMessageLimit) { + final int duplicateMessageLimit, + final SynchronizerUpdater sychronizerUpdater) { this( blockchain, ibftFinalState, ibftBlockHeightManagerFactory, gossiper, Maps.newHashMap(), - new MessageTracker(duplicateMessageLimit)); + new MessageTracker(duplicateMessageLimit), + sychronizerUpdater); } @VisibleForTesting @@ -75,13 +80,15 @@ public IbftController( final IbftBlockHeightManagerFactory ibftBlockHeightManagerFactory, final Gossiper gossiper, final Map> futureMessages, - final MessageTracker duplicateMessageTracker) { + final MessageTracker duplicateMessageTracker, + final SynchronizerUpdater sychronizerUpdater) { this.blockchain = blockchain; this.ibftFinalState = ibftFinalState; this.ibftBlockHeightManagerFactory = ibftBlockHeightManagerFactory; this.futureMessages = futureMessages; this.gossiper = gossiper; this.duplicateMessageTracker = duplicateMessageTracker; + this.sychronizerUpdater = sychronizerUpdater; } public void start() { @@ -213,6 +220,10 @@ private boolean processMessage(final IbftMessage msg, final Message rawMsg) { return isMsgFromKnownValidator(msg) && ibftFinalState.isLocalNodeValidator(); } else if (isMsgForFutureChainHeight(msgRoundIdentifier)) { addMessageToFutureMessageBuffer(msgRoundIdentifier.getSequenceNumber(), rawMsg); + // Notify the synchronizer the transmitting peer must have the parent block to the received + // message's target height. + sychronizerUpdater.updatePeerChainState( + msgRoundIdentifier.getSequenceNumber() - 1L, rawMsg.getConnection()); } else { LOG.debug( "IBFT message discarded as it is from a previous block height messageType={} chainHeight={} eventHeight={}", diff --git a/consensus/ibft/src/test/java/tech/pegasys/pantheon/consensus/ibft/EthSynchronizerUpdaterTest.java b/consensus/ibft/src/test/java/tech/pegasys/pantheon/consensus/ibft/EthSynchronizerUpdaterTest.java new file mode 100644 index 0000000000..730a17e4b3 --- /dev/null +++ b/consensus/ibft/src/test/java/tech/pegasys/pantheon/consensus/ibft/EthSynchronizerUpdaterTest.java @@ -0,0 +1,103 @@ +/* + * Copyright 2019 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. + */ +package tech.pegasys.pantheon.consensus.ibft; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyZeroInteractions; +import static org.mockito.Mockito.when; + +import tech.pegasys.pantheon.ethereum.eth.manager.ChainState; +import tech.pegasys.pantheon.ethereum.eth.manager.EthPeer; +import tech.pegasys.pantheon.ethereum.eth.manager.EthPeers; +import tech.pegasys.pantheon.ethereum.p2p.api.MessageData; +import tech.pegasys.pantheon.ethereum.p2p.api.PeerConnection; +import tech.pegasys.pantheon.ethereum.p2p.wire.Capability; +import tech.pegasys.pantheon.ethereum.p2p.wire.PeerInfo; +import tech.pegasys.pantheon.ethereum.p2p.wire.messages.DisconnectMessage.DisconnectReason; + +import java.net.SocketAddress; +import java.util.Set; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +@RunWith(MockitoJUnitRunner.class) +public class EthSynchronizerUpdaterTest { + + @Mock private EthPeers ethPeers; + @Mock private EthPeer ethPeer; + + @Mock private ChainState chainState; + + @Test + public void ethPeerIsMissingResultInNoUpdate() { + when(ethPeers.peer(any())).thenReturn(null); + + final EthSynchronizerUpdater updater = new EthSynchronizerUpdater(ethPeers); + + updater.updatePeerChainState(1, createAnonymousPeerConnection()); + + verifyZeroInteractions(ethPeer); + } + + @Test + public void chainStateUpdateIsAttemptedIfEthPeerExists() { + when(ethPeers.peer(any())).thenReturn(ethPeer); + when(ethPeer.chainState()).thenReturn(chainState); + + final EthSynchronizerUpdater updater = new EthSynchronizerUpdater(ethPeers); + + final long suppliedChainHeight = 6L; + updater.updatePeerChainState(suppliedChainHeight, createAnonymousPeerConnection()); + verify(chainState, times(1)).updateHeightEstimate(eq(suppliedChainHeight)); + } + + private PeerConnection createAnonymousPeerConnection() { + return new PeerConnection() { + @Override + public void send(final Capability capability, final MessageData message) + throws PeerNotConnected {} + + @Override + public Set getAgreedCapabilities() { + return null; + } + + @Override + public PeerInfo getPeer() { + return new PeerInfo(0, null, null, 0, null); + } + + @Override + public void terminateConnection(final DisconnectReason reason, final boolean peerInitiated) {} + + @Override + public void disconnect(final DisconnectReason reason) {} + + @Override + public SocketAddress getLocalAddress() { + return null; + } + + @Override + public SocketAddress getRemoteAddress() { + return null; + } + }; + } +} diff --git a/consensus/ibft/src/test/java/tech/pegasys/pantheon/consensus/ibft/statemachine/IbftControllerTest.java b/consensus/ibft/src/test/java/tech/pegasys/pantheon/consensus/ibft/statemachine/IbftControllerTest.java index 470d95da81..18df8689a9 100644 --- a/consensus/ibft/src/test/java/tech/pegasys/pantheon/consensus/ibft/statemachine/IbftControllerTest.java +++ b/consensus/ibft/src/test/java/tech/pegasys/pantheon/consensus/ibft/statemachine/IbftControllerTest.java @@ -16,6 +16,7 @@ import static org.assertj.core.util.Lists.newArrayList; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.atLeastOnce; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -23,6 +24,7 @@ import static org.mockito.Mockito.when; import tech.pegasys.pantheon.consensus.ibft.ConsensusRoundIdentifier; +import tech.pegasys.pantheon.consensus.ibft.EthSynchronizerUpdater; import tech.pegasys.pantheon.consensus.ibft.IbftGossip; import tech.pegasys.pantheon.consensus.ibft.MessageTracker; import tech.pegasys.pantheon.consensus.ibft.ibftevent.BlockTimerExpiry; @@ -103,7 +105,8 @@ public void setup() { blockHeightManagerFactory, ibftGossip, futureMessages, - messageTracker); + messageTracker, + mock(EthSynchronizerUpdater.class)); when(chainHeadBlockHeader.getNumber()).thenReturn(1L); when(chainHeadBlockHeader.getHash()).thenReturn(Hash.ZERO); diff --git a/ethereum/eth/src/main/java/tech/pegasys/pantheon/ethereum/eth/manager/ChainState.java b/ethereum/eth/src/main/java/tech/pegasys/pantheon/ethereum/eth/manager/ChainState.java index 05168036fd..b25428b525 100644 --- a/ethereum/eth/src/main/java/tech/pegasys/pantheon/ethereum/eth/manager/ChainState.java +++ b/ethereum/eth/src/main/java/tech/pegasys/pantheon/ethereum/eth/manager/ChainState.java @@ -88,11 +88,13 @@ public void updateForAnnouncedBlock( } } - private void updateHeightEstimate(final long blockNumber) { - estimatedHeightKnown = true; - if (blockNumber > estimatedHeight) { - estimatedHeight = blockNumber; - estimatedHeightListeners.forEach(e -> e.onEstimatedHeightChanged(estimatedHeight)); + public void updateHeightEstimate(final long blockNumber) { + synchronized (this) { + estimatedHeightKnown = true; + if (blockNumber > estimatedHeight) { + estimatedHeight = blockNumber; + estimatedHeightListeners.forEach(e -> e.onEstimatedHeightChanged(estimatedHeight)); + } } } diff --git a/ethereum/eth/src/main/java/tech/pegasys/pantheon/ethereum/eth/manager/EthPeers.java b/ethereum/eth/src/main/java/tech/pegasys/pantheon/ethereum/eth/manager/EthPeers.java index 7f44a56e3c..4992004a88 100644 --- a/ethereum/eth/src/main/java/tech/pegasys/pantheon/ethereum/eth/manager/EthPeers.java +++ b/ethereum/eth/src/main/java/tech/pegasys/pantheon/ethereum/eth/manager/EthPeers.java @@ -64,7 +64,7 @@ void registerDisconnect(final PeerConnection connection) { } } - EthPeer peer(final PeerConnection peerConnection) { + public EthPeer peer(final PeerConnection peerConnection) { return connections.get(peerConnection); } diff --git a/pantheon/src/main/java/tech/pegasys/pantheon/controller/IbftPantheonController.java b/pantheon/src/main/java/tech/pegasys/pantheon/controller/IbftPantheonController.java index 1c33574f0c..8dd931a462 100644 --- a/pantheon/src/main/java/tech/pegasys/pantheon/controller/IbftPantheonController.java +++ b/pantheon/src/main/java/tech/pegasys/pantheon/controller/IbftPantheonController.java @@ -22,6 +22,7 @@ import tech.pegasys.pantheon.consensus.common.VoteTallyCache; import tech.pegasys.pantheon.consensus.common.VoteTallyUpdater; import tech.pegasys.pantheon.consensus.ibft.BlockTimer; +import tech.pegasys.pantheon.consensus.ibft.EthSynchronizerUpdater; import tech.pegasys.pantheon.consensus.ibft.EventMultiplexer; import tech.pegasys.pantheon.consensus.ibft.IbftBlockInterface; import tech.pegasys.pantheon.consensus.ibft.IbftContext; @@ -56,6 +57,7 @@ import tech.pegasys.pantheon.ethereum.core.TransactionPool; import tech.pegasys.pantheon.ethereum.core.Util; import tech.pegasys.pantheon.ethereum.eth.EthProtocol; +import tech.pegasys.pantheon.ethereum.eth.manager.EthContext; import tech.pegasys.pantheon.ethereum.eth.manager.EthProtocolManager; import tech.pegasys.pantheon.ethereum.eth.sync.DefaultSynchronizer; import tech.pegasys.pantheon.ethereum.eth.sync.SyncMode; @@ -168,9 +170,10 @@ public static PantheonController init( metricsSystem); final SubProtocol ethSubProtocol = EthProtocol.get(); + final EthContext ethContext = ethProtocolManager.ethContext(); + final SyncState syncState = - new SyncState( - protocolContext.getBlockchain(), ethProtocolManager.ethContext().getEthPeers()); + new SyncState(protocolContext.getBlockchain(), ethContext.getEthPeers()); final Synchronizer synchronizer = new DefaultSynchronizer<>( syncConfig, @@ -183,8 +186,7 @@ public static PantheonController init( metricsSystem); final TransactionPool transactionPool = - TransactionPoolFactory.createTransactionPool( - protocolSchedule, protocolContext, ethProtocolManager.ethContext()); + TransactionPoolFactory.createTransactionPool(protocolSchedule, protocolContext, ethContext); final IbftEventQueue ibftEventQueue = new IbftEventQueue(ibftConfig.getMessageQueueLimit()); @@ -250,7 +252,8 @@ public static PantheonController init( messageValidatorFactory), messageValidatorFactory), gossiper, - ibftConfig.getDuplicateMessageLimit()); + ibftConfig.getDuplicateMessageLimit(), + new EthSynchronizerUpdater(ethContext.getEthPeers())); ibftController.start(); final EventMultiplexer eventMultiplexer = new EventMultiplexer(ibftController);