do not change connection to unsynced monero node

This commit is contained in:
woodser 2026-01-08 12:55:43 -05:00
parent eb492d3ebd
commit ba6b4141aa
No known key found for this signature in database
GPG key ID: 55A10DD48ADEE5EF

View file

@ -76,6 +76,7 @@ public final class XmrConnectionService {
private static final long KEY_IMAGE_REFRESH_PERIOD_MS_LOCAL = 20000; // 20 seconds
private static final long KEY_IMAGE_REFRESH_PERIOD_MS_REMOTE = 300000; // 5 minutes
private static final int MAX_CONSECUTIVE_ERRORS = 3; // max errors before switching connections
private static final int SYNC_TOLERANCE_NUM_BLOCKS = 3;
private static int numConsecutiveErrors = 0;
public enum XmrConnectionFallbackType {
@ -289,11 +290,39 @@ public final class XmrConnectionService {
// get best connection
Set<MoneroRpcConnection> ignoredConnectionsSet = new HashSet<>(ignoredConnections);
addLocalNodeIfIgnored(ignoredConnectionsSet);
MoneroRpcConnection bestConnection = connectionManager.getBestAvailableConnection(ignoredConnectionsSet.toArray(new MoneroRpcConnection[0])); // checks connections
if (bestConnection == null && connectionManager.getConnections().size() == 1 && !ignoredConnectionsSet.contains(connectionManager.getConnections().get(0))) bestConnection = connectionManager.getConnections().get(0);
MoneroRpcConnection bestConnection = connectionManager.getBestAvailableConnection(ignoredConnectionsSet.toArray(new MoneroRpcConnection[0])); // checks connections // TODO: capture set of connections to avoid repeatedly querying their status
// return only connection if no best connection
if (bestConnection == null && connectionManager.getConnections().size() == 1 && !ignoredConnectionsSet.contains(connectionManager.getConnections().get(0))) {
return connectionManager.getConnections().get(0);
}
// return next best connection if not connected or synced
if (bestConnection != null && bestConnection.isConnected() && !isSyncedWithinTolerance(new MoneroDaemonRpc(bestConnection))) {
ignoredConnectionsSet.add(bestConnection);
MoneroRpcConnection nextBestConnection = getBestConnection(ignoredConnectionsSet);
if (nextBestConnection != null) bestConnection = nextBestConnection;
}
return bestConnection;
}
private static boolean isSyncedWithinTolerance(MoneroDaemonRpc monerod) {
try {
return isSyncedWithinTolerance(monerod.getInfo());
} catch (Exception e) {
log.warn("Error checking if connection is synced within tolerance, connection={}, error={}", monerod.getRpcConnection().getUri(), e.getMessage());
return false;
}
}
private static boolean isSyncedWithinTolerance(MoneroDaemonInfo info) {
Long targetHeight = getTargetHeight(info);
if (targetHeight == null) return false;
if (targetHeight - getHeight(info) <= SYNC_TOLERANCE_NUM_BLOCKS) return true; // synced if within 3 blocks of target height
return false;
}
private boolean fallbackRequiredBeforeConnectionSwitch() {
return lastInfo == null && !fallbackApplied && usedSyncingLocalNodeBeforeStartup && (!xmrLocalNode.isDetected() || xmrLocalNode.shouldBeIgnored());
}
@ -418,20 +447,25 @@ public final class XmrConnectionService {
}
public Long getHeight() {
if (lastInfo == null) return null;
return lastInfo.getHeight();
return getHeight(lastInfo);
}
private static Long getHeight(MoneroDaemonInfo info) {
if (info == null) return null;
return info.getHeightWithoutBootstrap() == null || info.getHeightWithoutBootstrap() == 0 ? info.getHeight() : info.getHeightWithoutBootstrap();
}
public Long getTargetHeight() {
if (lastInfo == null) return null;
return lastInfo.getTargetHeight() == 0 ? lastInfo.getHeight() : lastInfo.getTargetHeight();
return getTargetHeight(lastInfo);
}
private static Long getTargetHeight(MoneroDaemonInfo info) {
if (info == null) return null;
return info.getTargetHeight() == 0 ? info.getHeight() : info.getTargetHeight();
}
public boolean isSyncedWithinTolerance() {
Long targetHeight = getTargetHeight();
if (targetHeight == null) return false;
if (targetHeight - chainHeight.get() <= 3) return true; // synced if within 3 blocks of target height
return false;
return isSyncedWithinTolerance(lastInfo);
}
public XmrKeyImagePoller getKeyImagePoller() {
@ -607,14 +641,19 @@ public final class XmrConnectionService {
}
// update connection
boolean isCurrentConnection = getConnection() != null && getConnection().getUri().equals(connection.getUri());
if (isConnected) {
setConnection(connection.getUri());
// reset error connecting to local node
if (connectionServiceFallbackType.get() == XmrConnectionFallbackType.LOCAL && isConnectionLocalHost()) {
connectionServiceFallbackType.set(null);
// set connection if local node is synced
if (isSyncedWithinTolerance(xmrLocalNode.getDaemon())) {
setConnection(connection.getUri());
// reset error connecting to local node
if (connectionServiceFallbackType.get() == XmrConnectionFallbackType.LOCAL && isConnectionLocalHost()) {
connectionServiceFallbackType.set(null);
}
}
} else if (getConnection() != null && getConnection().getUri().equals(connection.getUri())) {
} else if (isCurrentConnection) {
MoneroRpcConnection bestConnection = getBestConnection();
if (bestConnection != null) setConnection(bestConnection); // switch to best connection
}
@ -863,7 +902,7 @@ public final class XmrConnectionService {
connectionServiceFallbackType.set(null);
// set chain height
chainHeight.set(lastInfo.getHeight());
chainHeight.set(getHeight());
// determine if blockchain is syncing locally
boolean blockchainSyncing = lastInfo.getHeight().equals(lastInfo.getHeightWithoutBootstrap()) || (lastInfo.getTargetHeight().equals(0l) && lastInfo.getHeightWithoutBootstrap().equals(0l)); // blockchain is syncing if height equals height without bootstrap, or target height and height without bootstrap both equal 0