24
24
import haveno .common .app .DevEnv ;
25
25
import haveno .common .config .BaseCurrencyNetwork ;
26
26
import haveno .common .config .Config ;
27
- import haveno .core .locale .Res ;
28
27
import haveno .core .trade .HavenoUtils ;
29
28
import haveno .core .user .Preferences ;
30
29
import haveno .core .xmr .model .EncryptedConnectionList ;
@@ -73,6 +72,11 @@ public final class XmrConnectionService {
73
72
private static final long REFRESH_PERIOD_HTTP_MS = 20000 ; // refresh period when connected to remote node over http
74
73
private static final long REFRESH_PERIOD_ONION_MS = 30000 ; // refresh period when connected to remote node over tor
75
74
75
+ public enum XmrConnectionError {
76
+ LOCAL ,
77
+ CUSTOM
78
+ }
79
+
76
80
private final Object lock = new Object ();
77
81
private final Object pollLock = new Object ();
78
82
private final Object listenerLock = new Object ();
@@ -90,7 +94,7 @@ public final class XmrConnectionService {
90
94
private final LongProperty chainHeight = new SimpleLongProperty (0 );
91
95
private final DownloadListener downloadListener = new DownloadListener ();
92
96
@ Getter
93
- private final SimpleStringProperty connectionServiceFallbackHandler = new SimpleStringProperty ();
97
+ private final ObjectProperty < XmrConnectionError > connectionServiceError = new SimpleObjectProperty <> ();
94
98
@ Getter
95
99
private final StringProperty connectionServiceErrorMsg = new SimpleStringProperty ();
96
100
private final LongProperty numUpdates = new SimpleLongProperty (0 );
@@ -119,7 +123,7 @@ public final class XmrConnectionService {
119
123
private int numRequestsLastMinute ;
120
124
private long lastSwitchTimestamp ;
121
125
private Set <MoneroRpcConnection > excludedConnections = new HashSet <>();
122
- private static final long FALLBACK_INVOCATION_PERIOD_MS = 1000 * 60 * 1 ; // offer to fallback up to once every minute
126
+ private static final long FALLBACK_INVOCATION_PERIOD_MS = 1000 * 30 * 1 ; // offer to fallback up to once every 30s
123
127
private boolean fallbackApplied ;
124
128
125
129
@ Inject
@@ -260,7 +264,14 @@ public MoneroRpcConnection getBestConnection() {
260
264
261
265
private MoneroRpcConnection getBestConnection (Collection <MoneroRpcConnection > ignoredConnections ) {
262
266
accountService .checkAccountOpen ();
263
- if (!fallbackApplied && lastUsedLocalSyncingNode () && !xmrLocalNode .isDetected ()) return null ; // user needs to explicitly allow fallback after syncing local node
267
+
268
+ // user needs to authorize fallback on startup after using locally synced node
269
+ if (lastInfo == null && !fallbackApplied && lastUsedLocalSyncingNode () && !xmrLocalNode .isDetected ()) {
270
+ log .warn ("Cannot get best connection on startup because we last synced local node and user has not opted to fallback" );
271
+ return null ;
272
+ }
273
+
274
+ // get best connection
264
275
Set <MoneroRpcConnection > ignoredConnectionsSet = new HashSet <>(ignoredConnections );
265
276
addLocalNodeIfIgnored (ignoredConnectionsSet );
266
277
MoneroRpcConnection bestConnection = connectionManager .getBestAvailableConnection (ignoredConnectionsSet .toArray (new MoneroRpcConnection [0 ])); // checks connections
@@ -543,6 +554,11 @@ public void onConnectionChanged(MoneroRpcConnection connection) {
543
554
// update connection
544
555
if (isConnected ) {
545
556
setConnection (connection .getUri ());
557
+
558
+ // reset error connecting to local node
559
+ if (connectionServiceError .get () == XmrConnectionError .LOCAL && isConnectionLocalHost ()) {
560
+ connectionServiceError .set (null );
561
+ }
546
562
} else if (getConnection () != null && getConnection ().getUri ().equals (connection .getUri ())) {
547
563
MoneroRpcConnection bestConnection = getBestConnection ();
548
564
if (bestConnection != null ) setConnection (bestConnection ); // switch to best connection
@@ -632,6 +648,27 @@ private boolean lastUsedLocalSyncingNode() {
632
648
return connectionManager .getConnection () != null && xmrLocalNode .equalsUri (connectionManager .getConnection ().getUri ()) && !xmrLocalNode .isDetected () && !xmrLocalNode .shouldBeIgnored ();
633
649
}
634
650
651
+ public void startLocalNode () {
652
+
653
+ // cannot start local node as seed node
654
+ if (HavenoUtils .isSeedNode ()) {
655
+ throw new RuntimeException ("Cannot start local node on seed node" );
656
+ }
657
+
658
+ // start local node if offline and used as last connection
659
+ if (connectionManager .getConnection () != null && xmrLocalNode .equalsUri (connectionManager .getConnection ().getUri ()) && !xmrLocalNode .isDetected () && !xmrLocalNode .shouldBeIgnored ()) {
660
+ try {
661
+ log .info ("Starting local node" );
662
+ xmrLocalNode .start ();
663
+ } catch (Exception e ) {
664
+ log .error ("Unable to start local monero node, error={}\n " , e .getMessage (), e );
665
+ throw new RuntimeException (e );
666
+ }
667
+ } else {
668
+ throw new RuntimeException ("Local node is not offline and used as last connection" );
669
+ }
670
+ }
671
+
635
672
private void onConnectionChanged (MoneroRpcConnection currentConnection ) {
636
673
if (isShutDownStarted || !accountService .isAccountOpen ()) return ;
637
674
if (currentConnection == null ) {
@@ -717,14 +754,14 @@ private void doPollDaemon() {
717
754
// invoke fallback handling on startup error
718
755
boolean canFallback = isFixedConnection () || isCustomConnections () || lastUsedLocalSyncingNode ();
719
756
if (lastInfo == null && canFallback ) {
720
- if (connectionServiceFallbackHandler .get () == null || connectionServiceFallbackHandler . equals ( "" ) && (lastFallbackInvocation == null || System .currentTimeMillis () - lastFallbackInvocation > FALLBACK_INVOCATION_PERIOD_MS )) {
757
+ if (connectionServiceError .get () == null && (lastFallbackInvocation == null || System .currentTimeMillis () - lastFallbackInvocation > FALLBACK_INVOCATION_PERIOD_MS )) {
721
758
lastFallbackInvocation = System .currentTimeMillis ();
722
759
if (lastUsedLocalSyncingNode ()) {
723
760
log .warn ("Failed to fetch daemon info from local connection on startup: " + e .getMessage ());
724
- connectionServiceFallbackHandler .set (Res . get ( "connectionFallback.localNode" ) );
761
+ connectionServiceError .set (XmrConnectionError . LOCAL );
725
762
} else {
726
763
log .warn ("Failed to fetch daemon info from custom connection on startup: " + e .getMessage ());
727
- connectionServiceFallbackHandler .set (Res . get ( "connectionFallback.customNode" ) );
764
+ connectionServiceError .set (XmrConnectionError . CUSTOM );
728
765
}
729
766
}
730
767
return ;
0 commit comments