mirror of
https://github.com/sparrowwallet/sparrow.git
synced 2024-12-24 12:46:45 +00:00
add mix config persistence and initial usage
This commit is contained in:
parent
13e01451b7
commit
adb77771aa
16 changed files with 171 additions and 38 deletions
2
drongo
2
drongo
|
@ -1 +1 @@
|
||||||
Subproject commit 71b5778226ef22881240143425325525c1a98d06
|
Subproject commit 67836b2b557839317316a3e1c8d18b98a51d0e29
|
|
@ -899,6 +899,7 @@ public class AppController implements Initializable {
|
||||||
if(wallet.isWhirlpoolMasterWallet()) {
|
if(wallet.isWhirlpoolMasterWallet()) {
|
||||||
String walletId = storage.getWalletId(wallet);
|
String walletId = storage.getWalletId(wallet);
|
||||||
Whirlpool whirlpool = AppServices.get().getWhirlpool(walletId);
|
Whirlpool whirlpool = AppServices.get().getWhirlpool(walletId);
|
||||||
|
whirlpool.setScode(wallet.getOrCreateMixConfig().getScode());
|
||||||
whirlpool.setHDWallet(storage.getWalletId(wallet), copy);
|
whirlpool.setHDWallet(storage.getWalletId(wallet), copy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -469,7 +469,7 @@ public class AppServices {
|
||||||
Whirlpool whirlpool = whirlpoolMap.get(walletId);
|
Whirlpool whirlpool = whirlpoolMap.get(walletId);
|
||||||
if(whirlpool == null) {
|
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()));
|
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);
|
whirlpoolMap.put(walletId, whirlpool);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -477,12 +477,15 @@ public class AppServices {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void startAllWhirlpool() {
|
private void startAllWhirlpool() {
|
||||||
for(Whirlpool whirlpool : whirlpoolMap.values().stream().filter(whirlpool -> whirlpool.hasWallet() && !whirlpool.isStarted()).collect(Collectors.toList())) {
|
for(Map.Entry<String, Whirlpool> entry : whirlpoolMap.entrySet().stream().filter(entry -> entry.getValue().hasWallet() && !entry.getValue().isStarted()).collect(Collectors.toList())) {
|
||||||
Whirlpool.StartupService startupService = new Whirlpool.StartupService(whirlpool);
|
Wallet wallet = getWallet(entry.getKey());
|
||||||
startupService.setOnFailed(workerStateEvent -> {
|
if(wallet.getMixConfig() != null && wallet.getMixConfig().getMixOnStartup() != Boolean.FALSE) {
|
||||||
log.error("Failed to start whirlpool", workerStateEvent.getSource().getException());
|
Whirlpool.StartupService startupService = new Whirlpool.StartupService(entry.getValue());
|
||||||
});
|
startupService.setOnFailed(workerStateEvent -> {
|
||||||
startupService.start();
|
log.error("Failed to start whirlpool", workerStateEvent.getSource().getException());
|
||||||
|
});
|
||||||
|
startupService.start();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -974,7 +977,7 @@ public class AppServices {
|
||||||
public void walletOpened(WalletOpenedEvent event) {
|
public void walletOpened(WalletOpenedEvent event) {
|
||||||
String walletId = event.getStorage().getWalletId(event.getWallet());
|
String walletId = event.getStorage().getWalletId(event.getWallet());
|
||||||
Whirlpool whirlpool = whirlpoolMap.get(walletId);
|
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);
|
Whirlpool.StartupService startupService = new Whirlpool.StartupService(whirlpool);
|
||||||
startupService.setOnFailed(workerStateEvent -> {
|
startupService.setOnFailed(workerStateEvent -> {
|
||||||
log.error("Failed to start whirlpool", workerStateEvent.getSource().getException());
|
log.error("Failed to start whirlpool", workerStateEvent.getSource().getException());
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -61,7 +61,6 @@ public class Config {
|
||||||
private String proxyServer;
|
private String proxyServer;
|
||||||
private Double appWidth;
|
private Double appWidth;
|
||||||
private Double appHeight;
|
private Double appHeight;
|
||||||
private String scode;
|
|
||||||
|
|
||||||
private static Config INSTANCE;
|
private static Config INSTANCE;
|
||||||
|
|
||||||
|
@ -489,15 +488,6 @@ public class Config {
|
||||||
flush();
|
flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getScode() {
|
|
||||||
return scode;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setScode(String scode) {
|
|
||||||
this.scode = scode;
|
|
||||||
flush();
|
|
||||||
}
|
|
||||||
|
|
||||||
private synchronized void flush() {
|
private synchronized void flush() {
|
||||||
Gson gson = getGson();
|
Gson gson = getGson();
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -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()) {
|
if(!dirtyPersistables.changedUtxoMixes.isEmpty()) {
|
||||||
UtxoMixDataDao utxoMixDataDao = handle.attach(UtxoMixDataDao.class);
|
UtxoMixDataDao utxoMixDataDao = handle.attach(UtxoMixDataDao.class);
|
||||||
for(Map.Entry<Sha256Hash, UtxoMixData> utxoMixDataEntry : dirtyPersistables.changedUtxoMixes.entrySet()) {
|
for(Map.Entry<Sha256Hash, UtxoMixData> 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
|
@Subscribe
|
||||||
public void walletUtxoMixesChanged(WalletUtxoMixesChangedEvent event) {
|
public void walletUtxoMixesChanged(WalletUtxoMixesChangedEvent event) {
|
||||||
if(persistsFor(event.getWallet())) {
|
if(persistsFor(event.getWallet())) {
|
||||||
|
@ -680,6 +692,7 @@ public class DbPersistence implements Persistence {
|
||||||
public Integer blockHeight = null;
|
public Integer blockHeight = null;
|
||||||
public final List<Entry> labelEntries = new ArrayList<>();
|
public final List<Entry> labelEntries = new ArrayList<>();
|
||||||
public final List<BlockTransactionHashIndex> utxoStatuses = new ArrayList<>();
|
public final List<BlockTransactionHashIndex> utxoStatuses = new ArrayList<>();
|
||||||
|
public boolean mixConfig;
|
||||||
public final Map<Sha256Hash, UtxoMixData> changedUtxoMixes = new HashMap<>();
|
public final Map<Sha256Hash, UtxoMixData> changedUtxoMixes = new HashMap<>();
|
||||||
public final Map<Sha256Hash, UtxoMixData> removedUtxoMixes = new HashMap<>();
|
public final Map<Sha256Hash, UtxoMixData> removedUtxoMixes = new HashMap<>();
|
||||||
public final List<Keystore> labelKeystores = new ArrayList<>();
|
public final List<Keystore> 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()) +
|
"\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 labels:" + labelEntries.stream().filter(entry -> entry instanceof HashIndexEntry).map(entry -> ((HashIndexEntry)entry).getHashIndex().toString()).collect(Collectors.toList()) +
|
||||||
"\nUTXO statuses:" + utxoStatuses +
|
"\nUTXO statuses:" + utxoStatuses +
|
||||||
|
"\nMix config:" + mixConfig +
|
||||||
"\nUTXO mixes changed:" + changedUtxoMixes +
|
"\nUTXO mixes changed:" + changedUtxoMixes +
|
||||||
"\nUTXO mixes removed:" + removedUtxoMixes +
|
"\nUTXO mixes removed:" + removedUtxoMixes +
|
||||||
"\nKeystore labels:" + labelKeystores.stream().map(Keystore::getLabel).collect(Collectors.toList()) +
|
"\nKeystore labels:" + labelKeystores.stream().map(Keystore::getLabel).collect(Collectors.toList()) +
|
||||||
|
|
|
@ -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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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<MixConfig> {
|
||||||
|
@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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -30,6 +30,9 @@ public interface WalletDao {
|
||||||
@CreateSqlObject
|
@CreateSqlObject
|
||||||
BlockTransactionDao createBlockTransactionDao();
|
BlockTransactionDao createBlockTransactionDao();
|
||||||
|
|
||||||
|
@CreateSqlObject
|
||||||
|
MixConfigDao createMixConfigDao();
|
||||||
|
|
||||||
@CreateSqlObject
|
@CreateSqlObject
|
||||||
UtxoMixDataDao createUtxoMixDataDao();
|
UtxoMixDataDao createUtxoMixDataDao();
|
||||||
|
|
||||||
|
@ -91,6 +94,8 @@ public interface WalletDao {
|
||||||
Map<Sha256Hash, BlockTransaction> blockTransactions = createBlockTransactionDao().getForWalletId(wallet.getId()); //.stream().collect(Collectors.toMap(BlockTransaction::getHash, Function.identity(), (existing, replacement) -> existing, LinkedHashMap::new));
|
Map<Sha256Hash, BlockTransaction> blockTransactions = createBlockTransactionDao().getForWalletId(wallet.getId()); //.stream().collect(Collectors.toMap(BlockTransaction::getHash, Function.identity(), (existing, replacement) -> existing, LinkedHashMap::new));
|
||||||
wallet.updateTransactions(blockTransactions);
|
wallet.updateTransactions(blockTransactions);
|
||||||
|
|
||||||
|
wallet.setMixConfig(createMixConfigDao().getForWalletId(wallet.getId()));
|
||||||
|
|
||||||
Map<Sha256Hash, UtxoMixData> utxoMixes = createUtxoMixDataDao().getForWalletId(wallet.getId());
|
Map<Sha256Hash, UtxoMixData> utxoMixes = createUtxoMixDataDao().getForWalletId(wallet.getId());
|
||||||
wallet.getUtxoMixes().putAll(utxoMixes);
|
wallet.getUtxoMixes().putAll(utxoMixes);
|
||||||
}
|
}
|
||||||
|
@ -106,6 +111,7 @@ public interface WalletDao {
|
||||||
createKeystoreDao().addKeystores(wallet);
|
createKeystoreDao().addKeystores(wallet);
|
||||||
createWalletNodeDao().addWalletNodes(wallet);
|
createWalletNodeDao().addWalletNodes(wallet);
|
||||||
createBlockTransactionDao().addBlockTransactions(wallet);
|
createBlockTransactionDao().addBlockTransactions(wallet);
|
||||||
|
createMixConfigDao().addMixConfig(wallet);
|
||||||
createUtxoMixDataDao().addUtxoMixData(wallet);
|
createUtxoMixDataDao().addUtxoMixData(wallet);
|
||||||
} finally {
|
} finally {
|
||||||
setSchema(DbPersistence.DEFAULT_SCHEMA);
|
setSchema(DbPersistence.DEFAULT_SCHEMA);
|
||||||
|
|
|
@ -1110,7 +1110,8 @@ public class SendController extends WalletFormController implements Initializabl
|
||||||
|
|
||||||
public void broadcastPremix(ActionEvent event) {
|
public void broadcastPremix(ActionEvent event) {
|
||||||
//Ensure all child wallets have been saved
|
//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);
|
Storage storage = AppServices.get().getOpenWallets().get(childWallet);
|
||||||
if(!storage.isPersisted(childWallet)) {
|
if(!storage.isPersisted(childWallet)) {
|
||||||
try {
|
try {
|
||||||
|
@ -1122,7 +1123,7 @@ public class SendController extends WalletFormController implements Initializabl
|
||||||
}
|
}
|
||||||
|
|
||||||
//The WhirlpoolWallet has already been configured for the tx0 preview
|
//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<BlockTransactionHashIndex, WalletNode> utxos = walletTransactionProperty.get().getSelectedUtxos();
|
Map<BlockTransactionHashIndex, WalletNode> utxos = walletTransactionProperty.get().getSelectedUtxos();
|
||||||
Whirlpool.Tx0BroadcastService tx0BroadcastService = new Whirlpool.Tx0BroadcastService(whirlpool, whirlpoolProperty.get(), utxos.keySet());
|
Whirlpool.Tx0BroadcastService tx0BroadcastService = new Whirlpool.Tx0BroadcastService(whirlpool, whirlpoolProperty.get(), utxos.keySet());
|
||||||
tx0BroadcastService.setOnRunning(workerStateEvent -> {
|
tx0BroadcastService.setOnRunning(workerStateEvent -> {
|
||||||
|
|
|
@ -170,7 +170,7 @@ public class UtxosController extends WalletFormController implements Initializab
|
||||||
Wallet wallet = getWalletForm().getWallet();
|
Wallet wallet = getWalletForm().getWallet();
|
||||||
String walletId = walletForm.getWalletId();
|
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);
|
WalletPasswordDialog dlg = new WalletPasswordDialog(wallet.getMasterName(), WalletPasswordDialog.PasswordRequirement.LOAD);
|
||||||
Optional<SecureString> password = dlg.showAndWait();
|
Optional<SecureString> password = dlg.showAndWait();
|
||||||
if(password.isPresent()) {
|
if(password.isPresent()) {
|
||||||
|
@ -205,7 +205,7 @@ public class UtxosController extends WalletFormController implements Initializab
|
||||||
keyDerivationService.start();
|
keyDerivationService.start();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if(!wallet.isWhirlpoolMasterWallet()) {
|
if(wallet.isMasterWallet() && !wallet.isWhirlpoolMasterWallet()) {
|
||||||
prepareWhirlpoolWallet(wallet);
|
prepareWhirlpoolWallet(wallet);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -215,7 +215,7 @@ public class UtxosController extends WalletFormController implements Initializab
|
||||||
|
|
||||||
private void prepareWhirlpoolWallet(Wallet decryptedWallet) {
|
private void prepareWhirlpoolWallet(Wallet decryptedWallet) {
|
||||||
Whirlpool whirlpool = AppServices.get().getWhirlpool(getWalletForm().getWalletId());
|
Whirlpool whirlpool = AppServices.get().getWhirlpool(getWalletForm().getWalletId());
|
||||||
whirlpool.setScode(Config.get().getScode());
|
whirlpool.setScode(decryptedWallet.getOrCreateMixConfig().getScode());
|
||||||
whirlpool.setHDWallet(getWalletForm().getWalletId(), decryptedWallet);
|
whirlpool.setHDWallet(getWalletForm().getWalletId(), decryptedWallet);
|
||||||
|
|
||||||
for(StandardAccount whirlpoolAccount : StandardAccount.WHIRLPOOL_ACCOUNTS) {
|
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<UtxoEntry> utxoEntries) {
|
private void previewPremix(Wallet wallet, Tx0Preview tx0Preview, List<UtxoEntry> utxoEntries) {
|
||||||
Wallet premixWallet = wallet.getChildWallet(StandardAccount.WHIRLPOOL_PREMIX);
|
Wallet masterWallet = wallet.isMasterWallet() ? wallet : wallet.getMasterWallet();
|
||||||
Wallet badbankWallet = wallet.getChildWallet(StandardAccount.WHIRLPOOL_BADBANK);
|
|
||||||
|
Wallet premixWallet = masterWallet.getChildWallet(StandardAccount.WHIRLPOOL_PREMIX);
|
||||||
|
Wallet badbankWallet = masterWallet.getChildWallet(StandardAccount.WHIRLPOOL_BADBANK);
|
||||||
|
|
||||||
List<Payment> payments = new ArrayList<>();
|
List<Payment> payments = new ArrayList<>();
|
||||||
try {
|
try {
|
||||||
|
@ -284,6 +286,10 @@ public class UtxosController extends WalletFormController implements Initializab
|
||||||
});
|
});
|
||||||
startupService.start();
|
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) {
|
public void stopMixing(ActionEvent event) {
|
||||||
|
@ -302,6 +308,10 @@ public class UtxosController extends WalletFormController implements Initializab
|
||||||
//Ensure http clients are shutdown
|
//Ensure http clients are shutdown
|
||||||
whirlpool.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) {
|
public void exportUtxos(ActionEvent event) {
|
||||||
|
|
|
@ -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
|
@Subscribe
|
||||||
public void walletUtxoMixesChanged(WalletUtxoMixesChangedEvent event) {
|
public void walletUtxoMixesChanged(WalletUtxoMixesChangedEvent event) {
|
||||||
if(event.getWallet() == wallet) {
|
if(event.getWallet() == wallet) {
|
||||||
|
|
|
@ -69,7 +69,7 @@ public class Whirlpool {
|
||||||
|
|
||||||
private final BooleanProperty mixingProperty = new SimpleBooleanProperty(false);
|
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.torProxy = torProxy;
|
||||||
this.whirlpoolServer = WhirlpoolServer.valueOf(network.getName().toUpperCase());
|
this.whirlpoolServer = WhirlpoolServer.valueOf(network.getName().toUpperCase());
|
||||||
this.httpClientService = new JavaHttpClientService(torProxy);
|
this.httpClientService = new JavaHttpClientService(torProxy);
|
||||||
|
@ -77,12 +77,12 @@ public class Whirlpool {
|
||||||
this.torClientService = new WhirlpoolTorClientService();
|
this.torClientService = new WhirlpoolTorClientService();
|
||||||
|
|
||||||
this.whirlpoolWalletService = new WhirlpoolWalletService();
|
this.whirlpoolWalletService = new WhirlpoolWalletService();
|
||||||
this.config = computeWhirlpoolWalletConfig(sCode);
|
this.config = computeWhirlpoolWalletConfig();
|
||||||
|
|
||||||
WhirlpoolEventService.getInstance().register(this);
|
WhirlpoolEventService.getInstance().register(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
private WhirlpoolWalletConfig computeWhirlpoolWalletConfig(String sCode) {
|
private WhirlpoolWalletConfig computeWhirlpoolWalletConfig() {
|
||||||
DataPersisterFactory dataPersisterFactory = (whirlpoolWallet, bip44w) -> new SparrowDataPersister(whirlpoolWallet);
|
DataPersisterFactory dataPersisterFactory = (whirlpoolWallet, bip44w) -> new SparrowDataPersister(whirlpoolWallet);
|
||||||
DataSourceFactory dataSourceFactory = (whirlpoolWallet, bip44w, dataPersister) -> new SparrowDataSource(whirlpoolWallet, bip44w, dataPersister);
|
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 whirlpoolWalletConfig = new WhirlpoolWalletConfig(dataSourceFactory, httpClientService, stompClientService, torClientService, serverApi, whirlpoolServer.getParams(), false);
|
||||||
whirlpoolWalletConfig.setDataPersisterFactory(dataPersisterFactory);
|
whirlpoolWalletConfig.setDataPersisterFactory(dataPersisterFactory);
|
||||||
whirlpoolWalletConfig.setScode(sCode);
|
|
||||||
|
|
||||||
return whirlpoolWalletConfig;
|
return whirlpoolWalletConfig;
|
||||||
}
|
}
|
||||||
|
@ -343,6 +342,14 @@ public class Whirlpool {
|
||||||
config.setScode(scode);
|
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() {
|
public boolean isMixing() {
|
||||||
return mixingProperty.get();
|
return mixingProperty.get();
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,9 +4,12 @@ import com.samourai.whirlpool.client.tx0.Tx0Preview;
|
||||||
import com.samourai.whirlpool.client.whirlpool.beans.Pool;
|
import com.samourai.whirlpool.client.whirlpool.beans.Pool;
|
||||||
import com.sparrowwallet.drongo.BitcoinUnit;
|
import com.sparrowwallet.drongo.BitcoinUnit;
|
||||||
import com.sparrowwallet.drongo.protocol.Transaction;
|
import com.sparrowwallet.drongo.protocol.Transaction;
|
||||||
|
import com.sparrowwallet.drongo.wallet.MixConfig;
|
||||||
import com.sparrowwallet.drongo.wallet.Wallet;
|
import com.sparrowwallet.drongo.wallet.Wallet;
|
||||||
import com.sparrowwallet.sparrow.AppServices;
|
import com.sparrowwallet.sparrow.AppServices;
|
||||||
|
import com.sparrowwallet.sparrow.EventManager;
|
||||||
import com.sparrowwallet.sparrow.control.CoinLabel;
|
import com.sparrowwallet.sparrow.control.CoinLabel;
|
||||||
|
import com.sparrowwallet.sparrow.event.WalletMixConfigChangedEvent;
|
||||||
import com.sparrowwallet.sparrow.io.Config;
|
import com.sparrowwallet.sparrow.io.Config;
|
||||||
import com.sparrowwallet.sparrow.wallet.Entry;
|
import com.sparrowwallet.sparrow.wallet.Entry;
|
||||||
import com.sparrowwallet.sparrow.wallet.UtxoEntry;
|
import com.sparrowwallet.sparrow.wallet.UtxoEntry;
|
||||||
|
@ -72,6 +75,7 @@ public class WhirlpoolController {
|
||||||
|
|
||||||
private String walletId;
|
private String walletId;
|
||||||
private Wallet wallet;
|
private Wallet wallet;
|
||||||
|
private MixConfig mixConfig;
|
||||||
private List<UtxoEntry> utxoEntries;
|
private List<UtxoEntry> utxoEntries;
|
||||||
private final ObjectProperty<Tx0Preview> tx0PreviewProperty = new SimpleObjectProperty<>(null);
|
private final ObjectProperty<Tx0Preview> tx0PreviewProperty = new SimpleObjectProperty<>(null);
|
||||||
|
|
||||||
|
@ -79,6 +83,7 @@ public class WhirlpoolController {
|
||||||
this.walletId = walletId;
|
this.walletId = walletId;
|
||||||
this.wallet = wallet;
|
this.wallet = wallet;
|
||||||
this.utxoEntries = utxoEntries;
|
this.utxoEntries = utxoEntries;
|
||||||
|
this.mixConfig = wallet.isMasterWallet() ? wallet.getOrCreateMixConfig() : wallet.getMasterWallet().getOrCreateMixConfig();
|
||||||
|
|
||||||
step1.managedProperty().bind(step1.visibleProperty());
|
step1.managedProperty().bind(step1.visibleProperty());
|
||||||
step2.managedProperty().bind(step2.visibleProperty());
|
step2.managedProperty().bind(step2.visibleProperty());
|
||||||
|
@ -89,12 +94,13 @@ public class WhirlpoolController {
|
||||||
step3.setVisible(false);
|
step3.setVisible(false);
|
||||||
step4.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) -> {
|
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);
|
step1.setVisible(false);
|
||||||
step3.setVisible(true);
|
step3.setVisible(true);
|
||||||
}
|
}
|
||||||
|
@ -193,7 +199,7 @@ public class WhirlpoolController {
|
||||||
List<Pool> availablePools = poolsService.getValue().stream().filter(pool1 -> totalUtxoValue >= (pool1.getPremixValueMin() + pool1.getFeeValue())).toList();
|
List<Pool> availablePools = poolsService.getValue().stream().filter(pool1 -> totalUtxoValue >= (pool1.getPremixValueMin() + pool1.getFeeValue())).toList();
|
||||||
if(availablePools.isEmpty()) {
|
if(availablePools.isEmpty()) {
|
||||||
pool.setVisible(false);
|
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()) {
|
if(optMinValue.isPresent()) {
|
||||||
String satsValue = String.format(Locale.ENGLISH, "%,d", optMinValue.getAsLong()) + " sats";
|
String satsValue = String.format(Locale.ENGLISH, "%,d", optMinValue.getAsLong()) + " sats";
|
||||||
String btcValue = CoinLabel.BTC_FORMAT.format((double)optMinValue.getAsLong() / Transaction.SATOSHIS_PER_BITCOIN) + " BTC";
|
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) {
|
private void fetchTx0Preview(Pool pool) {
|
||||||
if(Config.get().getScode() == null) {
|
if(mixConfig.getScode() == null) {
|
||||||
Config.get().setScode("");
|
mixConfig.setScode("");
|
||||||
|
EventManager.get().post(new WalletMixConfigChangedEvent(wallet.isMasterWallet() ? wallet : wallet.getMasterWallet()));
|
||||||
}
|
}
|
||||||
|
|
||||||
Whirlpool whirlpool = AppServices.get().getWhirlpool(walletId);
|
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);
|
Whirlpool.Tx0PreviewService tx0PreviewService = new Whirlpool.Tx0PreviewService(whirlpool, wallet, pool, utxoEntries);
|
||||||
tx0PreviewService.setOnRunning(workerStateEvent -> {
|
tx0PreviewService.setOnRunning(workerStateEvent -> {
|
||||||
nbOutputsBox.setVisible(true);
|
nbOutputsBox.setVisible(true);
|
||||||
nbOutputsLoading.setText("Calculating...");
|
nbOutputsLoading.setText("Calculating...");
|
||||||
|
nbOutputs.setVisible(false);
|
||||||
|
discountFeeBox.setVisible(false);
|
||||||
});
|
});
|
||||||
tx0PreviewService.setOnSucceeded(workerStateEvent -> {
|
tx0PreviewService.setOnSucceeded(workerStateEvent -> {
|
||||||
Tx0Preview tx0Preview = tx0PreviewService.getValue();
|
Tx0Preview tx0Preview = tx0PreviewService.getValue();
|
||||||
|
|
|
@ -54,7 +54,8 @@ public class WhirlpoolDialog extends Dialog<Tx0Preview> {
|
||||||
backButton.managedProperty().bind(backButton.visibleProperty());
|
backButton.managedProperty().bind(backButton.visibleProperty());
|
||||||
previewButton.managedProperty().bind(previewButton.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);
|
backButton.setDisable(true);
|
||||||
}
|
}
|
||||||
previewButton.visibleProperty().bind(nextButton.visibleProperty().not());
|
previewButton.visibleProperty().bind(nextButton.visibleProperty().not());
|
||||||
|
|
|
@ -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);
|
create table utxoMixData (id identity not null, hash binary(32) not null, mixesDone integer not null default 0, expired bigint, wallet bigint not null);
|
Loading…
Reference in a new issue