diff --git a/pom.xml b/pom.xml
index 1289f02e..d17cc279 100644
--- a/pom.xml
+++ b/pom.xml
@@ -49,7 +49,7 @@
0.17
3.3.1
3.6.0
- 3.5.1
+ 3.5.2
3.25.3
1.5.3
1.17
diff --git a/src/main/java/org/qortal/ApplyRestart.java b/src/main/java/org/qortal/ApplyRestart.java
index 70d07df5..a2d4588d 100644
--- a/src/main/java/org/qortal/ApplyRestart.java
+++ b/src/main/java/org/qortal/ApplyRestart.java
@@ -1,14 +1,17 @@
package org.qortal;
+import org.apache.commons.io.FileUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.jsse.provider.BouncyCastleJsseProvider;
import org.qortal.api.ApiKey;
import org.qortal.api.ApiRequest;
+import org.qortal.controller.Controller;
import org.qortal.controller.RestartNode;
import org.qortal.settings.Settings;
+import java.io.File;
import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.nio.file.Files;
@@ -16,6 +19,8 @@ import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.Security;
import java.util.*;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;
import static org.qortal.controller.RestartNode.AGENTLIB_JVM_HOLDER_ARG;
@@ -57,15 +62,32 @@ public class ApplyRestart {
if (!shutdownNode())
return;
- // Restart node
- restartNode(args);
+ try {
+ // Give some time for shutdown
+ TimeUnit.SECONDS.sleep(30);
- LOGGER.info("Restarting...");
+ // Remove blockchain lock if exist
+ ReentrantLock blockchainLock = Controller.getInstance().getBlockchainLock();
+ if (blockchainLock.isLocked())
+ blockchainLock.unlock();
+
+ // Remove blockchain lock file if exist
+ TimeUnit.SECONDS.sleep(60);
+ deleteLock();
+
+ // Restart node
+ TimeUnit.SECONDS.sleep(30);
+ restartNode(args);
+
+ LOGGER.info("Restarting...");
+ } catch (InterruptedException e) {
+ LOGGER.error("Unable to restart", e);
+ }
}
private static boolean shutdownNode() {
String baseUri = "http://localhost:" + Settings.getInstance().getApiPort() + "/";
- LOGGER.info(() -> String.format("Shutting down node using API via %s", baseUri));
+ LOGGER.debug(() -> String.format("Shutting down node using API via %s", baseUri));
// The /admin/stop endpoint requires an API key, which may or may not be already generated
boolean apiKeyNewlyGenerated = false;
@@ -134,7 +156,22 @@ public class ApplyRestart {
apiKey.delete();
} catch (IOException e) {
- LOGGER.info("Error loading or deleting API key: {}", e.getMessage());
+ LOGGER.error("Error loading or deleting API key: {}", e.getMessage());
+ }
+ }
+
+ private static void deleteLock() {
+ // Get the repository path from settings
+ String repositoryPath = Settings.getInstance().getRepositoryPath();
+ LOGGER.debug(String.format("Repository path is: %s", repositoryPath));
+
+ try {
+ Path root = Paths.get(repositoryPath);
+ File lockFile = new File(root.resolve("blockchain.lck").toUri());
+ LOGGER.debug("Lockfile is: {}", lockFile);
+ FileUtils.forceDelete(FileUtils.getFile(lockFile));
+ } catch (IOException e) {
+ LOGGER.error("Error deleting blockchain lock file: {}", e.getMessage());
}
}
@@ -150,9 +187,10 @@ public class ApplyRestart {
List javaCmd;
if (Files.exists(exeLauncher)) {
- javaCmd = Arrays.asList(exeLauncher.toString());
+ javaCmd = List.of(exeLauncher.toString());
} else {
javaCmd = new ArrayList<>();
+
// Java runtime binary itself
javaCmd.add(javaBinary.toString());
diff --git a/src/main/java/org/qortal/controller/Controller.java b/src/main/java/org/qortal/controller/Controller.java
index 810c8e32..27341d1e 100644
--- a/src/main/java/org/qortal/controller/Controller.java
+++ b/src/main/java/org/qortal/controller/Controller.java
@@ -500,7 +500,6 @@ public class Controller extends Thread {
@Override
public void run() {
Thread.currentThread().setName("Shutdown hook");
-
Controller.getInstance().shutdown();
}
});
@@ -580,10 +579,31 @@ public class Controller extends Thread {
// If GUI is enabled, we're no longer starting up but actually running now
Gui.getInstance().notifyRunning();
- // Check every 10 minutes to see if the block minter is running
- Timer timer = new Timer();
+ // Check every 10 minutes if we have enough connected peers
+ Timer checkConnectedPeers = new Timer();
- timer.schedule(new TimerTask() {
+ checkConnectedPeers.schedule(new TimerTask() {
+ @Override
+ public void run() {
+ // Get the connected peers
+ int myConnectedPeers = Network.getInstance().getImmutableHandshakedPeers().size();
+ LOGGER.debug("Node have {} connected peers", myConnectedPeers);
+ if (myConnectedPeers == 0) {
+ // Restart node if we have 0 peers
+ LOGGER.info("Node have no connected peers, restarting node");
+ try {
+ RestartNode.attemptToRestart();
+ } catch (Exception e) {
+ LOGGER.error("Unable to restart the node", e);
+ }
+ }
+ }
+ }, 10*60*1000, 10*60*1000);
+
+ // Check every 10 minutes to see if the block minter is running
+ Timer checkBlockMinter = new Timer();
+
+ checkBlockMinter.schedule(new TimerTask() {
@Override
public void run() {
if (blockMinter.isAlive()) {
diff --git a/src/main/java/org/qortal/controller/repository/BlockArchiver.java b/src/main/java/org/qortal/controller/repository/BlockArchiver.java
index 12793f89..0de6e38e 100644
--- a/src/main/java/org/qortal/controller/repository/BlockArchiver.java
+++ b/src/main/java/org/qortal/controller/repository/BlockArchiver.java
@@ -21,7 +21,7 @@ public class BlockArchiver implements Runnable {
private static final Logger LOGGER = LogManager.getLogger(BlockArchiver.class);
- private static final long INITIAL_SLEEP_PERIOD = 5 * 60 * 1000L + 1234L; // ms
+ private static final long INITIAL_SLEEP_PERIOD = 15 * 60 * 1000L; // ms
public void run() {
Thread.currentThread().setName("Block archiver");
@@ -52,9 +52,29 @@ public class BlockArchiver implements Runnable {
Thread.sleep(Settings.getInstance().getArchiveInterval());
+<<<<<<< HEAD
BlockData chainTip = Controller.getInstance().getChainTip();
if (chainTip == null || NTP.getTime() == null) {
continue;
+=======
+ // We've reached the limit of the blocks we can archive
+ // Sleep for a while to allow more to become available
+ case NOT_ENOUGH_BLOCKS:
+ // We didn't reach our file size target, so that must mean that we don't have enough blocks
+ // yet or something went wrong. Sleep for a while and then try again.
+ repository.discardChanges();
+ Thread.sleep(2 * 60 * 60 * 1000L); // 2 hour around 100 blocks
+ break;
+
+ case BLOCK_NOT_FOUND:
+ // We tried to archive a block that didn't exist. This is a major failure and likely means
+ // that a bootstrap or re-sync is needed. Try again every minute until then.
+ LOGGER.info("Error: block not found when building archive. If this error persists, " +
+ "a bootstrap or re-sync may be needed.");
+ repository.discardChanges();
+ Thread.sleep(60 * 1000L); // 1 minute
+ break;
+>>>>>>> alphax/master
}
// Don't even attempt if we're mid-sync as our repository requests will be delayed for ages
diff --git a/src/main/java/org/qortal/network/Network.java b/src/main/java/org/qortal/network/Network.java
index d80892b3..f500b2e8 100644
--- a/src/main/java/org/qortal/network/Network.java
+++ b/src/main/java/org/qortal/network/Network.java
@@ -53,7 +53,7 @@ public class Network {
/**
* How long between informational broadcasts to all connected peers, in milliseconds.
*/
- private static final long BROADCAST_INTERVAL = 60 * 1000L; // ms
+ private static final long BROADCAST_INTERVAL = 30 * 1000L; // ms
/**
* Maximum time since last successful connection for peer info to be propagated, in milliseconds.
*/
@@ -83,12 +83,12 @@ public class Network {
"node6.qortalnodes.live", "node7.qortalnodes.live", "node8.qortalnodes.live"
};
- private static final long NETWORK_EPC_KEEPALIVE = 10L; // seconds
+ private static final long NETWORK_EPC_KEEPALIVE = 5L; // seconds
public static final int MAX_SIGNATURES_PER_REPLY = 500;
public static final int MAX_BLOCK_SUMMARIES_PER_REPLY = 500;
- private static final long DISCONNECTION_CHECK_INTERVAL = 10 * 1000L; // milliseconds
+ private static final long DISCONNECTION_CHECK_INTERVAL = 20 * 1000L; // milliseconds
private static final int BROADCAST_CHAIN_TIP_DEPTH = 7; // Just enough to fill a SINGLE TCP packet (~1440 bytes)
diff --git a/src/main/java/org/qortal/settings/Settings.java b/src/main/java/org/qortal/settings/Settings.java
index 67daa905..4abad781 100644
--- a/src/main/java/org/qortal/settings/Settings.java
+++ b/src/main/java/org/qortal/settings/Settings.java
@@ -197,21 +197,21 @@ public class Settings {
/** Target number of outbound connections to peers we should make. */
private int minOutboundPeers = 32;
/** Maximum number of peer connections we allow. */
- private int maxPeers = 60;
+ private int maxPeers = 64;
/** Number of slots to reserve for short-lived QDN data transfers */
private int maxDataPeers = 5;
/** Maximum number of threads for network engine. */
- private int maxNetworkThreadPoolSize = 620;
+ private int maxNetworkThreadPoolSize = 512;
/** Maximum number of threads for network proof-of-work compute, used during handshaking. */
- private int networkPoWComputePoolSize = 2;
+ private int networkPoWComputePoolSize = 4;
/** Maximum number of retry attempts if a peer fails to respond with the requested data */
- private int maxRetries = 2;
+ private int maxRetries = 3;
/** The number of seconds of no activity before recovery mode begins */
public long recoveryModeTimeout = 9999999999999L;
/** Minimum peer version number required in order to sync with them */
- private String minPeerVersion = "4.5.2";
+ private String minPeerVersion = "4.6.0";
/** Whether to allow connections with peers below minPeerVersion
* If true, we won't sync with them but they can still sync with us, and will show in the peers list
* If false, sync will be blocked both ways, and they will not appear in the peers list */