temporarily disconnect from whirlpool if gap limit is increasing rapidly

This commit is contained in:
Craig Raw 2023-11-08 11:59:19 +02:00
parent 0d7ae74f0f
commit 995d2c5e4e
5 changed files with 64 additions and 1 deletions

View file

@ -999,7 +999,7 @@ public class TransactionDiagram extends GridPane {
} }
private boolean isDuplicateAddress(Payment payment) { private boolean isDuplicateAddress(Payment payment) {
return walletTx.getPayments().stream().filter(p -> payment != p).anyMatch(p -> payment.getAddress().equals(p.getAddress())); return walletTx.getPayments().stream().filter(p -> payment != p).anyMatch(p -> payment.getAddress() != null && payment.getAddress().equals(p.getAddress()));
} }
public static Glyph getExcludeGlyph() { public static Glyph getExcludeGlyph() {

View file

@ -0,0 +1,15 @@
package com.sparrowwallet.sparrow.event;
import com.sparrowwallet.drongo.wallet.Wallet;
public class WhirlpoolIndexHighFrequencyEvent {
private final Wallet wallet;
public WhirlpoolIndexHighFrequencyEvent(Wallet wallet) {
this.wallet = wallet;
}
public Wallet getWallet() {
return wallet;
}
}

View file

@ -45,6 +45,7 @@ import javafx.beans.property.SimpleBooleanProperty;
import javafx.concurrent.ScheduledService; import javafx.concurrent.ScheduledService;
import javafx.concurrent.Service; import javafx.concurrent.Service;
import javafx.concurrent.Task; import javafx.concurrent.Task;
import javafx.util.Duration;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -75,6 +76,7 @@ public class Whirlpool {
private boolean resyncMixesDone; private boolean resyncMixesDone;
private StartupService startupService; private StartupService startupService;
private Duration startupServiceDelay;
private final BooleanProperty startingProperty = new SimpleBooleanProperty(false); private final BooleanProperty startingProperty = new SimpleBooleanProperty(false);
private final BooleanProperty stoppingProperty = new SimpleBooleanProperty(false); private final BooleanProperty stoppingProperty = new SimpleBooleanProperty(false);
@ -563,6 +565,14 @@ public class Whirlpool {
return stoppingProperty; return stoppingProperty;
} }
public Duration getStartupServiceDelay() {
return startupServiceDelay;
}
public void setStartupServiceDelay(Duration startupServiceDelay) {
this.startupServiceDelay = startupServiceDelay;
}
@Subscribe @Subscribe
public void onMixSuccess(MixSuccessEvent e) { public void onMixSuccess(MixSuccessEvent e) {
WalletUtxo walletUtxo = getUtxo(e.getWhirlpoolUtxo()); WalletUtxo walletUtxo = getUtxo(e.getWhirlpoolUtxo());

View file

@ -15,6 +15,7 @@ import com.sparrowwallet.sparrow.WalletTabData;
import com.sparrowwallet.sparrow.event.*; import com.sparrowwallet.sparrow.event.*;
import com.sparrowwallet.sparrow.io.Storage; import com.sparrowwallet.sparrow.io.Storage;
import com.sparrowwallet.sparrow.soroban.Soroban; import com.sparrowwallet.sparrow.soroban.Soroban;
import javafx.application.Platform;
import javafx.scene.input.KeyCode; import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyCodeCombination; import javafx.scene.input.KeyCodeCombination;
import javafx.scene.input.KeyCombination; import javafx.scene.input.KeyCombination;
@ -105,6 +106,11 @@ public class WhirlpoolServices {
} }
Whirlpool.StartupService startupService = whirlpool.createStartupService(); Whirlpool.StartupService startupService = whirlpool.createStartupService();
if(whirlpool.getStartupServiceDelay() != null) {
startupService.setDelay(whirlpool.getStartupServiceDelay());
whirlpool.setStartupServiceDelay(null);
}
startupService.setPeriod(Duration.minutes(2)); startupService.setPeriod(Duration.minutes(2));
startupService.setOnSucceeded(workerStateEvent -> { startupService.setOnSucceeded(workerStateEvent -> {
startupService.cancel(); startupService.cancel();
@ -281,4 +287,17 @@ public class WhirlpoolServices {
whirlpool.refreshUtxos(); whirlpool.refreshUtxos();
} }
} }
@Subscribe
public void whirlpoolIndexHighFrequency(WhirlpoolIndexHighFrequencyEvent event) {
Whirlpool whirlpool = getWhirlpool(event.getWallet());
if(whirlpool != null && whirlpool.isStarted() && !whirlpool.isStopping()) {
log.warn("Rapidly increasing address index detected, temporarily disconnecting " + event.getWallet().getMasterName() + " from Whirlpool");
Platform.runLater(() -> {
EventManager.get().post(new StatusEvent("Error communicating with Whirlpool, will retry soon..."));
whirlpool.setStartupServiceDelay(Duration.minutes(5));
stopWhirlpool(whirlpool, false);
});
}
}
} }

View file

@ -8,12 +8,17 @@ import com.sparrowwallet.sparrow.AppServices;
import com.sparrowwallet.sparrow.EventManager; import com.sparrowwallet.sparrow.EventManager;
import com.sparrowwallet.sparrow.event.WalletGapLimitChangedEvent; import com.sparrowwallet.sparrow.event.WalletGapLimitChangedEvent;
import com.sparrowwallet.sparrow.event.WalletMixConfigChangedEvent; import com.sparrowwallet.sparrow.event.WalletMixConfigChangedEvent;
import com.sparrowwallet.sparrow.event.WhirlpoolIndexHighFrequencyEvent;
public class SparrowIndexHandler extends AbstractIndexHandler { public class SparrowIndexHandler extends AbstractIndexHandler {
private final Wallet wallet; private final Wallet wallet;
private final WalletNode walletNode; private final WalletNode walletNode;
private final int defaultValue; private final int defaultValue;
private static final long PERIOD = 1000 * 60 * 10L; //Period of 10 minutes
private long periodStart;
private int periodCount;
public SparrowIndexHandler(Wallet wallet, WalletNode walletNode) { public SparrowIndexHandler(Wallet wallet, WalletNode walletNode) {
this(wallet, walletNode, 0); this(wallet, walletNode, 0);
} }
@ -77,6 +82,20 @@ public class SparrowIndexHandler extends AbstractIndexHandler {
if(index > highestUsedIndex + existingGapLimit) { if(index > highestUsedIndex + existingGapLimit) {
wallet.setGapLimit(Math.max(wallet.getGapLimit(), index - highestUsedIndex)); wallet.setGapLimit(Math.max(wallet.getGapLimit(), index - highestUsedIndex));
EventManager.get().post(new WalletGapLimitChangedEvent(getWalletId(), wallet, existingGapLimit)); EventManager.get().post(new WalletGapLimitChangedEvent(getWalletId(), wallet, existingGapLimit));
checkFrequency();
}
}
private void checkFrequency() {
if(periodStart > 0 && System.currentTimeMillis() - periodStart < PERIOD) {
periodCount++;
} else {
periodStart = System.currentTimeMillis();
periodCount = 0;
}
if(periodCount >= Wallet.DEFAULT_LOOKAHEAD) {
EventManager.get().post(new WhirlpoolIndexHighFrequencyEvent(wallet));
} }
} }