fix tor proxy switching for whirlpool client and mixing bip47 utxos

This commit is contained in:
Craig Raw 2024-04-02 17:14:19 +02:00
parent a9fd7c263f
commit 9ba4458f48
10 changed files with 65 additions and 10 deletions

View file

@ -189,6 +189,8 @@ application {
"--add-opens=java.base/java.net=com.sparrowwallet.sparrow",
"--add-opens=java.base/java.io=com.google.gson",
"--add-opens=java.smartcardio/sun.security.smartcardio=com.sparrowwallet.sparrow",
"--add-opens=com.samourai.whirlpool.client/com.samourai.whirlpool.client.whirlpool=com.sparrowwallet.sparrow",
"--add-opens=com.samourai.soroban.client/com.samourai.soroban.client.rpc=com.sparrowwallet.sparrow",
"--add-reads=kotlin.stdlib=kotlinx.coroutines.core"]
if(os.macOsX) {
@ -238,6 +240,8 @@ jlink {
"--add-opens=java.base/java.net=com.sparrowwallet.sparrow",
"--add-opens=java.base/java.io=com.google.gson",
"--add-opens=java.smartcardio/sun.security.smartcardio=com.sparrowwallet.sparrow",
"--add-opens=com.samourai.whirlpool.client/com.samourai.whirlpool.client.whirlpool=com.sparrowwallet.sparrow",
"--add-opens=com.samourai.soroban.client/com.samourai.soroban.client.rpc=com.sparrowwallet.sparrow",
"--add-reads=com.sparrowwallet.merged.module=java.desktop",
"--add-reads=com.sparrowwallet.merged.module=java.sql",
"--add-reads=com.sparrowwallet.merged.module=com.sparrowwallet.sparrow",

View file

@ -167,6 +167,11 @@ public class AppServices {
connectionService.cancel();
ratesService.cancel();
versionCheckService.cancel();
if(httpClientService != null) {
HttpClientService.ShutdownService shutdownService = new HttpClientService.ShutdownService(httpClientService);
shutdownService.start();
}
}
}
};

View file

