diff --git a/drongo b/drongo index b4f4cc87..94d22b87 160000 --- a/drongo +++ b/drongo @@ -1 +1 @@ -Subproject commit b4f4cc8726de3e7b5f875816affe1e0f78f2fa25 +Subproject commit 94d22b875868760a95222e0254ec10b59c71e04f diff --git a/src/main/java/com/sparrowwallet/sparrow/AppController.java b/src/main/java/com/sparrowwallet/sparrow/AppController.java index ade0dac5..396143bd 100644 --- a/src/main/java/com/sparrowwallet/sparrow/AppController.java +++ b/src/main/java/com/sparrowwallet/sparrow/AppController.java @@ -1721,7 +1721,7 @@ public class AppController implements Initializable { text += event.getValueAsText(event.getTotalValue()); } else if(blockTransactions.size() > 1) { if(event.getTotalBlockchainValue() > 0 && event.getTotalMempoolValue() > 0) { - text = "New transactions: " + event.getValueAsText(event.getTotalValue()) + " total (" + event.getValueAsText(event.getTotalMempoolValue()) + " in mempool)"; + text = "New transactions: " + event.getValueAsText(event.getTotalValue()) + " total"; } else if(event.getTotalMempoolValue() > 0) { text = "New mempool transactions: " + event.getValueAsText(event.getTotalMempoolValue()) + " total"; } else { diff --git a/src/main/java/com/sparrowwallet/sparrow/event/WalletMasterMixConfigChangedEvent.java b/src/main/java/com/sparrowwallet/sparrow/event/WalletMasterMixConfigChangedEvent.java new file mode 100644 index 00000000..5c38f182 --- /dev/null +++ b/src/main/java/com/sparrowwallet/sparrow/event/WalletMasterMixConfigChangedEvent.java @@ -0,0 +1,9 @@ +package com.sparrowwallet.sparrow.event; + +import com.sparrowwallet.drongo.wallet.Wallet; + +public class WalletMasterMixConfigChangedEvent extends WalletMixConfigChangedEvent { + public WalletMasterMixConfigChangedEvent(Wallet wallet) { + super(wallet.isMasterWallet() ? wallet : wallet.getMasterWallet()); + } +} diff --git a/src/main/java/com/sparrowwallet/sparrow/event/WalletMixConfigChangedEvent.java b/src/main/java/com/sparrowwallet/sparrow/event/WalletMixConfigChangedEvent.java index 7b7ea89b..c16c6663 100644 --- a/src/main/java/com/sparrowwallet/sparrow/event/WalletMixConfigChangedEvent.java +++ b/src/main/java/com/sparrowwallet/sparrow/event/WalletMixConfigChangedEvent.java @@ -4,6 +4,6 @@ import com.sparrowwallet.drongo.wallet.Wallet; public class WalletMixConfigChangedEvent extends WalletChangedEvent { public WalletMixConfigChangedEvent(Wallet wallet) { - super(wallet.isMasterWallet() ? wallet : wallet.getMasterWallet()); + super(wallet); } } diff --git a/src/main/java/com/sparrowwallet/sparrow/io/db/MixConfigDao.java b/src/main/java/com/sparrowwallet/sparrow/io/db/MixConfigDao.java index b2e7b571..22f1574f 100644 --- a/src/main/java/com/sparrowwallet/sparrow/io/db/MixConfigDao.java +++ b/src/main/java/com/sparrowwallet/sparrow/io/db/MixConfigDao.java @@ -8,16 +8,16 @@ 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 = ?") + @SqlQuery("select id, scode, mixOnStartup, mixToWalletFile, mixToWalletName, minMixes, receiveIndex, changeIndex from mixConfig where wallet = ?") @RegisterRowMapper(MixConfigMapper.class) MixConfig getForWalletId(Long id); - @SqlUpdate("insert into mixConfig (scode, mixOnStartup, mixToWalletFile, mixToWalletName, minMixes, wallet) values (?, ?, ?, ?, ?, ?)") + @SqlUpdate("insert into mixConfig (scode, mixOnStartup, mixToWalletFile, mixToWalletName, minMixes, receiveIndex, changeIndex, wallet) values (?, ?, ?, ?, ?, ?, ?, ?)") @GetGeneratedKeys("id") - long insertMixConfig(String scode, Boolean mixOnStartup, String mixToWalletFile, String mixToWalletName, Integer minMixes, long wallet); + long insertMixConfig(String scode, Boolean mixOnStartup, String mixToWalletFile, String mixToWalletName, Integer minMixes, int receiveIndex, int changeIndex, 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); + @SqlUpdate("update mixConfig set scode = ?, mixOnStartup = ?, mixToWalletFile = ?, mixToWalletName = ?, minMixes = ?, receiveIndex = ?, changeIndex = ?, wallet = ? where id = ?") + void updateMixConfig(String scode, Boolean mixOnStartup, String mixToWalletFile, String mixToWalletName, Integer minMixes, int receiveIndex, int changeIndex, long wallet, long id); default void addMixConfig(Wallet wallet) { if(wallet.getMixConfig() != null) { @@ -32,10 +32,10 @@ public interface MixConfigDao { } if(mixConfig.getId() == null) { - long id = insertMixConfig(mixConfig.getScode(), mixConfig.getMixOnStartup(), mixToWalletFile, mixConfig.getMixToWalletName(), mixConfig.getMinMixes(), wallet.getId()); + long id = insertMixConfig(mixConfig.getScode(), mixConfig.getMixOnStartup(), mixToWalletFile, mixConfig.getMixToWalletName(), mixConfig.getMinMixes(), mixConfig.getReceiveIndex(), mixConfig.getChangeIndex(), wallet.getId()); mixConfig.setId(id); } else { - updateMixConfig(mixConfig.getScode(), mixConfig.getMixOnStartup(), mixToWalletFile, mixConfig.getMixToWalletName(), mixConfig.getMinMixes(), wallet.getId(), mixConfig.getId()); + updateMixConfig(mixConfig.getScode(), mixConfig.getMixOnStartup(), mixToWalletFile, mixConfig.getMixToWalletName(), mixConfig.getMinMixes(), mixConfig.getReceiveIndex(), mixConfig.getChangeIndex(), 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 index fdef41e9..1e592672 100644 --- a/src/main/java/com/sparrowwallet/sparrow/io/db/MixConfigMapper.java +++ b/src/main/java/com/sparrowwallet/sparrow/io/db/MixConfigMapper.java @@ -26,7 +26,7 @@ public class MixConfigMapper implements RowMapper { minMixes = null; } - MixConfig mixConfig = new MixConfig(scode, mixOnStartup, mixToWalletFile == null ? null : new File(mixToWalletFile), mixToWalletName, minMixes); + MixConfig mixConfig = new MixConfig(scode, mixOnStartup, mixToWalletFile == null ? null : new File(mixToWalletFile), mixToWalletName, minMixes, rs.getInt("receiveIndex"), rs.getInt("changeIndex")); mixConfig.setId(rs.getLong("id")); return mixConfig; } diff --git a/src/main/java/com/sparrowwallet/sparrow/wallet/MixToController.java b/src/main/java/com/sparrowwallet/sparrow/wallet/MixToController.java index b2225085..6811af68 100644 --- a/src/main/java/com/sparrowwallet/sparrow/wallet/MixToController.java +++ b/src/main/java/com/sparrowwallet/sparrow/wallet/MixToController.java @@ -6,7 +6,7 @@ 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.WalletMixConfigChangedEvent; +import com.sparrowwallet.sparrow.event.WalletMasterMixConfigChangedEvent; import com.sparrowwallet.sparrow.whirlpool.Whirlpool; import javafx.collections.FXCollections; import javafx.fxml.FXML; @@ -72,14 +72,14 @@ public class MixToController implements Initializable { mixConfig.setMixToWalletFile(AppServices.get().getOpenWallets().get(newValue).getWalletFile()); } - EventManager.get().post(new WalletMixConfigChangedEvent(wallet)); + EventManager.get().post(new WalletMasterMixConfigChangedEvent(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 WalletMixConfigChangedEvent(wallet)); + EventManager.get().post(new WalletMasterMixConfigChangedEvent(wallet)); }); } } diff --git a/src/main/java/com/sparrowwallet/sparrow/wallet/UtxosController.java b/src/main/java/com/sparrowwallet/sparrow/wallet/UtxosController.java index 7abd84a5..ebdb621a 100644 --- a/src/main/java/com/sparrowwallet/sparrow/wallet/UtxosController.java +++ b/src/main/java/com/sparrowwallet/sparrow/wallet/UtxosController.java @@ -322,7 +322,7 @@ public class UtxosController extends WalletFormController implements Initializab } getWalletForm().getWallet().getMasterMixConfig().setMixOnStartup(Boolean.TRUE); - EventManager.get().post(new WalletMixConfigChangedEvent(getWalletForm().getWallet())); + EventManager.get().post(new WalletMasterMixConfigChangedEvent(getWalletForm().getWallet())); } public void stopMixing(ActionEvent event) { @@ -343,7 +343,7 @@ public class UtxosController extends WalletFormController implements Initializab } getWalletForm().getWallet().getMasterMixConfig().setMixOnStartup(Boolean.FALSE); - EventManager.get().post(new WalletMixConfigChangedEvent(getWalletForm().getWallet())); + EventManager.get().post(new WalletMasterMixConfigChangedEvent(getWalletForm().getWallet())); } public void showMixToDialog(ActionEvent event) { @@ -359,7 +359,7 @@ public class UtxosController extends WalletFormController implements Initializab } catch(NoSuchElementException e) { mixConfig.setMixToWalletName(null); mixConfig.setMixToWalletFile(null); - EventManager.get().post(new WalletMixConfigChangedEvent(getWalletForm().getWallet())); + EventManager.get().post(new WalletMasterMixConfigChangedEvent(getWalletForm().getWallet())); whirlpool.setMixToWallet(null, null); } diff --git a/src/main/java/com/sparrowwallet/sparrow/whirlpool/WhirlpoolController.java b/src/main/java/com/sparrowwallet/sparrow/whirlpool/WhirlpoolController.java index f767a63b..7b27df94 100644 --- a/src/main/java/com/sparrowwallet/sparrow/whirlpool/WhirlpoolController.java +++ b/src/main/java/com/sparrowwallet/sparrow/whirlpool/WhirlpoolController.java @@ -9,7 +9,7 @@ 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.event.WalletMasterMixConfigChangedEvent; import com.sparrowwallet.sparrow.io.Config; import com.sparrowwallet.sparrow.wallet.Entry; import com.sparrowwallet.sparrow.wallet.UtxoEntry; @@ -95,9 +95,13 @@ public class WhirlpoolController { step4.setVisible(false); scode.setText(mixConfig.getScode() == null ? "" : mixConfig.getScode()); + scode.setTextFormatter(new TextFormatter<>((change) -> { + change.setText(change.getText().toUpperCase()); + return change; + })); scode.textProperty().addListener((observable, oldValue, newValue) -> { mixConfig.setScode(newValue); - EventManager.get().post(new WalletMixConfigChangedEvent(wallet)); + EventManager.get().post(new WalletMasterMixConfigChangedEvent(wallet)); }); if(mixConfig.getScode() != null) { @@ -232,7 +236,7 @@ public class WhirlpoolController { private void fetchTx0Preview(Pool pool) { if(mixConfig.getScode() == null) { mixConfig.setScode(""); - EventManager.get().post(new WalletMixConfigChangedEvent(wallet)); + EventManager.get().post(new WalletMasterMixConfigChangedEvent(wallet)); } Whirlpool whirlpool = AppServices.getWhirlpoolServices().getWhirlpool(walletId); diff --git a/src/main/java/com/sparrowwallet/sparrow/whirlpool/dataSource/SparrowIndexHandler.java b/src/main/java/com/sparrowwallet/sparrow/whirlpool/dataSource/SparrowIndexHandler.java index a0aa8d4d..84f3bf88 100644 --- a/src/main/java/com/sparrowwallet/sparrow/whirlpool/dataSource/SparrowIndexHandler.java +++ b/src/main/java/com/sparrowwallet/sparrow/whirlpool/dataSource/SparrowIndexHandler.java @@ -1,33 +1,70 @@ package com.sparrowwallet.sparrow.whirlpool.dataSource; import com.samourai.wallet.client.indexHandler.AbstractIndexHandler; +import com.sparrowwallet.drongo.KeyPurpose; +import com.sparrowwallet.drongo.wallet.Wallet; import com.sparrowwallet.drongo.wallet.WalletNode; +import com.sparrowwallet.sparrow.EventManager; +import com.sparrowwallet.sparrow.event.WalletMixConfigChangedEvent; public class SparrowIndexHandler extends AbstractIndexHandler { + private final Wallet wallet; private final WalletNode walletNode; private final int defaultValue; - public SparrowIndexHandler(WalletNode walletNode) { - this(walletNode, 0); + public SparrowIndexHandler(Wallet wallet, WalletNode walletNode) { + this(wallet, walletNode, 0); } - public SparrowIndexHandler(WalletNode walletNode, int defaultValue) { + public SparrowIndexHandler(Wallet wallet, WalletNode walletNode, int defaultValue) { + this.wallet = wallet; this.walletNode = walletNode; this.defaultValue = defaultValue; } @Override public synchronized int get() { - Integer currentIndex = walletNode.getHighestUsedIndex(); - return currentIndex == null ? defaultValue : currentIndex + 1; + return Math.max(getCurrentIndex(), getStoredIndex()); } @Override public synchronized int getAndIncrement() { - return get(); + int index = get(); + set(index + 1); + return index; } @Override public synchronized void set(int value) { + setStoredIndex(value); + } + + private int getCurrentIndex() { + Integer currentIndex = walletNode.getHighestUsedIndex(); + return currentIndex == null ? defaultValue : currentIndex + 1; + } + + private int getStoredIndex() { + if(wallet.getMixConfig() != null) { + if(walletNode.getKeyPurpose() == KeyPurpose.RECEIVE) { + return wallet.getMixConfig().getReceiveIndex(); + } else if(walletNode.getKeyPurpose() == KeyPurpose.CHANGE) { + return wallet.getMixConfig().getChangeIndex(); + } + } + + return defaultValue; + } + + private void setStoredIndex(int index) { + if(wallet.getMixConfig() != null) { + if(walletNode.getKeyPurpose() == KeyPurpose.RECEIVE) { + wallet.getMixConfig().setReceiveIndex(index); + } else if(walletNode.getKeyPurpose() == KeyPurpose.CHANGE) { + wallet.getMixConfig().setChangeIndex(index); + } + } + + EventManager.get().post(new WalletMixConfigChangedEvent(wallet)); } } diff --git a/src/main/java/com/sparrowwallet/sparrow/whirlpool/dataSource/SparrowWalletStateSupplier.java b/src/main/java/com/sparrowwallet/sparrow/whirlpool/dataSource/SparrowWalletStateSupplier.java index 6ebe6cfa..c7fe1740 100644 --- a/src/main/java/com/sparrowwallet/sparrow/whirlpool/dataSource/SparrowWalletStateSupplier.java +++ b/src/main/java/com/sparrowwallet/sparrow/whirlpool/dataSource/SparrowWalletStateSupplier.java @@ -8,6 +8,7 @@ import com.samourai.whirlpool.client.wallet.beans.WhirlpoolAccount; import com.samourai.whirlpool.client.wallet.data.walletState.WalletStateSupplier; import com.sparrowwallet.drongo.KeyPurpose; import com.sparrowwallet.drongo.crypto.ChildNumber; +import com.sparrowwallet.drongo.wallet.MixConfig; import com.sparrowwallet.drongo.wallet.Wallet; import com.sparrowwallet.drongo.wallet.WalletNode; import com.sparrowwallet.sparrow.whirlpool.Whirlpool; @@ -32,10 +33,21 @@ public class SparrowWalletStateSupplier implements WalletStateSupplier { String key = mapKey(whirlpoolAccount, addressType, chain); IIndexHandler indexHandler = indexHandlerWallets.get(key); if (indexHandler == null) { - WalletNode walletNode = findWalletNode(whirlpoolAccount, addressType, chain); - indexHandler = new SparrowIndexHandler(walletNode, 0); + Wallet wallet = findWallet(whirlpoolAccount); + KeyPurpose keyPurpose = (chain == Chain.RECEIVE ? KeyPurpose.RECEIVE : KeyPurpose.CHANGE); + WalletNode walletNode = wallet.getNode(keyPurpose); + + //Ensure mix config is present + MixConfig mixConfig = wallet.getMixConfig(); + if(mixConfig == null) { + mixConfig = new MixConfig(); + wallet.setMixConfig(mixConfig); + } + + indexHandler = new SparrowIndexHandler(wallet, walletNode, 0); indexHandlerWallets.put(key, indexHandler); } + return indexHandler; } @@ -53,7 +65,7 @@ public class SparrowWalletStateSupplier implements WalletStateSupplier { KeyPurpose keyPurpose = KeyPurpose.fromChildNumber(new ChildNumber(externalDestination.getChain())); WalletNode externalNode = externalWallet.getNode(keyPurpose); - externalIndexHandler = new SparrowIndexHandler(externalNode, externalDestination.getStartIndex()); + externalIndexHandler = new SparrowIndexHandler(externalWallet, externalNode, externalDestination.getStartIndex()); } return externalIndexHandler; @@ -89,18 +101,13 @@ public class SparrowWalletStateSupplier implements WalletStateSupplier { return whirlpoolAccount.name()+"_"+addressType.getPurpose()+"_"+chain.getIndex(); } - private WalletNode findWalletNode(WhirlpoolAccount whirlpoolAccount, AddressType addressType, Chain chain) { + private Wallet findWallet(WhirlpoolAccount whirlpoolAccount) { Wallet wallet = getWallet(); if(wallet == null) { throw new IllegalStateException("Can't find wallet with walletId " + walletId); } - // account - Wallet childWallet = Whirlpool.getStandardAccountWallet(whirlpoolAccount, wallet); - - // purpose - KeyPurpose keyPurpose = chain == Chain.RECEIVE ? KeyPurpose.RECEIVE : KeyPurpose.CHANGE; - return childWallet.getNode(keyPurpose); + return Whirlpool.getStandardAccountWallet(whirlpoolAccount, wallet); } private Wallet getWallet() { 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 d2f62c62..ddfc23c1 100644 --- a/src/main/resources/com/sparrowwallet/sparrow/sql/V2__Whirlpool.sql +++ b/src/main/resources/com/sparrowwallet/sparrow/sql/V2__Whirlpool.sql @@ -1,2 +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 mixConfig (id identity not null, scode varchar(255), mixOnStartup boolean, mixToWalletFile varchar(1024), mixToWalletName varchar(255), minMixes integer, receiveIndex integer not null, changeIndex integer not null, 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