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 03f0e6535b..7880b44754 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 @@ -25,6 +25,7 @@ import tech.pegasys.pantheon.consensus.common.VoteTallyUpdater; import tech.pegasys.pantheon.consensus.ibft.BlockTimer; import tech.pegasys.pantheon.consensus.ibft.EventMultiplexer; +import tech.pegasys.pantheon.consensus.ibft.Gossiper; import tech.pegasys.pantheon.consensus.ibft.IbftBlockHashing; import tech.pegasys.pantheon.consensus.ibft.IbftBlockInterface; import tech.pegasys.pantheon.consensus.ibft.IbftContext; @@ -34,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.UniqueMessageMulticaster; import tech.pegasys.pantheon.consensus.ibft.blockcreation.IbftBlockCreatorFactory; import tech.pegasys.pantheon.consensus.ibft.blockcreation.ProposerSelector; import tech.pegasys.pantheon.consensus.ibft.payload.MessageFactory; @@ -156,7 +158,9 @@ public TestContext build() { // Use a stubbed version of the multicaster, to prevent creating PeerConnections etc. final StubValidatorMulticaster multicaster = new StubValidatorMulticaster(); - final IbftGossip gossiper = useGossip ? new IbftGossip(multicaster) : mock(IbftGossip.class); + final UniqueMessageMulticaster uniqueMulticaster = new UniqueMessageMulticaster(multicaster); + + final Gossiper gossiper = useGossip ? new IbftGossip(uniqueMulticaster) : mock(Gossiper.class); final ControllerAndState controllerAndState = createControllerAndFinalState( @@ -219,11 +223,11 @@ private static Block createGenesisBlock(final Set
validators) { private static ControllerAndState createControllerAndFinalState( final MutableBlockchain blockChain, - final StubValidatorMulticaster stubbedMulticaster, + final StubValidatorMulticaster multicaster, final KeyPair nodeKeys, final Clock clock, final IbftEventQueue ibftEventQueue, - final IbftGossip gossiper) { + final Gossiper gossiper) { final WorldStateArchive worldStateArchive = createInMemoryWorldStateArchive(); @@ -272,7 +276,7 @@ private static ControllerAndState createControllerAndFinalState( nodeKeys, Util.publicKeyToAddress(nodeKeys.getPublicKey()), proposerSelector, - stubbedMulticaster, + multicaster, new RoundTimer( ibftEventQueue, ROUND_TIMER_SEC * 1000, Executors.newScheduledThreadPool(1)), new BlockTimer( @@ -298,8 +302,8 @@ private static ControllerAndState createControllerAndFinalState( new IbftRoundFactory( finalState, protocolContext, protocolSchedule, minedBlockObservers), messageValidatorFactory), - new HashMap<>(), - gossiper); + gossiper, + new HashMap<>()); final EventMultiplexer eventMultiplexer = new EventMultiplexer(ibftController); //////////////////////////// END IBFT PantheonController //////////////////////////// diff --git a/consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/Gossiper.java b/consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/Gossiper.java new file mode 100644 index 0000000000..cbac83ac65 --- /dev/null +++ b/consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/Gossiper.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.Message; + +public interface Gossiper { + + void send(Message message); +} diff --git a/consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/IbftGossip.java b/consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/IbftGossip.java index bccd9da18b..64cbbcb973 100644 --- a/consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/IbftGossip.java +++ b/consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/IbftGossip.java @@ -20,40 +20,18 @@ import tech.pegasys.pantheon.consensus.ibft.messagedata.RoundChangeMessageData; import tech.pegasys.pantheon.consensus.ibft.network.ValidatorMulticaster; import tech.pegasys.pantheon.consensus.ibft.payload.SignedData; -import tech.pegasys.pantheon.crypto.SECP256K1.Signature; import tech.pegasys.pantheon.ethereum.core.Address; import tech.pegasys.pantheon.ethereum.p2p.api.Message; import tech.pegasys.pantheon.ethereum.p2p.api.MessageData; -import java.util.Collections; -import java.util.LinkedHashMap; import java.util.List; -import java.util.Map; -import java.util.Set; import com.google.common.collect.Lists; /** Class responsible for rebroadcasting IBFT messages to known validators */ -public class IbftGossip { - private final ValidatorMulticaster multicaster; - - // Size of the seenMessages cache, should end up utilising 65bytes * this number + some meta data - private final int maxSeenMessages; - - // Set that starts evicting members when it hits capacity - private final Setvoid consumeMessage( signedPayload.getPayload().getMessageType(), signedPayload); if (processMessage(signedPayload, message)) { - gossiper.gossipMessage(message); + gossiper.send(message); handleMessage.accept(signedPayload); } } diff --git a/consensus/ibft/src/test/java/tech/pegasys/pantheon/consensus/ibft/IbftGossipTest.java b/consensus/ibft/src/test/java/tech/pegasys/pantheon/consensus/ibft/IbftGossipTest.java index e189b9e76c..a188e16726 100644 --- a/consensus/ibft/src/test/java/tech/pegasys/pantheon/consensus/ibft/IbftGossipTest.java +++ b/consensus/ibft/src/test/java/tech/pegasys/pantheon/consensus/ibft/IbftGossipTest.java @@ -13,19 +13,14 @@ package tech.pegasys.pantheon.consensus.ibft; import static com.google.common.collect.Lists.newArrayList; -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; -import tech.pegasys.pantheon.consensus.ibft.messagedata.CommitMessageData; import tech.pegasys.pantheon.consensus.ibft.messagedata.NewRoundMessageData; -import tech.pegasys.pantheon.consensus.ibft.messagedata.PrepareMessageData; import tech.pegasys.pantheon.consensus.ibft.messagedata.ProposalMessageData; import tech.pegasys.pantheon.consensus.ibft.messagedata.RoundChangeMessageData; import tech.pegasys.pantheon.consensus.ibft.network.MockPeerFactory; import tech.pegasys.pantheon.consensus.ibft.network.ValidatorMulticaster; import tech.pegasys.pantheon.consensus.ibft.payload.Payload; -import tech.pegasys.pantheon.consensus.ibft.payload.ProposalPayload; import tech.pegasys.pantheon.consensus.ibft.payload.SignedData; import tech.pegasys.pantheon.crypto.SECP256K1.KeyPair; import tech.pegasys.pantheon.ethereum.core.Address; @@ -52,7 +47,7 @@ public class IbftGossipTest { @Before public void setup() { - ibftGossip = new IbftGossip(validatorMulticaster, 10); + ibftGossip = new IbftGossip(validatorMulticaster); peerConnection = MockPeerFactory.create(senderAddress); } @@ -64,131 +59,26 @@ private
void assertRebroadcastToAllExceptSignerAndSender( final MessageData messageData = createMessageData.apply(payload); final Message message = new DefaultMessage(peerConnection, messageData); - final boolean gossipResult = ibftGossip.gossipMessage(message); - assertThat(gossipResult).isTrue(); + ibftGossip.send(message); verify(validatorMulticaster) .send(messageData, newArrayList(senderAddress, payload.getSender())); } - private
void assertRebroadcastOnlyOnce(
- final Function payload = createPayload.apply(keypair);
- final MessageData messageData = createMessageData.apply(payload);
- final Message message = new DefaultMessage(peerConnection, messageData);
-
- final boolean gossip1Result = ibftGossip.gossipMessage(message);
- final boolean gossip2Result = ibftGossip.gossipMessage(message);
- assertThat(gossip1Result).isTrue();
- assertThat(gossip2Result).isFalse();
- verify(validatorMulticaster, times(1))
- .send(messageData, newArrayList(senderAddress, payload.getSender()));
- }
-
@Test
public void assertRebroadcastsProposalToAllExceptSignerAndSender() {
assertRebroadcastToAllExceptSignerAndSender(
TestHelpers::createSignedProposalPayload, ProposalMessageData::create);
}
- @Test
- public void assertRebroadcastsProposalOnlyOnce() {
- assertRebroadcastOnlyOnce(
- TestHelpers::createSignedProposalPayload, ProposalMessageData::create);
- }
-
- @Test
- public void assertRebroadcastsPrepareToAllExceptSignerAndSender() {
- assertRebroadcastToAllExceptSignerAndSender(
- TestHelpers::createSignedPreparePayload, PrepareMessageData::create);
- }
-
- @Test
- public void assertRebroadcastsPrepareOnlyOnce() {
- assertRebroadcastOnlyOnce(TestHelpers::createSignedPreparePayload, PrepareMessageData::create);
- }
-
- @Test
- public void assertRebroadcastsCommitToAllExceptSignerAndSender() {
- assertRebroadcastToAllExceptSignerAndSender(
- TestHelpers::createSignedCommitPayload, CommitMessageData::create);
- }
-
- @Test
- public void assertRebroadcastsCommitOnlyOnce() {
- assertRebroadcastOnlyOnce(TestHelpers::createSignedCommitPayload, CommitMessageData::create);
- }
-
@Test
public void assertRebroadcastsRoundChangeToAllExceptSignerAndSender() {
assertRebroadcastToAllExceptSignerAndSender(
TestHelpers::createSignedRoundChangePayload, RoundChangeMessageData::create);
}
- @Test
- public void assertRebroadcastsRoundChangeOnlyOnce() {
- assertRebroadcastOnlyOnce(
- TestHelpers::createSignedRoundChangePayload, RoundChangeMessageData::create);
- }
-
@Test
public void assertRebroadcastsNewRoundToAllExceptSignerAndSender() {
assertRebroadcastToAllExceptSignerAndSender(
TestHelpers::createSignedNewRoundPayload, NewRoundMessageData::create);
}
-
- @Test
- public void assertRebroadcastsNewRoundOnlyOnce() {
- assertRebroadcastOnlyOnce(
- TestHelpers::createSignedNewRoundPayload, NewRoundMessageData::create);
- }
-
- @Test
- public void evictMessageRecordAtCapacity() {
- final KeyPair keypair = KeyPair.generate();
- final SignedData