Repository: consensys/tessera
Issue: Tessera Peer Discovery - Exclude 'Self' as active 'configured peer list' in Partystore

When a node has intermittent connection drop from a network it will drop all connection to the network and repopulates 'Partystore' from configured peer list to reestablish connection. But if 'self' url is also in the configured peer list, it will be fooled to believe it is connected to at least 1 active peer list and will not establish connection back to the network. This change is to exclude 'self' as active configured peer.

Changed files:
tessera-jaxrs/sync-jaxrs/src/test/java/com/quorum/tessera/p2p/partyinfo/PartyStoreFactoryTest.java
tessera-jaxrs/sync-jaxrs/src/test/java/com/quorum/tessera/p2p/MockRuntimeContextFactory.java
tessera-jaxrs/sync-jaxrs/src/test/java/com/quorum/tessera/p2p/P2PRestAppTest.java
tessera-jaxrs/sync-jaxrs/src/main/java/com/quorum/tessera/p2p/partyinfo/PartyStore.java

diff --git a/tessera-jaxrs/sync-jaxrs/src/main/java/com/quorum/tessera/p2p/partyinfo/PartyStore.java b/tessera-jaxrs/sync-jaxrs/src/main/java/com/quorum/tessera/p2p/partyinfo/PartyStore.java
index f51bb93f7..8c0971a39 100644
--- a/tessera-jaxrs/sync-jaxrs/src/main/java/com/quorum/tessera/p2p/partyinfo/PartyStore.java
+++ b/tessera-jaxrs/sync-jaxrs/src/main/java/com/quorum/tessera/p2p/partyinfo/PartyStore.java
@@ -6,6 +6,7 @@ import com.quorum.tessera.discovery.NodeUri;
 import java.net.URI;
 import java.util.ServiceLoader;
 import java.util.Set;