@ -2,7 +2,6 @@ package com.sparrowwallet.sparrow.soroban;
import com.samourai.soroban.client.SorobanConfig;
import com.samourai.soroban.client.wallet.SorobanWalletService;
import com.samourai.wallet.chain.ChainSupplier;
import com.samourai.wallet.hd.HD_Wallet;
import com.sparrowwallet.drongo.Network;
import com.sparrowwallet.drongo.protocol.ScriptType;
@ -10,8 +9,6 @@ import com.sparrowwallet.drongo.wallet.Wallet;
import com.sparrowwallet.sparrow.AppServices;
import com.sparrowwallet.sparrow.whirlpool.Whirlpool;
import com.sparrowwallet.sparrow.whirlpool.dataSource.SparrowChainSupplier;
import javafx.concurrent.Service;
import javafx.concurrent.Task;
import org.bitcoinj.core.NetworkParameters;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -28,6 +25,7 @@ public class Soroban {
private HD_Wallet hdWallet;
private int bip47Account;
private SparrowChainSupplier chainSupplier;
public Soroban() {
SorobanConfig sorobanConfig = AppServices.getWhirlpoolServices().getSorobanConfig();
@ -63,7 +61,10 @@ public class Soroban {
}
try {
ChainSupplier chainSupplier = new SparrowChainSupplier(wallet.getStoredBlockHeight());
if(chainSupplier == null) {
chainSupplier = new SparrowChainSupplier(wallet.getStoredBlockHeight());
chainSupplier.open();
}
return new SparrowCahootsWallet(chainSupplier, wallet, hdWallet, bip47Account);
} catch(Exception e) {
log.error("Could not create cahoots wallet", e);
@ -79,4 +80,10 @@ public class Soroban {
public SorobanWalletService getSorobanWalletService() {
return sorobanWalletService;
}
public void close() {
if(chainSupplier != null) {
chainSupplier.close();
}
}
}

View file

@ -53,7 +53,10 @@ public class SorobanServices {
public void walletTabsClosed(WalletTabsClosedEvent event) {
for(WalletTabData walletTabData : event.getClosedWalletTabData()) {
String walletId = walletTabData.getStorage().getWalletId(walletTabData.getWallet());
sorobanMap.remove(walletId);
Soroban soroban = sorobanMap.remove(walletId);
if(soroban != null) {
soroban.close();
}
}
}
}

View file

@ -43,7 +43,7 @@ public class MixTableCell extends TableCell {
private String getMixFail(UtxoEntry.MixStatus mixStatus) {
long elapsed = mixStatus.getMixErrorTimestamp() == null ? 0L : System.currentTimeMillis() - mixStatus.getMixErrorTimestamp();
if(mixStatus.getMixFailReason() == MixFailReason.STOP_UTXO || !mixStatus.getMixFailReason().isError() || elapsed >= ERROR_DISPLAY_MILLIS) {
if(!mixStatus.getMixFailReason().isError() || elapsed >= ERROR_DISPLAY_MILLIS) {
return getMixCountOnly(mixStatus);
}

View file

@ -29,6 +29,7 @@ import com.samourai.whirlpool.client.wallet.data.dataPersister.DataPersisterFact
import com.samourai.whirlpool.client.wallet.data.dataSource.DataSourceConfig;
import com.samourai.whirlpool.client.wallet.data.dataSource.DataSourceFactory;
import com.samourai.whirlpool.client.wallet.data.utxo.UtxoSupplier;
import com.samourai.whirlpool.client.whirlpool.WhirlpoolClientConfig;
import com.samourai.whirlpool.client.whirlpool.beans.Pool;
import com.sparrowwallet.drongo.ExtendedKey;
import com.sparrowwallet.drongo.KeyPurpose;
@ -60,6 +61,7 @@ import org.bitcoinj.core.NetworkParameters;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.reflect.Field;
import java.util.*;
import java.util.stream.Collectors;
@ -110,6 +112,18 @@ public class Whirlpool {
return whirlpoolWalletConfig;
}
void setOnion(boolean onion) {
if(config.isTorOnionCoordinator() ^ onion) {
try {
Field torField = WhirlpoolClientConfig.class.getDeclaredField("torOnionCoordinator");
torField.setAccessible(true);
torField.set(config, onion);
} catch(Exception e) {
log.warn("Error changing onion on WhirlpoolWalletConfig", e);
}
}
}
private DataSourceConfig computeDataSourceConfig(Integer storedBlockHeight) {
return new DataSourceConfig(SparrowMinerFeeSupplier.getInstance(), new SparrowChainSupplier(storedBlockHeight), BIP_FORMAT.PROVIDER, BIP_WALLETS.WHIRLPOOL);
}
@ -469,7 +483,7 @@ public class Whirlpool {
UnspentOutput.Xpub xpub = new UnspentOutput.Xpub();
ExtendedKey.Header header = testnet ? ExtendedKey.Header.tpub : ExtendedKey.Header.xpub;
xpub.m = wallet.getKeystores().get(0).getExtendedPublicKey().toString(header);
xpub.path = node.getDerivationPath().toUpperCase(Locale.ROOT);
xpub.path = node.getWallet().isBip47() ? null : node.getDerivationPath().toUpperCase(Locale.ROOT);
out.xpub = xpub;

View file

@ -3,6 +3,7 @@ package com.sparrowwallet.sparrow.whirlpool;
import com.google.common.eventbus.Subscribe;
import com.google.common.net.HostAndPort;
import com.samourai.soroban.client.SorobanConfig;
import com.samourai.soroban.client.rpc.RpcClientService;
import com.samourai.wallet.constants.SamouraiNetwork;
import com.samourai.wallet.util.ExtLibJConfig;
import com.samourai.whirlpool.client.wallet.WhirlpoolEventService;
@ -29,11 +30,13 @@ import javafx.util.Duration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.reflect.Field;
import java.net.SocketTimeoutException;
import java.util.*;
import java.util.concurrent.TimeoutException;
import java.util.stream.Collectors;
import static com.sparrowwallet.sparrow.AppServices.getHttpClientService;
import static com.sparrowwallet.sparrow.AppServices.getTorProxy;
import static org.bitcoinj.crypto.MnemonicCode.SPARROW_FIX_NFKD_MNEMONIC;
@ -52,9 +55,9 @@ public class WhirlpoolServices {
private ExtLibJConfig computeExtLibJConfig() {
HttpClientService httpClientService = AppServices.getHttpClientService();
boolean onion = (AppServices.getTorProxy() != null);
boolean onion = (getTorProxy() != null);
SamouraiNetwork samouraiNetwork = getSamouraiNetwork();
return new ExtLibJConfig(samouraiNetwork, onion, Drongo.getProvider(), httpClientService);
return new ExtLibJConfig(samouraiNetwork, onion, Drongo.getProvider(), httpClientService);
}
public SamouraiNetwork getSamouraiNetwork() {
@ -107,6 +110,8 @@ public class WhirlpoolServices {
public void startWhirlpool(Wallet wallet, Whirlpool whirlpool, boolean notifyIfMixToMissing) {
if(wallet.getMasterMixConfig().getMixOnStartup() != Boolean.FALSE) {
whirlpool.setOnion(sorobanConfig.getExtLibJConfig().isOnion());
try {
String mixToWalletId = getWhirlpoolMixToWalletId(wallet.getMasterMixConfig());
whirlpool.setMixToWallet(mixToWalletId, wallet.getMasterMixConfig().getMinMixes());
@ -221,6 +226,18 @@ public class WhirlpoolServices {
@Subscribe
public void newConnection(ConnectionEvent event) {
ExtLibJConfig extLibJConfig = sorobanConfig.getExtLibJConfig();
extLibJConfig.setOnion(getTorProxy() != null);
getHttpClientService(); //Ensure proxy is updated
try {
Field onionField = RpcClientService.class.getDeclaredField("onion");
onionField.setAccessible(true);
onionField.set(sorobanConfig.getRpcClientService(), getTorProxy() != null);
} catch(Exception e) {
log.warn("Error changing onion on RpcClientService", e);
}
startAllWhirlpool();
bindDebugAccelerator();
}

View file

@ -16,6 +16,9 @@ public class SparrowChainSupplier implements ChainSupplier {
public SparrowChainSupplier(Integer storedBlockHeight) {
this.storedBlockHeight = AppServices.getCurrentBlockHeight() == null ? (storedBlockHeight != null ? storedBlockHeight : 0) : AppServices.getCurrentBlockHeight();
this.latestBlock = computeLatestBlock();
}
public void open() {
EventManager.get().register(this);
}

View file

@ -83,6 +83,7 @@ public class SparrowDataSource extends AbstractDataSource {
public void open(CoordinatorSupplier coordinatorSupplier) throws Exception {
super.open(coordinatorSupplier);
EventManager.get().register(this);
((SparrowChainSupplier)getDataSourceConfig().getChainSupplier()).open();
}
@Override

View file

@ -128,7 +128,8 @@ public class SparrowUtxoSupplier extends BasicUtxoSupplier {
@Override
public byte[] _getPrivKeyBip47(UnspentOutput utxo) throws Exception {
Wallet wallet = SparrowDataSource.getWallet(utxo.xpub.m);
BipWallet bipWallet = getWalletSupplier().getWalletByXPub(utxo.xpub.m);
Wallet wallet = SparrowDataSource.getWallet(bipWallet.getBipPub());
Map<BlockTransactionHashIndex, WalletNode> walletUtxos = wallet.getWalletUtxos();
WalletNode node = walletUtxos.entrySet().stream()
.filter(entry -> entry.getKey().getHash().equals(Sha256Hash.wrap(utxo.tx_hash)) && entry.getKey().getIndex() == utxo.tx_output_n)