mirror of
https://github.com/sparrowwallet/sparrow.git
synced 2024-12-23 20:36:44 +00:00
upgrade to bwt with earlier termination, various bitcoin core related ui changes
This commit is contained in:
parent
628b15a3b5
commit
546ccd66b3
13 changed files with 99 additions and 66 deletions
|
@ -69,7 +69,7 @@ dependencies {
|
|||
exclude group: 'org.openjfx', module: 'javafx-web'
|
||||
exclude group: 'org.openjfx', module: 'javafx-media'
|
||||
}
|
||||
implementation('dev.bwt:bwt-jni:0.1.5')
|
||||
implementation('dev.bwt:bwt-jni:0.1.6')
|
||||
testImplementation('junit:junit:4.12')
|
||||
}
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@ import com.sparrowwallet.sparrow.control.*;
|
|||
import com.sparrowwallet.sparrow.event.*;
|
||||
import com.sparrowwallet.sparrow.io.*;
|
||||
import com.sparrowwallet.sparrow.net.ElectrumServer;
|
||||
import com.sparrowwallet.sparrow.net.ServerType;
|
||||
import com.sparrowwallet.sparrow.preferences.PreferencesDialog;
|
||||
import com.sparrowwallet.sparrow.transaction.TransactionController;
|
||||
import com.sparrowwallet.sparrow.transaction.TransactionData;
|
||||
|
@ -223,6 +224,7 @@ public class AppController implements Initializable {
|
|||
showTxHex.setSelected(Config.get().isShowTransactionHex());
|
||||
exportWallet.setDisable(true);
|
||||
|
||||
setServerType(Config.get().getServerType());
|
||||
serverToggle.setSelected(isConnected());
|
||||
onlineProperty().bindBidirectional(serverToggle.selectedProperty());
|
||||
onlineProperty().addListener((observable, oldValue, newValue) -> {
|
||||
|
@ -1042,6 +1044,14 @@ public class AppController implements Initializable {
|
|||
return contextMenu;
|
||||
}
|
||||
|
||||
public void setServerType(ServerType serverType) {
|
||||
if(serverType == ServerType.BITCOIN_CORE && !serverToggle.getStyleClass().contains("core-server")) {
|
||||
serverToggle.getStyleClass().add("core-server");
|
||||
} else {
|
||||
serverToggle.getStyleClass().remove("core-server");
|
||||
}
|
||||
}
|
||||
|
||||
public void setTheme(ActionEvent event) {
|
||||
Theme selectedTheme = (Theme)theme.getSelectedToggle().getUserData();
|
||||
if(Config.get().getTheme() != selectedTheme) {
|
||||
|
@ -1063,6 +1073,11 @@ public class AppController implements Initializable {
|
|||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void serverTypeChanged(ServerTypeChangedEvent event) {
|
||||
setServerType(event.getServerType());
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void tabSelected(TabSelectedEvent event) {
|
||||
if(tabs.getTabs().contains(event.getTab())) {
|
||||
|
|
|
@ -2,6 +2,7 @@ package com.sparrowwallet.sparrow.control;
|
|||
|
||||
import com.sparrowwallet.sparrow.AppServices;
|
||||
import com.sparrowwallet.sparrow.Mode;
|
||||
import com.sparrowwallet.sparrow.net.ServerType;
|
||||
import javafx.application.HostServices;
|
||||
import javafx.geometry.Insets;
|
||||
import javafx.scene.control.*;
|
||||
|
@ -13,13 +14,10 @@ import org.controlsfx.control.StatusBar;
|
|||
import org.controlsfx.control.ToggleSwitch;
|
||||
|
||||
public class WelcomeDialog extends Dialog<Mode> {
|
||||
private static final String[] ELECTRUM_SERVERS = new String[]{
|
||||
"ElectrumX (Recommended)", "https://github.com/spesmilo/electrumx",
|
||||
"electrs", "https://github.com/romanz/electrs",
|
||||
"esplora-electrs", "https://github.com/Blockstream/electrs"};
|
||||
|
||||
private final HostServices hostServices;
|
||||
|
||||
private ServerType serverType = ServerType.ELECTRUM_SERVER;
|
||||
|
||||
public WelcomeDialog(HostServices services) {
|
||||
this.hostServices = services;
|
||||
|
||||
|
@ -30,7 +28,7 @@ public class WelcomeDialog extends Dialog<Mode> {
|
|||
dialogPane.getStylesheets().add(AppServices.class.getResource("general.css").toExternalForm());
|
||||
AppServices.setStageIcon(dialogPane.getScene().getWindow());
|
||||
dialogPane.setPrefWidth(600);
|
||||
dialogPane.setPrefHeight(480);
|
||||
dialogPane.setPrefHeight(520);
|
||||
|
||||
Image image = new Image("image/sparrow-small.png", 50, 50, false, false);
|
||||
if (!image.isError()) {
|
||||
|
@ -46,16 +44,10 @@ public class WelcomeDialog extends Dialog<Mode> {
|
|||
|
||||
final VBox content = new VBox(20);
|
||||
content.setPadding(new Insets(20, 20, 20, 20));
|
||||
content.getChildren().add(createParagraph("Sparrow can operate in both an online and offline mode. In the online mode it connects to your Electrum server to display transaction history. In the offline mode it is useful as a transaction editor and as an airgapped multisig coordinator."));
|
||||
content.getChildren().add(createParagraph("For privacy and security reasons it is not recommended to use a public Electrum server. Install an Electrum server that connects to your full node to index the blockchain and provide full privacy. Examples include:"));
|
||||
|
||||
VBox linkBox = new VBox();
|
||||
for(int i = 0; i < ELECTRUM_SERVERS.length; i+=2) {
|
||||
linkBox.getChildren().add(createBulletedLink(ELECTRUM_SERVERS[i], ELECTRUM_SERVERS[i+1]));
|
||||
}
|
||||
content.getChildren().add(linkBox);
|
||||
|
||||
content.getChildren().add(createParagraph("You can change your mode at any time using the toggle in the status bar:"));
|
||||
content.getChildren().add(createParagraph("Sparrow can operate in both an online and offline mode. In the online mode it connects to your Bitcoin Core node or Electrum server to display transaction history. In the offline mode it is useful as a transaction editor and as an airgapped multisig coordinator."));
|
||||
content.getChildren().add(createParagraph("Connecting Sparrow to your Bitcoin Core node ensures your privacy, while connecting Sparrow to your own Electrum server ensures wallets load quicker, you have access to a full blockchain explorer, and your public keys are always encrypted on disk. Examples of Electrum servers include ElectrumX and electrs."));
|
||||
content.getChildren().add(createParagraph("It's also possible to connect Sparrow to a public Electrum server (such as blockstream.info:700) but this is not recommended as you will share your public key information with that server."));
|
||||
content.getChildren().add(createParagraph("You can change your mode at any time using the toggle in the status bar. A blue toggle indicates you are connected to an Electrum server, while a green toggle indicates you are connected to a Bitcoin Code node."));
|
||||
content.getChildren().add(createStatusBar(onlineButtonType, offlineButtonType));
|
||||
|
||||
dialogPane.setContent(content);
|
||||
|
@ -70,16 +62,6 @@ public class WelcomeDialog extends Dialog<Mode> {
|
|||
return label;
|
||||
}
|
||||
|
||||
private HyperlinkLabel createBulletedLink(String name, String url) {
|
||||
String[] nameParts = name.split(" ");
|
||||
HyperlinkLabel label = new HyperlinkLabel(" \u2022 [" + nameParts[0] + "] " + (nameParts.length > 1 ? nameParts[1] : ""));
|
||||
label.setOnAction(event -> {
|
||||
hostServices.showDocument(url);
|
||||
});
|
||||
|
||||
return label;
|
||||
}
|
||||
|
||||
private StatusBar createStatusBar(ButtonType onlineButtonType, ButtonType offlineButtonType) {
|
||||
StatusBar statusBar = new StatusBar();
|
||||
statusBar.setText("Online Mode");
|
||||
|
@ -97,7 +79,18 @@ public class WelcomeDialog extends Dialog<Mode> {
|
|||
onlineButton.setDefaultButton(newValue);
|
||||
Button offlineButton = (Button) getDialogPane().lookupButton(offlineButtonType);
|
||||
offlineButton.setDefaultButton(!newValue);
|
||||
statusBar.setText(newValue ? "Online Mode" : "Offline Mode");
|
||||
|
||||
if(!newValue) {
|
||||
serverType = (serverType == ServerType.BITCOIN_CORE ? ServerType.ELECTRUM_SERVER : ServerType.BITCOIN_CORE);
|
||||
|
||||
if(serverType == ServerType.BITCOIN_CORE && !toggleSwitch.getStyleClass().contains("core-server")) {
|
||||
toggleSwitch.getStyleClass().add("core-server");
|
||||
} else {
|
||||
toggleSwitch.getStyleClass().remove("core-server");
|
||||
}
|
||||
}
|
||||
|
||||
statusBar.setText(newValue ? "Online Mode: " + serverType.getName() : "Offline Mode");
|
||||
});
|
||||
|
||||
toggleSwitch.setSelected(true);
|
||||
|
|
|
@ -1,14 +1,7 @@
|
|||
package com.sparrowwallet.sparrow.event;
|
||||
|
||||
public class BwtReadyStatusEvent extends BwtStatusEvent {
|
||||
private final long shutdownPtr;
|
||||
|
||||
public BwtReadyStatusEvent(String status, long shutdownPtr) {
|
||||
public BwtReadyStatusEvent(String status) {
|
||||
super(status);
|
||||
this.shutdownPtr = shutdownPtr;
|
||||
}
|
||||
|
||||
public long getShutdownPtr() {
|
||||
return shutdownPtr;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
package com.sparrowwallet.sparrow.event;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
public class BwtSyncStatusEvent extends BwtStatusEvent {
|
||||
private final int progress;
|
||||
private final int tip;
|
||||
private final Date tip;
|
||||
|
||||
public BwtSyncStatusEvent(String status, int progress, int tip) {
|
||||
public BwtSyncStatusEvent(String status, int progress, Date tip) {
|
||||
super(status);
|
||||
this.progress = progress;
|
||||
this.tip = tip;
|
||||
|
@ -18,7 +20,7 @@ public class BwtSyncStatusEvent extends BwtStatusEvent {
|
|||
return progress == 100;
|
||||
}
|
||||
|
||||
public int getTip() {
|
||||
public Date getTip() {
|
||||
return tip;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
package com.sparrowwallet.sparrow.event;
|
||||
|
||||
import com.sparrowwallet.sparrow.net.ServerType;
|
||||
|
||||
public class ServerTypeChangedEvent {
|
||||
private final ServerType serverType;
|
||||
|
||||
public ServerTypeChangedEvent(ServerType serverType) {
|
||||
this.serverType = serverType;
|
||||
}
|
||||
|
||||
public ServerType getServerType() {
|
||||
return serverType;
|
||||
}
|
||||
}
|
|
@ -204,7 +204,8 @@ public class BatchedElectrumServerRpc implements ElectrumServerRpc {
|
|||
}
|
||||
|
||||
try {
|
||||
return new RetryLogic<Map<String, VerboseTransaction>>(MAX_RETRIES, RETRY_DELAY, IllegalStateException.class).getResult(batchRequest::execute);
|
||||
//The server may return an error if the transaction has not yet been broadcasted - this is a valid state so only try once
|
||||
return new RetryLogic<Map<String, VerboseTransaction>>(1, RETRY_DELAY, IllegalStateException.class).getResult(batchRequest::execute);
|
||||
} catch(JsonRpcBatchException e) {
|
||||
log.warn("Some errors retrieving transactions: " + e.getErrors());
|
||||
return (Map<String, VerboseTransaction>)e.getSuccesses();
|
||||
|
|
|
@ -23,6 +23,7 @@ import java.util.*;
|
|||
|
||||
public class Bwt {
|
||||
private static final Logger log = LoggerFactory.getLogger(Bwt.class);
|
||||
private static final int IMPORT_BATCH_SIZE = 350;
|
||||
private Long shutdownPtr;
|
||||
private boolean terminating;
|
||||
|
||||
|
@ -85,7 +86,8 @@ public class Bwt {
|
|||
bwtConfig.descriptors = outputDescriptors;
|
||||
bwtConfig.rescanSince = (rescanSince == null || rescanSince < 0 ? "now" : rescanSince);
|
||||
bwtConfig.forceRescan = forceRescan;
|
||||
bwtConfig.gapLimit = gapLimit;
|
||||
//bwtConfig.initialImportSize = IMPORT_BATCH_SIZE;
|
||||
bwtConfig.gapLimit = IMPORT_BATCH_SIZE;
|
||||
} else {
|
||||
bwtConfig.requireAddresses = false;
|
||||
}
|
||||
|
@ -220,9 +222,14 @@ public class Bwt {
|
|||
protected Void call() {
|
||||
CallbackNotifier notifier = new CallbackNotifier() {
|
||||
@Override
|
||||
public void onBooting() {
|
||||
public void onBooting(long shutdownPtr) {
|
||||
log.debug("Booting bwt");
|
||||
if(!terminating) {
|
||||
|
||||
Bwt.this.shutdownPtr = shutdownPtr;
|
||||
if(terminating) {
|
||||
Bwt.this.shutdown();
|
||||
terminating = false;
|
||||
} else {
|
||||
Platform.runLater(() -> EventManager.get().post(new BwtBootStatusEvent("Connecting to Bitcoin Core node at " + Config.get().getCoreServer() + "...")));
|
||||
}
|
||||
}
|
||||
|
@ -230,9 +237,10 @@ public class Bwt {
|
|||
@Override
|
||||
public void onSyncProgress(float progress, int tip) {
|
||||
int percent = (int) (progress * 100.0);
|
||||
Date tipDate = new Date((long)tip * 1000);
|
||||
log.debug("Syncing " + percent + "%");
|
||||
if(!terminating) {
|
||||
Platform.runLater(() -> EventManager.get().post(new BwtSyncStatusEvent("Syncing" + (percent < 100 ? " (" + percent + "%)" : ""), percent, tip)));
|
||||
Platform.runLater(() -> EventManager.get().post(new BwtSyncStatusEvent("Syncing" + (percent < 100 ? " (" + percent + "%)" : ""), percent, tipDate)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -260,14 +268,10 @@ public class Bwt {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onReady(long shutdownPtr) {
|
||||
public void onReady() {
|
||||
log.debug("Bwt ready");
|
||||
Bwt.this.shutdownPtr = shutdownPtr;
|
||||
if(terminating) {
|
||||
Bwt.this.shutdown();
|
||||
terminating = false;
|
||||
} else {
|
||||
Platform.runLater(() -> EventManager.get().post(new BwtReadyStatusEvent("Server ready", shutdownPtr)));
|
||||
if(!terminating) {
|
||||
Platform.runLater(() -> EventManager.get().post(new BwtReadyStatusEvent("Server ready")));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -54,7 +54,7 @@ public class ElectrumServer {
|
|||
|
||||
if(Config.get().getServerType() == ServerType.BITCOIN_CORE) {
|
||||
if(bwtElectrumServer == null) {
|
||||
throw new ServerException("BWT server not started");
|
||||
throw new ServerException("Could not connect to Bitcoin Core RPC");
|
||||
}
|
||||
electrumServer = bwtElectrumServer;
|
||||
} else if(Config.get().getServerType() == ServerType.ELECTRUM_SERVER) {
|
||||
|
@ -928,14 +928,16 @@ public class ElectrumServer {
|
|||
}
|
||||
|
||||
private void shutdownBwt() {
|
||||
Bwt.DisconnectionService disconnectionService = bwt.getDisconnectionService();
|
||||
disconnectionService.setOnSucceeded(workerStateEvent -> {
|
||||
ElectrumServer.bwtElectrumServer = null;
|
||||
});
|
||||
disconnectionService.setOnFailed(workerStateEvent -> {
|
||||
log.error("Failed to stop BWT", workerStateEvent.getSource().getException());
|
||||
});
|
||||
Platform.runLater(disconnectionService::start);
|
||||
if(Config.get().getServerType() == ServerType.BITCOIN_CORE) {
|
||||
Bwt.DisconnectionService disconnectionService = bwt.getDisconnectionService();
|
||||
disconnectionService.setOnSucceeded(workerStateEvent -> {
|
||||
ElectrumServer.bwtElectrumServer = null;
|
||||
});
|
||||
disconnectionService.setOnFailed(workerStateEvent -> {
|
||||
log.error("Failed to stop BWT", workerStateEvent.getSource().getException());
|
||||
});
|
||||
Platform.runLater(disconnectionService::start);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -181,7 +181,8 @@ public class SimpleElectrumServerRpc implements ElectrumServerRpc {
|
|||
Map<String, VerboseTransaction> result = new LinkedHashMap<>();
|
||||
for(String txid : txids) {
|
||||
try {
|
||||
VerboseTransaction verboseTransaction = new RetryLogic<VerboseTransaction>(MAX_RETRIES, RETRY_DELAY, IllegalStateException.class).getResult(() ->
|
||||
//The server may return an error if the transaction has not yet been broadcasted - this is a valid state so only try once
|
||||
VerboseTransaction verboseTransaction = new RetryLogic<VerboseTransaction>(1, RETRY_DELAY, IllegalStateException.class).getResult(() ->
|
||||
client.createRequest().returnAs(VerboseTransaction.class).method("blockchain.transaction.get").id(idCounter.incrementAndGet()).params(txid, true).execute());
|
||||
result.put(txid, verboseTransaction);
|
||||
} catch(Exception e) {
|
||||
|
|
|
@ -6,10 +6,7 @@ import com.sparrowwallet.drongo.Network;
|
|||
import com.sparrowwallet.sparrow.EventManager;
|
||||
import com.sparrowwallet.sparrow.control.TextFieldValidator;
|
||||
import com.sparrowwallet.sparrow.control.UnlabeledToggleSwitch;
|
||||
import com.sparrowwallet.sparrow.event.BwtStatusEvent;
|
||||
import com.sparrowwallet.sparrow.event.BwtSyncStatusEvent;
|
||||
import com.sparrowwallet.sparrow.event.ConnectionEvent;
|
||||
import com.sparrowwallet.sparrow.event.RequestDisconnectEvent;
|
||||
import com.sparrowwallet.sparrow.event.*;
|
||||
import com.sparrowwallet.sparrow.glyphfont.FontAwesome5;
|
||||
import com.sparrowwallet.sparrow.io.Config;
|
||||
import com.sparrowwallet.sparrow.net.*;
|
||||
|
@ -38,6 +35,8 @@ import javax.net.ssl.SSLHandshakeException;
|
|||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.security.cert.CertificateFactory;
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.List;
|
||||
|
||||
public class ServerPreferencesController extends PreferencesDetailController {
|
||||
|
@ -141,6 +140,7 @@ public class ServerPreferencesController extends PreferencesDetailController {
|
|||
config.setServerType(serverType);
|
||||
testConnection.setGraphic(getGlyph(FontAwesome5.Glyph.QUESTION_CIRCLE, ""));
|
||||
testResults.clear();
|
||||
EventManager.get().post(new ServerTypeChangedEvent(serverType));
|
||||
} else if(oldValue != null) {
|
||||
oldValue.setSelected(true);
|
||||
}
|
||||
|
@ -626,7 +626,9 @@ public class ServerPreferencesController extends PreferencesDetailController {
|
|||
@Subscribe
|
||||
public void bwtSyncStatus(BwtSyncStatusEvent event) {
|
||||
if(connectionService != null && connectionService.isRunning() && event.getProgress() < 100) {
|
||||
testResults.appendText("\nThe connection to the Bitcoin Core node was successful, but it is still syncing to the the blockchain tip at " + event.getTip() + " blocks (" + event.getProgress() + "% completed)");
|
||||
DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm");
|
||||
testResults.appendText("\nThe connection to the Bitcoin Core node was successful, but it is still syncing and cannot be used yet.");
|
||||
testResults.appendText("\nCurrently " + event.getProgress() + "% completed to date " + dateFormat.format(event.getTip()));
|
||||
testConnection.setGraphic(getGlyph(FontAwesome5.Glyph.QUESTION_CIRCLE, null));
|
||||
connectionService.cancel();
|
||||
}
|
||||
|
|
|
@ -159,3 +159,8 @@
|
|||
.root .header-panel {
|
||||
-fx-background-color: -fx-box-border, derive(-fx-background, 10%);
|
||||
}
|
||||
|
||||
.core-server.toggle-switch:selected .thumb-area {
|
||||
-fx-background-color: linear-gradient(to bottom, derive(-fx-text-box-border, -20%), derive(-fx-text-box-border, -30%)), linear-gradient(to bottom, derive(#50a14f, 30%), #50a14f);
|
||||
-fx-background-insets: 0, 1;
|
||||
}
|
Binary file not shown.
Loading…
Reference in a new issue