Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix connection issues #1102

Merged
merged 6 commits into from
Jul 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions common/src/main/java/haveno/common/ThreadUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ public static Future<?> execute(Runnable command, String threadId) {
synchronized (THREADS) {
THREADS.put(threadId, Thread.currentThread());
}
Thread.currentThread().setName(threadId);
command.run();
});
}
Expand Down
75 changes: 67 additions & 8 deletions core/src/main/java/haveno/core/api/XmrConnectionService.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,10 @@
import haveno.network.p2p.P2PService;
import haveno.network.p2p.P2PServiceListener;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.LongProperty;
Expand Down Expand Up @@ -103,6 +106,12 @@ public final class XmrConnectionService {
private boolean isShutDownStarted;
private List<MoneroConnectionManagerListener> listeners = new ArrayList<>();

// connection switching
private static final int EXCLUDE_CONNECTION_SECONDS = 300;
private static final int SKIP_SWITCH_WITHIN_MS = 60000;
private Set<MoneroRpcConnection> excludedConnections = new HashSet<>();
private long lastSwitchRequestTimestamp;

@Inject
public XmrConnectionService(P2PService p2PService,
Config config,
Expand Down Expand Up @@ -201,12 +210,6 @@ public List<MoneroRpcConnection> getConnections() {
return connectionManager.getConnections();
}

public void switchToBestConnection() {
if (isFixedConnection() || !connectionManager.getAutoSwitch()) return;
MoneroRpcConnection bestConnection = getBestAvailableConnection();
if (bestConnection != null) setConnection(bestConnection);
}

public void setConnection(String connectionUri) {
accountService.checkAccountOpen();
connectionManager.setConnection(connectionUri); // listener will update connection list
Expand Down Expand Up @@ -244,10 +247,67 @@ public void stopCheckingConnection() {
public MoneroRpcConnection getBestAvailableConnection() {
accountService.checkAccountOpen();
List<MoneroRpcConnection> ignoredConnections = new ArrayList<MoneroRpcConnection>();
if (xmrLocalNode.shouldBeIgnored() && connectionManager.hasConnection(xmrLocalNode.getUri())) ignoredConnections.add(connectionManager.getConnectionByUri(xmrLocalNode.getUri()));
addLocalNodeIfIgnored(ignoredConnections);
return connectionManager.getBestAvailableConnection(ignoredConnections.toArray(new MoneroRpcConnection[0]));
}

private MoneroRpcConnection getBestAvailableConnection(Collection<MoneroRpcConnection> ignoredConnections) {
accountService.checkAccountOpen();
Set<MoneroRpcConnection> ignoredConnectionsSet = new HashSet<>(ignoredConnections);
addLocalNodeIfIgnored(ignoredConnectionsSet);
return connectionManager.getBestAvailableConnection(ignoredConnectionsSet.toArray(new MoneroRpcConnection[0]));
}

private void addLocalNodeIfIgnored(Collection<MoneroRpcConnection> ignoredConnections) {
if (xmrLocalNode.shouldBeIgnored() && connectionManager.hasConnection(xmrLocalNode.getUri())) ignoredConnections.add(connectionManager.getConnectionByUri(xmrLocalNode.getUri()));
}

private void switchToBestConnection() {
if (isFixedConnection() || !connectionManager.getAutoSwitch()) {
log.info("Skipping switch to best Monero connection because connection is fixed or auto switch is disabled");
return;
}
MoneroRpcConnection bestConnection = getBestAvailableConnection();
if (bestConnection != null) setConnection(bestConnection);
}

public boolean requestSwitchToNextBestConnection() {
log.warn("Request made to switch to next best monerod, current monerod={}", getConnection() == null ? null : getConnection().getUri());

// skip if connection is fixed
if (isFixedConnection() || !connectionManager.getAutoSwitch()) {
log.info("Skipping switch to next best Monero connection because connection is fixed or auto switch is disabled");
return false;
}

// skip if last switch was too recent
boolean skipSwitch = System.currentTimeMillis() - lastSwitchRequestTimestamp < SKIP_SWITCH_WITHIN_MS;
lastSwitchRequestTimestamp = System.currentTimeMillis();
if (skipSwitch) {
log.warn("Skipping switch to next best Monero connection because last switch was less than {} seconds ago", SKIP_SWITCH_WITHIN_MS / 1000);
lastSwitchRequestTimestamp = System.currentTimeMillis();
return false;
}

// try to get connection to switch to
MoneroRpcConnection currentConnection = getConnection();
if (currentConnection != null) excludedConnections.add(currentConnection);
MoneroRpcConnection bestConnection = getBestAvailableConnection(excludedConnections);

// remove from excluded connections after period
UserThread.runAfter(() -> {
if (currentConnection != null) excludedConnections.remove(currentConnection);
}, EXCLUDE_CONNECTION_SECONDS);

// switch to best connection
if (bestConnection == null) {
log.warn("Could not get connection to switch to");
return false;
}
setConnection(bestConnection);
return true;
}

public void setAutoSwitch(boolean autoSwitch) {
accountService.checkAccountOpen();
connectionManager.setAutoSwitch(autoSwitch);
Expand Down Expand Up @@ -505,7 +565,6 @@ public void onConnectionChanged(MoneroRpcConnection connection) {

// register connection listener
connectionManager.addListener(this::onConnectionChanged);

isInitialized = true;
}

Expand Down
2 changes: 1 addition & 1 deletion core/src/main/java/haveno/core/app/HavenoSetup.java
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@
public class HavenoSetup {
private static final String VERSION_FILE_NAME = "version";

private static final long STARTUP_TIMEOUT_MINUTES = 5;
private static final long STARTUP_TIMEOUT_MINUTES = 4;

private final DomainInitialisation domainInitialisation;
private final P2PNetworkSetup p2PNetworkSetup;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1057,6 +1057,7 @@ private MoneroTxWallet splitAndSchedule(OpenOffer openOffer) {
} catch (Exception e) {
log.warn("Error creating split output tx to fund offer {} at subaddress {}, attempt={}/{}, error={}", openOffer.getShortId(), entry.getSubaddressIndex(), i + 1, TradeProtocol.MAX_ATTEMPTS, e.getMessage());
if (stopped || i == TradeProtocol.MAX_ATTEMPTS - 1) throw e;
if (xmrConnectionService.isConnected()) xmrWalletService.requestSwitchToNextBestConnection();
HavenoUtils.waitFor(TradeProtocol.REPROCESS_DELAY_MS); // wait before retrying
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ protected void run() {
log.warn("Error creating reserve tx, attempt={}/{}, offerId={}, error={}", i + 1, TradeProtocol.MAX_ATTEMPTS, openOffer.getShortId(), e.getMessage());
if (i == TradeProtocol.MAX_ATTEMPTS - 1) throw e;
model.getProtocol().startTimeoutTimer(); // reset protocol timeout
if (model.getXmrWalletService().getConnectionService().isConnected()) model.getXmrWalletService().requestSwitchToNextBestConnection();
HavenoUtils.waitFor(TradeProtocol.REPROCESS_DELAY_MS); // wait before retrying
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -478,6 +478,7 @@ private MoneroTxSet signAndPublishDisputePayoutTx(Trade trade) {
if (trade.isPayoutPublished()) throw new IllegalStateException("Payout tx already published for " + trade.getClass().getSimpleName() + " " + trade.getShortId());
log.warn("Failed to submit dispute payout tx, attempt={}/{}, tradeId={}, error={}", i + 1, TradeProtocol.MAX_ATTEMPTS, trade.getShortId(), e.getMessage());
if (i == TradeProtocol.MAX_ATTEMPTS - 1) throw e;
if (trade.getXmrConnectionService().isConnected()) trade.requestSwitchToNextBestConnection();
HavenoUtils.waitFor(TradeProtocol.REPROCESS_DELAY_MS); // wait before retrying
}
}
Expand Down
Loading
Loading