use cached tx0previews, only save mixconfig on apply

This commit is contained in:
Craig Raw 2021-09-20 15:30:13 +02:00
parent 1c1099217b
commit cfd06a8513
7 changed files with 98 additions and 56 deletions

View file

@ -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')

View file

@ -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;
}
}

View file

@ -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<Integer> 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<Wallet> 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;
}
}

View file

@ -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<Boolean> {
public class MixToDialog extends Dialog<MixConfig> {
private final Wallet wallet;
private final Button applyButton;
@ -47,7 +48,7 @@ public class MixToDialog extends Dialog<Boolean> {
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<Boolean> {
}
@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);
}
}

View file

@ -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<Boolean> optApply = mixToDialog.showAndWait();
if(optApply.isPresent() && optApply.get()) {
Whirlpool whirlpool = AppServices.getWhirlpoolServices().getWhirlpool(getWalletForm().getWallet());
Optional<MixConfig> 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());

View file

@ -112,14 +112,10 @@ public class Whirlpool {
return poolSupplier.getPools();
}
public Tx0Preview getTx0Preview(Pool pool, Collection<UnspentOutput> utxos) throws Exception {
public Tx0Previews getTx0Previews(Collection<UnspentOutput> 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<BlockTransactionHashIndex> utxos) throws Exception {
@ -477,28 +473,26 @@ public class Whirlpool {
}
}
public static class Tx0PreviewService extends Service<Tx0Preview> {
public static class Tx0PreviewsService extends Service<Tx0Previews> {
private final Whirlpool whirlpool;
private final Wallet wallet;
private final Pool pool;
private final List<UtxoEntry> utxoEntries;
public Tx0PreviewService(Whirlpool whirlpool, Wallet wallet, Pool pool, List<UtxoEntry> utxoEntries) {
public Tx0PreviewsService(Whirlpool whirlpool, Wallet wallet, List<UtxoEntry> utxoEntries) {
this.whirlpool = whirlpool;
this.wallet = wallet;
this.pool = pool;
this.utxoEntries = utxoEntries;
}
@Override
protected Task<Tx0Preview> createTask() {
protected Task<Tx0Previews> 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<UnspentOutput> 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);
}
};
}

View file

@ -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<UtxoEntry> utxoEntries;
private Tx0Previews tx0Previews;
private final ObjectProperty<Tx0Preview> tx0PreviewProperty = new SimpleObjectProperty<>(null);
public void initializeView(String walletId, Wallet wallet, List<UtxoEntry> 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,26 +259,27 @@ public class WhirlpoolController {
}
Whirlpool whirlpool = AppServices.getWhirlpoolServices().getWhirlpool(walletId);
if(tx0Previews != null && mixConfig.getScode().equals(whirlpool.getScode())) {
Tx0Preview tx0Preview = tx0Previews.getTx0Preview(pool.getPoolId());
tx0PreviewProperty.set(tx0Preview);
} else {
tx0Previews = null;
whirlpool.setScode(mixConfig.getScode());
Whirlpool.Tx0PreviewService tx0PreviewService = new Whirlpool.Tx0PreviewService(whirlpool, wallet, pool, utxoEntries);
tx0PreviewService.setOnRunning(workerStateEvent -> {
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);
});
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);
tx0PreviewsService.setOnSucceeded(workerStateEvent -> {
tx0Previews = tx0PreviewsService.getValue();
Tx0Preview tx0Preview = tx0Previews.getTx0Preview(pool.getPoolId());
tx0PreviewProperty.set(tx0Preview);
});
tx0PreviewService.setOnFailed(workerStateEvent -> {
tx0PreviewsService.setOnFailed(workerStateEvent -> {
Throwable exception = workerStateEvent.getSource().getException();
while(exception.getCause() != null) {
exception = exception.getCause();
@ -267,7 +287,8 @@ public class WhirlpoolController {
nbOutputsLoading.setText("Error fetching fee: " + exception.getMessage());
});
tx0PreviewService.start();
tx0PreviewsService.start();
}
}
public ObjectProperty<Tx0Preview> getTx0PreviewProperty() {