diff --git a/drongo b/drongo index 71b57782..67836b2b 160000 --- a/drongo +++ b/drongo @@ -1 +1 @@ -Subproject commit 71b5778226ef22881240143425325525c1a98d06 +Subproject commit 67836b2b557839317316a3e1c8d18b98a51d0e29 diff --git a/src/main/java/com/sparrowwallet/sparrow/AppController.java b/src/main/java/com/sparrowwallet/sparrow/AppController.java index b3448942..c95dc15f 100644 --- a/src/main/java/com/sparrowwallet/sparrow/AppController.java +++ b/src/main/java/com/sparrowwallet/sparrow/AppController.java @@ -899,6 +899,7 @@ public class AppController implements Initializable { if(wallet.isWhirlpoolMasterWallet()) { String walletId = storage.getWalletId(wallet); Whirlpool whirlpool = AppServices.get().getWhirlpool(walletId); + whirlpool.setScode(wallet.getOrCreateMixConfig().getScode()); whirlpool.setHDWallet(storage.getWalletId(wallet), copy); } diff --git a/src/main/java/com/sparrowwallet/sparrow/AppServices.java b/src/main/java/com/sparrowwallet/sparrow/AppServices.java index b68312cc..9f217082 100644 --- a/src/main/java/com/sparrowwallet/sparrow/AppServices.java +++ b/src/main/java/com/sparrowwallet/sparrow/AppServices.java @@ -469,7 +469,7 @@ public class AppServices { Whirlpool whirlpool = whirlpoolMap.get(walletId); if(whirlpool == null) { HostAndPort torProxy = AppServices.isTorRunning() ? HostAndPort.fromParts("localhost", TorService.PROXY_PORT) : (Config.get().getProxyServer() == null || Config.get().getProxyServer().isEmpty() || !Config.get().isUseProxy() ? null : HostAndPort.fromString(Config.get().getProxyServer())); - whirlpool = new Whirlpool(Network.get(), torProxy, Config.get().getScode()); + whirlpool = new Whirlpool(Network.get(), torProxy); whirlpoolMap.put(walletId, whirlpool); } @@ -477,12 +477,15 @@ public class AppServices { } private void startAllWhirlpool() { - for(Whirlpool whirlpool : whirlpoolMap.values().stream().filter(whirlpool -> whirlpool.hasWallet() && !whirlpool.isStarted()).collect(Collectors.toList())) { - Whirlpool.StartupService startupService = new Whirlpool.StartupService(whirlpool); - startupService.setOnFailed(workerStateEvent -> { - log.error("Failed to start whirlpool", workerStateEvent.getSource().getException()); - }); - startupService.start(); + for(Map.Entry entry : whirlpoolMap.entrySet().stream().filter(entry -> entry.getValue().hasWallet() && !entry.getValue().isStarted()).collect(Collectors.toList())) { + Wallet wallet = getWallet(entry.getKey()); + if(wallet.getMixConfig() != null && wallet.getMixConfig().getMixOnStartup() != Boolean.FALSE) { + Whirlpool.StartupService startupService = new Whirlpool.StartupService(entry.getValue()); + startupService.setOnFailed(workerStateEvent -> { + log.error("Failed to start whirlpool", workerStateEvent.getSource().getException()); + }); + startupService.start(); + } } } @@ -974,7 +977,7 @@ public class AppServices { public void walletOpened(WalletOpenedEvent event) { String walletId = event.getStorage().getWalletId(event.getWallet()); Whirlpool whirlpool = whirlpoolMap.get(walletId); - if(whirlpool != null && !whirlpool.isStarted() && isConnected()) { + if(whirlpool != null && !whirlpool.isStarted() && isConnected() && event.getWallet().getMixConfig() != null && event.getWallet().getMixConfig().getMixOnStartup() != Boolean.FALSE) { Whirlpool.StartupService startupService = new Whirlpool.StartupService(whirlpool); startupService.setOnFailed(workerStateEvent -> { log.error("Failed to start whirlpool", workerStateEvent.getSource().getException()); diff --git a/src/main/java/com/sparrowwallet/sparrow/event/WalletMixConfigChangedEvent.java b/src/main/java/com/sparrowwallet/sparrow/event/WalletMixConfigChangedEvent.java new file mode 100644 index 00000000..c16c6663 --- /dev/null +++ b/src/main/java/com/sparrowwallet/sparrow/event/WalletMixConfigChangedEvent.java @@ -0,0 +1,9 @@ +package com.sparrowwallet.sparrow.event; + +import com.sparrowwallet.drongo.wallet.Wallet; + +public class WalletMixConfigChangedEvent extends WalletChangedEvent { + public WalletMixConfigChangedEvent(Wallet wallet) { + super(wallet); + } +} diff --git a/src/main/java/com/sparrowwallet/sparrow/io/Config.java b/src/main/java/com/sparrowwallet/sparrow/io/Config.java index 61da15f1..9a0d52b4 100644 --- a/src/main/java/com/sparrowwallet/sparrow/io/Config.java +++ b/src/main/java/com/sparrowwallet/sparrow/io/Config.java @@ -61,7 +61,6 @@ public class Config { private String proxyServer; private Double appWidth; private Double appHeight; - private String scode; private static Config INSTANCE; @@ -489,15 +488,6 @@ public class Config { flush(); } - public String getScode() { - return scode; - } - - public void setScode(String scode) { - this.scode = scode; - flush(); - } - private synchronized void flush() { Gson gson = getGson(); try { diff --git a/src/main/java/com/sparrowwallet/sparrow/io/db/DbPersistence.java b/src/main/java/com/sparrowwallet/sparrow/io/db/DbPersistence.java index 68f08258..7811088f 100644 --- a/src/main/java/com/sparrowwallet/sparrow/io/db/DbPersistence.java +++ b/src/main/java/com/sparrowwallet/sparrow/io/db/DbPersistence.java @@ -272,6 +272,11 @@ public class DbPersistence implements Persistence { } } + if(dirtyPersistables.mixConfig) { + MixConfigDao mixConfigDao = handle.attach(MixConfigDao.class); + mixConfigDao.addOrUpdate(wallet, wallet.getMixConfig()); + } + if(!dirtyPersistables.changedUtxoMixes.isEmpty()) { UtxoMixDataDao utxoMixDataDao = handle.attach(UtxoMixDataDao.class); for(Map.Entry utxoMixDataEntry : dirtyPersistables.changedUtxoMixes.entrySet()) { @@ -652,6 +657,13 @@ public class DbPersistence implements Persistence { } } + @Subscribe + public void walletMixConfigChanged(WalletMixConfigChangedEvent event) { + if(persistsFor(event.getWallet()) && event.getWallet().getMixConfig() != null) { + dirtyPersistablesMap.computeIfAbsent(event.getWallet(), key -> new DirtyPersistables()).mixConfig = true; + } + } + @Subscribe public void walletUtxoMixesChanged(WalletUtxoMixesChangedEvent event) { if(persistsFor(event.getWallet())) { @@ -680,6 +692,7 @@ public class DbPersistence implements Persistence { public Integer blockHeight = null; public final List labelEntries = new ArrayList<>(); public final List utxoStatuses = new ArrayList<>(); + public boolean mixConfig; public final Map changedUtxoMixes = new HashMap<>(); public final Map removedUtxoMixes = new HashMap<>(); public final List labelKeystores = new ArrayList<>(); @@ -694,6 +707,7 @@ public class DbPersistence implements Persistence { "\nAddress labels:" + labelEntries.stream().filter(entry -> entry instanceof NodeEntry).map(entry -> ((NodeEntry)entry).getNode().toString() + " " + entry.getLabel()).collect(Collectors.toList()) + "\nUTXO labels:" + labelEntries.stream().filter(entry -> entry instanceof HashIndexEntry).map(entry -> ((HashIndexEntry)entry).getHashIndex().toString()).collect(Collectors.toList()) + "\nUTXO statuses:" + utxoStatuses + + "\nMix config:" + mixConfig + "\nUTXO mixes changed:" + changedUtxoMixes + "\nUTXO mixes removed:" + removedUtxoMixes + "\nKeystore labels:" + labelKeystores.stream().map(Keystore::getLabel).collect(Collectors.toList()) + diff --git a/src/main/java/com/sparrowwallet/sparrow/io/db/MixConfigDao.java b/src/main/java/com/sparrowwallet/sparrow/io/db/MixConfigDao.java new file mode 100644 index 00000000..b2e7b571 --- /dev/null +++ b/src/main/java/com/sparrowwallet/sparrow/io/db/MixConfigDao.java @@ -0,0 +1,41 @@ +package com.sparrowwallet.sparrow.io.db; + +import com.sparrowwallet.drongo.wallet.MixConfig; +import com.sparrowwallet.drongo.wallet.Wallet; +import org.jdbi.v3.sqlobject.config.RegisterRowMapper; +import org.jdbi.v3.sqlobject.statement.GetGeneratedKeys; +import org.jdbi.v3.sqlobject.statement.SqlQuery; +import org.jdbi.v3.sqlobject.statement.SqlUpdate; + +public interface MixConfigDao { + @SqlQuery("select id, scode, mixOnStartup, mixToWalletFile, mixToWalletName, minMixes from mixConfig where wallet = ?") + @RegisterRowMapper(MixConfigMapper.class) + MixConfig getForWalletId(Long id); + + @SqlUpdate("insert into mixConfig (scode, mixOnStartup, mixToWalletFile, mixToWalletName, minMixes, wallet) values (?, ?, ?, ?, ?, ?)") + @GetGeneratedKeys("id") + long insertMixConfig(String scode, Boolean mixOnStartup, String mixToWalletFile, String mixToWalletName, Integer minMixes, long wallet); + + @SqlUpdate("update mixConfig set scode = ?, mixOnStartup = ?, mixToWalletFile = ?, mixToWalletName = ?, minMixes = ?, wallet = ? where id = ?") + void updateMixConfig(String scode, Boolean mixOnStartup, String mixToWalletFile, String mixToWalletName, Integer minMixes, long wallet, long id); + + default void addMixConfig(Wallet wallet) { + if(wallet.getMixConfig() != null) { + addOrUpdate(wallet, wallet.getMixConfig()); + } + } + + default void addOrUpdate(Wallet wallet, MixConfig mixConfig) { + String mixToWalletFile = null; + if(mixConfig.getMixToWalletFile() != null) { + mixToWalletFile = mixConfig.getMixToWalletFile().getAbsolutePath(); + } + + if(mixConfig.getId() == null) { + long id = insertMixConfig(mixConfig.getScode(), mixConfig.getMixOnStartup(), mixToWalletFile, mixConfig.getMixToWalletName(), mixConfig.getMinMixes(), wallet.getId()); + mixConfig.setId(id); + } else { + updateMixConfig(mixConfig.getScode(), mixConfig.getMixOnStartup(), mixToWalletFile, mixConfig.getMixToWalletName(), mixConfig.getMinMixes(), wallet.getId(), mixConfig.getId()); + } + } +} diff --git a/src/main/java/com/sparrowwallet/sparrow/io/db/MixConfigMapper.java b/src/main/java/com/sparrowwallet/sparrow/io/db/MixConfigMapper.java new file mode 100644 index 00000000..fdef41e9 --- /dev/null +++ b/src/main/java/com/sparrowwallet/sparrow/io/db/MixConfigMapper.java @@ -0,0 +1,33 @@ +package com.sparrowwallet.sparrow.io.db; + +import com.sparrowwallet.drongo.wallet.MixConfig; +import org.jdbi.v3.core.mapper.RowMapper; +import org.jdbi.v3.core.statement.StatementContext; + +import java.io.File; +import java.sql.ResultSet; +import java.sql.SQLException; + +public class MixConfigMapper implements RowMapper { + @Override + public MixConfig map(ResultSet rs, StatementContext ctx) throws SQLException { + String scode = rs.getString("scode"); + + Boolean mixOnStartup = rs.getBoolean("mixOnStartup"); + if(rs.wasNull()) { + mixOnStartup = null; + } + + String mixToWalletFile = rs.getString("mixToWalletFile"); + String mixToWalletName = rs.getString("mixToWalletName"); + + Integer minMixes = rs.getInt("minMixes"); + if(rs.wasNull()) { + minMixes = null; + } + + MixConfig mixConfig = new MixConfig(scode, mixOnStartup, mixToWalletFile == null ? null : new File(mixToWalletFile), mixToWalletName, minMixes); + mixConfig.setId(rs.getLong("id")); + return mixConfig; + } +} diff --git a/src/main/java/com/sparrowwallet/sparrow/io/db/WalletDao.java b/src/main/java/com/sparrowwallet/sparrow/io/db/WalletDao.java index fcbac482..206bc0a8 100644 --- a/src/main/java/com/sparrowwallet/sparrow/io/db/WalletDao.java +++ b/src/main/java/com/sparrowwallet/sparrow/io/db/WalletDao.java @@ -30,6 +30,9 @@ public interface WalletDao { @CreateSqlObject BlockTransactionDao createBlockTransactionDao(); + @CreateSqlObject + MixConfigDao createMixConfigDao(); + @CreateSqlObject UtxoMixDataDao createUtxoMixDataDao(); @@ -91,6 +94,8 @@ public interface WalletDao { Map blockTransactions = createBlockTransactionDao().getForWalletId(wallet.getId()); //.stream().collect(Collectors.toMap(BlockTransaction::getHash, Function.identity(), (existing, replacement) -> existing, LinkedHashMap::new)); wallet.updateTransactions(blockTransactions); + wallet.setMixConfig(createMixConfigDao().getForWalletId(wallet.getId())); + Map utxoMixes = createUtxoMixDataDao().getForWalletId(wallet.getId()); wallet.getUtxoMixes().putAll(utxoMixes); } @@ -106,6 +111,7 @@ public interface WalletDao { createKeystoreDao().addKeystores(wallet); createWalletNodeDao().addWalletNodes(wallet); createBlockTransactionDao().addBlockTransactions(wallet); + createMixConfigDao().addMixConfig(wallet); createUtxoMixDataDao().addUtxoMixData(wallet); } finally { setSchema(DbPersistence.DEFAULT_SCHEMA); diff --git a/src/main/java/com/sparrowwallet/sparrow/wallet/SendController.java b/src/main/java/com/sparrowwallet/sparrow/wallet/SendController.java index d1afe22e..c466e638 100644 --- a/src/main/java/com/sparrowwallet/sparrow/wallet/SendController.java +++ b/src/main/java/com/sparrowwallet/sparrow/wallet/SendController.java @@ -1110,7 +1110,8 @@ public class SendController extends WalletFormController implements Initializabl public void broadcastPremix(ActionEvent event) { //Ensure all child wallets have been saved - for(Wallet childWallet : getWalletForm().getWallet().getChildWallets()) { + Wallet masterWallet = getWalletForm().getWallet().isMasterWallet() ? getWalletForm().getWallet() : getWalletForm().getWallet().getMasterWallet(); + for(Wallet childWallet : masterWallet.getChildWallets()) { Storage storage = AppServices.get().getOpenWallets().get(childWallet); if(!storage.isPersisted(childWallet)) { try { @@ -1122,7 +1123,7 @@ public class SendController extends WalletFormController implements Initializabl } //The WhirlpoolWallet has already been configured for the tx0 preview - Whirlpool whirlpool = AppServices.get().getWhirlpool(getWalletForm().getWalletId()); + Whirlpool whirlpool = AppServices.get().getWhirlpool(getWalletForm().getStorage().getWalletId(masterWallet)); Map utxos = walletTransactionProperty.get().getSelectedUtxos(); Whirlpool.Tx0BroadcastService tx0BroadcastService = new Whirlpool.Tx0BroadcastService(whirlpool, whirlpoolProperty.get(), utxos.keySet()); tx0BroadcastService.setOnRunning(workerStateEvent -> { diff --git a/src/main/java/com/sparrowwallet/sparrow/wallet/UtxosController.java b/src/main/java/com/sparrowwallet/sparrow/wallet/UtxosController.java index 9710b5fe..a81e5b25 100644 --- a/src/main/java/com/sparrowwallet/sparrow/wallet/UtxosController.java +++ b/src/main/java/com/sparrowwallet/sparrow/wallet/UtxosController.java @@ -170,7 +170,7 @@ public class UtxosController extends WalletFormController implements Initializab Wallet wallet = getWalletForm().getWallet(); String walletId = walletForm.getWalletId(); - if(!wallet.isWhirlpoolMasterWallet() && wallet.isEncrypted()) { + if(wallet.isMasterWallet() && !wallet.isWhirlpoolMasterWallet() && wallet.isEncrypted()) { WalletPasswordDialog dlg = new WalletPasswordDialog(wallet.getMasterName(), WalletPasswordDialog.PasswordRequirement.LOAD); Optional password = dlg.showAndWait(); if(password.isPresent()) { @@ -205,7 +205,7 @@ public class UtxosController extends WalletFormController implements Initializab keyDerivationService.start(); } } else { - if(!wallet.isWhirlpoolMasterWallet()) { + if(wallet.isMasterWallet() && !wallet.isWhirlpoolMasterWallet()) { prepareWhirlpoolWallet(wallet); } @@ -215,7 +215,7 @@ public class UtxosController extends WalletFormController implements Initializab private void prepareWhirlpoolWallet(Wallet decryptedWallet) { Whirlpool whirlpool = AppServices.get().getWhirlpool(getWalletForm().getWalletId()); - whirlpool.setScode(Config.get().getScode()); + whirlpool.setScode(decryptedWallet.getOrCreateMixConfig().getScode()); whirlpool.setHDWallet(getWalletForm().getWalletId(), decryptedWallet); for(StandardAccount whirlpoolAccount : StandardAccount.WHIRLPOOL_ACCOUNTS) { @@ -227,8 +227,10 @@ public class UtxosController extends WalletFormController implements Initializab } private void previewPremix(Wallet wallet, Tx0Preview tx0Preview, List utxoEntries) { - Wallet premixWallet = wallet.getChildWallet(StandardAccount.WHIRLPOOL_PREMIX); - Wallet badbankWallet = wallet.getChildWallet(StandardAccount.WHIRLPOOL_BADBANK); + Wallet masterWallet = wallet.isMasterWallet() ? wallet : wallet.getMasterWallet(); + + Wallet premixWallet = masterWallet.getChildWallet(StandardAccount.WHIRLPOOL_PREMIX); + Wallet badbankWallet = masterWallet.getChildWallet(StandardAccount.WHIRLPOOL_BADBANK); List payments = new ArrayList<>(); try { @@ -284,6 +286,10 @@ public class UtxosController extends WalletFormController implements Initializab }); startupService.start(); } + + Wallet masterWallet = getWalletForm().getWallet().isMasterWallet() ? getWalletForm().getWallet() : getWalletForm().getWallet().getMasterWallet(); + masterWallet.getOrCreateMixConfig().setMixOnStartup(Boolean.TRUE); + EventManager.get().post(new WalletMixConfigChangedEvent(masterWallet)); } public void stopMixing(ActionEvent event) { @@ -302,6 +308,10 @@ public class UtxosController extends WalletFormController implements Initializab //Ensure http clients are shutdown whirlpool.shutdown(); } + + Wallet masterWallet = getWalletForm().getWallet().isMasterWallet() ? getWalletForm().getWallet() : getWalletForm().getWallet().getMasterWallet(); + masterWallet.getOrCreateMixConfig().setMixOnStartup(Boolean.FALSE); + EventManager.get().post(new WalletMixConfigChangedEvent(masterWallet)); } public void exportUtxos(ActionEvent event) { diff --git a/src/main/java/com/sparrowwallet/sparrow/wallet/WalletForm.java b/src/main/java/com/sparrowwallet/sparrow/wallet/WalletForm.java index a7d601c4..9b99f727 100644 --- a/src/main/java/com/sparrowwallet/sparrow/wallet/WalletForm.java +++ b/src/main/java/com/sparrowwallet/sparrow/wallet/WalletForm.java @@ -469,6 +469,13 @@ public class WalletForm { } } + @Subscribe + public void walletMixConfigChanged(WalletMixConfigChangedEvent event) { + if(event.getWallet() == wallet) { + Platform.runLater(() -> EventManager.get().post(new WalletDataChangedEvent(wallet))); + } + } + @Subscribe public void walletUtxoMixesChanged(WalletUtxoMixesChangedEvent event) { if(event.getWallet() == wallet) { diff --git a/src/main/java/com/sparrowwallet/sparrow/whirlpool/Whirlpool.java b/src/main/java/com/sparrowwallet/sparrow/whirlpool/Whirlpool.java index f96d5051..30d54cf3 100644 --- a/src/main/java/com/sparrowwallet/sparrow/whirlpool/Whirlpool.java +++ b/src/main/java/com/sparrowwallet/sparrow/whirlpool/Whirlpool.java @@ -69,7 +69,7 @@ public class Whirlpool { private final BooleanProperty mixingProperty = new SimpleBooleanProperty(false); - public Whirlpool(Network network, HostAndPort torProxy, String sCode) { + public Whirlpool(Network network, HostAndPort torProxy) { this.torProxy = torProxy; this.whirlpoolServer = WhirlpoolServer.valueOf(network.getName().toUpperCase()); this.httpClientService = new JavaHttpClientService(torProxy); @@ -77,12 +77,12 @@ public class Whirlpool { this.torClientService = new WhirlpoolTorClientService(); this.whirlpoolWalletService = new WhirlpoolWalletService(); - this.config = computeWhirlpoolWalletConfig(sCode); + this.config = computeWhirlpoolWalletConfig(); WhirlpoolEventService.getInstance().register(this); } - private WhirlpoolWalletConfig computeWhirlpoolWalletConfig(String sCode) { + private WhirlpoolWalletConfig computeWhirlpoolWalletConfig() { DataPersisterFactory dataPersisterFactory = (whirlpoolWallet, bip44w) -> new SparrowDataPersister(whirlpoolWallet); DataSourceFactory dataSourceFactory = (whirlpoolWallet, bip44w, dataPersister) -> new SparrowDataSource(whirlpoolWallet, bip44w, dataPersister); @@ -92,7 +92,6 @@ public class Whirlpool { WhirlpoolWalletConfig whirlpoolWalletConfig = new WhirlpoolWalletConfig(dataSourceFactory, httpClientService, stompClientService, torClientService, serverApi, whirlpoolServer.getParams(), false); whirlpoolWalletConfig.setDataPersisterFactory(dataPersisterFactory); - whirlpoolWalletConfig.setScode(sCode); return whirlpoolWalletConfig; } @@ -343,6 +342,14 @@ public class Whirlpool { config.setScode(scode); } + public void setExternalDestination(ExternalDestination externalDestination) { + if(whirlpoolWalletService.whirlpoolWallet() != null) { + throw new IllegalStateException("Cannot set external destination while WhirlpoolWallet is running"); + } + + config.setExternalDestination(externalDestination); + } + public boolean isMixing() { return mixingProperty.get(); } diff --git a/src/main/java/com/sparrowwallet/sparrow/whirlpool/WhirlpoolController.java b/src/main/java/com/sparrowwallet/sparrow/whirlpool/WhirlpoolController.java index fd828c65..3066bd48 100644 --- a/src/main/java/com/sparrowwallet/sparrow/whirlpool/WhirlpoolController.java +++ b/src/main/java/com/sparrowwallet/sparrow/whirlpool/WhirlpoolController.java @@ -4,9 +4,12 @@ import com.samourai.whirlpool.client.tx0.Tx0Preview; import com.samourai.whirlpool.client.whirlpool.beans.Pool; import com.sparrowwallet.drongo.BitcoinUnit; import com.sparrowwallet.drongo.protocol.Transaction; +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.control.CoinLabel; +import com.sparrowwallet.sparrow.event.WalletMixConfigChangedEvent; import com.sparrowwallet.sparrow.io.Config; import com.sparrowwallet.sparrow.wallet.Entry; import com.sparrowwallet.sparrow.wallet.UtxoEntry; @@ -72,6 +75,7 @@ public class WhirlpoolController { private String walletId; private Wallet wallet; + private MixConfig mixConfig; private List utxoEntries; private final ObjectProperty tx0PreviewProperty = new SimpleObjectProperty<>(null); @@ -79,6 +83,7 @@ public class WhirlpoolController { this.walletId = walletId; this.wallet = wallet; this.utxoEntries = utxoEntries; + this.mixConfig = wallet.isMasterWallet() ? wallet.getOrCreateMixConfig() : wallet.getMasterWallet().getOrCreateMixConfig(); step1.managedProperty().bind(step1.visibleProperty()); step2.managedProperty().bind(step2.visibleProperty()); @@ -89,12 +94,13 @@ public class WhirlpoolController { step3.setVisible(false); step4.setVisible(false); - scode.setText(Config.get().getScode() == null ? "" : Config.get().getScode()); + scode.setText(mixConfig.getScode() == null ? "" : mixConfig.getScode()); scode.textProperty().addListener((observable, oldValue, newValue) -> { - Config.get().setScode(newValue); + mixConfig.setScode(newValue); + EventManager.get().post(new WalletMixConfigChangedEvent(wallet.isMasterWallet() ? wallet : wallet.getMasterWallet())); }); - if(Config.get().getScode() != null) { + if(mixConfig.getScode() != null) { step1.setVisible(false); step3.setVisible(true); } @@ -193,7 +199,7 @@ public class WhirlpoolController { List availablePools = poolsService.getValue().stream().filter(pool1 -> totalUtxoValue >= (pool1.getPremixValueMin() + pool1.getFeeValue())).toList(); if(availablePools.isEmpty()) { pool.setVisible(false); - OptionalLong optMinValue = poolsService.getValue().stream().mapToLong(Pool::getMustMixBalanceMin).min(); + OptionalLong optMinValue = poolsService.getValue().stream().mapToLong(pool1 -> pool1.getPremixValueMin() + pool1.getFeeValue()).min(); if(optMinValue.isPresent()) { String satsValue = String.format(Locale.ENGLISH, "%,d", optMinValue.getAsLong()) + " sats"; String btcValue = CoinLabel.BTC_FORMAT.format((double)optMinValue.getAsLong() / Transaction.SATOSHIS_PER_BITCOIN) + " BTC"; @@ -224,17 +230,20 @@ public class WhirlpoolController { } private void fetchTx0Preview(Pool pool) { - if(Config.get().getScode() == null) { - Config.get().setScode(""); + if(mixConfig.getScode() == null) { + mixConfig.setScode(""); + EventManager.get().post(new WalletMixConfigChangedEvent(wallet.isMasterWallet() ? wallet : wallet.getMasterWallet())); } Whirlpool whirlpool = AppServices.get().getWhirlpool(walletId); - whirlpool.setScode(Config.get().getScode()); + 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); }); tx0PreviewService.setOnSucceeded(workerStateEvent -> { Tx0Preview tx0Preview = tx0PreviewService.getValue(); diff --git a/src/main/java/com/sparrowwallet/sparrow/whirlpool/WhirlpoolDialog.java b/src/main/java/com/sparrowwallet/sparrow/whirlpool/WhirlpoolDialog.java index 103d13f4..0270f955 100644 --- a/src/main/java/com/sparrowwallet/sparrow/whirlpool/WhirlpoolDialog.java +++ b/src/main/java/com/sparrowwallet/sparrow/whirlpool/WhirlpoolDialog.java @@ -54,7 +54,8 @@ public class WhirlpoolDialog extends Dialog { backButton.managedProperty().bind(backButton.visibleProperty()); previewButton.managedProperty().bind(previewButton.visibleProperty()); - if(Config.get().getScode() == null) { + Wallet masterWallet = wallet.isMasterWallet() ? wallet : wallet.getMasterWallet(); + if(masterWallet.getOrCreateMixConfig().getScode() == null) { backButton.setDisable(true); } previewButton.visibleProperty().bind(nextButton.visibleProperty().not()); diff --git a/src/main/resources/com/sparrowwallet/sparrow/sql/V2__Whirlpool.sql b/src/main/resources/com/sparrowwallet/sparrow/sql/V2__Whirlpool.sql index c99d6760..d2f62c62 100644 --- a/src/main/resources/com/sparrowwallet/sparrow/sql/V2__Whirlpool.sql +++ b/src/main/resources/com/sparrowwallet/sparrow/sql/V2__Whirlpool.sql @@ -1 +1,2 @@ +create table mixConfig (id identity not null, scode varchar(255), mixOnStartup boolean, mixToWalletFile varchar(1024), mixToWalletName varchar(255), minMixes integer, wallet bigint not null); create table utxoMixData (id identity not null, hash binary(32) not null, mixesDone integer not null default 0, expired bigint, wallet bigint not null); \ No newline at end of file