Skip to content

Commit

Permalink
merge whirlpool 1.x client using decentralized soroban
Browse files Browse the repository at this point in the history
  • Loading branch information
craigraw committed Apr 11, 2024
2 parents 2441b4d + e178168 commit 15cb028
Show file tree
Hide file tree
Showing 34 changed files with 1,007 additions and 877 deletions.
87 changes: 16 additions & 71 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -123,8 +123,9 @@ dependencies {
implementation('org.slf4j:jul-to-slf4j:2.0.12') {
exclude group: 'org.slf4j'
}
implementation('com.sparrowwallet.nightjar:nightjar:0.2.40')
implementation('com.sparrowwallet.bokmakierie:bokmakierie:1.0')
implementation('io.samourai.code.whirlpool:whirlpool-client:1.0.6')
implementation('io.samourai.code.wallet:java-http-client:2.0.2')
implementation('io.reactivex.rxjava2:rxjava:2.2.15')
implementation('io.reactivex.rxjava2:rxjavafx:2.2.2')
implementation('org.apache.commons:commons-lang3:3.7')
Expand Down Expand Up @@ -212,8 +213,6 @@ jlink {
uses 'org.flywaydb.core.extensibility.FlywayExtension'
uses 'org.flywaydb.core.internal.database.DatabaseType'
uses 'org.eclipse.jetty.http.HttpFieldPreEncoder'
uses 'org.eclipse.jetty.websocket.api.extensions.Extension'
uses 'org.eclipse.jetty.websocket.common.RemoteEndpointFactory'
}

options = ['--strip-native-commands', '--strip-java-debug-attributes', '--compress', '2', '--no-header-files', '--no-man-pages', '--ignore-signing-information', '--exclude-files', '**.png', '--exclude-resources', 'glob:/com.sparrowwallet.merged.module/META-INF/*']
Expand Down Expand Up @@ -493,88 +492,34 @@ extraJavaModuleInfo {
exports('co.nstant.in.cbor.model')
exports('co.nstant.in.cbor.builder')
}
module('nightjar-0.2.40.jar', 'com.sparrowwallet.nightjar', '0.2.40') {
requires('com.google.common')
requires('net.sourceforge.streamsupport')
requires('org.slf4j')
requires('org.bouncycastle.provider')
requires('com.fasterxml.jackson.databind')
requires('com.fasterxml.jackson.annotation')
requires('com.fasterxml.jackson.core')
requires('ch.qos.logback.classic')
requires('org.json')
requires('io.reactivex.rxjava2')
exports('com.samourai.http.client')
exports('com.samourai.tor.client')
exports('com.samourai.wallet.api.backend')
exports('com.samourai.wallet.api.backend.beans')
exports('com.samourai.wallet.client.indexHandler')
exports('com.samourai.wallet.hd')
exports('com.samourai.wallet.util')
exports('com.samourai.wallet.bip47.rpc')
exports('com.samourai.wallet.bip47.rpc.java')
exports('com.samourai.wallet.cahoots')
exports('com.samourai.wallet.cahoots.psbt')
exports('com.samourai.wallet.cahoots.stonewallx2')
exports('com.samourai.soroban.cahoots')
exports('com.samourai.soroban.client')
exports('com.samourai.soroban.client.cahoots')
exports('com.samourai.soroban.client.meeting')
exports('com.samourai.soroban.client.rpc')
exports('com.samourai.wallet.send')
exports('com.samourai.whirlpool.client.event')
exports('com.samourai.whirlpool.client.wallet')
exports('com.samourai.whirlpool.client.wallet.beans')
exports('com.samourai.whirlpool.client.wallet.data.dataSource')
exports('com.samourai.whirlpool.client.wallet.data.dataPersister')
exports('com.samourai.whirlpool.client.whirlpool')
exports('com.samourai.whirlpool.client.whirlpool.beans')
exports('com.samourai.whirlpool.client.wallet.data.pool')
exports('com.samourai.whirlpool.client.wallet.data.utxo')
exports('com.samourai.whirlpool.client.wallet.data.utxoConfig')
exports('com.samourai.whirlpool.client.wallet.data.supplier')
exports('com.samourai.whirlpool.client.mix.handler')
exports('com.samourai.whirlpool.client.mix.listener')
exports('com.samourai.whirlpool.protocol.beans')
exports('com.samourai.whirlpool.protocol.rest')
exports('com.samourai.whirlpool.client.tx0')
exports('com.samourai.wallet.segwit.bech32')
exports('com.samourai.whirlpool.client.wallet.data.chain')
exports('com.samourai.whirlpool.client.wallet.data.wallet')
exports('com.samourai.whirlpool.client.wallet.data.minerFee')
exports('com.samourai.whirlpool.client.wallet.data.walletState')
exports('com.sparrowwallet.nightjar.http')
exports('com.sparrowwallet.nightjar.stomp')
exports('com.sparrowwallet.nightjar.tor')
}
module('throwing-supplier-1.0.3.jar', 'zeroleak.throwingsupplier', '1.0.3') {
exports('com.zeroleak.throwingsupplier')
}
module('okhttp-2.7.5.jar', 'com.squareup.okhttp', '2.7.5') {
exports('com.squareup.okhttp')
module('commons-codec-1.10.jar', 'commons.codec', '1.10') {
exports('org.apache.commons.codec')
}
module('okio-1.6.0.jar', 'com.squareup.okio', '1.6.0') {
exports('okio')
module('logback-core-1.2.13.jar', 'ch.qos.logback.core', '1.2.13') {
exports('ch.qos.logback.core')
}
module('java-jwt-3.8.1.jar', 'com.auth0.jwt', '3.8.1') {
exports('com.auth0.jwt')
module('jackson-datatype-jsr310-2.13.2.jar', 'jackson-datatype-jsr310', '2.13.2') {
exports('com.fasterxml.jackson.datatype.jsr310')
}
module('json-20180130.jar', 'org.json', '1.0') {
module('json-20240205.jar', 'org.json', '20240205') {
exports('org.json')
}
module('scrypt-1.4.0.jar', 'com.lambdaworks.scrypt', '1.4.0') {
module('scrypt-1.4.0.jar', 'scrypt', '1.4.0') {
exports('com.lambdaworks.codec')
exports('com.lambdaworks.crypto')
}
module('okio-1.6.0.jar', 'com.squareup.okio', '1.6.0') {
exports('okio')
}
module('java-jwt-3.8.1.jar', 'com.auth0.jwt', '3.8.1') {
exports('com.auth0.jwt')
}
module('streamsupport-1.7.0.jar', 'net.sourceforge.streamsupport', '1.7.0') {
requires('jdk.unsupported')
exports('java8.util')
exports('java8.util.function')
exports('java8.util.stream')
}
module('protobuf-java-2.6.1.jar', 'com.google.protobuf', '2.6.1') {
exports('com.google.protobuf')
}
module('commons-text-1.2.jar', 'org.apache.commons.text', '1.2') {
exports('org.apache.commons.text')
}
Expand Down
8 changes: 6 additions & 2 deletions src/main/java/com/sparrowwallet/sparrow/AppServices.java
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,11 @@ public void changed(ObservableValue<? extends Boolean> observable, Boolean oldVa
connectionService.cancel();
ratesService.cancel();
versionCheckService.cancel();

if(httpClientService != null) {
HttpClientService.ShutdownService shutdownService = new HttpClientService.ShutdownService(httpClientService);
shutdownService.start();
}
}
}
};
Expand Down Expand Up @@ -542,11 +547,10 @@ public static InteractionServices getInteractionServices() {
}

public static HttpClientService getHttpClientService() {
HostAndPort torProxy = getTorProxy();
if(httpClientService == null) {
HostAndPort torProxy = getTorProxy();
httpClientService = new HttpClientService(torProxy);
} else {
HostAndPort torProxy = getTorProxy();
if(!Objects.equals(httpClientService.getTorProxy(), torProxy)) {
httpClientService.setTorProxy(getTorProxy());
}
Expand Down
18 changes: 3 additions & 15 deletions src/main/java/com/sparrowwallet/sparrow/control/MixStatusCell.java
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ private void setMixSuccess(Utxo nextMixUtxo) {
}

private void setMixFail(MixFailReason mixFailReason, String mixError, Long mixErrorTimestamp) {
if(mixFailReason != MixFailReason.CANCEL) {
if(mixFailReason.isError()) {
long elapsed = mixErrorTimestamp == null ? 0L : System.currentTimeMillis() - mixErrorTimestamp;
if(elapsed >= ERROR_DISPLAY_MILLIS) {
//Old error, don't set again.
Expand Down Expand Up @@ -116,22 +116,10 @@ private void setMixProgress(UtxoEntry utxoEntry, MixProgress mixProgress) {
progressIndicator.setProgress(mixProgress.getMixStep().getProgressPercent() == 100 ? -1 : mixProgress.getMixStep().getProgressPercent() / 100.0);
setGraphic(progressIndicator);
Tooltip tt = new Tooltip();
String status = mixProgress.getMixStep().getMessage().substring(0, 1).toUpperCase(Locale.ROOT) + mixProgress.getMixStep().getMessage().substring(1);
String status = mixProgress.getMixStep().getMessage().replaceAll("_", " ");
status = status.substring(0, 1).toUpperCase(Locale.ROOT) + status.substring(1).toLowerCase(Locale.ROOT);
tt.setText(status);
setTooltip(tt);

if(mixProgress.getMixStep() == MixStep.REGISTERED_INPUT) {
tt.setOnShowing(event -> {
Whirlpool whirlpool = AppServices.getWhirlpoolServices().getWhirlpool(utxoEntry.getWallet());
Whirlpool.RegisteredInputsService registeredInputsService = new Whirlpool.RegisteredInputsService(whirlpool, mixProgress.getPoolId());
registeredInputsService.setOnSucceeded(eventStateHandler -> {
if(registeredInputsService.getValue() != null) {
tt.setText(status + " (1 of " + registeredInputsService.getValue() + ")");
}
});
registeredInputsService.start();
});
}
} else {
setGraphic(null);
setTooltip(null);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,10 @@ private void update(Storage storage, Wallet wallet, String password) throws Stor
}
for(Sha256Hash txid : referencedTxIds) {
BlockTransaction blkTx = wallet.getTransactions().get(txid);
blockTransactionDao.addOrUpdate(wallet, txid, blkTx);
//May be null for a nested wallet if still updating
if(blkTx != null) {
blockTransactionDao.addOrUpdate(wallet, txid, blkTx);
}
}
if(!dirtyPersistables.clearHistory) {
DetachedLabelDao detachedLabelDao = handle.attach(DetachedLabelDao.class);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package com.sparrowwallet.sparrow.net;

import com.google.common.net.HostAndPort;
import com.samourai.wallet.httpClient.HttpResponseException;
import com.sparrowwallet.drongo.Network;
import com.sparrowwallet.drongo.Utils;
import com.sparrowwallet.drongo.protocol.Sha256Hash;
import com.sparrowwallet.drongo.protocol.Transaction;
import com.sparrowwallet.nightjar.http.JavaHttpException;
import com.sparrowwallet.sparrow.AppServices;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand Down Expand Up @@ -158,7 +158,7 @@ public Sha256Hash postTransactionData(String data) throws BroadcastException {
} catch(Exception e) {
throw new BroadcastException("Could not retrieve txid from broadcast, server returned: " + response);
}
} catch(JavaHttpException e) {
} catch(HttpResponseException e) {
throw new BroadcastException("Could not broadcast transaction, server returned " + e.getStatusCode() + ": " + e.getResponseBody());
} catch(Exception e) {
log.error("Could not post transaction via " + getName(), e);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.sparrowwallet.sparrow.net;

import com.sparrowwallet.nightjar.http.JavaHttpException;
import com.samourai.wallet.httpClient.HttpResponseException;
import com.sparrowwallet.sparrow.AppServices;
import com.sparrowwallet.sparrow.event.ExchangeRatesUpdatedEvent;
import javafx.concurrent.ScheduledService;
Expand Down Expand Up @@ -107,7 +107,7 @@ public Map<Date, Double> getHistoricalExchangeRates(Currency currency, Date star
if(log.isDebugEnabled()) {
log.warn("Error retrieving historical currency rates", e);
} else {
if(e instanceof JavaHttpException javaHttpException && javaHttpException.getStatusCode() == 404) {
if(e instanceof HttpResponseException httpException && httpException.getStatusCode() == 404) {
log.warn("Error retrieving historical currency rates (" + e.getMessage() + "). BTC-" + currency.getCurrencyCode() + " may not be supported by " + this);
} else {
log.warn("Error retrieving historical currency rates (" + e.getMessage() + ")");
Expand Down
47 changes: 21 additions & 26 deletions src/main/java/com/sparrowwallet/sparrow/net/HttpClientService.java
Original file line number Diff line number Diff line change
@@ -1,57 +1,52 @@
package com.sparrowwallet.sparrow.net;

import com.google.common.net.HostAndPort;
import com.samourai.http.client.HttpUsage;
import com.samourai.http.client.IHttpClient;
import com.sparrowwallet.nightjar.http.JavaHttpClientService;
import com.samourai.http.client.JettyHttpClientService;
import com.samourai.wallet.httpClient.HttpUsage;
import com.samourai.wallet.httpClient.IHttpClient;
import com.samourai.wallet.util.AsyncUtil;
import com.samourai.wallet.util.ThreadUtil;
import com.samourai.whirlpool.client.utils.ClientUtils;
import io.reactivex.Observable;
import java8.util.Optional;
import javafx.concurrent.Service;
import javafx.concurrent.Task;

import java.util.Map;
import java.util.Optional;

public class HttpClientService {
private final JavaHttpClientService httpClientService;
public class HttpClientService extends JettyHttpClientService {
private static final int REQUEST_TIMEOUT = 120000;

public HttpClientService(HostAndPort torProxy) {
this.httpClientService = new JavaHttpClientService(torProxy, 120000);
super(REQUEST_TIMEOUT, new HttpProxySupplier(torProxy));
}

public <T> T requestJson(String url, Class<T> responseType, Map<String, String> headers) throws Exception {
IHttpClient httpClient = httpClientService.getHttpClient(HttpUsage.COORDINATOR_REST);
return httpClient.getJson(url, responseType, headers);
return getHttpClient(HttpUsage.BACKEND).getJson(url, responseType, headers);
}

public <T> Observable<Optional<T>> postJson(String url, Class<T> responseType, Map<String, String> headers, Object body) {
IHttpClient httpClient = httpClientService.getHttpClient(HttpUsage.COORDINATOR_REST);
return httpClient.postJson(url, responseType, headers, body);
return getHttpClient(HttpUsage.BACKEND).postJson(url, responseType, headers, body).toObservable();
}

public String postString(String url, Map<String, String> headers, String contentType, String content) throws Exception {
IHttpClient httpClient = httpClientService.getHttpClient(HttpUsage.COORDINATOR_REST);
return httpClient.postString(url, headers, contentType, content);
}

public void changeIdentity() {
HostAndPort torProxy = getTorProxy();
if(torProxy != null) {
TorUtils.changeIdentity(torProxy);
}
IHttpClient httpClient = getHttpClient(HttpUsage.BACKEND);
return AsyncUtil.getInstance().blockingGet(httpClient.postString(url, headers, contentType, content)).get();
}

public HostAndPort getTorProxy() {
return httpClientService.getTorProxy();
return getHttpProxySupplier().getTorProxy();
}

public void setTorProxy(HostAndPort torProxy) {
//Ensure all http clients are shutdown first
httpClientService.shutdown();
httpClientService.setTorProxy(torProxy);
stop();
getHttpProxySupplier()._setTorProxy(torProxy);
}

public void shutdown() {
httpClientService.shutdown();
@Override
public HttpProxySupplier getHttpProxySupplier() {
return (HttpProxySupplier)super.getHttpProxySupplier();
}

public static class ShutdownService extends Service<Boolean> {
Expand All @@ -65,7 +60,7 @@ public ShutdownService(HttpClientService httpClientService) {
protected Task<Boolean> createTask() {
return new Task<>() {
protected Boolean call() throws Exception {
httpClientService.shutdown();
httpClientService.stop();
return true;
}
};
Expand Down
51 changes: 51 additions & 0 deletions src/main/java/com/sparrowwallet/sparrow/net/HttpProxySupplier.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package com.sparrowwallet.sparrow.net;

import com.google.common.net.HostAndPort;
import com.samourai.http.client.IHttpProxySupplier;
import com.samourai.wallet.httpClient.HttpProxy;
import com.samourai.wallet.httpClient.HttpProxyProtocol;
import com.samourai.wallet.httpClient.HttpUsage;

import java.util.Optional;

public class HttpProxySupplier implements IHttpProxySupplier {
private HostAndPort torProxy;
private HttpProxy httpProxy;

public HttpProxySupplier(HostAndPort torProxy) {
this.torProxy = torProxy;
this.httpProxy = computeHttpProxy(torProxy);
}

private HttpProxy computeHttpProxy(HostAndPort hostAndPort) {
if (hostAndPort == null) {
return null;
}

return new HttpProxy(HttpProxyProtocol.SOCKS, hostAndPort.getHost(), hostAndPort.getPort());
}

public HostAndPort getTorProxy() {
return torProxy;
}

// shouldnt call directly but use httpClientService.setTorProxy()
public void _setTorProxy(HostAndPort hostAndPort) {
// set proxy
this.torProxy = hostAndPort;
this.httpProxy = computeHttpProxy(hostAndPort);
}

@Override
public Optional<HttpProxy> getHttpProxy(HttpUsage httpUsage) {
return Optional.ofNullable(httpProxy);
}

@Override
public void changeIdentity() {
HostAndPort torProxy = getTorProxy();
if(torProxy != null) {
TorUtils.changeIdentity(torProxy);
}
}
}
7 changes: 7 additions & 0 deletions src/main/java/com/sparrowwallet/sparrow/net/TorUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@
import java.io.*;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.nio.file.AccessDeniedException;
import java.nio.file.FileSystemException;
import java.nio.file.Files;
import java.nio.file.NoSuchFileException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

Expand All @@ -37,6 +40,10 @@ public static void changeIdentity(HostAndPort proxy) {
log.warn("Error authenticating to Tor at " + control + ", server returned " + e.getMessage());
} catch(SocketTimeoutException e) {
log.warn("Timeout reading from " + control + ", is this a Tor ControlPort?");
} catch(AccessDeniedException e) {
log.warn("Permission denied reading Tor cookie file at " + e.getFile());
} catch(FileSystemException e) {
log.warn("Error reading Tor cookie file at " + e.getFile());
} catch(Exception e) {
log.warn("Error connecting to " + control + ", no Tor ControlPort configured?");
}
Expand Down
Loading

0 comments on commit 15cb028

Please sign in to comment.