diff --git a/lib/io/reticulum/reticulum-network-stack/1.0-SNAPSHOT/maven-metadata-local.xml b/lib/io/reticulum/reticulum-network-stack/1.0-SNAPSHOT/maven-metadata-local.xml
deleted file mode 100644
index 0c856aac..00000000
--- a/lib/io/reticulum/reticulum-network-stack/1.0-SNAPSHOT/maven-metadata-local.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
- io.reticulum
- reticulum-network-stack
- 1.0-SNAPSHOT
-
-
- true
-
- 20250418180444
-
-
- jar
- 1.0-SNAPSHOT
- 20250418180444
-
-
- pom
- 1.0-SNAPSHOT
- 20241218212752
-
-
-
-
diff --git a/lib/io/reticulum/reticulum-network-stack/1.0-SNAPSHOT/reticulum-network-stack-1.0-SNAPSHOT.jar b/lib/io/reticulum/reticulum-network-stack/1.0-SNAPSHOT/reticulum-network-stack-1.0-SNAPSHOT.jar
deleted file mode 100644
index e1d6ad48..00000000
Binary files a/lib/io/reticulum/reticulum-network-stack/1.0-SNAPSHOT/reticulum-network-stack-1.0-SNAPSHOT.jar and /dev/null differ
diff --git a/lib/io/reticulum/reticulum-network-stack/1.0-SNAPSHOT/reticulum-network-stack-1.0-SNAPSHOT.pom b/lib/io/reticulum/reticulum-network-stack/1.0-SNAPSHOT/reticulum-network-stack-1.0-SNAPSHOT.pom
deleted file mode 100644
index 1b1cc206..00000000
--- a/lib/io/reticulum/reticulum-network-stack/1.0-SNAPSHOT/reticulum-network-stack-1.0-SNAPSHOT.pom
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
- 4.0.0
- io.reticulum
- reticulum-network-stack
- 1.0-SNAPSHOT
- POM was created from install:install-file
-
diff --git a/lib/io/reticulum/reticulum-network-stack/maven-metadata-local.xml b/lib/io/reticulum/reticulum-network-stack/maven-metadata-local.xml
deleted file mode 100644
index 45dbe562..00000000
--- a/lib/io/reticulum/reticulum-network-stack/maven-metadata-local.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
- io.reticulum
- reticulum-network-stack
-
-
- 1.0-SNAPSHOT
-
- 20250418180444
-
-
diff --git a/pom.xml b/pom.xml
index 82e0f42f..11d747fd 100644
--- a/pom.xml
+++ b/pom.xml
@@ -52,6 +52,7 @@
3.5.2
3.25.3
1.5.3
+ c0eeadf
1.17
2.0.10
5.18.2
@@ -512,6 +513,12 @@
altcoinj
${altcoinj.version}
+
+
+ com.github.sergst83
+ reticulum-network-stack
+ ${reticulum.version}
+
com.googlecode.json-simple
diff --git a/src/main/java/org/qortal/controller/Controller.java b/src/main/java/org/qortal/controller/Controller.java
index ae2d6a99..733286c1 100644
--- a/src/main/java/org/qortal/controller/Controller.java
+++ b/src/main/java/org/qortal/controller/Controller.java
@@ -543,8 +543,8 @@ public class Controller extends Thread {
LOGGER.info("Starting synchronizer");
Synchronizer.getInstance().start();
- //LOGGER.info("Starting synchronizer over Reticulum");
- //RNSSynchronizer.getInstance().start();
+ LOGGER.info("Starting synchronizer over Reticulum");
+ RNSSynchronizer.getInstance().start();
LOGGER.info("Starting block minter");
blockMinter = new BlockMinter();
@@ -743,6 +743,73 @@ public class Controller extends Thread {
}
}
}, 3*60*1000, 3*60*1000);
+ //Timer syncFromGenesisRNS = new Timer();
+ //syncFromGenesisRNS.schedule(new TimerTask() {
+ // @Override
+ // public void run() {
+ // LOGGER.debug("Start sync from genesis check (RNS).");
+ // boolean canBootstrap = Settings.getInstance().getBootstrap();
+ // boolean needsArchiveRebuildRNS = false;
+ // int checkHeightRNS = 0;
+ //
+ // try (final Repository repository = RepositoryManager.getRepository()){
+ // needsArchiveRebuildRNS = (repository.getBlockArchiveRepository().fromHeight(2) == null);
+ // checkHeightRNS = repository.getBlockRepository().getBlockchainHeight();
+ // } catch (DataException e) {
+ // throw new RuntimeException(e);
+ // }
+ //
+ // if (canBootstrap || !needsArchiveRebuildRNS || checkHeightRNS > 3) {
+ // LOGGER.debug("Bootstrapping is enabled or we have more than 2 blocks, cancel sync from genesis check.");
+ // syncFromGenesisRNS.cancel();
+ // return;
+ // }
+ //
+ // if (needsArchiveRebuildRNS && !canBootstrap) {
+ // LOGGER.info("Start syncing from genesis (RNS)!");
+ // List seeds = new ArrayList<>(RNSNetwork.getInstance().getImmutableActiveLinkedPeers());
+ //
+ // // Check if have a qualified peer to sync
+ // if (seeds.isEmpty()) {
+ // LOGGER.info("No connected RNSPeer(s), will try again later.");
+ // return;
+ // }
+ //
+ // int index = new SecureRandom().nextInt(seeds.size());
+ // RNSPeer syncPeer = seeds.get(index);
+ // var syncPeerLinkAsString = syncPeer.getPeerLink().toString();
+ // //String syncNode = String.valueOf(seeds.get(index));
+ // //PeerAddress peerAddress = PeerAddress.fromString(syncNode);
+ // //InetSocketAddress resolvedAddress = null;
+ // //
+ // //try {
+ // // resolvedAddress = peerAddress.toSocketAddress();
+ // //} catch (UnknownHostException e) {
+ // // throw new RuntimeException(e);
+ // //}
+ // //
+ // //InetSocketAddress finalResolvedAddress = resolvedAddress;
+ // //Peer targetPeer = seeds.stream().filter(peer -> peer.getResolvedAddress().equals(finalResolvedAddress)).findFirst().orElse(null);
+ // //RNSPeer targetPeerRNS = seeds.stream().findFirst().orElse(null);
+ // RNSPeer targetPeerRNS = seeds.stream().filter(peer -> peer.getPeerLink().toString().equals(syncPeerLinkAsString)).findFirst().orElse(null);
+ // RNSSynchronizer.SynchronizationResult syncResultRNS;
+ //
+ // try {
+ // do {
+ // try {
+ // syncResultRNS = RNSSynchronizer.getInstance().actuallySynchronize(targetPeerRNS, true);
+ // } catch (InterruptedException e) {
+ // throw new RuntimeException(e);
+ // }
+ // }
+ // while (syncResultRNS == RNSSynchronizer.SynchronizationResult.OK);
+ // } finally {
+ // // We are syncing now, so can cancel the check
+ // syncFromGenesisRNS.cancel();
+ // }
+ // }
+ // }
+ //}, 3*60*1000, 3*60*1000);
}
/** Called by AdvancedInstaller's launch EXE in single-instance mode, when an instance is already running. */
@@ -858,29 +925,29 @@ public class Controller extends Thread {
repositoryMaintenanceInterval = getRandomRepositoryMaintenanceInterval();
}
- //// Prune stuck/slow/old peers
- //if (now >= prunePeersTimestamp + prunePeersInterval) {
- // prunePeersTimestamp = now + prunePeersInterval;
- //
- // try {
- // LOGGER.debug("Pruning peers...");
- // Network.getInstance().prunePeers();
- // } catch (DataException e) {
- // LOGGER.warn(String.format("Repository issue when trying to prune peers: %s", e.getMessage()));
- // }
- //}
+ // Prune stuck/slow/old peers
+ if (now >= prunePeersTimestamp + prunePeersInterval) {
+ prunePeersTimestamp = now + prunePeersInterval;
- //// Q: Do we need global pruning?
- //if (now >= pruneRNSPeersTimestamp + pruneRNSPeersInterval) {
- // pruneRNSPeersTimestamp = now + pruneRNSPeersInterval;
- //
- // try {
- // LOGGER.debug("Pruning Reticulum peers...");
- // RNSNetwork.getInstance().prunePeers();
- // } catch (DataException e) {
- // LOGGER.warn(String.format("Repository issue when trying to prune Reticulum peers: %s", e.getMessage()));
- // }
- //}
+ try {
+ LOGGER.debug("Pruning peers...");
+ Network.getInstance().prunePeers();
+ } catch (DataException e) {
+ LOGGER.warn(String.format("Repository issue when trying to prune peers: %s", e.getMessage()));
+ }
+ }
+
+ // Q: Do we need global pruning?
+ if (now >= pruneRNSPeersTimestamp + pruneRNSPeersInterval) {
+ pruneRNSPeersTimestamp = now + pruneRNSPeersInterval;
+
+ try {
+ LOGGER.debug("Pruning Reticulum peers...");
+ RNSNetwork.getInstance().prunePeers();
+ } catch (DataException e) {
+ LOGGER.warn(String.format("Repository issue when trying to prune Reticulum peers: %s", e.getMessage()));
+ }
+ }
// Delete expired transactions
if (now >= deleteExpiredTimestamp) {
diff --git a/src/main/java/org/qortal/network/RNSNetwork.java b/src/main/java/org/qortal/network/RNSNetwork.java
index 85d26bf6..d0e3708b 100644
--- a/src/main/java/org/qortal/network/RNSNetwork.java
+++ b/src/main/java/org/qortal/network/RNSNetwork.java
@@ -24,7 +24,7 @@ import static io.reticulum.link.TeardownSession.TIMEOUT;
import static io.reticulum.link.LinkStatus.ACTIVE;
import static io.reticulum.link.LinkStatus.STALE;
import static io.reticulum.link.LinkStatus.CLOSED;
-//import static io.reticulum.link.LinkStatus.PENDING;
+import static io.reticulum.link.LinkStatus.PENDING;
import static io.reticulum.link.LinkStatus.HANDSHAKE;
//import static io.reticulum.packet.PacketContextType.LINKCLOSE;
//import static io.reticulum.identity.IdentityKnownDestination.recall;
@@ -372,7 +372,7 @@ public class RNSNetwork {
newPeer.setMessageMagic(getMessageMagic());
// make sure the peer has a channel and buffer
newPeer.getOrInitPeerBuffer();
- incomingPeers.add(newPeer);
+ addIncomingPeer(newPeer);
log.info("***> Client connected, link: {}", link);
}
@@ -409,7 +409,7 @@ public class RNSNetwork {
// add to peer list if we can use more peers
//synchronized (this) {
- var lps = RNSNetwork.getInstance().getLinkedPeers();
+ var lps = RNSNetwork.getInstance().getImmutableLinkedPeers();
for (RNSPeer p: lps) {
var pl = p.getPeerLink();
if ((nonNull(pl) && (pl.getStatus() == ACTIVE))) {
@@ -488,11 +488,11 @@ public class RNSNetwork {
final Long now = NTP.getTime();
- // Prune stuck/slow/old peers (moved from Controller)
- task = maybeProduceRNSPrunePeersTask(now);
- if (task != null) {
- return task;
- }
+ //// Prune stuck/slow/old peers (moved from Controller)
+ //task = maybeProduceRNSPrunePeersTask(now);
+ //if (task != null) {
+ // return task;
+ //}
// ping task (Link+Channel+Buffer)
task = maybeProducePeerPingTask(now);
@@ -505,11 +505,11 @@ public class RNSNetwork {
return task;
}
- // Prune stuck/slow/old peers (moved from Controller)
- task = maybeProduceRNSPrunePeersTask(now);
- if (task != null) {
- return task;
- }
+ //// Prune stuck/slow/old peers (moved from Controller)
+ //task = maybeProduceRNSPrunePeersTask(now);
+ //if (task != null) {
+ // return task;
+ //}
return null;
}
@@ -609,9 +609,9 @@ public class RNSNetwork {
}
public void removeLinkedPeer(RNSPeer peer) {
- if (nonNull(peer.getPeerBuffer())) {
- peer.getPeerBuffer().close();
- }
+ //if (nonNull(peer.getPeerBuffer())) {
+ // peer.getPeerBuffer().close();
+ //}
if (nonNull(peer.getPeerLink())) {
peer.getPeerLink().teardown();
}
@@ -649,23 +649,6 @@ public class RNSNetwork {
// TODO, methods for: getAvailablePeer
- // maintenance
- //public void removePeer(RNSPeer peer) {
- // synchronized(this) {
- // List peerList = this.linkedPeers;
- // log.info("removing peer {} on peer shutdown", peer);
- // peerList.remove(peer);
- // }
- //}
-
- //public void pingPeer(RNSPeer peer) {
- // if (nonNull(peer)) {
- // peer.pingRemote();
- // } else {
- // log.error("peer argument is null");
- // }
- //}
-
private Boolean isUnreachable(RNSPeer peer) {
var result = peer.getDeleteMe();
var now = Instant.now();
@@ -713,22 +696,30 @@ public class RNSNetwork {
//@Synchronized
public void prunePeers() throws DataException {
// run periodically (by the Controller)
- var peerList = getLinkedPeers();
- var incomingPeerList = getIncomingPeers();
- log.info("number of links (linkedPeers / incomingPeers) before prunig: {}, {}", peerList.size(),
- incomingPeerList.size());
+ var peerList = getImmutableLinkedPeers();
+ var incomingPeerList = getImmutableIncomingPeers();
+ //log.info("number of links (linkedPeers / incomingPeers) before prunig: {}, {}", peerList.size(),
+ // incomingPeerList.size());
+ log.info("number of links (linkedPeers (active) / incomingPeers before prunig: {} ({}), {}",
+ getImmutableLinkedPeers().size(), getImmutableActiveLinkedPeers().size(),
+ getImmutableIncomingPeers().size());
// prune initiator peers
- List lps = getLinkedPeers();
+ List lps = getImmutableLinkedPeers();
for (RNSPeer p : lps) {
var pLink = p.getPeerLink();
if (nonNull(pLink)) {
- log.info("peer link: {}, status: {}", pLink, pLink.getStatus());
- if (pLink.getStatus() == ACTIVE) {
- p.pingRemote();
+ if (pLink.getStatus() == PENDING) {
+ pLink.teardown();
}
if (p.getPeerTimedOut()) {
pLink.teardown();
}
+ log.info("peer link: {}, status: {}", pLink, pLink.getStatus());
+ if (pLink.getStatus() == ACTIVE) {
+ p.pingRemote();
+ } else {
+ removeLinkedPeer(p);
+ }
}
}
//Link pLink;
@@ -773,15 +764,17 @@ public class RNSNetwork {
List inaps = incomingNonActivePeers();
//log.info("number of inactive incoming peers: {}", inaps.size());
for (RNSPeer p: inaps) {
- incomingPeerList.remove(incomingPeerList.indexOf(p));
+ //incomingPeerList.remove(incomingPeerList.indexOf(p));
+ removeIncomingPeer(p);
}
- log.info("number of links (linkedPeers / incomingPeers) after prunig: {}, {}", peerList.size(),
- incomingPeerList.size());
+ log.info("number of links (linkedPeers (active) / incomingPeers after prunig: {} ({}), {}",
+ getImmutableLinkedPeers().size(), getImmutableActiveLinkedPeers().size(),
+ getImmutableIncomingPeers().size());
maybeAnnounce(getBaseDestination());
}
public void maybeAnnounce(Destination d) {
- if (getLinkedPeers().size() < MIN_DESIRED_PEERS) {
+ if (getImmutableActiveLinkedPeers().size() < MIN_DESIRED_PEERS) {
d.announce();
}
}
diff --git a/src/main/java/org/qortal/network/RNSPeer.java b/src/main/java/org/qortal/network/RNSPeer.java
index 81d693d5..dba40878 100644
--- a/src/main/java/org/qortal/network/RNSPeer.java
+++ b/src/main/java/org/qortal/network/RNSPeer.java
@@ -108,8 +108,8 @@ public class RNSPeer {
// for qortal networking
private static final int RESPONSE_TIMEOUT = 3000; // [ms]
- private static final int PING_INTERVAL = 34_000; // [ms]
- private static final long LINK_PING_INTERVAL = 34 * 1000L; // ms
+ private static final int PING_INTERVAL = 55_000; // [ms]
+ private static final long LINK_PING_INTERVAL = 55 * 1000L; // ms
private byte[] messageMagic; // set in message creating classes
private Long lastPing = null; // last (packet) ping roundtrip time [ms]
private Long lastPingSent = null; // time last (packet) ping was sent, or null if not started.
@@ -370,7 +370,7 @@ public class RNSPeer {
break;
case PONG:
- //log.info("PONG received");
+ log.trace("PONG received");
break;
// Do we need this ? (no need to relay peer list...)
@@ -378,30 +378,30 @@ public class RNSPeer {
// onPeersV2Message(peer, message);
// break;
- case BLOCK_SUMMARIES:
- // from Synchronizer
- addToQueue(message);
- break;
-
- case BLOCK_SUMMARIES_V2:
- // from Synchronizer
- addToQueue(message);
- break;
-
- case SIGNATURES:
- // from Synchronizer
- addToQueue(message);
- break;
-
- case BLOCK:
- // from Synchronizer
- addToQueue(message);
- break;
-
- case BLOCK_V2:
- // from Synchronizer
- addToQueue(message);
- break;
+ //case BLOCK_SUMMARIES:
+ // // from Synchronizer
+ // addToQueue(message);
+ // break;
+ //
+ //case BLOCK_SUMMARIES_V2:
+ // // from Synchronizer
+ // addToQueue(message);
+ // break;
+ //
+ //case SIGNATURES:
+ // // from Synchronizer
+ // addToQueue(message);
+ // break;
+ //
+ //case BLOCK:
+ // // from Synchronizer
+ // addToQueue(message);
+ // break;
+ //
+ //case BLOCK_V2:
+ // // from Synchronizer
+ // addToQueue(message);
+ // break;
default:
log.info("default - type {} message received ({} bytes)", message.getType(), data.length);
@@ -419,7 +419,7 @@ public class RNSPeer {
}
/**
- * we need to queue all incomming messages that follow request/response
+ * we need to queue all incoming messages that follow request/response
* with explicit handling of the response message.
*/
public void addToQueue(Message message) {
@@ -499,10 +499,12 @@ public class RNSPeer {
public void packetTimedOut(PacketReceipt receipt) {
log.info("packet timed out, receipt status: {}", receipt.getStatus());
- if (receipt.getStatus() == PacketReceiptStatus.FAILED) {
- this.peerTimedOut = true;
- this.peerLink.teardown();
- }
+ //if (receipt.getStatus() == PacketReceiptStatus.FAILED) {
+ // this.peerTimedOut = true;
+ // this.peerLink.teardown();
+ //}
+ this.peerTimedOut = true;
+ this.peerLink.teardown();
}
/** Link Request callbacks */
diff --git a/src/main/java/org/qortal/settings/Settings.java b/src/main/java/org/qortal/settings/Settings.java
index f3f84e12..b15abefe 100644
--- a/src/main/java/org/qortal/settings/Settings.java
+++ b/src/main/java/org/qortal/settings/Settings.java
@@ -616,6 +616,8 @@ public class Settings {
// Related to Reticulum networking
+ /** Preferred network: tcpip or reticulum */
+ private String preferredNetwork = "reticulum";
/** Maximum number of Reticulum peers allowed. */
private int reticulumMaxPeers = 55;
/** Minimum number of Reticulum peers desired. */
@@ -1380,6 +1382,10 @@ public class Settings {
return connectionPoolMonitorEnabled;
}
+ public String getPreferredNetwork () {
+ return this.preferredNetwork.toLowerCase(Locale.getDefault());
+ }
+
public int getReticulumMaxPeers() {
return this.reticulumMaxPeers;
}