diff --git a/core/src/main/java/bisq/core/app/misc/ExecutableForAppWithP2p.java b/core/src/main/java/bisq/core/app/misc/ExecutableForAppWithP2p.java index 813660dd724..d4c14206708 100644 --- a/core/src/main/java/bisq/core/app/misc/ExecutableForAppWithP2p.java +++ b/core/src/main/java/bisq/core/app/misc/ExecutableForAppWithP2p.java @@ -24,7 +24,9 @@ import bisq.core.offer.OpenOfferManager; import bisq.core.support.dispute.arbitration.arbitrator.ArbitratorManager; +import bisq.network.p2p.NodeAddress; import bisq.network.p2p.P2PService; +import bisq.network.p2p.seed.SeedNodeRepository; import bisq.common.UserThread; import bisq.common.config.Config; @@ -36,8 +38,15 @@ import com.google.common.util.concurrent.ThreadFactoryBuilder; +import java.time.Instant; +import java.time.ZoneId; +import java.time.ZonedDateTime; + import java.io.IOException; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; import java.util.concurrent.Executors; import java.util.concurrent.ThreadFactory; import java.util.concurrent.TimeUnit; @@ -106,6 +115,62 @@ public void gracefulShutDown(ResultHandler resultHandler) { } } + public void startShutDownInterval(GracefulShutDownHandler gracefulShutDownHandler) { + List seedNodeAddresses = new ArrayList<>(injector.getInstance(SeedNodeRepository.class).getSeedNodeAddresses()); + seedNodeAddresses.sort(Comparator.comparing(NodeAddress::getFullAddress)); + + NodeAddress myAddress = injector.getInstance(P2PService.class).getNetworkNode().getNodeAddress(); + int myIndex = -1; + for (int i = 0; i < seedNodeAddresses.size(); i++) { + if (seedNodeAddresses.get(i).equals(myAddress)) { + myIndex = i; + break; + } + } + + if (myIndex == -1) { + log.warn("We did not find our node address in the seed nodes repository. " + + "We use a 24 hour delay after startup as shut down strategy." + + "myAddress={}, seedNodeAddresses={}", + myAddress, seedNodeAddresses); + + UserThread.runPeriodically(() -> { + if (System.currentTimeMillis() - startTime > SHUTDOWN_INTERVAL) { + log.warn("\n\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n" + + "Shut down as node was running longer as {} hours" + + "\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n\n", + SHUTDOWN_INTERVAL / 3600000); + + shutDown(gracefulShutDownHandler); + } + + }, CHECK_SHUTDOWN_SEC); + return; + } + + // We interpret the value of myIndex as hour of day (0-23). That way we avoid the risk of a restart of + // multiple nodes around the same time in case it would be not deterministic. + + // We wrap our periodic check in a delay of 2 hours to avoid that we get + // triggered multiple times after a restart while being in the same hour. It can be that we miss our target + // hour during that delay but that is not considered problematic, the seed would just restart a bit longer than + // 24 hours. + int target = myIndex; + UserThread.runAfter(() -> { + // We check every hour if we are in the target hour. + UserThread.runPeriodically(() -> { + int currentHour = ZonedDateTime.ofInstant(Instant.now(), ZoneId.of("GMT0")).getHour(); + if (currentHour == target) { + log.warn("\n\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n" + + "Shut down node at hour {}" + + "\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n\n", target); + shutDown(gracefulShutDownHandler); + } + }, TimeUnit.MINUTES.toSeconds(10)); + }, TimeUnit.HOURS.toSeconds(2)); + } + + /////////////////////////////////////////////////////////////////////////////////////////// // UncaughtExceptionHandler implementation /////////////////////////////////////////////////////////////////////////////////////////// @@ -128,20 +193,6 @@ protected void keepRunning() { } } - protected void startShutDownInterval(GracefulShutDownHandler gracefulShutDownHandler) { - UserThread.runPeriodically(() -> { - if (System.currentTimeMillis() - startTime > SHUTDOWN_INTERVAL) { - log.warn("\n\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n" + - "Shut down as node was running longer as {} hours" + - "\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n\n", - SHUTDOWN_INTERVAL / 3600000); - - shutDown(gracefulShutDownHandler); - } - - }, CHECK_SHUTDOWN_SEC); - } - protected void checkMemory(Config config, GracefulShutDownHandler gracefulShutDownHandler) { int maxMemory = config.maxMemory; UserThread.runPeriodically(() -> { diff --git a/p2p/src/main/java/bisq/network/p2p/peers/getdata/RequestDataHandler.java b/p2p/src/main/java/bisq/network/p2p/peers/getdata/RequestDataHandler.java index 568c08cd183..2beafd6edc2 100644 --- a/p2p/src/main/java/bisq/network/p2p/peers/getdata/RequestDataHandler.java +++ b/p2p/src/main/java/bisq/network/p2p/peers/getdata/RequestDataHandler.java @@ -55,6 +55,7 @@ class RequestDataHandler implements MessageListener { private static final long TIMEOUT = 180; private NodeAddress peersNodeAddress; + private String getDataRequestType; /* */ @@ -138,7 +139,8 @@ void requestData(NodeAddress nodeAddress, boolean isPreliminaryDataRequest) { TIMEOUT); } - log.info("We send a {} to peer {}. ", getDataRequest.getClass().getSimpleName(), nodeAddress); + getDataRequestType = getDataRequest.getClass().getSimpleName(); + log.info("We send a {} to peer {}. ", getDataRequestType, nodeAddress); networkNode.addMessageListener(this); SettableFuture future = networkNode.sendMessage(nodeAddress, getDataRequest); //noinspection UnstableApiUsage @@ -259,8 +261,9 @@ private void logContents(NetworkEnvelope networkEnvelope, StringBuilder sb = new StringBuilder(); sb.append("\n#################################################################\n"); sb.append("Connected to node: " + peersNodeAddress.getFullAddress() + "\n"); - final int items = dataSet.size() + persistableNetworkPayloadSet.size(); - sb.append("Received ").append(items).append(" instances\n"); + int items = dataSet.size() + persistableNetworkPayloadSet.size(); + sb.append("Received ").append(items).append(" instances from a ") + .append(getDataRequestType).append("\n"); payloadByClassName.forEach((key, value) -> sb.append(key) .append(": ") .append(value.size()) diff --git a/seednode/src/main/java/bisq/seednode/SeedNodeMain.java b/seednode/src/main/java/bisq/seednode/SeedNodeMain.java index d8a853deeb4..3db42fa5858 100644 --- a/seednode/src/main/java/bisq/seednode/SeedNodeMain.java +++ b/seednode/src/main/java/bisq/seednode/SeedNodeMain.java @@ -20,6 +20,9 @@ import bisq.core.app.misc.ExecutableForAppWithP2p; import bisq.core.app.misc.ModuleForAppWithP2p; +import bisq.network.p2p.P2PService; +import bisq.network.p2p.P2PServiceListener; + import bisq.common.UserThread; import bisq.common.app.AppModule; import bisq.common.app.Capabilities; @@ -47,7 +50,6 @@ protected void doExecute() { super.doExecute(); checkMemory(config, this); - startShutDownInterval(this); CommonSetup.setup(this); keepRunning(); @@ -95,5 +97,47 @@ protected void applyInjector() { @Override protected void startApplication() { seedNode.startApplication(); + + injector.getInstance(P2PService.class).addP2PServiceListener(new P2PServiceListener() { + @Override + public void onDataReceived() { + // Do nothing + } + + @Override + public void onNoSeedNodeAvailable() { + // Do nothing + } + + @Override + public void onNoPeersAvailable() { + // Do nothing + } + + @Override + public void onUpdatedDataReceived() { + // Do nothing + } + + @Override + public void onTorNodeReady() { + // Do nothing + } + + @Override + public void onHiddenServicePublished() { + startShutDownInterval(SeedNodeMain.this); + } + + @Override + public void onSetupFailed(Throwable throwable) { + // Do nothing + } + + @Override + public void onRequestCustomBridges() { + // Do nothing + } + }); } }