mirror of
https://github.com/sparrowwallet/sparrow.git
synced 2024-12-24 12:46:45 +00:00
add broadcasting step to soroban initiator dialog and indicate when transaction has been successfully broadcasted
This commit is contained in:
parent
a76d9dba21
commit
8fb7f544de
4 changed files with 199 additions and 33 deletions
|
@ -1,5 +1,6 @@
|
||||||
package com.sparrowwallet.sparrow.soroban;
|
package com.sparrowwallet.sparrow.soroban;
|
||||||
|
|
||||||
|
import com.google.common.eventbus.Subscribe;
|
||||||
import com.samourai.soroban.cahoots.CahootsContext;
|
import com.samourai.soroban.cahoots.CahootsContext;
|
||||||
import com.samourai.soroban.client.cahoots.OnlineCahootsMessage;
|
import com.samourai.soroban.client.cahoots.OnlineCahootsMessage;
|
||||||
import com.samourai.soroban.client.cahoots.SorobanCahootsService;
|
import com.samourai.soroban.client.cahoots.SorobanCahootsService;
|
||||||
|
@ -12,6 +13,7 @@ import com.sparrowwallet.drongo.crypto.EncryptionType;
|
||||||
import com.sparrowwallet.drongo.crypto.InvalidPasswordException;
|
import com.sparrowwallet.drongo.crypto.InvalidPasswordException;
|
||||||
import com.sparrowwallet.drongo.crypto.Key;
|
import com.sparrowwallet.drongo.crypto.Key;
|
||||||
import com.sparrowwallet.drongo.protocol.Transaction;
|
import com.sparrowwallet.drongo.protocol.Transaction;
|
||||||
|
import com.sparrowwallet.drongo.protocol.TransactionInput;
|
||||||
import com.sparrowwallet.drongo.psbt.PSBTParseException;
|
import com.sparrowwallet.drongo.psbt.PSBTParseException;
|
||||||
import com.sparrowwallet.drongo.wallet.*;
|
import com.sparrowwallet.drongo.wallet.*;
|
||||||
import com.sparrowwallet.sparrow.AppServices;
|
import com.sparrowwallet.sparrow.AppServices;
|
||||||
|
@ -22,8 +24,10 @@ import com.sparrowwallet.sparrow.control.TransactionDiagram;
|
||||||
import com.sparrowwallet.sparrow.control.WalletPasswordDialog;
|
import com.sparrowwallet.sparrow.control.WalletPasswordDialog;
|
||||||
import com.sparrowwallet.sparrow.event.StorageEvent;
|
import com.sparrowwallet.sparrow.event.StorageEvent;
|
||||||
import com.sparrowwallet.sparrow.event.TimedEvent;
|
import com.sparrowwallet.sparrow.event.TimedEvent;
|
||||||
|
import com.sparrowwallet.sparrow.event.WalletNodeHistoryChangedEvent;
|
||||||
import com.sparrowwallet.sparrow.io.Config;
|
import com.sparrowwallet.sparrow.io.Config;
|
||||||
import com.sparrowwallet.sparrow.io.Storage;
|
import com.sparrowwallet.sparrow.io.Storage;
|
||||||
|
import com.sparrowwallet.sparrow.net.ElectrumServer;
|
||||||
import io.reactivex.Observable;
|
import io.reactivex.Observable;
|
||||||
import io.reactivex.rxjavafx.schedulers.JavaFxScheduler;
|
import io.reactivex.rxjavafx.schedulers.JavaFxScheduler;
|
||||||
import io.reactivex.schedulers.Schedulers;
|
import io.reactivex.schedulers.Schedulers;
|
||||||
|
@ -37,6 +41,7 @@ import javafx.event.ActionEvent;
|
||||||
import javafx.fxml.FXML;
|
import javafx.fxml.FXML;
|
||||||
import javafx.scene.control.*;
|
import javafx.scene.control.*;
|
||||||
import javafx.scene.layout.VBox;
|
import javafx.scene.layout.VBox;
|
||||||
|
import javafx.util.Duration;
|
||||||
import javafx.util.StringConverter;
|
import javafx.util.StringConverter;
|
||||||
import org.controlsfx.glyphfont.Glyph;
|
import org.controlsfx.glyphfont.Glyph;
|
||||||
import org.controlsfx.validation.ValidationResult;
|
import org.controlsfx.validation.ValidationResult;
|
||||||
|
@ -69,6 +74,9 @@ public class InitiatorController extends SorobanController {
|
||||||
@FXML
|
@FXML
|
||||||
private VBox step3;
|
private VBox step3;
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private VBox step4;
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private ComboBox<PayNym> payNymFollowers;
|
private ComboBox<PayNym> payNymFollowers;
|
||||||
|
|
||||||
|
@ -108,6 +116,18 @@ public class InitiatorController extends SorobanController {
|
||||||
@FXML
|
@FXML
|
||||||
private TransactionDiagram transactionDiagram;
|
private TransactionDiagram transactionDiagram;
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private Label step4Desc;
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private ProgressBar broadcastProgressBar;
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private Label broadcastProgressLabel;
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private Glyph broadcastSuccessful;
|
||||||
|
|
||||||
private final StringProperty counterpartyPayNymName = new SimpleStringProperty();
|
private final StringProperty counterpartyPayNymName = new SimpleStringProperty();
|
||||||
|
|
||||||
private final ObjectProperty<PaymentCode> counterpartyPaymentCode = new SimpleObjectProperty<>(null);
|
private final ObjectProperty<PaymentCode> counterpartyPaymentCode = new SimpleObjectProperty<>(null);
|
||||||
|
@ -120,6 +140,10 @@ public class InitiatorController extends SorobanController {
|
||||||
|
|
||||||
private CahootsType cahootsType = CahootsType.STONEWALLX2;
|
private CahootsType cahootsType = CahootsType.STONEWALLX2;
|
||||||
|
|
||||||
|
private ElectrumServer.TransactionMempoolService transactionMempoolService;
|
||||||
|
|
||||||
|
private boolean closed;
|
||||||
|
|
||||||
public void initializeView(String walletId, Wallet wallet, WalletTransaction walletTransaction) {
|
public void initializeView(String walletId, Wallet wallet, WalletTransaction walletTransaction) {
|
||||||
this.walletId = walletId;
|
this.walletId = walletId;
|
||||||
this.wallet = wallet;
|
this.wallet = wallet;
|
||||||
|
@ -128,6 +152,7 @@ public class InitiatorController extends SorobanController {
|
||||||
step1.managedProperty().bind(step1.visibleProperty());
|
step1.managedProperty().bind(step1.visibleProperty());
|
||||||
step2.managedProperty().bind(step2.visibleProperty());
|
step2.managedProperty().bind(step2.visibleProperty());
|
||||||
step3.managedProperty().bind(step3.visibleProperty());
|
step3.managedProperty().bind(step3.visibleProperty());
|
||||||
|
step4.managedProperty().bind(step4.visibleProperty());
|
||||||
|
|
||||||
sorobanProgressBar.managedProperty().bind(sorobanProgressBar.visibleProperty());
|
sorobanProgressBar.managedProperty().bind(sorobanProgressBar.visibleProperty());
|
||||||
sorobanProgressLabel.managedProperty().bind(sorobanProgressLabel.visibleProperty());
|
sorobanProgressLabel.managedProperty().bind(sorobanProgressLabel.visibleProperty());
|
||||||
|
@ -135,12 +160,17 @@ public class InitiatorController extends SorobanController {
|
||||||
sorobanProgressBar.visibleProperty().bind(sorobanProgressLabel.visibleProperty());
|
sorobanProgressBar.visibleProperty().bind(sorobanProgressLabel.visibleProperty());
|
||||||
mixDeclined.visibleProperty().bind(sorobanProgressLabel.visibleProperty().not());
|
mixDeclined.visibleProperty().bind(sorobanProgressLabel.visibleProperty().not());
|
||||||
step2Timer.visibleProperty().bind(sorobanProgressLabel.visibleProperty());
|
step2Timer.visibleProperty().bind(sorobanProgressLabel.visibleProperty());
|
||||||
|
broadcastProgressBar.managedProperty().bind(broadcastProgressBar.visibleProperty());
|
||||||
|
broadcastProgressLabel.managedProperty().bind(broadcastProgressLabel.visibleProperty());
|
||||||
|
broadcastSuccessful.managedProperty().bind(broadcastSuccessful.visibleProperty());
|
||||||
|
broadcastSuccessful.setVisible(false);
|
||||||
|
|
||||||
step2.setVisible(false);
|
step2.setVisible(false);
|
||||||
step3.setVisible(false);
|
step3.setVisible(false);
|
||||||
|
step4.setVisible(false);
|
||||||
|
|
||||||
transactionAccepted.addListener((observable, oldValue, accepted) -> {
|
transactionAccepted.addListener((observable, oldValue, accepted) -> {
|
||||||
if(transactionProperty.get() != null) {
|
if(transactionProperty.get() != null && stepProperty.get() != Step.REBROADCAST) {
|
||||||
Platform.exitNestedEventLoop(transactionAccepted, accepted);
|
Platform.exitNestedEventLoop(transactionAccepted, accepted);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -240,6 +270,16 @@ public class InitiatorController extends SorobanController {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
stepProperty.addListener((observable, oldValue, step) -> {
|
||||||
|
if(step == Step.BROADCAST) {
|
||||||
|
step4Desc.setText("Broadcasting the mix transaction...");
|
||||||
|
broadcastProgressLabel.setVisible(true);
|
||||||
|
} else if(step == Step.REBROADCAST) {
|
||||||
|
step4Desc.setText("Rebroadcast the mix transaction.");
|
||||||
|
broadcastProgressLabel.setVisible(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
Payment payment = walletTransaction.getPayments().get(0);
|
Payment payment = walletTransaction.getPayments().get(0);
|
||||||
if(payment.getAddress() instanceof PayNymAddress payNymAddress) {
|
if(payment.getAddress() instanceof PayNymAddress payNymAddress) {
|
||||||
PayNym payNym = payNymAddress.getPayNym();
|
PayNym payNym = payNymAddress.getPayNym();
|
||||||
|
@ -429,13 +469,14 @@ public class InitiatorController extends SorobanController {
|
||||||
if(cahoots.getStep() == 3) {
|
if(cahoots.getStep() == 3) {
|
||||||
next();
|
next();
|
||||||
step3Timer.start(e -> {
|
step3Timer.start(e -> {
|
||||||
if(stepProperty.get() != Step.BROADCAST) {
|
if(stepProperty.get() != Step.BROADCAST && stepProperty.get() != Step.REBROADCAST) {
|
||||||
step3Desc.setText("Transaction declined due to timeout.");
|
step3Desc.setText("Transaction declined due to timeout.");
|
||||||
transactionAccepted.set(Boolean.FALSE);
|
transactionAccepted.set(Boolean.FALSE);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else if(cahoots.getStep() == 4) {
|
} else if(cahoots.getStep() == 4) {
|
||||||
stepProperty.set(Step.BROADCAST);
|
next();
|
||||||
|
broadcastTransaction();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch(PSBTParseException e) {
|
} catch(PSBTParseException e) {
|
||||||
|
@ -458,6 +499,70 @@ public class InitiatorController extends SorobanController {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void broadcastTransaction() {
|
||||||
|
stepProperty.set(Step.BROADCAST);
|
||||||
|
|
||||||
|
ElectrumServer.BroadcastTransactionService broadcastTransactionService = new ElectrumServer.BroadcastTransactionService(getTransaction());
|
||||||
|
broadcastTransactionService.setOnRunning(workerStateEvent -> {
|
||||||
|
broadcastProgressBar.setProgress(-1);
|
||||||
|
});
|
||||||
|
broadcastTransactionService.setOnSucceeded(workerStateEvent -> {
|
||||||
|
Map<BlockTransactionHashIndex, WalletNode> selectedUtxos = new HashMap<>();
|
||||||
|
Map<BlockTransactionHashIndex, WalletNode> walletTxos = wallet.getWalletTxos();
|
||||||
|
for(TransactionInput txInput : getTransaction().getInputs()) {
|
||||||
|
Optional<BlockTransactionHashIndex> optSelectedUtxo = walletTxos.keySet().stream().filter(txo -> txInput.getOutpoint().getHash().equals(txo.getHash()) && txInput.getOutpoint().getIndex() == txo.getIndex())
|
||||||
|
.findFirst();
|
||||||
|
optSelectedUtxo.ifPresent(blockTransactionHashIndex -> selectedUtxos.put(blockTransactionHashIndex, walletTxos.get(blockTransactionHashIndex)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(transactionMempoolService != null) {
|
||||||
|
transactionMempoolService.cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
transactionMempoolService = new ElectrumServer.TransactionMempoolService(wallet, getTransaction().getTxId(), new HashSet<>(selectedUtxos.values()));
|
||||||
|
transactionMempoolService.setDelay(Duration.seconds(3));
|
||||||
|
transactionMempoolService.setPeriod(Duration.seconds(10));
|
||||||
|
transactionMempoolService.setRestartOnFailure(false);
|
||||||
|
transactionMempoolService.setOnSucceeded(mempoolWorkerStateEvent -> {
|
||||||
|
Set<String> scriptHashes = transactionMempoolService.getValue();
|
||||||
|
if(!scriptHashes.isEmpty()) {
|
||||||
|
Platform.runLater(() -> EventManager.get().post(new WalletNodeHistoryChangedEvent(scriptHashes.iterator().next())));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(transactionMempoolService.getIterationCount() > 3 && transactionMempoolService.isRunning()) {
|
||||||
|
transactionMempoolService.cancel();
|
||||||
|
broadcastProgressBar.setProgress(0);
|
||||||
|
log.error("Timeout searching for broadcasted transaction");
|
||||||
|
AppServices.showErrorDialog("Timeout searching for broadcasted transaction", "The transaction was broadcast but the server did not register it in the mempool. It is safe to try broadcasting again.");
|
||||||
|
stepProperty.set(Step.REBROADCAST);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
transactionMempoolService.setOnFailed(mempoolWorkerStateEvent -> {
|
||||||
|
transactionMempoolService.cancel();
|
||||||
|
broadcastProgressBar.setProgress(0);
|
||||||
|
log.error("Timeout searching for broadcasted transaction");
|
||||||
|
AppServices.showErrorDialog("Timeout searching for broadcasted transaction", "The transaction was broadcast but the server did not indicate it had entered the mempool. It is safe to try broadcasting again.");
|
||||||
|
stepProperty.set(Step.REBROADCAST);
|
||||||
|
});
|
||||||
|
|
||||||
|
if(!closed) {
|
||||||
|
transactionMempoolService.start();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
broadcastTransactionService.setOnFailed(workerStateEvent -> {
|
||||||
|
broadcastProgressBar.setProgress(0);
|
||||||
|
Throwable exception = workerStateEvent.getSource().getException();
|
||||||
|
while(exception.getCause() != null) {
|
||||||
|
exception = exception.getCause();
|
||||||
|
}
|
||||||
|
|
||||||
|
log.error("Error broadcasting transaction", exception);
|
||||||
|
AppServices.showErrorDialog("Error broadcasting transaction", exception.getMessage());
|
||||||
|
stepProperty.set(Step.REBROADCAST);
|
||||||
|
});
|
||||||
|
broadcastTransactionService.start();
|
||||||
|
}
|
||||||
|
|
||||||
public void next() {
|
public void next() {
|
||||||
if(step1.isVisible()) {
|
if(step1.isVisible()) {
|
||||||
step1.setVisible(false);
|
step1.setVisible(false);
|
||||||
|
@ -470,6 +575,13 @@ public class InitiatorController extends SorobanController {
|
||||||
step2.setVisible(false);
|
step2.setVisible(false);
|
||||||
step3.setVisible(true);
|
step3.setVisible(true);
|
||||||
stepProperty.set(Step.REVIEW);
|
stepProperty.set(Step.REVIEW);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(step3.isVisible()) {
|
||||||
|
step3.setVisible(false);
|
||||||
|
step4.setVisible(true);
|
||||||
|
stepProperty.set(Step.BROADCAST);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -525,11 +637,36 @@ public class InitiatorController extends SorobanController {
|
||||||
return transactionProperty.get();
|
return transactionProperty.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void close() {
|
||||||
|
closed = true;
|
||||||
|
if(transactionMempoolService != null) {
|
||||||
|
transactionMempoolService.cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isTransactionAccepted() {
|
||||||
|
return transactionAccepted.get() == Boolean.TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
public ObjectProperty<Boolean> transactionAcceptedProperty() {
|
public ObjectProperty<Boolean> transactionAcceptedProperty() {
|
||||||
return transactionAccepted;
|
return transactionAccepted;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
public void walletNodeHistoryChanged(WalletNodeHistoryChangedEvent event) {
|
||||||
|
if(event.getWalletNode(wallet) != null) {
|
||||||
|
if(transactionMempoolService != null) {
|
||||||
|
transactionMempoolService.cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
broadcastProgressBar.setVisible(false);
|
||||||
|
broadcastProgressLabel.setVisible(false);
|
||||||
|
step4Desc.setText("Transaction broadcasted.");
|
||||||
|
broadcastSuccessful.setVisible(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public enum Step {
|
public enum Step {
|
||||||
SETUP, COMMUNICATE, REVIEW, BROADCAST
|
SETUP, COMMUNICATE, REVIEW, BROADCAST, REBROADCAST
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,6 +41,8 @@ public class InitiatorDialog extends Dialog<Transaction> {
|
||||||
InitiatorController initiatorController = initiatorLoader.getController();
|
InitiatorController initiatorController = initiatorLoader.getController();
|
||||||
initiatorController.initializeView(walletId, wallet, walletTransaction);
|
initiatorController.initializeView(walletId, wallet, walletTransaction);
|
||||||
|
|
||||||
|
EventManager.get().register(initiatorController);
|
||||||
|
|
||||||
dialogPane.setPrefWidth(730);
|
dialogPane.setPrefWidth(730);
|
||||||
dialogPane.setPrefHeight(530);
|
dialogPane.setPrefHeight(530);
|
||||||
AppServices.moveToActiveWindowScreen(this);
|
AppServices.moveToActiveWindowScreen(this);
|
||||||
|
@ -51,18 +53,23 @@ public class InitiatorDialog extends Dialog<Transaction> {
|
||||||
final ButtonType nextButtonType = new javafx.scene.control.ButtonType("Next", ButtonBar.ButtonData.OK_DONE);
|
final ButtonType nextButtonType = new javafx.scene.control.ButtonType("Next", ButtonBar.ButtonData.OK_DONE);
|
||||||
final ButtonType cancelButtonType = new javafx.scene.control.ButtonType("Cancel", ButtonBar.ButtonData.CANCEL_CLOSE);
|
final ButtonType cancelButtonType = new javafx.scene.control.ButtonType("Cancel", ButtonBar.ButtonData.CANCEL_CLOSE);
|
||||||
final ButtonType broadcastButtonType = new javafx.scene.control.ButtonType("Sign & Broadcast", ButtonBar.ButtonData.APPLY);
|
final ButtonType broadcastButtonType = new javafx.scene.control.ButtonType("Sign & Broadcast", ButtonBar.ButtonData.APPLY);
|
||||||
dialogPane.getButtonTypes().addAll(nextButtonType, cancelButtonType, broadcastButtonType);
|
final ButtonType doneButtonType = new javafx.scene.control.ButtonType("Done", ButtonBar.ButtonData.APPLY);
|
||||||
|
dialogPane.getButtonTypes().addAll(nextButtonType, cancelButtonType, broadcastButtonType, doneButtonType);
|
||||||
|
|
||||||
Button nextButton = (Button)dialogPane.lookupButton(nextButtonType);
|
Button nextButton = (Button)dialogPane.lookupButton(nextButtonType);
|
||||||
Button cancelButton = (Button)dialogPane.lookupButton(cancelButtonType);
|
Button cancelButton = (Button)dialogPane.lookupButton(cancelButtonType);
|
||||||
Button broadcastButton = (Button)dialogPane.lookupButton(broadcastButtonType);
|
Button broadcastButton = (Button)dialogPane.lookupButton(broadcastButtonType);
|
||||||
|
Button doneButton = (Button)dialogPane.lookupButton(doneButtonType);
|
||||||
nextButton.setDisable(initiatorController.counterpartyPaymentCodeProperty().get() == null);
|
nextButton.setDisable(initiatorController.counterpartyPaymentCodeProperty().get() == null);
|
||||||
broadcastButton.setDisable(true);
|
broadcastButton.setDisable(true);
|
||||||
|
|
||||||
nextButton.managedProperty().bind(nextButton.visibleProperty());
|
nextButton.managedProperty().bind(nextButton.visibleProperty());
|
||||||
|
cancelButton.managedProperty().bind(cancelButton.visibleProperty());
|
||||||
broadcastButton.managedProperty().bind(broadcastButton.visibleProperty());
|
broadcastButton.managedProperty().bind(broadcastButton.visibleProperty());
|
||||||
|
doneButton.managedProperty().bind(doneButton.visibleProperty());
|
||||||
|
|
||||||
broadcastButton.visibleProperty().bind(nextButton.visibleProperty().not());
|
broadcastButton.setVisible(false);
|
||||||
|
doneButton.setVisible(false);
|
||||||
|
|
||||||
initiatorController.counterpartyPaymentCodeProperty().addListener((observable, oldValue, paymentCode) -> {
|
initiatorController.counterpartyPaymentCodeProperty().addListener((observable, oldValue, paymentCode) -> {
|
||||||
nextButton.setDisable(paymentCode == null || !AppServices.isConnected());
|
nextButton.setDisable(paymentCode == null || !AppServices.isConnected());
|
||||||
|
@ -77,10 +84,19 @@ public class InitiatorDialog extends Dialog<Transaction> {
|
||||||
nextButton.setVisible(true);
|
nextButton.setVisible(true);
|
||||||
} else if(step == InitiatorController.Step.REVIEW) {
|
} else if(step == InitiatorController.Step.REVIEW) {
|
||||||
nextButton.setVisible(false);
|
nextButton.setVisible(false);
|
||||||
|
broadcastButton.setVisible(true);
|
||||||
broadcastButton.setDefaultButton(true);
|
broadcastButton.setDefaultButton(true);
|
||||||
broadcastButton.setDisable(false);
|
broadcastButton.setDisable(false);
|
||||||
} else if(step == InitiatorController.Step.BROADCAST) {
|
} else if(step == InitiatorController.Step.BROADCAST) {
|
||||||
setResult(initiatorController.getTransaction());
|
cancelButton.setVisible(false);
|
||||||
|
broadcastButton.setVisible(false);
|
||||||
|
doneButton.setVisible(true);
|
||||||
|
doneButton.setDefaultButton(true);
|
||||||
|
} else if(step == InitiatorController.Step.REBROADCAST) {
|
||||||
|
cancelButton.setVisible(true);
|
||||||
|
broadcastButton.setVisible(true);
|
||||||
|
broadcastButton.setDisable(false);
|
||||||
|
doneButton.setVisible(false);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -98,10 +114,19 @@ public class InitiatorDialog extends Dialog<Transaction> {
|
||||||
});
|
});
|
||||||
|
|
||||||
broadcastButton.addEventFilter(ActionEvent.ACTION, event -> {
|
broadcastButton.addEventFilter(ActionEvent.ACTION, event -> {
|
||||||
acceptAndBroadcast(initiatorController, walletId, wallet);
|
if(initiatorController.isTransactionAccepted()) {
|
||||||
|
initiatorController.broadcastTransaction();
|
||||||
|
} else {
|
||||||
|
acceptAndBroadcast(initiatorController, walletId, wallet);
|
||||||
|
}
|
||||||
event.consume();
|
event.consume();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
setOnCloseRequest(event -> {
|
||||||
|
initiatorController.close();
|
||||||
|
EventManager.get().unregister(initiatorController);
|
||||||
|
});
|
||||||
|
|
||||||
setResultConverter(dialogButton -> dialogButton.getButtonData().equals(ButtonBar.ButtonData.APPLY) ? initiatorController.getTransaction() : null);
|
setResultConverter(dialogButton -> dialogButton.getButtonData().equals(ButtonBar.ButtonData.APPLY) ? initiatorController.getTransaction() : null);
|
||||||
} catch(IOException e) {
|
} catch(IOException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
|
|
|
@ -1406,32 +1406,16 @@ public class SendController extends WalletFormController implements Initializabl
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
InitiatorDialog initiatorDialog = new InitiatorDialog(getWalletForm().getWalletId(), getWalletForm().getWallet(), walletTransactionProperty.get());
|
Platform.runLater(() -> {
|
||||||
if(Config.get().isSameAppMixing()) {
|
InitiatorDialog initiatorDialog = new InitiatorDialog(getWalletForm().getWalletId(), getWalletForm().getWallet(), walletTransactionProperty.get());
|
||||||
initiatorDialog.initModality(Modality.NONE);
|
if(Config.get().isSameAppMixing()) {
|
||||||
}
|
initiatorDialog.initModality(Modality.NONE);
|
||||||
Optional<Transaction> optTransaction = initiatorDialog.showAndWait();
|
}
|
||||||
if(optTransaction.isPresent()) {
|
Optional<Transaction> optTransaction = initiatorDialog.showAndWait();
|
||||||
ElectrumServer.BroadcastTransactionService broadcastTransactionService = new ElectrumServer.BroadcastTransactionService(optTransaction.get());
|
if(optTransaction.isPresent()) {
|
||||||
broadcastTransactionService.setOnRunning(workerStateEvent -> {
|
|
||||||
createButton.setDisable(true);
|
|
||||||
addWalletTransactionNodes();
|
|
||||||
});
|
|
||||||
broadcastTransactionService.setOnSucceeded(workerStateEvent -> {
|
|
||||||
createButton.setDisable(false);
|
|
||||||
clear(null);
|
clear(null);
|
||||||
});
|
}
|
||||||
broadcastTransactionService.setOnFailed(workerStateEvent -> {
|
});
|
||||||
createButton.setDisable(false);
|
|
||||||
Throwable exception = workerStateEvent.getSource().getException();
|
|
||||||
while(exception.getCause() != null) {
|
|
||||||
exception = exception.getCause();
|
|
||||||
}
|
|
||||||
|
|
||||||
AppServices.showErrorDialog("Error broadcasting mix transaction", exception.getMessage());
|
|
||||||
});
|
|
||||||
broadcastTransactionService.start();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -106,6 +106,26 @@
|
||||||
<TransactionDiagram fx:id="transactionDiagram" maxWidth="700" final="true"/>
|
<TransactionDiagram fx:id="transactionDiagram" maxWidth="700" final="true"/>
|
||||||
</HBox>
|
</HBox>
|
||||||
</VBox>
|
</VBox>
|
||||||
|
<VBox fx:id="step4" spacing="15">
|
||||||
|
<HBox>
|
||||||
|
<Label text="Broadcast Transaction" styleClass="title-text">
|
||||||
|
<graphic>
|
||||||
|
<Glyph fontFamily="Font Awesome 5 Free Solid" fontSize="20" icon="RANDOM" styleClass="title-icon" />
|
||||||
|
</graphic>
|
||||||
|
</Label>
|
||||||
|
</HBox>
|
||||||
|
<Label fx:id="step4Desc" text="Broadcasting the mix transaction..." wrapText="true" styleClass="content-text" />
|
||||||
|
<HBox>
|
||||||
|
<padding>
|
||||||
|
<Insets top="20" />
|
||||||
|
</padding>
|
||||||
|
<ProgressBar fx:id="broadcastProgressBar" prefWidth="680" />
|
||||||
|
</HBox>
|
||||||
|
<VBox alignment="CENTER" spacing="20">
|
||||||
|
<Label fx:id="broadcastProgressLabel" text="Broadcasting..." styleClass="content-text" alignment="CENTER"/>
|
||||||
|
<Glyph fx:id="broadcastSuccessful" fontFamily="Font Awesome 5 Free Solid" fontSize="80" icon="CHECK_CIRCLE" styleClass="success" />
|
||||||
|
</VBox>
|
||||||
|
</VBox>
|
||||||
</VBox>
|
</VBox>
|
||||||
</VBox>
|
</VBox>
|
||||||
</StackPane>
|
</StackPane>
|
||||||
|
|
Loading…
Reference in a new issue