diff --git a/build.gradle b/build.gradle index 14823bfc..1c1d6651 100644 --- a/build.gradle +++ b/build.gradle @@ -91,7 +91,7 @@ dependencies { implementation('org.slf4j:jul-to-slf4j:1.7.30') { exclude group: 'org.slf4j' } - implementation('com.sparrowwallet.nightjar:nightjar:0.2.16-SNAPSHOT') + implementation('com.sparrowwallet.nightjar:nightjar:0.2.17-SNAPSHOT') testImplementation('junit:junit:4.12') } @@ -449,7 +449,7 @@ extraJavaModuleInfo { module('cbor-0.9.jar', 'co.nstant.in.cbor', '0.9') { exports('co.nstant.in.cbor') } - module('nightjar-0.2.16-SNAPSHOT.jar', 'com.sparrowwallet.nightjar', '0.2.16-SNAPSHOT') { + module('nightjar-0.2.17-SNAPSHOT.jar', 'com.sparrowwallet.nightjar', '0.2.17-SNAPSHOT') { requires('com.google.common') requires('net.sourceforge.streamsupport') requires('org.slf4j') diff --git a/src/main/java/com/sparrowwallet/sparrow/event/MixToConfigChangedEvent.java b/src/main/java/com/sparrowwallet/sparrow/event/MixToConfigChangedEvent.java new file mode 100644 index 00000000..e57fe089 --- /dev/null +++ b/src/main/java/com/sparrowwallet/sparrow/event/MixToConfigChangedEvent.java @@ -0,0 +1,15 @@ +package com.sparrowwallet.sparrow.event; + +import com.sparrowwallet.drongo.wallet.Wallet; + +public class MixToConfigChangedEvent { + private final Wallet wallet; + + public MixToConfigChangedEvent(Wallet wallet) { + this.wallet = wallet; + } + + public Wallet getWallet() { + return wallet; + } +} diff --git a/src/main/java/com/sparrowwallet/sparrow/wallet/MixToController.java b/src/main/java/com/sparrowwallet/sparrow/wallet/MixToController.java index 3070cc9b..538bd197 100644 --- a/src/main/java/com/sparrowwallet/sparrow/wallet/MixToController.java +++ b/src/main/java/com/sparrowwallet/sparrow/wallet/MixToController.java @@ -1,12 +1,11 @@ package com.sparrowwallet.sparrow.wallet; -import com.sparrowwallet.drongo.policy.PolicyType; import com.sparrowwallet.drongo.wallet.MixConfig; import com.sparrowwallet.drongo.wallet.StandardAccount; import com.sparrowwallet.drongo.wallet.Wallet; import com.sparrowwallet.sparrow.AppServices; import com.sparrowwallet.sparrow.EventManager; -import com.sparrowwallet.sparrow.event.WalletMasterMixConfigChangedEvent; +import com.sparrowwallet.sparrow.event.MixToConfigChangedEvent; import com.sparrowwallet.sparrow.whirlpool.Whirlpool; import javafx.collections.FXCollections; import javafx.fxml.FXML; @@ -31,13 +30,15 @@ public class MixToController implements Initializable { @FXML private Spinner minMixes; + private MixConfig mixConfig; + @Override public void initialize(URL location, ResourceBundle resources) { } public void initializeView(Wallet wallet) { - MixConfig mixConfig = wallet.getMasterMixConfig(); + mixConfig = wallet.getMasterMixConfig().copy(); List allWallets = new ArrayList<>(); allWallets.add(NONE_WALLET); @@ -71,14 +72,18 @@ public class MixToController implements Initializable { mixConfig.setMixToWalletFile(AppServices.get().getOpenWallets().get(newValue).getWalletFile()); } - EventManager.get().post(new WalletMasterMixConfigChangedEvent(wallet)); + EventManager.get().post(new MixToConfigChangedEvent(wallet)); }); int initialMinMixes = mixConfig.getMinMixes() == null ? Whirlpool.DEFAULT_MIXTO_MIN_MIXES : mixConfig.getMinMixes(); minMixes.setValueFactory(new SpinnerValueFactory.IntegerSpinnerValueFactory(1, 10000, initialMinMixes)); minMixes.valueProperty().addListener((observable, oldValue, newValue) -> { mixConfig.setMinMixes(newValue); - EventManager.get().post(new WalletMasterMixConfigChangedEvent(wallet)); + EventManager.get().post(new MixToConfigChangedEvent(wallet)); }); } + + public MixConfig getMixConfig() { + return mixConfig; + } } diff --git a/src/main/java/com/sparrowwallet/sparrow/wallet/MixToDialog.java b/src/main/java/com/sparrowwallet/sparrow/wallet/MixToDialog.java index 75345a3c..8a844e6c 100644 --- a/src/main/java/com/sparrowwallet/sparrow/wallet/MixToDialog.java +++ b/src/main/java/com/sparrowwallet/sparrow/wallet/MixToDialog.java @@ -1,10 +1,11 @@ package com.sparrowwallet.sparrow.wallet; import com.google.common.eventbus.Subscribe; +import com.sparrowwallet.drongo.wallet.MixConfig; import com.sparrowwallet.drongo.wallet.Wallet; import com.sparrowwallet.sparrow.AppServices; import com.sparrowwallet.sparrow.EventManager; -import com.sparrowwallet.sparrow.event.WalletMixConfigChangedEvent; +import com.sparrowwallet.sparrow.event.MixToConfigChangedEvent; import com.sparrowwallet.sparrow.whirlpool.Whirlpool; import javafx.fxml.FXMLLoader; import javafx.scene.control.*; @@ -13,7 +14,7 @@ import org.controlsfx.tools.Borders; import java.io.IOException; import java.util.NoSuchElementException; -public class MixToDialog extends Dialog { +public class MixToDialog extends Dialog { private final Wallet wallet; private final Button applyButton; @@ -47,7 +48,7 @@ public class MixToDialog extends Dialog { dialogPane.setPrefHeight(300); AppServices.moveToActiveWindowScreen(this); - setResultConverter(dialogButton -> dialogButton == applyButtonType); + setResultConverter(dialogButton -> dialogButton == applyButtonType ? mixToController.getMixConfig() : null); setOnCloseRequest(event -> { EventManager.get().unregister(this); @@ -60,8 +61,8 @@ public class MixToDialog extends Dialog { } @Subscribe - public void walletMixConfigChanged(WalletMixConfigChangedEvent event) { - if(event.getWallet() == (wallet.isMasterWallet() ? wallet : wallet.getMasterWallet())) { + public void mixToConfigChanged(MixToConfigChangedEvent event) { + if(event.getWallet() == wallet) { applyButton.setDisable(false); } } diff --git a/src/main/java/com/sparrowwallet/sparrow/wallet/UtxosController.java b/src/main/java/com/sparrowwallet/sparrow/wallet/UtxosController.java index 3f1c3cff..dfd1e264 100644 --- a/src/main/java/com/sparrowwallet/sparrow/wallet/UtxosController.java +++ b/src/main/java/com/sparrowwallet/sparrow/wallet/UtxosController.java @@ -101,7 +101,7 @@ public class UtxosController extends WalletFormController implements Initializab startMix.visibleProperty().bind(stopMix.visibleProperty().not()); stopMix.visibleProperty().addListener((observable, oldValue, newValue) -> { stopMix.setDisable(!newValue); - startMix.setDisable(newValue); + startMix.setDisable(newValue || !AppServices.onlineProperty().get()); }); mixTo.managedProperty().bind(mixTo.visibleProperty()); mixTo.setVisible(getWalletForm().getWallet().getStandardAccountType() == StandardAccount.WHIRLPOOL_POSTMIX); @@ -338,11 +338,17 @@ public class UtxosController extends WalletFormController implements Initializab public void showMixToDialog(ActionEvent event) { MixToDialog mixToDialog = new MixToDialog(getWalletForm().getWallet()); - Optional optApply = mixToDialog.showAndWait(); - if(optApply.isPresent() && optApply.get()) { - Whirlpool whirlpool = AppServices.getWhirlpoolServices().getWhirlpool(getWalletForm().getWallet()); + Optional optMixConfig = mixToDialog.showAndWait(); + if(optMixConfig.isPresent()) { + MixConfig changedMixConfig = optMixConfig.get(); MixConfig mixConfig = getWalletForm().getWallet().getMasterMixConfig(); + mixConfig.setMixToWalletName(changedMixConfig.getMixToWalletName()); + mixConfig.setMixToWalletFile(changedMixConfig.getMixToWalletFile()); + mixConfig.setMinMixes(changedMixConfig.getMinMixes()); + EventManager.get().post(new WalletMasterMixConfigChangedEvent(getWalletForm().getWallet())); + + Whirlpool whirlpool = AppServices.getWhirlpoolServices().getWhirlpool(getWalletForm().getWallet()); try { String mixToWalletId = AppServices.getWhirlpoolServices().getWhirlpoolMixToWalletId(mixConfig); whirlpool.setMixToWallet(mixToWalletId, mixConfig.getMinMixes()); diff --git a/src/main/java/com/sparrowwallet/sparrow/whirlpool/Whirlpool.java b/src/main/java/com/sparrowwallet/sparrow/whirlpool/Whirlpool.java index b0f6f83f..c16e463a 100644 --- a/src/main/java/com/sparrowwallet/sparrow/whirlpool/Whirlpool.java +++ b/src/main/java/com/sparrowwallet/sparrow/whirlpool/Whirlpool.java @@ -112,14 +112,10 @@ public class Whirlpool { return poolSupplier.getPools(); } - public Tx0Preview getTx0Preview(Pool pool, Collection utxos) throws Exception { + public Tx0Previews getTx0Previews(Collection utxos) throws Exception { // preview all pools Tx0Config tx0Config = computeTx0Config(); - Tx0Previews tx0Previews = tx0Service.tx0Previews(utxos, tx0Config); - - // pool preview - String poolId = pool.getPoolId(); - return tx0Previews.getTx0Preview(poolId); + return tx0Service.tx0Previews(utxos, tx0Config); } public Tx0 broadcastTx0(Pool pool, Collection utxos) throws Exception { @@ -477,28 +473,26 @@ public class Whirlpool { } } - public static class Tx0PreviewService extends Service { + public static class Tx0PreviewsService extends Service { private final Whirlpool whirlpool; private final Wallet wallet; - private final Pool pool; private final List utxoEntries; - public Tx0PreviewService(Whirlpool whirlpool, Wallet wallet, Pool pool, List utxoEntries) { + public Tx0PreviewsService(Whirlpool whirlpool, Wallet wallet, List utxoEntries) { this.whirlpool = whirlpool; this.wallet = wallet; - this.pool = pool; this.utxoEntries = utxoEntries; } @Override - protected Task createTask() { + protected Task createTask() { return new Task<>() { - protected Tx0Preview call() throws Exception { + protected Tx0Previews call() throws Exception { updateProgress(-1, 1); - updateMessage("Fetching premix transaction..."); + updateMessage("Fetching premix preview..."); Collection utxos = utxoEntries.stream().map(utxoEntry -> Whirlpool.getUnspentOutput(wallet, utxoEntry.getNode(), utxoEntry.getBlockTransaction(), (int)utxoEntry.getHashIndex().getIndex())).collect(Collectors.toList()); - return whirlpool.getTx0Preview(pool, utxos); + return whirlpool.getTx0Previews(utxos); } }; } diff --git a/src/main/java/com/sparrowwallet/sparrow/whirlpool/WhirlpoolController.java b/src/main/java/com/sparrowwallet/sparrow/whirlpool/WhirlpoolController.java index d059136d..c1ef0c79 100644 --- a/src/main/java/com/sparrowwallet/sparrow/whirlpool/WhirlpoolController.java +++ b/src/main/java/com/sparrowwallet/sparrow/whirlpool/WhirlpoolController.java @@ -1,6 +1,7 @@ package com.sparrowwallet.sparrow.whirlpool; import com.samourai.whirlpool.client.tx0.Tx0Preview; +import com.samourai.whirlpool.client.tx0.Tx0Previews; import com.samourai.whirlpool.client.whirlpool.beans.Pool; import com.sparrowwallet.drongo.BitcoinUnit; import com.sparrowwallet.drongo.protocol.Transaction; @@ -77,6 +78,7 @@ public class WhirlpoolController { private Wallet wallet; private MixConfig mixConfig; private List utxoEntries; + private Tx0Previews tx0Previews; private final ObjectProperty tx0PreviewProperty = new SimpleObjectProperty<>(null); public void initializeView(String walletId, Wallet wallet, List utxoEntries) { @@ -100,6 +102,8 @@ public class WhirlpoolController { return change; })); scode.textProperty().addListener((observable, oldValue, newValue) -> { + pool.setItems(FXCollections.emptyObservableList()); + tx0PreviewProperty.set(null); mixConfig.setScode(newValue); EventManager.get().post(new WalletMasterMixConfigChangedEvent(wallet)); }); @@ -151,6 +155,21 @@ public class WhirlpoolController { nbOutputs.managedProperty().bind(nbOutputs.visibleProperty()); nbOutputsLoading.visibleProperty().bind(nbOutputs.visibleProperty().not()); nbOutputs.setVisible(false); + + tx0PreviewProperty.addListener((observable, oldValue, tx0Preview) -> { + if(tx0Preview == null) { + nbOutputsBox.setVisible(true); + nbOutputsLoading.setText("Calculating..."); + nbOutputs.setVisible(false); + discountFeeBox.setVisible(false); + } else { + discountFeeBox.setVisible(tx0Preview.getPool().getFeeValue() != tx0Preview.getTx0Data().getFeeValue()); + discountFee.setValue(tx0Preview.getTx0Data().getFeeValue()); + nbOutputsBox.setVisible(true); + nbOutputs.setText(tx0Preview.getNbPremix() + " UTXOs"); + nbOutputs.setVisible(true); + } + }); } public boolean next() { @@ -240,34 +259,36 @@ public class WhirlpoolController { } Whirlpool whirlpool = AppServices.getWhirlpoolServices().getWhirlpool(walletId); - whirlpool.setScode(mixConfig.getScode()); - - Whirlpool.Tx0PreviewService tx0PreviewService = new Whirlpool.Tx0PreviewService(whirlpool, wallet, pool, utxoEntries); - tx0PreviewService.setOnRunning(workerStateEvent -> { - nbOutputsBox.setVisible(true); - nbOutputsLoading.setText("Calculating..."); - nbOutputs.setVisible(false); - discountFeeBox.setVisible(false); - tx0PreviewProperty.set(null); - }); - tx0PreviewService.setOnSucceeded(workerStateEvent -> { - Tx0Preview tx0Preview = tx0PreviewService.getValue(); - discountFeeBox.setVisible(tx0Preview.getPool().getFeeValue() != tx0Preview.getTx0Data().getFeeValue()); - discountFee.setValue(tx0Preview.getTx0Data().getFeeValue()); - nbOutputsBox.setVisible(true); - nbOutputs.setText(tx0Preview.getNbPremix() + " UTXOs"); - nbOutputs.setVisible(true); + if(tx0Previews != null && mixConfig.getScode().equals(whirlpool.getScode())) { + Tx0Preview tx0Preview = tx0Previews.getTx0Preview(pool.getPoolId()); tx0PreviewProperty.set(tx0Preview); - }); - tx0PreviewService.setOnFailed(workerStateEvent -> { - Throwable exception = workerStateEvent.getSource().getException(); - while(exception.getCause() != null) { - exception = exception.getCause(); - } + } else { + tx0Previews = null; + whirlpool.setScode(mixConfig.getScode()); - nbOutputsLoading.setText("Error fetching fee: " + exception.getMessage()); - }); - tx0PreviewService.start(); + Whirlpool.Tx0PreviewsService tx0PreviewsService = new Whirlpool.Tx0PreviewsService(whirlpool, wallet, utxoEntries); + tx0PreviewsService.setOnRunning(workerStateEvent -> { + nbOutputsBox.setVisible(true); + nbOutputsLoading.setText("Calculating..."); + nbOutputs.setVisible(false); + discountFeeBox.setVisible(false); + tx0PreviewProperty.set(null); + }); + tx0PreviewsService.setOnSucceeded(workerStateEvent -> { + tx0Previews = tx0PreviewsService.getValue(); + Tx0Preview tx0Preview = tx0Previews.getTx0Preview(pool.getPoolId()); + tx0PreviewProperty.set(tx0Preview); + }); + tx0PreviewsService.setOnFailed(workerStateEvent -> { + Throwable exception = workerStateEvent.getSource().getException(); + while(exception.getCause() != null) { + exception = exception.getCause(); + } + + nbOutputsLoading.setText("Error fetching fee: " + exception.getMessage()); + }); + tx0PreviewsService.start(); + } } public ObjectProperty getTx0PreviewProperty() {