|
7 | 7 | import java.io.IOException; |
8 | 8 | import java.net.InetSocketAddress; |
9 | 9 | import java.util.HashSet; |
| 10 | +import java.util.List; |
10 | 11 | import java.util.Set; |
11 | 12 | import javax.annotation.Resource; |
12 | 13 | import org.junit.After; |
@@ -97,6 +98,57 @@ public void testDisconnectRandom() { |
97 | 98 | Assert.assertEquals(maxConnection - 1, PeerManager.getPeers().size()); |
98 | 99 | } |
99 | 100 |
|
| 101 | + @Test |
| 102 | + public void testDisconnectRandomPreservesRecentBlockRcvTimePeer() { |
| 103 | + int maxConnection = 30; |
| 104 | + Assert.assertEquals(0, PeerManager.getPeers().size()); |
| 105 | + |
| 106 | + ApplicationContext ctx = (ApplicationContext) ReflectUtils.getFieldObject(p2pEventHandler, |
| 107 | + "ctx"); |
| 108 | + |
| 109 | + // Create maxConnection + 1 peers (triggers disconnectRandom) |
| 110 | + for (int i = 0; i < maxConnection + 1; i++) { |
| 111 | + InetSocketAddress inetSocketAddress = new InetSocketAddress("202.0.0." + i, 10001); |
| 112 | + Channel c1 = spy(Channel.class); |
| 113 | + ReflectUtils.setFieldValue(c1, "inetSocketAddress", inetSocketAddress); |
| 114 | + ReflectUtils.setFieldValue(c1, "inetAddress", inetSocketAddress.getAddress()); |
| 115 | + ReflectUtils.setFieldValue(c1, "ctx", spy(ChannelHandlerContext.class)); |
| 116 | + Mockito.doNothing().when(c1).send((byte[]) any()); |
| 117 | + PeerManager.add(ctx, c1); |
| 118 | + } |
| 119 | + |
| 120 | + // Set first minBroadcastPeerSize peers as broadcast-state |
| 121 | + List<PeerConnection> peers = PeerManager.getPeers(); |
| 122 | + for (PeerConnection peer : peers.subList(0, ResilienceService.minBroadcastPeerSize)) { |
| 123 | + peer.setNeedSyncFromPeer(false); |
| 124 | + peer.setNeedSyncFromUs(false); |
| 125 | + peer.setLastInteractiveTime(System.currentTimeMillis() - 1000); |
| 126 | + } |
| 127 | + for (PeerConnection peer : peers.subList(ResilienceService.minBroadcastPeerSize, |
| 128 | + maxConnection + 1)) { |
| 129 | + peer.setNeedSyncFromPeer(false); |
| 130 | + peer.setNeedSyncFromUs(true); |
| 131 | + } |
| 132 | + |
| 133 | + // Give the LAST broadcast peer a very recent blockRcvTime — it must NOT be disconnected |
| 134 | + PeerConnection bestPeer = peers.stream() |
| 135 | + .filter(p -> !p.isNeedSyncFromUs() && !p.isNeedSyncFromPeer()) |
| 136 | + .reduce((a, b) -> b) // last broadcast peer |
| 137 | + .orElseThrow(() -> new AssertionError("no broadcast peer")); |
| 138 | + bestPeer.setBlockRcvTime(System.currentTimeMillis()); |
| 139 | + |
| 140 | + InetSocketAddress bestPeerAddress = bestPeer.getChannel().getInetSocketAddress(); |
| 141 | + |
| 142 | + // With minBroadcastPeerSize=3 broadcast peers, getRandomDisconnectionPeers returns |
| 143 | + // the 1 peer with oldest blockRcvTime (0). bestPeer has most recent time → exempt. |
| 144 | + ReflectUtils.invokeMethod(service, "disconnectRandom"); |
| 145 | + |
| 146 | + boolean bestPeerStillConnected = PeerManager.getPeers().stream() |
| 147 | + .anyMatch(p -> p.getChannel().getInetSocketAddress().equals(bestPeerAddress)); |
| 148 | + Assert.assertTrue("Peer with most recent blockRcvTime should not be disconnected", |
| 149 | + bestPeerStillConnected); |
| 150 | + } |
| 151 | + |
100 | 152 | @Test |
101 | 153 | public void testDisconnectLan() { |
102 | 154 | int minConnection = 8; |
|
0 commit comments