+import java.util.stream.Collectors;
 
 /*
  * Support legacy collation of all parties to be added to
@@ -18,12 +19,17 @@ public interface PartyStore {
 
         final Set<URI> parties = getParties();
 
-        if (parties.isEmpty()
-                || !runtimeContext.getPeers().stream()
+        final URI ownUri = NodeUri.create(runtimeContext.getP2pServerUri()).asURI();
+
+        final Set<URI> peerList =
+                runtimeContext.getPeers().stream()
                         .map(NodeUri::create)
                         .map(NodeUri::asURI)
-                        .anyMatch(parties::contains)) {
-            runtimeContext.getPeers().forEach(this::store);
+                        .filter(p -> !p.equals(ownUri))
+                        .collect(Collectors.toUnmodifiableSet());
+
+        if (parties.isEmpty() || !peerList.stream().anyMatch(parties::contains)) {
+            peerList.forEach(this::store);
         }
     }
 
diff --git a/tessera-jaxrs/sync-jaxrs/src/test/java/com/quorum/tessera/p2p/MockRuntimeContextFactory.java b/tessera-jaxrs/sync-jaxrs/src/test/java/com/quorum/tessera/p2p/MockRuntimeContextFactory.java
index 45b3682e4..04d2ed4db 100644
--- a/tessera-jaxrs/sync-jaxrs/src/test/java/com/quorum/tessera/p2p/MockRuntimeContextFactory.java
+++ b/tessera-jaxrs/sync-jaxrs/src/test/java/com/quorum/tessera/p2p/MockRuntimeContextFactory.java
@@ -5,22 +5,13 @@ import com.quorum.tessera.context.ContextHolder;
 import com.quorum.tessera.context.RuntimeContext;
 import com.quorum.tessera.context.RuntimeContextFactory;
 
-import java.net.URI;
-import java.util.List;
 import java.util.Optional;
 
 import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
 
 public class MockRuntimeContextFactory implements RuntimeContextFactory<Config>, ContextHolder {
     static ThreadLocal<RuntimeContext> runtimeContextThreadLocal =
-        ThreadLocal.withInitial(
-            () -> {
-                RuntimeContext mockContext = mock(RuntimeContext.class);
-                when(mockContext.getP2pServerUri()).thenReturn(URI.create("http://own.com/"));
-                when(mockContext.getPeers()).thenReturn(List.of(URI.create("http://peer.com/")));
-                return mockContext;
-            });
+            ThreadLocal.withInitial(() -> mock(RuntimeContext.class));
 
     @Override
     public void setContext(RuntimeContext runtimeContext) {
diff --git a/tessera-jaxrs/sync-jaxrs/src/test/java/com/quorum/tessera/p2p/P2PRestAppTest.java b/tessera-jaxrs/sync-jaxrs/src/test/java/com/quorum/tessera/p2p/P2PRestAppTest.java
index 842329d05..0a340c1e1 100644
--- a/tessera-jaxrs/sync-jaxrs/src/test/java/com/quorum/tessera/p2p/P2PRestAppTest.java
+++ b/tessera-jaxrs/sync-jaxrs/src/test/java/com/quorum/tessera/p2p/P2PRestAppTest.java
@@ -19,7 +19,9 @@ import org.junit.Test;
 
 import javax.ws.rs.client.Client;
 import javax.ws.rs.core.Application;
+import java.net.URI;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Set;
 
 import static org.assertj.core.api.Assertions.assertThat;
@@ -44,6 +46,8 @@ public class P2PRestAppTest {
         Client client = mock(Client.class);
         when(runtimeContext.getP2pClient()).thenReturn(client);
         when(runtimeContext.isRemoteKeyValidation()).thenReturn(true);
+        when(runtimeContext.getP2pServerUri()).thenReturn(URI.create("http://own.com/"));
+        when(runtimeContext.getPeers()).thenReturn(List.of(URI.create("http://peer.com/")));
 
         MockServiceLocator serviceLocator = (MockServiceLocator) ServiceLocator.create();
         serviceLocator.setServices(services);
@@ -77,7 +81,10 @@ public class P2PRestAppTest {
                 o ->
                         assertThat(o)
                                 .isInstanceOfAny(
-                                        PartyInfoResource.class, IPWhitelistFilter.class, UpCheckResource.class, TransactionResource.class));
+                                        PartyInfoResource.class,
+                                        IPWhitelistFilter.class,
+                                        UpCheckResource.class,
+                                        TransactionResource.class));
     }
 
     @Test
@@ -90,7 +97,10 @@ public class P2PRestAppTest {
                 o ->
                         assertThat(o)
                                 .isInstanceOfAny(
-                                        PartyInfoResource.class, IPWhitelistFilter.class, UpCheckResource.class, RecoveryResource.class));
+                                        PartyInfoResource.class,
+                                        IPWhitelistFilter.class,
+                                        UpCheckResource.class,
+                                        RecoveryResource.class));
     }
 
     @Test
diff --git a/tessera-jaxrs/sync-jaxrs/src/test/java/com/quorum/tessera/p2p/partyinfo/PartyStoreFactoryTest.java b/tessera-jaxrs/sync-jaxrs/src/test/java/com/quorum/tessera/p2p/partyinfo/PartyStoreFactoryTest.java
index c7036caa1..232fd1b98 100644
--- a/tessera-jaxrs/sync-jaxrs/src/test/java/com/quorum/tessera/p2p/partyinfo/PartyStoreFactoryTest.java
+++ b/tessera-jaxrs/sync-jaxrs/src/test/java/com/quorum/tessera/p2p/partyinfo/PartyStoreFactoryTest.java
@@ -1,9 +1,9 @@
 package com.quorum.tessera.p2p.partyinfo;
 
+import com.quorum.tessera.config.Config;
 import com.quorum.tessera.context.RuntimeContext;
-import com.quorum.tessera.p2p.partyinfo.PartyStore;
-import com.quorum.tessera.p2p.partyinfo.PartyStoreFactory;
-import com.quorum.tessera.p2p.partyinfo.SimplePartyStore;
+import com.quorum.tessera.context.RuntimeContextFactory;
+import com.quorum.tessera.discovery.NodeUri;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -22,10 +22,15 @@ public class PartyStoreFactoryTest {
 
     private PartyStore partyStore;
 
+    static final RuntimeContext runtimeContext = RuntimeContextFactory.newFactory().create(mock(Config.class));
+
     @Before
     public void beforeTest() {
         partyStore = mock(PartyStore.class);
         partyStoreFactory = new PartyStoreFactory(partyStore);
+
+        when(runtimeContext.getP2pServerUri()).thenReturn(URI.create("http://own.com/"));
+        when(runtimeContext.getPeers()).thenReturn(List.of(URI.create("http://peer.com/")));
     }
 
     @After
@@ -60,7 +65,21 @@ public class PartyStoreFactoryTest {
         partyStoreFactory.loadFromConfigIfEmpty();
 
         verify(partyStore).getParties();
-        verify(partyStore).store(RuntimeContext.getInstance().getPeers().get(0));
+        verify(partyStore).store(runtimeContext.getPeers().get(0));
+    }
+
+    @Test
+    public void whenPeerListContainsSelf() {
+
+        when(runtimeContext.getPeers())
+                .thenReturn(List.of(URI.create("http://peer.com/"), URI.create("http://own.com/")));
+
+        when(partyStore.getParties()).thenReturn(Set.of(URI.create("http://own.com/")));
+
+        partyStoreFactory.loadFromConfigIfEmpty();
+
+        verify(partyStore).getParties();
+        verify(partyStore).store(NodeUri.create("http://peer.com/").asURI());
     }
 
     @Test
@@ -70,7 +89,7 @@ public class PartyStoreFactoryTest {
         partyStoreFactory.loadFromConfigIfEmpty();
 
         verify(partyStore).getParties();
-        verify(partyStore).store(RuntimeContext.getInstance().getPeers().get(0));
+        verify(partyStore).store(runtimeContext.getPeers().get(0));
     }
 
     @Test
@@ -87,13 +106,12 @@ public class PartyStoreFactoryTest {
 
         when(partyStore.getParties()).thenReturn(Set.of(URI.create("http://peer.com/")));
 
-        when(RuntimeContext.getInstance().getPeers()).thenReturn(List.of(URI.create("http://peer.com")));
+        when(runtimeContext.getPeers()).thenReturn(List.of(URI.create("http://peer.com")));
 
         partyStoreFactory.loadFromConfigIfEmpty();
 
         verify(partyStore).getParties();
         verify(partyStore, times(0)).store(any());
-
     }
 
     @Test