All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.quorum.tessera.p2p.partyinfo.PartyInfoBroadcaster Maven / Gradle / Ivy

package com.quorum.tessera.p2p.partyinfo;

import com.quorum.tessera.discovery.Discovery;
import com.quorum.tessera.discovery.NodeUri;
import com.quorum.tessera.partyinfo.P2pClient;
import com.quorum.tessera.partyinfo.model.PartyInfo;
import com.quorum.tessera.partyinfo.model.PartyInfoBuilder;
import com.quorum.tessera.partyinfo.node.NodeInfo;
import jakarta.ws.rs.ProcessingException;
import java.net.URI;
import java.util.Objects;
import java.util.Optional;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Polls every so often to all known nodes for any new discoverable nodes. This keeps all nodes
 * up-to date and discoverable by other nodes
 */
public class PartyInfoBroadcaster implements Runnable {

  private static final Logger LOGGER = LoggerFactory.getLogger(PartyInfoBroadcaster.class);

  private final Discovery discovery;

  private final PartyInfoParser partyInfoParser;

  private final P2pClient p2pClient;

  private final PartyStore partyStore;

  public PartyInfoBroadcaster(final P2pClient p2pClient) {
    this(Discovery.create(), PartyInfoParser.create(), p2pClient, PartyStore.getInstance());
  }

  public PartyInfoBroadcaster(
      final Discovery discovery,
      final PartyInfoParser partyInfoParser,
      final P2pClient p2pClient,
      final PartyStore partyStore) {
    this.discovery = Objects.requireNonNull(discovery);
    this.partyInfoParser = Objects.requireNonNull(partyInfoParser);
    this.p2pClient = Objects.requireNonNull(p2pClient);
    this.partyStore = Objects.requireNonNull(partyStore);
  }

  /**
   * Iterates over all known parties and contacts them for the current state of their known node
   * discovery list
   *
   * 

For Tessera 0.9 backwards, after contacting the known parties, this poller then updates this * nodes list of data with any new information collected. * *

This behaviour is now deprecated since the /partyinfo API call now has been made more strict * with node validation to prevent exploiting the API to attack the Tessera network. * *

This call is merely to let its parties know about this node existence, any recipients that * want to be added to this node's PartyInfo will need to make their own partyinfo call and * validation */ @Override public void run() { LOGGER.info("Started PartyInfo polling round"); partyStore.loadFromConfigIfEmpty(); final NodeInfo nodeInfo = discovery.getCurrent(); final NodeUri ourUrl = NodeUri.create(nodeInfo.getUrl()); final PartyInfo partyInfo = PartyInfoBuilder.create() .withUri(nodeInfo.getUrl()) .withRecipients(nodeInfo.getRecipientsAsMap()) .build(); final byte[] encodedPartyInfo = partyInfoParser.to(partyInfo); LOGGER.debug("Contacting following peers with PartyInfo: {}", partyInfo.getParties()); LOGGER.debug("Sending party info {}", nodeInfo); partyStore.getParties().stream() .map(NodeUri::create) .filter(url -> !ourUrl.equals(url)) .forEach(url -> pollSingleParty(url.asString(), encodedPartyInfo)); LOGGER.info("Finished PartyInfo polling round"); } /** * Sends a request for node information to a single target * * @param url the target URL to call * @param encodedPartyInfo the encoded current party information */ protected void pollSingleParty(final String url, final byte[] encodedPartyInfo) { final NodeUri nodeUri = NodeUri.create(url); try { LOGGER.debug("Sending party info to {}", nodeUri.asString()); p2pClient.sendPartyInfo(url, encodedPartyInfo); LOGGER.debug("Sent party info to {}", nodeUri.asString()); } catch (Exception ex) { Throwable cause = Optional.of(ex).map(Throwable::getCause).orElse(ex); LOGGER.warn("Failed to connect to node {}, due to {}", url, cause.getMessage()); LOGGER.debug("Send failure exception", cause); if (ProcessingException.class.isInstance(cause)) { discovery.onDisconnect(URI.create(url)); partyStore.remove(URI.create(url)); } } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy