public void simulatePeerRestartingOnDifferentEndpoint(
      final boolean updateHost, final boolean updatePort) {
    // Setup peer
    final MockPeerDiscoveryAgent agent = helper.startDiscoveryAgent();
    assertThat(agent.getAdvertisedPeer().isPresent()).isTrue();
    final DiscoveryPeer agentPeer = agent.getAdvertisedPeer().get();

    final NodeKey remoteKeyPair = NodeKeyUtils.generate();
    final String remoteIp = "1.2.3.4";
    final MockPeerDiscoveryAgent remoteAgent =
        helper.createDiscoveryAgent(
            helper
                .agentBuilder()
                .nodeKey(remoteKeyPair)
                .advertisedHost(remoteIp)
                .bootstrapPeers(agentPeer));

    agent.start(999);
    remoteAgent.start(888);
    assertThat(remoteAgent.getAdvertisedPeer().isPresent()).isTrue();
    final DiscoveryPeer remotePeer = remoteAgent.getAdvertisedPeer().get();

    // Remote agent should have bonded with agent
    assertThat(agent.streamDiscoveredPeers()).hasSize(1);
    assertThat(agent.streamDiscoveredPeers()).contains(remotePeer);

    // Create a new remote agent with same id, and new endpoint
    remoteAgent.stop();
    final int newPort = updatePort ? 0 : remotePeer.getEndpoint().getUdpPort();
    final String newIp = updateHost ? "1.2.3.5" : remoteIp;
    final MockPeerDiscoveryAgent updatedRemoteAgent =
        helper.createDiscoveryAgent(
            helper
                .agentBuilder()
                .nodeKey(remoteKeyPair)
                .advertisedHost(newIp)
                .bindPort(newPort)
                .bootstrapPeers(agentPeer));
    updatedRemoteAgent.start(889);
    assertThat(updatedRemoteAgent.getAdvertisedPeer().isPresent()).isTrue();
    final DiscoveryPeer updatedRemotePeer = updatedRemoteAgent.getAdvertisedPeer().get();

    // Sanity check
    assertThat(
            updatedRemotePeer.getEndpoint().getUdpPort() == remotePeer.getEndpoint().getUdpPort())
        .isEqualTo(!updatePort);
    assertThat(updatedRemotePeer.getEndpoint().getHost().equals(remotePeer.getEndpoint().getHost()))
        .isEqualTo(!updateHost);
    assertThat(updatedRemotePeer.getId()).isEqualTo(remotePeer.getId());

    // Check that our restarted agent receives a PONG response
    final List<IncomingPacket> incomingPackets = updatedRemoteAgent.getIncomingPackets();
    assertThat(incomingPackets).hasSizeGreaterThan(0);
    final long pongCount =
        incomingPackets.stream()
            .filter(packet -> packet.fromAgent.equals(agent))
            .filter(packet -> packet.packet.getType().equals(PacketType.PONG))
            .count();
    assertThat(pongCount).isGreaterThan(0);

    // Check that agent has an endpoint matching the restarted node
    final List<DiscoveryPeer> matchingPeers =
        agent
            .streamDiscoveredPeers()
            .filter(peer -> peer.getId().equals(updatedRemotePeer.getId()))
            .collect(toList());
    // We should have only one peer matching this id
    assertThat(matchingPeers.size()).isEqualTo(1);
    final DiscoveryPeer discoveredPeer = matchingPeers.get(0);
    assertThat(discoveredPeer.getEndpoint().getUdpPort())
        .isEqualTo(updatedRemotePeer.getEndpoint().getUdpPort());
    assertThat(discoveredPeer.getEndpoint().getHost())
        .isEqualTo(updatedRemotePeer.getEndpoint().getHost());
    // Check endpoint is consistent with enodeURL
    assertThat(discoveredPeer.getEnodeURL().getDiscoveryPortOrZero())
        .isEqualTo(updatedRemotePeer.getEndpoint().getUdpPort());
    assertThat(discoveredPeer.getEnodeURL().getListeningPortOrZero())
        .isEqualTo(updatedRemotePeer.getEndpoint().getFunctionalTcpPort());
    assertThat(discoveredPeer.getEnodeURL().getIpAsString())
        .isEqualTo(updatedRemotePeer.getEndpoint().getHost());
  }
These tests simulates the case where a node crashes then comes back up with a new ip address or
listening port.
ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/PeerDiscoveryAgentTest.java