Merge branch 'haveno-dex:master' into take3

This commit is contained in:
preland 2024-03-15 16:07:03 -05:00 committed by GitHub
commit 1b09fd2808
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
26 changed files with 283 additions and 414 deletions

View File

@ -17,19 +17,20 @@
package haveno.asset.coins; package haveno.asset.coins;
import haveno.asset.Base58AddressValidator; import haveno.asset.BitcoinAddressValidator;
import haveno.asset.Coin; import haveno.asset.Coin;
import haveno.asset.NetworkParametersAdapter; import haveno.asset.NetworkParametersAdapter;
public class Litecoin extends Coin { public class Litecoin extends Coin {
public Litecoin() { public Litecoin() {
super("Litecoin", "LTC", new Base58AddressValidator(new LitecoinMainNetParams()), Network.MAINNET); super("Litecoin", "LTC", new BitcoinAddressValidator(new LitecoinMainNetParams()), Network.MAINNET);
} }
public static class LitecoinMainNetParams extends NetworkParametersAdapter { public static class LitecoinMainNetParams extends NetworkParametersAdapter {
public LitecoinMainNetParams() { public LitecoinMainNetParams() {
this.addressHeader = 48; this.addressHeader = 48;
this.p2shHeader = 5; this.p2shHeader = 50;
this.segwitAddressHrp = "ltc";
} }
} }
} }

View File

@ -31,6 +31,17 @@ public class LitecoinTest extends AbstractAssetTest {
assertValidAddress("Lg3PX8wRWmApFCoCMAsPF5P9dPHYQHEWKW"); assertValidAddress("Lg3PX8wRWmApFCoCMAsPF5P9dPHYQHEWKW");
assertValidAddress("LTuoeY6RBHV3n3cfhXVVTbJbxzxnXs9ofm"); assertValidAddress("LTuoeY6RBHV3n3cfhXVVTbJbxzxnXs9ofm");
assertValidAddress("LgfapHEPhZbRF9pMd5WPT35hFXcZS1USrW"); assertValidAddress("LgfapHEPhZbRF9pMd5WPT35hFXcZS1USrW");
assertValidAddress("M8T1B2Z97gVdvmfkQcAtYbEepune1tzGua");
assertValidAddress("ltc1qr07zu594qf63xm7l7x6pu3a2v39m2z6hh5pp4t");
assertValidAddress("ltc1qzvcgmntglcuv4smv3lzj6k8szcvsrmvk0phrr9wfq8w493r096ssm2fgsw");
assertValidAddress("MESruSiB2uC9i7tMU6VMUVom91ohM7Rnbd");
assertValidAddress("ltc1q2a0laq2jg2gntzhfs43qptajd325kkx7hrq9cs");
assertValidAddress("ltc1qd6d54mt8xxcg0xg3l0vh6fymdfvd2tv0vnwyrv");
assertValidAddress("ltc1gmay6ht028aurcm680f8e8wxdup07y2tq46f6z2d4v8rutewqmmcqk29jtm");
assertValidAddress("MTf4tP1TCNBn8dNkyxeBVoPrFCcVzxJvvh");
assertValidAddress("LaRoRBC6utQtY3U2FbHwhmhhDPyxodDeKA");
assertValidAddress("MDMFP9Dx84tyaxiYksjvkG1jymBdqCuHGA");
//assertValidAddress("3MSvaVbVFFLML86rt5eqgA9SvW23upaXdY"); // deprecated
} }
@Test @Test
@ -38,5 +49,14 @@ public class LitecoinTest extends AbstractAssetTest {
assertInvalidAddress("1LgfapHEPhZbRF9pMd5WPT35hFXcZS1USrW"); assertInvalidAddress("1LgfapHEPhZbRF9pMd5WPT35hFXcZS1USrW");
assertInvalidAddress("LgfapHEPhZbdRF9pMd5WPT35hFXcZS1USrW"); assertInvalidAddress("LgfapHEPhZbdRF9pMd5WPT35hFXcZS1USrW");
assertInvalidAddress("LgfapHEPhZbRF9pMd5WPT35hFXcZS1USrW#"); assertInvalidAddress("LgfapHEPhZbRF9pMd5WPT35hFXcZS1USrW#");
assertInvalidAddress("3MSvaVbVFFLML86rt5eqgl9SvW23upaXdY"); // contains lowercase l
assertInvalidAddress("LURw7hYhREXjWHyiXhQNsKInWtPezwNe98"); // contains uppercase I
assertInvalidAddress("LM4ch8ZtAowdiGLSnf92MrMOC9dVmve2hr"); // contains uppercase O
assertInvalidAddress("MArsfeyS7P0HzsqLpAFGC9pFdhuqHgdL2R"); // contains number 0
assertInvalidAddress("ltc1qr6quwn3v2gxpadd0cu040r9385gayk5vdcyl5"); // too short
assertInvalidAddress("ltc1q5det08ke2gpet06wczcdfs2v3hgfqllxw28uln8vxxx82qlue6uswceljma"); // too long
assertInvalidAddress("MADpfTtabZ6pDjms4pMd3ZmnrgyhTCo4N8?time=1708476729&exp=86400"); // additional information
assertInvalidAddress("ltc1q8tk47lvgqu55h4pfast39r3t9360gmll5z9m6z?time=1708476604&exp=600"); // additional information
assertInvalidAddress("ltc1q026xyextkwhmveh7rpf6v6mp5p88vwc25aynxr?time=1708476626"); // additional information
} }
} }

View File

@ -49,7 +49,7 @@ configure(subprojects) {
gsonVersion = '2.8.5' gsonVersion = '2.8.5'
guavaVersion = '32.1.1-jre' guavaVersion = '32.1.1-jre'
guiceVersion = '7.0.0' guiceVersion = '7.0.0'
moneroJavaVersion = '0.8.10' moneroJavaVersion = '0.8.11'
httpclient5Version = '5.0' httpclient5Version = '5.0'
hamcrestVersion = '2.2' hamcrestVersion = '2.2'
httpclientVersion = '4.5.12' httpclientVersion = '4.5.12'
@ -71,7 +71,7 @@ configure(subprojects) {
loggingVersion = '1.2' loggingVersion = '1.2'
lombokVersion = '1.18.30' lombokVersion = '1.18.30'
mockitoVersion = '5.10.0' mockitoVersion = '5.10.0'
netlayerVersion = '6797461310f077bbea4f43a3a509c077b0ed8c34' // Netlayer version 0.7.3 with Tor browser version 11.0.14 and tor binary version: 0.4.7.7 netlayerVersion = '2b459dc' // Tor browser version 11.5.2 and tor binary version: 0.4.7.10
protobufVersion = '3.19.1' protobufVersion = '3.19.1'
protocVersion = protobufVersion protocVersion = protobufVersion
pushyVersion = '0.13.2' pushyVersion = '0.13.2'
@ -436,6 +436,11 @@ configure(project(':core')) {
systemProperty 'jdk.attach.allowAttachSelf', true systemProperty 'jdk.attach.allowAttachSelf', true
} }
task generateKeypairs(type: JavaExec) {
mainClass = 'haveno.core.util.GenerateKeyPairs'
classpath = sourceSets.main.runtimeClasspath
}
task havenoDeps { task havenoDeps {
doLast { doLast {
// get monero binaries download url // get monero binaries download url

View File

@ -22,7 +22,6 @@ import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.Future; import java.util.concurrent.Future;
@ -41,10 +40,10 @@ public class ThreadUtils {
* @param command the command to execute * @param command the command to execute
* @param threadId the thread id * @param threadId the thread id
*/ */
public static void execute(Runnable command, String threadId) { public static Future<?> execute(Runnable command, String threadId) {
synchronized (EXECUTORS) { synchronized (EXECUTORS) {
if (!EXECUTORS.containsKey(threadId)) EXECUTORS.put(threadId, Executors.newFixedThreadPool(1)); if (!EXECUTORS.containsKey(threadId)) EXECUTORS.put(threadId, Executors.newFixedThreadPool(1));
EXECUTORS.get(threadId).execute(() -> { return EXECUTORS.get(threadId).submit(() -> {
synchronized (THREADS) { synchronized (THREADS) {
THREADS.put(threadId, Thread.currentThread()); THREADS.put(threadId, Thread.currentThread());
} }
@ -60,26 +59,12 @@ public class ThreadUtils {
* @param threadId the thread id * @param threadId the thread id
*/ */
public static void await(Runnable command, String threadId) { public static void await(Runnable command, String threadId) {
if (isCurrentThread(Thread.currentThread(), threadId)) {
command.run();
} else {
CountDownLatch latch = new CountDownLatch(1);
execute(() -> {
try { try {
command.run(); execute(command, threadId).get();
} catch (Exception e) { } catch (Exception e) {
throw e;
} finally {
latch.countDown();
}
}, threadId);
try {
latch.await();
} catch (InterruptedException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
} }
}
public static void shutDown(String threadId) { public static void shutDown(String threadId) {
shutDown(threadId, null); shutDown(threadId, null);

View File

@ -84,6 +84,7 @@ public class Config {
public static final String USE_TOR_FOR_XMR = "useTorForXmr"; public static final String USE_TOR_FOR_XMR = "useTorForXmr";
public static final String TORRC_FILE = "torrcFile"; public static final String TORRC_FILE = "torrcFile";
public static final String TORRC_OPTIONS = "torrcOptions"; public static final String TORRC_OPTIONS = "torrcOptions";
public static final String TOR_CONTROL_HOST = "torControlHost";
public static final String TOR_CONTROL_PORT = "torControlPort"; public static final String TOR_CONTROL_PORT = "torControlPort";
public static final String TOR_CONTROL_PASSWORD = "torControlPassword"; public static final String TOR_CONTROL_PASSWORD = "torControlPassword";
public static final String TOR_CONTROL_COOKIE_FILE = "torControlCookieFile"; public static final String TOR_CONTROL_COOKIE_FILE = "torControlCookieFile";
@ -173,6 +174,7 @@ public class Config {
public final String socks5ProxyHttpAddress; public final String socks5ProxyHttpAddress;
public final File torrcFile; public final File torrcFile;
public final String torrcOptions; public final String torrcOptions;
public final String torControlHost;
public final int torControlPort; public final int torControlPort;
public final String torControlPassword; public final String torControlPassword;
public final File torControlCookieFile; public final File torControlCookieFile;
@ -446,6 +448,11 @@ public class Config {
.withValuesConvertedBy(RegexMatcher.regex("^([^\\s,]+\\s[^,]+,?\\s*)+$")) .withValuesConvertedBy(RegexMatcher.regex("^([^\\s,]+\\s[^,]+,?\\s*)+$"))
.defaultsTo(""); .defaultsTo("");
ArgumentAcceptingOptionSpec<String> torControlHostOpt =
parser.accepts(TOR_CONTROL_HOST, "The control hostname of an already running Tor service to be used by Haveno.")
.withRequiredArg()
.defaultsTo("127.0.0.1");
ArgumentAcceptingOptionSpec<Integer> torControlPortOpt = ArgumentAcceptingOptionSpec<Integer> torControlPortOpt =
parser.accepts(TOR_CONTROL_PORT, parser.accepts(TOR_CONTROL_PORT,
"The control port of an already running Tor service to be used by Haveno.") "The control port of an already running Tor service to be used by Haveno.")
@ -667,6 +674,7 @@ public class Config {
this.bitcoinRegtestHost = options.valueOf(bitcoinRegtestHostOpt); this.bitcoinRegtestHost = options.valueOf(bitcoinRegtestHostOpt);
this.torrcFile = options.has(torrcFileOpt) ? options.valueOf(torrcFileOpt).toFile() : null; this.torrcFile = options.has(torrcFileOpt) ? options.valueOf(torrcFileOpt).toFile() : null;
this.torrcOptions = options.valueOf(torrcOptionsOpt); this.torrcOptions = options.valueOf(torrcOptionsOpt);
this.torControlHost = options.valueOf(torControlHostOpt);
this.torControlPort = options.valueOf(torControlPortOpt); this.torControlPort = options.valueOf(torControlPortOpt);
this.torControlPassword = options.valueOf(torControlPasswordOpt); this.torControlPassword = options.valueOf(torControlPasswordOpt);
this.torControlCookieFile = options.has(torControlCookieFileOpt) ? this.torControlCookieFile = options.has(torControlCookieFileOpt) ?

View File

@ -19,16 +19,6 @@ package haveno.common.crypto;
import haveno.common.util.Hex; import haveno.common.util.Hex;
import haveno.common.util.Utilities; import haveno.common.util.Utilities;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.OAEPParameterSpec;
import javax.crypto.spec.PSource;
import javax.crypto.spec.SecretKeySpec;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.security.InvalidKeyException; import java.security.InvalidKeyException;
@ -43,10 +33,17 @@ import java.security.spec.InvalidKeySpecException;
import java.security.spec.MGF1ParameterSpec; import java.security.spec.MGF1ParameterSpec;
import java.security.spec.X509EncodedKeySpec; import java.security.spec.X509EncodedKeySpec;
import java.util.Arrays; import java.util.Arrays;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.OAEPParameterSpec;
import javax.crypto.spec.PSource;
import javax.crypto.spec.SecretKeySpec;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class Encryption { public class Encryption {
private static final Logger log = LoggerFactory.getLogger(Encryption.class);
public static final String ASYM_KEY_ALGO = "RSA"; public static final String ASYM_KEY_ALGO = "RSA";
private static final String ASYM_CIPHER = "RSA/ECB/OAEPWithSHA-256AndMGF1PADDING"; private static final String ASYM_CIPHER = "RSA/ECB/OAEPWithSHA-256AndMGF1PADDING";

View File

@ -458,8 +458,8 @@ public class CoreApi {
paymentAccount); paymentAccount);
} }
public void cancelOffer(String id) { public void cancelOffer(String id, ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) {
coreOffersService.cancelOffer(id); coreOffersService.cancelOffer(id, resultHandler, errorMessageHandler);
} }
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////

View File

@ -38,6 +38,7 @@ import com.google.inject.Inject;
import com.google.inject.Singleton; import com.google.inject.Singleton;
import haveno.common.crypto.KeyRing; import haveno.common.crypto.KeyRing;
import haveno.common.handlers.ErrorMessageHandler; import haveno.common.handlers.ErrorMessageHandler;
import haveno.common.handlers.ResultHandler;
import static haveno.common.util.MathUtils.exactMultiply; import static haveno.common.util.MathUtils.exactMultiply;
import static haveno.common.util.MathUtils.roundDoubleToLong; import static haveno.common.util.MathUtils.roundDoubleToLong;
import static haveno.common.util.MathUtils.scaleUpByPowerOf10; import static haveno.common.util.MathUtils.scaleUpByPowerOf10;
@ -236,14 +237,9 @@ public class CoreOffersService {
paymentAccount); paymentAccount);
} }
void cancelOffer(String id) { void cancelOffer(String id, ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) {
Offer offer = getMyOffer(id).getOffer(); Offer offer = getMyOffer(id).getOffer();
openOfferManager.removeOffer(offer, openOfferManager.removeOffer(offer, resultHandler, errorMessageHandler);
() -> {
},
errorMessage -> {
throw new IllegalStateException(errorMessage);
});
} }
// -------------------------- PRIVATE HELPERS ----------------------------- // -------------------------- PRIVATE HELPERS -----------------------------

View File

@ -133,7 +133,6 @@ class CoreWalletsService {
verifyWalletCurrencyCodeIsValid(currencyCode); verifyWalletCurrencyCodeIsValid(currencyCode);
verifyWalletsAreAvailable(); verifyWalletsAreAvailable();
verifyEncryptedWalletIsUnlocked(); verifyEncryptedWalletIsUnlocked();
if (balances.getAvailableBalance().get() == null) throw new IllegalStateException("balance is not yet available");
switch (currencyCode.trim().toUpperCase()) { switch (currencyCode.trim().toUpperCase()) {
case "": case "":
@ -418,28 +417,8 @@ class CoreWalletsService {
private XmrBalanceInfo getXmrBalances() { private XmrBalanceInfo getXmrBalances() {
verifyWalletsAreAvailable(); verifyWalletsAreAvailable();
verifyEncryptedWalletIsUnlocked(); verifyEncryptedWalletIsUnlocked();
if (balances.getAvailableBalance() == null) throw new IllegalStateException("Balances are not yet available");
var availableBalance = balances.getAvailableBalance().get(); return balances.getBalances();
if (availableBalance == null)
throw new IllegalStateException("available balance is not yet available");
var pendingBalance = balances.getPendingBalance().get();
if (pendingBalance == null)
throw new IllegalStateException("locked balance is not yet available");
var reservedOfferBalance = balances.getReservedOfferBalance().get();
if (reservedOfferBalance == null)
throw new IllegalStateException("reserved offer balance is not yet available");
var reservedTradeBalance = balances.getReservedTradeBalance().get();
if (reservedTradeBalance == null)
throw new IllegalStateException("reserved trade balance is not yet available");
return new XmrBalanceInfo(availableBalance.longValue() + pendingBalance.longValue(),
availableBalance.longValue(),
pendingBalance.longValue(),
reservedOfferBalance.longValue(),
reservedTradeBalance.longValue());
} }
// Returns a Coin for the transfer amount string, or a RuntimeException if invalid. // Returns a Coin for the transfer amount string, or a RuntimeException if invalid.

View File

@ -1,10 +1,10 @@
package haveno.core.api.model; package haveno.core.api.model;
import java.math.BigInteger;
import com.google.common.annotations.VisibleForTesting; import com.google.common.annotations.VisibleForTesting;
import haveno.common.Payload; import haveno.common.Payload;
import lombok.Getter;
@Getter
public class XmrBalanceInfo implements Payload { public class XmrBalanceInfo implements Payload {
public static final XmrBalanceInfo EMPTY = new XmrBalanceInfo(-1, public static final XmrBalanceInfo EMPTY = new XmrBalanceInfo(-1,
@ -19,17 +19,19 @@ public class XmrBalanceInfo implements Payload {
private final long pendingBalance; private final long pendingBalance;
private final long reservedOfferBalance; private final long reservedOfferBalance;
private final long reservedTradeBalance; private final long reservedTradeBalance;
private final long reservedBalance;
public XmrBalanceInfo(long balance, public XmrBalanceInfo(long balance,
long unlockedBalance, long unlockedBalance,
long lockedBalance, long pendingBalance,
long reservedOfferBalance, long reservedOfferBalance,
long reservedTradeBalance) { long reservedTradeBalance) {
this.balance = balance; this.balance = balance;
this.availableBalance = unlockedBalance; this.availableBalance = unlockedBalance;
this.pendingBalance = lockedBalance; this.pendingBalance = pendingBalance;
this.reservedOfferBalance = reservedOfferBalance; this.reservedOfferBalance = reservedOfferBalance;
this.reservedTradeBalance = reservedTradeBalance; this.reservedTradeBalance = reservedTradeBalance;
this.reservedBalance = reservedOfferBalance + reservedTradeBalance;
} }
@VisibleForTesting @VisibleForTesting
@ -45,6 +47,30 @@ public class XmrBalanceInfo implements Payload {
reservedTradeBalance); reservedTradeBalance);
} }
public BigInteger getBalance() {
return BigInteger.valueOf(balance);
}
public BigInteger getAvailableBalance() {
return BigInteger.valueOf(availableBalance);
}
public BigInteger getPendingBalance() {
return BigInteger.valueOf(pendingBalance);
}
public BigInteger getReservedOfferBalance() {
return BigInteger.valueOf(reservedOfferBalance);
}
public BigInteger getReservedTradeBalance() {
return BigInteger.valueOf(reservedTradeBalance);
}
public BigInteger getReservedBalance() {
return BigInteger.valueOf(reservedBalance);
}
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// PROTO BUFFER // PROTO BUFFER
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////

View File

@ -620,9 +620,13 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
if (!offersToBeEdited.containsKey(openOffer.getId())) { if (!offersToBeEdited.containsKey(openOffer.getId())) {
if (openOffer.isDeactivated()) { if (openOffer.isDeactivated()) {
onCancelled(openOffer); onCancelled(openOffer);
resultHandler.handleResult();
} else { } else {
offerBookService.removeOffer(openOffer.getOffer().getOfferPayload(), offerBookService.removeOffer(openOffer.getOffer().getOfferPayload(),
() -> onCancelled(openOffer), () -> {
onCancelled(openOffer);
resultHandler.handleResult();
},
errorMessageHandler); errorMessageHandler);
} }
} else { } else {

View File

@ -19,6 +19,7 @@ package haveno.core.presentation;
import com.google.inject.Inject; import com.google.inject.Inject;
import haveno.common.UserThread; import haveno.common.UserThread;
import haveno.core.api.model.XmrBalanceInfo;
import haveno.core.trade.HavenoUtils; import haveno.core.trade.HavenoUtils;
import haveno.core.xmr.Balances; import haveno.core.xmr.Balances;
import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.SimpleStringProperty;
@ -38,14 +39,13 @@ public class BalancePresentation {
@Inject @Inject
public BalancePresentation(Balances balances) { public BalancePresentation(Balances balances) {
balances.getAvailableBalance().addListener((observable, oldValue, newValue) -> { balances.getUpdateCounter().addListener((observable, oldValue, newValue) -> {
UserThread.execute(() -> availableBalance.set(HavenoUtils.formatXmr(newValue, true))); XmrBalanceInfo info = balances.getBalances();
UserThread.execute(() -> {
availableBalance.set(HavenoUtils.formatXmr(info.getAvailableBalance(), true));
pendingBalance.set(HavenoUtils.formatXmr(info.getPendingBalance(), true));
reservedBalance.set(HavenoUtils.formatXmr(info.getReservedBalance(), true));
}); });
balances.getPendingBalance().addListener((observable, oldValue, newValue) -> {
UserThread.execute(() -> pendingBalance.set(HavenoUtils.formatXmr(newValue, true)));
});
balances.getReservedBalance().addListener((observable, oldValue, newValue) -> {
UserThread.execute(() -> reservedBalance.set(HavenoUtils.formatXmr(newValue, true)));
}); });
} }
} }

View File

@ -12,29 +12,29 @@ import org.bitcoinj.core.Utils;
import haveno.common.crypto.Encryption; import haveno.common.crypto.Encryption;
/** /**
* This utility generates and prints public/private keypairs * This utility generates and prints public/private key-pairs
* which can be used to register arbitrators on the network. * which can be used to register arbitrators on the network.
*/ */
public class GenerateKeypairs { public class GenerateKeyPairs {
public static void main(String[] args) { public static void main(String[] args) {
// generate public/private keypairs // generate public/private key-pairs
List<SecretKey> secretKeys = new ArrayList<SecretKey>(); List<SecretKey> secretKeys = new ArrayList<>();
for (int i = 0; i < 20; i++) { for (int i = 0; i < 20; i++) {
secretKeys.add(Encryption.generateSecretKey(256)); secretKeys.add(Encryption.generateSecretKey(256));
} }
// print keypairs // print key-pairs
System.out.println("Private keys:"); System.out.println("Private keys:");
for (SecretKey sk : secretKeys) { for (SecretKey sk : secretKeys) {
String privKey = Utils.HEX.encode(sk.getEncoded()); String privateKey = Utils.HEX.encode(sk.getEncoded());
System.out.println(privKey); System.out.println(privateKey);
} }
System.out.println("Corresponding public keys:"); System.out.println("Corresponding public keys:");
for (SecretKey sk : secretKeys) { for (SecretKey sk : secretKeys) {
String privKey = Utils.HEX.encode(sk.getEncoded()); String privateKey = Utils.HEX.encode(sk.getEncoded());
ECKey ecKey = ECKey.fromPrivate(new BigInteger(1, Utils.HEX.decode(privKey))); ECKey ecKey = ECKey.fromPrivate(new BigInteger(1, Utils.HEX.decode(privateKey)));
String pubKey = Utils.HEX.encode(ecKey.getPubKey()); String pubKey = Utils.HEX.encode(ecKey.getPubKey());
System.out.println(pubKey); System.out.println(pubKey);
} }

View File

@ -37,6 +37,7 @@ package haveno.core.xmr;
import com.google.inject.Inject; import com.google.inject.Inject;
import haveno.common.ThreadUtils; import haveno.common.ThreadUtils;
import haveno.common.UserThread; import haveno.common.UserThread;
import haveno.core.api.model.XmrBalanceInfo;
import haveno.core.offer.OpenOffer; import haveno.core.offer.OpenOffer;
import haveno.core.offer.OpenOfferManager; import haveno.core.offer.OpenOfferManager;
import haveno.core.support.dispute.Dispute; import haveno.core.support.dispute.Dispute;
@ -51,8 +52,8 @@ import haveno.core.xmr.wallet.XmrWalletService;
import java.math.BigInteger; import java.math.BigInteger;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import javafx.beans.property.ObjectProperty; import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleObjectProperty; import javafx.beans.property.SimpleIntegerProperty;
import javafx.collections.ListChangeListener; import javafx.collections.ListChangeListener;
import lombok.Getter; import lombok.Getter;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@ -67,15 +68,18 @@ public class Balances {
private final RefundManager refundManager; private final RefundManager refundManager;
@Getter @Getter
private final ObjectProperty<BigInteger> availableBalance = new SimpleObjectProperty<>(); private BigInteger availableBalance;
@Getter @Getter
private final ObjectProperty<BigInteger> pendingBalance = new SimpleObjectProperty<>(); private BigInteger pendingBalance;
@Getter @Getter
private final ObjectProperty<BigInteger> reservedOfferBalance = new SimpleObjectProperty<>(); private BigInteger reservedOfferBalance;
@Getter @Getter
private final ObjectProperty<BigInteger> reservedTradeBalance = new SimpleObjectProperty<>(); private BigInteger reservedTradeBalance;
@Getter @Getter
private final ObjectProperty<BigInteger> reservedBalance = new SimpleObjectProperty<>(); // TODO (woodser): this balance is sum of reserved funds for offers and trade multisigs; remove? private BigInteger reservedBalance; // TODO (woodser): this balance is sum of reserved funds for offers and trade multisigs; remove?
@Getter
private final IntegerProperty updateCounter = new SimpleIntegerProperty(0);
@Inject @Inject
public Balances(TradeManager tradeManager, public Balances(TradeManager tradeManager,
@ -103,18 +107,29 @@ public class Balances {
updateBalances(); updateBalances();
} }
public XmrBalanceInfo getBalances() {
synchronized (this) {
return new XmrBalanceInfo(availableBalance.longValue() + pendingBalance.longValue(),
availableBalance.longValue(),
pendingBalance.longValue(),
reservedOfferBalance.longValue(),
reservedTradeBalance.longValue());
}
}
private void updateBalances() { private void updateBalances() {
ThreadUtils.submitToPool(() -> doUpdateBalances()); ThreadUtils.submitToPool(() -> doUpdateBalances());
} }
private void doUpdateBalances() { private void doUpdateBalances() {
synchronized (this) {
// get wallet balances // get wallet balances
BigInteger balance = xmrWalletService.getWallet() == null ? BigInteger.ZERO : xmrWalletService.getWallet().getBalance(0); BigInteger balance = xmrWalletService.getWallet() == null ? BigInteger.ZERO : xmrWalletService.getBalance();
BigInteger unlockedBalance = xmrWalletService.getWallet() == null ? BigInteger.ZERO : xmrWalletService.getWallet().getUnlockedBalance(0); availableBalance = xmrWalletService.getWallet() == null ? BigInteger.ZERO : xmrWalletService.getAvailableBalance();
// calculate pending balance by adding frozen trade balances - reserved amounts // calculate pending balance by adding frozen trade balances - reserved amounts
BigInteger pendingBalance = balance.subtract(unlockedBalance); pendingBalance = balance.subtract(availableBalance);
List<Trade> trades = tradeManager.getTradesStreamWithFundsLockedIn().collect(Collectors.toList()); List<Trade> trades = tradeManager.getTradesStreamWithFundsLockedIn().collect(Collectors.toList());
for (Trade trade : trades) { for (Trade trade : trades) {
if (trade.getFrozenAmount().equals(new BigInteger("0"))) continue; if (trade.getFrozenAmount().equals(new BigInteger("0"))) continue;
@ -123,7 +138,7 @@ public class Balances {
} }
// calculate reserved offer balance // calculate reserved offer balance
BigInteger reservedOfferBalance = BigInteger.ZERO; reservedOfferBalance = BigInteger.ZERO;
if (xmrWalletService.getWallet() != null) { if (xmrWalletService.getWallet() != null) {
List<MoneroOutputWallet> frozenOutputs = xmrWalletService.getWallet().getOutputs(new MoneroOutputQuery().setIsFrozen(true).setIsSpent(false)); List<MoneroOutputWallet> frozenOutputs = xmrWalletService.getWallet().getOutputs(new MoneroOutputQuery().setIsFrozen(true).setIsSpent(false));
for (MoneroOutputWallet frozenOutput : frozenOutputs) reservedOfferBalance = reservedOfferBalance.add(frozenOutput.getAmount()); for (MoneroOutputWallet frozenOutput : frozenOutputs) reservedOfferBalance = reservedOfferBalance.add(frozenOutput.getAmount());
@ -133,22 +148,16 @@ public class Balances {
} }
// calculate reserved trade balance // calculate reserved trade balance
BigInteger reservedTradeBalance = BigInteger.ZERO; reservedTradeBalance = BigInteger.ZERO;
for (Trade trade : trades) { for (Trade trade : trades) {
reservedTradeBalance = reservedTradeBalance.add(trade.getReservedAmount()); reservedTradeBalance = reservedTradeBalance.add(trade.getReservedAmount());
} }
// set balances // calculate reserved balance
setBalances(balance, unlockedBalance, pendingBalance, reservedOfferBalance, reservedTradeBalance); reservedBalance = reservedOfferBalance.add(reservedTradeBalance);
}
private void setBalances(BigInteger balance, BigInteger unlockedBalance, BigInteger pendingBalance, BigInteger reservedOfferBalance, BigInteger reservedTradeBalance) { // notify balance update
UserThread.execute(() -> { UserThread.execute(() -> updateCounter.set(updateCounter.get() + 1));
this.availableBalance.set(unlockedBalance); }
this.pendingBalance.set(pendingBalance);
this.reservedOfferBalance.set(reservedOfferBalance);
this.reservedTradeBalance.set(reservedTradeBalance);
this.reservedBalance.set(reservedOfferBalance.add(reservedTradeBalance));
});
} }
} }

View File

@ -333,7 +333,9 @@ public class XmrWalletService {
Callable<MoneroSyncResult> task = () -> wallet.sync(); Callable<MoneroSyncResult> task = () -> wallet.sync();
Future<MoneroSyncResult> future = syncWalletThreadPool.submit(task); Future<MoneroSyncResult> future = syncWalletThreadPool.submit(task);
try { try {
return future.get(); MoneroSyncResult result = future.get();
wallet.getTxs(); // TODO: this is necessary to sync from pool, otherwise balance can be incorrect
return result;
} catch (Exception e) { } catch (Exception e) {
throw new MoneroError(e.getMessage()); throw new MoneroError(e.getMessage());
} }
@ -893,7 +895,7 @@ public class XmrWalletService {
} }
// register internal listener to notify external listeners // register internal listener to notify external listeners
wallet.addListener(new XmrWalletListener()); wallet.addListener(new XmrWalletListener()); // TODO: initial snapshot calls getTxs() which updates balance after returning but will not announce change
} }
} }
} }

View File

@ -140,11 +140,7 @@ class GrpcOffersService extends OffersImplBase {
@Override @Override
public void postOffer(PostOfferRequest req, public void postOffer(PostOfferRequest req,
StreamObserver<PostOfferReply> responseObserver) { StreamObserver<PostOfferReply> responseObserver) {
GrpcErrorMessageHandler errorMessageHandler = GrpcErrorMessageHandler errorMessageHandler = new GrpcErrorMessageHandler(getPostOfferMethod().getFullMethodName(), responseObserver, exceptionHandler, log);
new GrpcErrorMessageHandler(getPostOfferMethod().getFullMethodName(),
responseObserver,
exceptionHandler,
log);
try { try {
coreApi.postOffer( coreApi.postOffer(
req.getCurrencyCode(), req.getCurrencyCode(),
@ -170,8 +166,7 @@ class GrpcOffersService extends OffersImplBase {
responseObserver.onCompleted(); responseObserver.onCompleted();
}, },
errorMessage -> { errorMessage -> {
if (!errorMessageHandler.isErrorHandled()) if (!errorMessageHandler.isErrorHandled()) errorMessageHandler.handleErrorMessage(errorMessage);
errorMessageHandler.handleErrorMessage(errorMessage);
}); });
} catch (Throwable cause) { } catch (Throwable cause) {
exceptionHandler.handleException(log, cause, responseObserver); exceptionHandler.handleException(log, cause, responseObserver);
@ -181,11 +176,15 @@ class GrpcOffersService extends OffersImplBase {
@Override @Override
public void cancelOffer(CancelOfferRequest req, public void cancelOffer(CancelOfferRequest req,
StreamObserver<CancelOfferReply> responseObserver) { StreamObserver<CancelOfferReply> responseObserver) {
GrpcErrorMessageHandler errorMessageHandler = new GrpcErrorMessageHandler(getCancelOfferMethod().getFullMethodName(), responseObserver, exceptionHandler, log);
try { try {
coreApi.cancelOffer(req.getId()); coreApi.cancelOffer(req.getId(), () -> {
var reply = CancelOfferReply.newBuilder().build(); var reply = CancelOfferReply.newBuilder().build();
responseObserver.onNext(reply); responseObserver.onNext(reply);
responseObserver.onCompleted(); responseObserver.onCompleted();
}, errorMessage -> {
if (!errorMessageHandler.isErrorHandled()) errorMessageHandler.handleErrorMessage(errorMessage);
});
} catch (Throwable cause) { } catch (Throwable cause) {
exceptionHandler.handleException(log, cause, responseObserver); exceptionHandler.handleException(log, cause, responseObserver);
} }

View File

@ -236,203 +236,44 @@
<sha256 value="6306d89cfdb12bd0b6436390de71cef31879985da10d071a3bdad56bf287bbbb" origin="Generated by Gradle"/> <sha256 value="6306d89cfdb12bd0b6436390de71cef31879985da10d071a3bdad56bf287bbbb" origin="Generated by Gradle"/>
</artifact> </artifact>
</component> </component>
<component group="com.github.bisq-network.netlayer" name="tor" version="6797461310f077bbea4f43a3a509c077b0ed8c34"> <component group="com.github.bisq-network.netlayer" name="tor" version="2b459dc">
<artifact name="tor-6797461310f077bbea4f43a3a509c077b0ed8c34.jar"> <artifact name="tor-2b459dc.jar">
<sha256 value="1536211d3f204059e2ad49c136978b36ebaa19e62103fcd46dcb926842fa0718" origin="Generated by Gradle"/> <sha256 value="d8aba69568795826bd1139b6854b479d9af9fc945eccf2b15d7f9ecb304c5cc4" origin="Generated by Gradle"/>
</artifact>
<artifact name="tor-6797461310f077bbea4f43a3a509c077b0ed8c34.pom">
<sha256 value="7a0ccbecf1471f6be02fb034c006e36b7a6fd249544521c653fed09fbbcec0b1" origin="Generated by Gradle"/>
</artifact> </artifact>
</component> </component>
<component group="com.github.bisq-network.netlayer" name="tor" version="8db4a13"> <component group="com.github.bisq-network.netlayer" name="tor.external" version="2b459dc">
<artifact name="tor-8db4a13.jar"> <artifact name="tor.external-2b459dc.jar">
<sha256 value="37198bc56e8fe112f8c80441544a2b9731929dae586bda841a4a926fdc04f457" origin="Generated by Gradle"/> <sha256 value="6646b6ce9312a16f6b4b61ee91512b8725b55a2f7204aec29f64974207fd5015" origin="Generated by Gradle"/>
</artifact>
<artifact name="tor-8db4a13.pom">
<sha256 value="d1cb5d57710c43642771681d8b1c9039c722fb949bdc5a2022389f5a81501f42" origin="Generated by Gradle"/>
</artifact> </artifact>
</component> </component>
<component group="com.github.bisq-network.netlayer" name="tor.external" version="0.7.2"> <component group="com.github.bisq-network.netlayer" name="tor.native" version="2b459dc">
<artifact name="tor.external-0.7.2.jar"> <artifact name="tor.native-2b459dc.jar">
<sha256 value="45daf9b30f753c49b62cf56226539e824886ce1ff430e03dbef1bddff919cbfc" origin="Generated by Gradle"/> <sha256 value="dc5850e232f2c579d948213a3ea1ce536f56bcc49045a43d3bc63f1e065f1c94" origin="Generated by Gradle"/>
</artifact>
<artifact name="tor.external-0.7.2.pom">
<sha256 value="605e15f473aa7163c4dfa75b0fa17a96466d24c6e3d7a66925b29aadde98dfb4" origin="Generated by Gradle"/>
</artifact> </artifact>
</component> </component>
<component group="com.github.bisq-network.netlayer" name="tor.external" version="6797461310f077bbea4f43a3a509c077b0ed8c34"> <component group="com.github.bisq-network.tor-binary" name="tor-binary-geoip" version="580d31bdcf1fabccd38456aa084044064d89d5c1">
<artifact name="tor.external-6797461310f077bbea4f43a3a509c077b0ed8c34.jar"> <artifact name="tor-binary-geoip-580d31bdcf1fabccd38456aa084044064d89d5c1.jar">
<sha256 value="d79dee1380fcc912dd9f321e6689b99129a90c6b30085b3f86a0b81830ecee71" origin="Generated by Gradle"/> <sha256 value="5a1795e95128e8c6fb3381d1c31ac39f2ec4e4fc3a0262f3f9ac3c7987e0c87e" origin="Generated by Gradle"/>
</artifact>
<artifact name="tor.external-6797461310f077bbea4f43a3a509c077b0ed8c34.pom">
<sha256 value="949ab51a912ba5c126ffda083da2f0366bc9eda36afc5358183e040fee24d86f" origin="Generated by Gradle"/>
</artifact> </artifact>
</component> </component>
<component group="com.github.bisq-network.netlayer" name="tor.external" version="8db4a13"> <component group="com.github.bisq-network.tor-binary" name="tor-binary-linux32" version="580d31bdcf1fabccd38456aa084044064d89d5c1">
<artifact name="tor.external-8db4a13.jar"> <artifact name="tor-binary-linux32-580d31bdcf1fabccd38456aa084044064d89d5c1.jar">
<sha256 value="e1d6b8fe73891207701c6b14317be789fd4acd25f7b499425d2471598d9a22ac" origin="Generated by Gradle"/> <sha256 value="2516ce5549ef5687ef7f855db5940574fc9232ff3ba531fbc216275b8d51ae85" origin="Generated by Gradle"/>
</artifact>
<artifact name="tor.external-8db4a13.pom">
<sha256 value="11918499210e0c12e9d517596eedb34b897021686cf8a1efd8ea87ae3b7e184d" origin="Generated by Gradle"/>
</artifact> </artifact>
</component> </component>
<component group="com.github.bisq-network.netlayer" name="tor.native" version="0.7.2"> <component group="com.github.bisq-network.tor-binary" name="tor-binary-linux64" version="580d31bdcf1fabccd38456aa084044064d89d5c1">
<artifact name="tor.native-0.7.2.jar"> <artifact name="tor-binary-linux64-580d31bdcf1fabccd38456aa084044064d89d5c1.jar">
<sha256 value="ebb37e76fa14461be1ab2750daa3f8e5b78c8ff0d2adb72832ca0d38a1fb8f0d" origin="Generated by Gradle"/> <sha256 value="afc7ad5e1bc57e73aae55d9b022ff63f41f7c73a9a7603d4c24975288432daa1" origin="Generated by Gradle"/>
</artifact>
<artifact name="tor.native-0.7.2.pom">
<sha256 value="021ab6d438023653afee96c0fab1262eed6b7522fce76e114593d55e6d7d9928" origin="Generated by Gradle"/>
</artifact> </artifact>
</component> </component>
<component group="com.github.bisq-network.netlayer" name="tor.native" version="6797461310f077bbea4f43a3a509c077b0ed8c34"> <component group="com.github.bisq-network.tor-binary" name="tor-binary-macos" version="580d31bdcf1fabccd38456aa084044064d89d5c1">
<artifact name="tor.native-6797461310f077bbea4f43a3a509c077b0ed8c34.jar"> <artifact name="tor-binary-macos-580d31bdcf1fabccd38456aa084044064d89d5c1.jar">
<sha256 value="7ab70a9948fffea33da9fee161c5783a74aeb1531e3fda09995c47bb5e2de0f5" origin="Generated by Gradle"/> <sha256 value="5bfb2eaf7efe5d280d6b68e222c910cc6ae2a925e3d06fa35c6b5295ebf94651" origin="Generated by Gradle"/>
</artifact>
<artifact name="tor.native-6797461310f077bbea4f43a3a509c077b0ed8c34.pom">
<sha256 value="17ba4bb22d00441e286dde286045d68190003e849f49871bdac96a5b41478533" origin="Generated by Gradle"/>
</artifact> </artifact>
</component> </component>
<component group="com.github.bisq-network.netlayer" name="tor.native" version="8db4a13"> <component group="com.github.bisq-network.tor-binary" name="tor-binary-windows" version="580d31bdcf1fabccd38456aa084044064d89d5c1">
<artifact name="tor.native-8db4a13.jar"> <artifact name="tor-binary-windows-580d31bdcf1fabccd38456aa084044064d89d5c1.jar">
<sha256 value="aa3edf9c27071fdc2b7d55b00dbc7c6cd5dc9aa9f87aafa4be0805f818a466be" origin="Generated by Gradle"/> <sha256 value="b5fbe9f9e2681b0cfdd0d8a26c7b216c38acfea74fe2103633fe7e81b6cc4bf7" origin="Generated by Gradle"/>
</artifact>
<artifact name="tor.native-8db4a13.pom">
<sha256 value="13e497b9fa97fc994e907aaad69ed81c5433380887a8ac7237bc18e8da48683b" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="com.github.bisq-network.tor-binary" name="tor-binary" version="6d1fd95">
<artifact name="tor-binary-6d1fd95.pom">
<sha256 value="ac20fe51c6473ecaa440458c8255294ff2b30cfed45918527742315bb3d74a86" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="com.github.bisq-network.tor-binary" name="tor-binary" version="787183b147286d783a6392bb9ffcd8ba920d6fff">
<artifact name="tor-binary-787183b147286d783a6392bb9ffcd8ba920d6fff.pom">
<sha256 value="4e127121fefb50fed62a83d5fbd31064b9f16f1a528571675e0ec3042376dab3" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="com.github.bisq-network.tor-binary" name="tor-binary" version="b9c6227">
<artifact name="tor-binary-b9c6227.pom">
<sha256 value="f1ef0c2b2a1df585f057b96b62b05e2e7d7953353b64e29ac798810ff2919b42" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="com.github.bisq-network.tor-binary" name="tor-binary-geoip" version="6d1fd95">
<artifact name="tor-binary-geoip-6d1fd95.jar">
<sha256 value="5a55df3a5bed0aa57165e9bae9ecda8b14d5e85b97dd1a266fa77602fbdaec54" origin="Generated by Gradle"/>
</artifact>
<artifact name="tor-binary-geoip-6d1fd95.pom">
<sha256 value="14fbcfc4de8e07b8c5bf7c1e279704905cc98795e7460cf558288ce1eaaf1927" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="com.github.bisq-network.tor-binary" name="tor-binary-geoip" version="787183b147286d783a6392bb9ffcd8ba920d6fff">
<artifact name="tor-binary-geoip-787183b147286d783a6392bb9ffcd8ba920d6fff.jar">
<sha256 value="e1f0a9708ad5fc5373db84fb14570d36eff842eb71e99c0930db64617604a2bf" origin="Generated by Gradle"/>
</artifact>
<artifact name="tor-binary-geoip-787183b147286d783a6392bb9ffcd8ba920d6fff.pom">
<sha256 value="a6f45951fb73b57c9ac37d389f5adcfecde5f06c2e50d1a8381e640261e5a6b5" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="com.github.bisq-network.tor-binary" name="tor-binary-geoip" version="b9c6227">
<artifact name="tor-binary-geoip-b9c6227.jar">
<sha256 value="cfefbf2d8591b5dd321ec17a02a3682d21763cf50525fa5496c9ec8968413c4e" origin="Generated by Gradle"/>
</artifact>
<artifact name="tor-binary-geoip-b9c6227.pom">
<sha256 value="197d034216b332fcfaa7111442ac4a23bddc60fb71fefba1c736fe9844c1001b" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="com.github.bisq-network.tor-binary" name="tor-binary-linux32" version="6d1fd95">
<artifact name="tor-binary-linux32-6d1fd95.jar">
<sha256 value="fe8b0ddb1c109b453adf9b055e067be04b6ca4cda9d2b33c875b99d2092f0eae" origin="Generated by Gradle"/>
</artifact>
<artifact name="tor-binary-linux32-6d1fd95.pom">
<sha256 value="0ae70e17d9566c88204d02de32c1646d672e78711da97124d23fd397a1da9d13" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="com.github.bisq-network.tor-binary" name="tor-binary-linux32" version="787183b147286d783a6392bb9ffcd8ba920d6fff">
<artifact name="tor-binary-linux32-787183b147286d783a6392bb9ffcd8ba920d6fff.jar">
<sha256 value="b1e8b3f83b08c839a4282a32ef75be69db3ec3061b3472e367606782b861cb55" origin="Generated by Gradle"/>
</artifact>
<artifact name="tor-binary-linux32-787183b147286d783a6392bb9ffcd8ba920d6fff.pom">
<sha256 value="4166e686e18b875fe09e34e19ea294a5841b9d0354072e60fb7779b813c9ff45" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="com.github.bisq-network.tor-binary" name="tor-binary-linux32" version="b9c6227">
<artifact name="tor-binary-linux32-b9c6227.jar">
<sha256 value="b82b6595f78ef52a44e58000fe5d7f679681739451872f5bbd123e5dbd2af050" origin="Generated by Gradle"/>
</artifact>
<artifact name="tor-binary-linux32-b9c6227.pom">
<sha256 value="a01902c476556a0529413b0f3810e954a5eb8a7cdc1a9cc604ec2d24ceca91ce" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="com.github.bisq-network.tor-binary" name="tor-binary-linux64" version="6d1fd95">
<artifact name="tor-binary-linux64-6d1fd95.jar">
<sha256 value="7f58d31dd684b2e361e2980ba23922cadd5d9d8f8dbab9b3a2c6737741b21f7e" origin="Generated by Gradle"/>
</artifact>
<artifact name="tor-binary-linux64-6d1fd95.pom">
<sha256 value="48f0435519eae6ff6af88656a64502320befc392b2c5d59ac2fb47412c9ba52d" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="com.github.bisq-network.tor-binary" name="tor-binary-linux64" version="787183b147286d783a6392bb9ffcd8ba920d6fff">
<artifact name="tor-binary-linux64-787183b147286d783a6392bb9ffcd8ba920d6fff.jar">
<sha256 value="4e956beca59ffce771d0fa40a0b20181c3531d278ff0f1d474a378c0fa9bc76b" origin="Generated by Gradle"/>
</artifact>
<artifact name="tor-binary-linux64-787183b147286d783a6392bb9ffcd8ba920d6fff.pom">
<sha256 value="1f98896ea3822644bebd3c3278497684504e291df03531bf72f072ab2d6b44a1" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="com.github.bisq-network.tor-binary" name="tor-binary-linux64" version="b9c6227">
<artifact name="tor-binary-linux64-b9c6227.jar">
<sha256 value="d5c1d54b2c2323ac1124435be633c7822a28e6fe9160486d03102cc2b444df24" origin="Generated by Gradle"/>
</artifact>
<artifact name="tor-binary-linux64-b9c6227.pom">
<sha256 value="ee305ee12585057bcce380710e4a5ae3a3ed43e1701f5e565f15b75854e3e715" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="com.github.bisq-network.tor-binary" name="tor-binary-macos" version="6d1fd95">
<artifact name="tor-binary-macos-6d1fd95.jar">
<sha256 value="a23802ff66d4ac01366ebe712879e2f51df960572dc34db269588da87453a70d" origin="Generated by Gradle"/>
</artifact>
<artifact name="tor-binary-macos-6d1fd95.pom">
<sha256 value="0c1b6633882ca625f50c78b960714baa81ef286b5dfc26886145f7960feab738" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="com.github.bisq-network.tor-binary" name="tor-binary-macos" version="787183b147286d783a6392bb9ffcd8ba920d6fff">
<artifact name="tor-binary-macos-787183b147286d783a6392bb9ffcd8ba920d6fff.jar">
<sha256 value="9b4114bd7699951dc6b04a10398bd6acc17a966db48c7fa79e302cc0b6fe7ecf" origin="Generated by Gradle"/>
</artifact>
<artifact name="tor-binary-macos-787183b147286d783a6392bb9ffcd8ba920d6fff.pom">
<sha256 value="6b8f372ac6dc38c06575612cc00f5e6d804d80dfe761f8ca0d1aa4562da9d2dd" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="com.github.bisq-network.tor-binary" name="tor-binary-macos" version="b9c6227">
<artifact name="tor-binary-macos-b9c6227.jar">
<sha256 value="6216d66241e020fec1a55648d7176ef64959e094c493df8f49e7e8e8f62fe1e1" origin="Generated by Gradle"/>
</artifact>
<artifact name="tor-binary-macos-b9c6227.pom">
<sha256 value="143a9bfc539101d8293b7d151d6a952135fa5ad76d752639d2ed72fb9c9c494d" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="com.github.bisq-network.tor-binary" name="tor-binary-windows" version="6d1fd95">
<artifact name="tor-binary-windows-6d1fd95.jar">
<sha256 value="8e0dee7429228aa0c9f7a36f40f303a016ed8dfb40fea77382f7076c13fc27f1" origin="Generated by Gradle"/>
</artifact>
<artifact name="tor-binary-windows-6d1fd95.pom">
<sha256 value="08dd80bd3c5e6c6b031ea3e28d8819adec875593a8f1fb9101c0f952f8307b80" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="com.github.bisq-network.tor-binary" name="tor-binary-windows" version="787183b147286d783a6392bb9ffcd8ba920d6fff">
<artifact name="tor-binary-windows-787183b147286d783a6392bb9ffcd8ba920d6fff.jar">
<sha256 value="eebd616315cb7263f07837d5a95c96fdcd627f7fcbfc69e9ca7b840495895197" origin="Generated by Gradle"/>
</artifact>
<artifact name="tor-binary-windows-787183b147286d783a6392bb9ffcd8ba920d6fff.pom">
<sha256 value="fa1cc1b84e4705b9102f269a3ec2602e00ed8dae035d99f60a70194551dc8e08" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="com.github.bisq-network.tor-binary" name="tor-binary-windows" version="b9c6227">
<artifact name="tor-binary-windows-b9c6227.jar">
<sha256 value="28a1031d7610863f774eedbd00b83b06b132781c31077b805033299de3e3a263" origin="Generated by Gradle"/>
</artifact>
<artifact name="tor-binary-windows-b9c6227.pom">
<sha256 value="e067cfa37ee54a2f31d05391319e46484366fda4ef0ee28c3483194b02025e8f" origin="Generated by Gradle"/>
</artifact> </artifact>
</component> </component>
<component group="com.github.johnrengelman" name="shadow" version="8.1.1"> <component group="com.github.johnrengelman" name="shadow" version="8.1.1">
@ -1005,9 +846,9 @@
<sha256 value="c92e2ca40a3f2474d61e56831aeb379cf8ae3dddeea61b4a828cee2d99f71f38" origin="Generated by Gradle"/> <sha256 value="c92e2ca40a3f2474d61e56831aeb379cf8ae3dddeea61b4a828cee2d99f71f38" origin="Generated by Gradle"/>
</artifact> </artifact>
</component> </component>
<component group="io.github.woodser" name="monero-java" version="0.8.10"> <component group="io.github.woodser" name="monero-java" version="0.8.11">
<artifact name="monero-java-0.8.10.jar"> <artifact name="monero-java-0.8.11.jar">
<sha256 value="3ea921cb8122e9be4401479e7040055063b2132e8210f7129117b8b10472f773" origin="Generated by Gradle"/> <sha256 value="37c125a31463c44e43452bc3e18e74a05b65d1fbebb11adc5131521b29b48a6b" origin="Generated by Gradle"/>
</artifact> </artifact>
</component> </component>
<component group="io.grpc" name="grpc-api" version="1.42.1"> <component group="io.grpc" name="grpc-api" version="1.42.1">

View File

@ -47,6 +47,7 @@ public class NetworkNodeProvider implements Provider<NetworkNode> {
@Named(Config.TOR_DIR) File torDir, @Named(Config.TOR_DIR) File torDir,
@Nullable @Named(Config.TORRC_FILE) File torrcFile, @Nullable @Named(Config.TORRC_FILE) File torrcFile,
@Named(Config.TORRC_OPTIONS) String torrcOptions, @Named(Config.TORRC_OPTIONS) String torrcOptions,
@Named(Config.TOR_CONTROL_HOST) String controlHost,
@Named(Config.TOR_CONTROL_PORT) int controlPort, @Named(Config.TOR_CONTROL_PORT) int controlPort,
@Named(Config.TOR_CONTROL_PASSWORD) String password, @Named(Config.TOR_CONTROL_PASSWORD) String password,
@Nullable @Named(Config.TOR_CONTROL_COOKIE_FILE) File cookieFile, @Nullable @Named(Config.TOR_CONTROL_COOKIE_FILE) File cookieFile,
@ -59,11 +60,12 @@ public class NetworkNodeProvider implements Provider<NetworkNode> {
torDir, torDir,
torrcFile, torrcFile,
torrcOptions, torrcOptions,
controlHost,
controlPort, controlPort,
password, password,
cookieFile, cookieFile,
useSafeCookieAuthentication); useSafeCookieAuthentication);
networkNode = new TorNetworkNode(port, networkProtoResolver, streamIsolation, torMode, banFilter, maxConnections); networkNode = new TorNetworkNode(port, networkProtoResolver, streamIsolation, torMode, banFilter, maxConnections, controlHost);
} }
} }
@ -71,12 +73,13 @@ public class NetworkNodeProvider implements Provider<NetworkNode> {
File torDir, File torDir,
@Nullable File torrcFile, @Nullable File torrcFile,
String torrcOptions, String torrcOptions,
String controlHost,
int controlPort, int controlPort,
String password, String password,
@Nullable File cookieFile, @Nullable File cookieFile,
boolean useSafeCookieAuthentication) { boolean useSafeCookieAuthentication) {
return controlPort != Config.UNSPECIFIED_PORT ? return controlPort != Config.UNSPECIFIED_PORT ?
new RunningTor(torDir, controlPort, password, cookieFile, useSafeCookieAuthentication) : new RunningTor(torDir, controlHost, controlPort, password, cookieFile, useSafeCookieAuthentication) :
new NewTor(torDir, torrcFile, torrcOptions, bridgeAddressProvider); new NewTor(torDir, torrcFile, torrcOptions, bridgeAddressProvider);
} }

View File

@ -19,8 +19,26 @@ package haveno.network.p2p;
import com.google.inject.Singleton; import com.google.inject.Singleton;
import com.google.inject.TypeLiteral; import com.google.inject.TypeLiteral;
import static com.google.inject.name.Names.named;
import static com.google.inject.util.Providers.of;
import haveno.common.app.AppModule; import haveno.common.app.AppModule;
import haveno.common.config.Config; import haveno.common.config.Config;
import static haveno.common.config.Config.BAN_LIST;
import static haveno.common.config.Config.MAX_CONNECTIONS;
import static haveno.common.config.Config.NODE_PORT;
import static haveno.common.config.Config.REPUBLISH_MAILBOX_ENTRIES;
import static haveno.common.config.Config.SOCKS_5_PROXY_HTTP_ADDRESS;
import static haveno.common.config.Config.SOCKS_5_PROXY_XMR_ADDRESS;
import static haveno.common.config.Config.TORRC_FILE;
import static haveno.common.config.Config.TORRC_OPTIONS;
import static haveno.common.config.Config.TOR_CONTROL_COOKIE_FILE;
import static haveno.common.config.Config.TOR_CONTROL_HOST;
import static haveno.common.config.Config.TOR_CONTROL_PASSWORD;
import static haveno.common.config.Config.TOR_CONTROL_PORT;
import static haveno.common.config.Config.TOR_CONTROL_USE_SAFE_COOKIE_AUTH;
import static haveno.common.config.Config.TOR_DIR;
import static haveno.common.config.Config.TOR_STREAM_ISOLATION;
import static haveno.common.config.Config.USE_LOCALHOST_FOR_P2P;
import haveno.network.Socks5ProxyProvider; import haveno.network.Socks5ProxyProvider;
import haveno.network.http.HttpClient; import haveno.network.http.HttpClient;
import haveno.network.http.HttpClientImpl; import haveno.network.http.HttpClientImpl;
@ -35,29 +53,10 @@ import haveno.network.p2p.storage.P2PDataStorage;
import haveno.network.p2p.storage.persistence.AppendOnlyDataStoreService; import haveno.network.p2p.storage.persistence.AppendOnlyDataStoreService;
import haveno.network.p2p.storage.persistence.ProtectedDataStoreService; import haveno.network.p2p.storage.persistence.ProtectedDataStoreService;
import haveno.network.p2p.storage.persistence.ResourceDataStoreService; import haveno.network.p2p.storage.persistence.ResourceDataStoreService;
import java.io.File; import java.io.File;
import java.time.Clock; import java.time.Clock;
import java.util.List; import java.util.List;
import static com.google.inject.name.Names.named;
import static com.google.inject.util.Providers.of;
import static haveno.common.config.Config.BAN_LIST;
import static haveno.common.config.Config.MAX_CONNECTIONS;
import static haveno.common.config.Config.NODE_PORT;
import static haveno.common.config.Config.REPUBLISH_MAILBOX_ENTRIES;
import static haveno.common.config.Config.SOCKS_5_PROXY_XMR_ADDRESS;
import static haveno.common.config.Config.SOCKS_5_PROXY_HTTP_ADDRESS;
import static haveno.common.config.Config.TORRC_FILE;
import static haveno.common.config.Config.TORRC_OPTIONS;
import static haveno.common.config.Config.TOR_CONTROL_COOKIE_FILE;
import static haveno.common.config.Config.TOR_CONTROL_PASSWORD;
import static haveno.common.config.Config.TOR_CONTROL_PORT;
import static haveno.common.config.Config.TOR_CONTROL_USE_SAFE_COOKIE_AUTH;
import static haveno.common.config.Config.TOR_DIR;
import static haveno.common.config.Config.TOR_STREAM_ISOLATION;
import static haveno.common.config.Config.USE_LOCALHOST_FOR_P2P;
public class P2PModule extends AppModule { public class P2PModule extends AppModule {
public P2PModule(Config config) { public P2PModule(Config config) {
@ -96,6 +95,7 @@ public class P2PModule extends AppModule {
bindConstant().annotatedWith(named(SOCKS_5_PROXY_HTTP_ADDRESS)).to(config.socks5ProxyHttpAddress); bindConstant().annotatedWith(named(SOCKS_5_PROXY_HTTP_ADDRESS)).to(config.socks5ProxyHttpAddress);
bind(File.class).annotatedWith(named(TORRC_FILE)).toProvider(of(config.torrcFile)); // allow null value bind(File.class).annotatedWith(named(TORRC_FILE)).toProvider(of(config.torrcFile)); // allow null value
bindConstant().annotatedWith(named(TORRC_OPTIONS)).to(config.torrcOptions); bindConstant().annotatedWith(named(TORRC_OPTIONS)).to(config.torrcOptions);
bindConstant().annotatedWith(named(TOR_CONTROL_HOST)).to(config.torControlHost);
bindConstant().annotatedWith(named(TOR_CONTROL_PORT)).to(config.torControlPort); bindConstant().annotatedWith(named(TOR_CONTROL_PORT)).to(config.torControlPort);
bindConstant().annotatedWith(named(TOR_CONTROL_PASSWORD)).to(config.torControlPassword); bindConstant().annotatedWith(named(TOR_CONTROL_PASSWORD)).to(config.torControlPassword);
bind(File.class).annotatedWith(named(TOR_CONTROL_COOKIE_FILE)).toProvider(of(config.torControlCookieFile)); bind(File.class).annotatedWith(named(TOR_CONTROL_COOKIE_FILE)).toProvider(of(config.torControlCookieFile));

View File

@ -17,15 +17,13 @@
package haveno.network.p2p.network; package haveno.network.p2p.network;
import java.io.File;
import java.util.Date;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.berndpruenster.netlayer.tor.ExternalTor; import org.berndpruenster.netlayer.tor.ExternalTor;
import org.berndpruenster.netlayer.tor.Tor; import org.berndpruenster.netlayer.tor.Tor;
import org.berndpruenster.netlayer.tor.TorCtlException; import org.berndpruenster.netlayer.tor.TorCtlException;
import java.io.File;
import java.io.IOException;
import java.util.Date;
/** /**
* This class creates a brand new instance of the Tor onion router. * This class creates a brand new instance of the Tor onion router.
* *
@ -39,15 +37,21 @@ import java.util.Date;
@Slf4j @Slf4j
public class RunningTor extends TorMode { public class RunningTor extends TorMode {
private final String controlHost;
private final int controlPort; private final int controlPort;
private final String password; private final String password;
private final File cookieFile; private final File cookieFile;
private final boolean useSafeCookieAuthentication; private final boolean useSafeCookieAuthentication;
public RunningTor(final File torDir, final int controlPort, final String password, final File cookieFile, public RunningTor(final File torDir,
final String controlHost,
final int controlPort,
final String password,
final File cookieFile,
final boolean useSafeCookieAuthentication) { final boolean useSafeCookieAuthentication) {
super(torDir); super(torDir);
this.controlHost = controlHost;
this.controlPort = controlPort; this.controlPort = controlPort;
this.password = password; this.password = password;
this.cookieFile = cookieFile; this.cookieFile = cookieFile;
@ -55,18 +59,18 @@ public class RunningTor extends TorMode {
} }
@Override @Override
public Tor getTor() throws IOException, TorCtlException { public Tor getTor() throws TorCtlException {
long ts1 = new Date().getTime(); long ts1 = new Date().getTime();
log.info("Connecting to running tor"); log.info("Connecting to running tor");
Tor result; Tor result;
if (!password.isEmpty()) if (!password.isEmpty())
result = new ExternalTor(controlPort, password); result = new ExternalTor(controlHost, controlPort, password);
else if (cookieFile != null && cookieFile.exists()) else if (cookieFile != null && cookieFile.exists())
result = new ExternalTor(controlPort, cookieFile, useSafeCookieAuthentication); result = new ExternalTor(controlHost, controlPort, cookieFile, useSafeCookieAuthentication);
else else
result = new ExternalTor(controlPort); result = new ExternalTor(controlHost, controlPort);
log.info( log.info(
"\n################################################################\n" "\n################################################################\n"

View File

@ -51,6 +51,8 @@ import static com.google.common.base.Preconditions.checkArgument;
public class TorNetworkNode extends NetworkNode { public class TorNetworkNode extends NetworkNode {
private static final long SHUT_DOWN_TIMEOUT = 2; private static final long SHUT_DOWN_TIMEOUT = 2;
private final String torControlHost;
private HiddenServiceSocket hiddenServiceSocket; private HiddenServiceSocket hiddenServiceSocket;
private Timer shutDownTimeoutTimer; private Timer shutDownTimeoutTimer;
private Tor tor; private Tor tor;
@ -70,10 +72,11 @@ public class TorNetworkNode extends NetworkNode {
boolean useStreamIsolation, boolean useStreamIsolation,
TorMode torMode, TorMode torMode,
@Nullable BanFilter banFilter, @Nullable BanFilter banFilter,
int maxConnections) { int maxConnections, String torControlHost) {
super(servicePort, networkProtoResolver, banFilter, maxConnections); super(servicePort, networkProtoResolver, banFilter, maxConnections);
this.torMode = torMode; this.torMode = torMode;
this.streamIsolation = useStreamIsolation; this.streamIsolation = useStreamIsolation;
this.torControlHost = torControlHost;
executor = SingleThreadExecutorUtils.getSingleThreadExecutor("StartTor"); executor = SingleThreadExecutorUtils.getSingleThreadExecutor("StartTor");
} }
@ -97,7 +100,7 @@ public class TorNetworkNode extends NetworkNode {
checkArgument(peerNodeAddress.getHostName().endsWith(".onion"), "PeerAddress is not an onion address"); checkArgument(peerNodeAddress.getHostName().endsWith(".onion"), "PeerAddress is not an onion address");
// If streamId is null stream isolation gets deactivated. // If streamId is null stream isolation gets deactivated.
// Hidden services use stream isolation by default, so we pass null. // Hidden services use stream isolation by default, so we pass null.
return new TorSocket(peerNodeAddress.getHostName(), peerNodeAddress.getPort(), null); return new TorSocket(peerNodeAddress.getHostName(), peerNodeAddress.getPort(), torControlHost, null);
} }
public Socks5Proxy getSocksProxy() { public Socks5Proxy getSocksProxy() {
@ -111,7 +114,7 @@ public class TorNetworkNode extends NetworkNode {
if (socksProxy == null || streamIsolation) { if (socksProxy == null || streamIsolation) {
tor = Tor.getDefault(); tor = Tor.getDefault();
socksProxy = tor != null ? tor.getProxy(stream) : null; socksProxy = tor != null ? tor.getProxy(torControlHost, stream) : null;
} }
return socksProxy; return socksProxy;
} catch (Throwable t) { } catch (Throwable t) {

View File

@ -51,7 +51,7 @@ public class TorNetworkNodeTest {
latch = new CountDownLatch(1); latch = new CountDownLatch(1);
int port = 9001; int port = 9001;
TorNetworkNode node1 = new TorNetworkNode(port, TestUtils.getNetworkProtoResolver(), false, TorNetworkNode node1 = new TorNetworkNode(port, TestUtils.getNetworkProtoResolver(), false,
new NewTor(new File("torNode_" + port), null, "", this::getBridgeAddresses), null, 12); new NewTor(new File("torNode_" + port), null, "", this::getBridgeAddresses), null, 12, "127.0.0.1");
node1.start(new SetupListener() { node1.start(new SetupListener() {
@Override @Override
public void onTorNodeReady() { public void onTorNodeReady() {
@ -78,7 +78,7 @@ public class TorNetworkNodeTest {
latch = new CountDownLatch(1); latch = new CountDownLatch(1);
int port2 = 9002; int port2 = 9002;
TorNetworkNode node2 = new TorNetworkNode(port2, TestUtils.getNetworkProtoResolver(), false, TorNetworkNode node2 = new TorNetworkNode(port2, TestUtils.getNetworkProtoResolver(), false,
new NewTor(new File("torNode_" + port), null, "", this::getBridgeAddresses), null, 12); new NewTor(new File("torNode_" + port), null, "", this::getBridgeAddresses), null, 12, "127.0.0.1");
node2.start(new SetupListener() { node2.start(new SetupListener() {
@Override @Override
public void onTorNodeReady() { public void onTorNodeReady() {
@ -136,7 +136,7 @@ public class TorNetworkNodeTest {
latch = new CountDownLatch(2); latch = new CountDownLatch(2);
int port = 9001; int port = 9001;
TorNetworkNode node1 = new TorNetworkNode(port, TestUtils.getNetworkProtoResolver(), false, TorNetworkNode node1 = new TorNetworkNode(port, TestUtils.getNetworkProtoResolver(), false,
new NewTor(new File("torNode_" + port), null, "", this::getBridgeAddresses), null, 12); new NewTor(new File("torNode_" + port), null, "", this::getBridgeAddresses), null, 12, "127.0.0.1");
node1.start(new SetupListener() { node1.start(new SetupListener() {
@Override @Override
public void onTorNodeReady() { public void onTorNodeReady() {
@ -162,7 +162,7 @@ public class TorNetworkNodeTest {
int port2 = 9002; int port2 = 9002;
TorNetworkNode node2 = new TorNetworkNode(port2, TestUtils.getNetworkProtoResolver(), false, TorNetworkNode node2 = new TorNetworkNode(port2, TestUtils.getNetworkProtoResolver(), false,
new NewTor(new File("torNode_" + port), null, "", this::getBridgeAddresses), null, 12); new NewTor(new File("torNode_" + port), null, "", this::getBridgeAddresses), null, 12, "127.0.0.1");
node2.start(new SetupListener() { node2.start(new SetupListener() {
@Override @Override
public void onTorNodeReady() { public void onTorNodeReady() {

View File

@ -1,7 +1,7 @@
# docker run -it -p 9050 -p 2002 --restart-policy unless-stopped --name haveno-seednode haveno-seednode # docker run -it -p 9050 -p 2002 --restart-policy unless-stopped --name haveno-seednode haveno-seednode
# TODO: image very heavy, but it's hard to significantly reduce the size without bins # TODO: image very heavy, but it's hard to significantly reduce the size without bins
FROM openjdk:11 FROM openjdk:21-jdk-bullseye
RUN set -ex && \ RUN set -ex && \
apt update && \ apt update && \

View File

@ -1,11 +1,11 @@
# configuration for haveno service # configuration for haveno service
# install in /etc/default/haveno.env # install in /etc/default/haveno.env
# java home, set to openjdk 10 # java home, set to latest openjdk 21 from os repository
JAVA_HOME=/usr/lib/jvm/openjdk-10.0.2 JAVA_HOME=/usr/lib/jvm/openjdk-21
# java memory and remote management options # java memory and remote management options
JAVA_OPTS="-Xms4096M -Xmx4096M" JAVA_OPTS="-Xms4096M -Xmx4096M" -XX:+ExitOnOutOfMemoryError"
# use external tor (change to -1 for internal tor binary) # use external tor (change to -1 for internal tor binary)
HAVENO_EXTERNAL_TOR_PORT=9051 HAVENO_EXTERNAL_TOR_PORT=9051
@ -28,7 +28,7 @@ BITCOIN_RPC_BLOCKNOTIFY_PORT=5120
HAVENO_HOME=__HAVENO_HOME__ HAVENO_HOME=__HAVENO_HOME__
HAVENO_APP_NAME=haveno-seednode HAVENO_APP_NAME=haveno-seednode
HAVENO_ENTRYPOINT=haveno-seednode HAVENO_ENTRYPOINT=haveno-seednode
HAVENO_BASE_CURRENCY=btc_mainnet HAVENO_BASE_CURRENCY=xmr_mainnet
# haveno node settings # haveno node settings
HAVENO_NODE_PORT=8000 HAVENO_NODE_PORT=8000

View File

@ -7,22 +7,21 @@ echo "[*] Haveno Seednode installation script"
ROOT_USER=root ROOT_USER=root
ROOT_GROUP=root ROOT_GROUP=root
ROOT_PKG="build-essential libtool autotools-dev automake pkg-config bsdmainutils python3 git vim screen ufw" ROOT_PKG="build-essential libtool autotools-dev automake pkg-config bsdmainutils python3 git vim screen ufw openjdk-21-jdk"
ROOT_HOME=/root ROOT_HOME=/root
SYSTEMD_SERVICE_HOME=/etc/systemd/system SYSTEMD_SERVICE_HOME=/etc/systemd/system
SYSTEMD_ENV_HOME=/etc/default SYSTEMD_ENV_HOME=/etc/default
HAVENO_REPO_URL=https://github.com/bisq-network/bisq HAVENO_REPO_URL=https://github.com/haveno-dex/haveno
HAVENO_REPO_NAME=haveno HAVENO_REPO_NAME=haveno
HAVENO_REPO_TAG=master HAVENO_REPO_TAG=master
HAVENO_LATEST_RELEASE=$(curl -s https://api.github.com/repos/bisq-network/bisq/releases/latest|grep tag_name|head -1|cut -d '"' -f4) HAVENO_LATEST_RELEASE=$(curl -s https://api.github.com/repos/haveno-dex/haveno/releases/latest|grep tag_name|head -1|cut -d '"' -f4)
HAVENO_HOME=/haveno HAVENO_HOME=/haveno
HAVENO_USER=haveno HAVENO_USER=haveno
# by default, this script will build and setup bitcoin fullnode # by default, this script will not build and setup bitcoin full-node
# if you want to use an existing bitcoin fullnode, see next section BITCOIN_INSTALL=false
BITCOIN_INSTALL=true
BITCOIN_REPO_URL=https://github.com/bitcoin/bitcoin BITCOIN_REPO_URL=https://github.com/bitcoin/bitcoin
BITCOIN_REPO_NAME=bitcoin BITCOIN_REPO_NAME=bitcoin
BITCOIN_REPO_TAG=$(curl -s https://api.github.com/repos/bitcoin/bitcoin/releases/latest|grep tag_name|head -1|cut -d '"' -f4) BITCOIN_REPO_TAG=$(curl -s https://api.github.com/repos/bitcoin/bitcoin/releases/latest|grep tag_name|head -1|cut -d '"' -f4)
@ -60,19 +59,13 @@ sudo -H -i -u "${ROOT_USER}" DEBIAN_FRONTEND=noninteractive apt-get upgrade -qq
echo "[*] Installing base packages" echo "[*] Installing base packages"
sudo -H -i -u "${ROOT_USER}" DEBIAN_FRONTEND=noninteractive apt-get install -qq -y ${ROOT_PKG} sudo -H -i -u "${ROOT_USER}" DEBIAN_FRONTEND=noninteractive apt-get install -qq -y ${ROOT_PKG}
echo "[*] Installing Git LFS"
sudo -H -i -u "${ROOT_USER}" apt-get install git-lfs
sudo -H -i -u "${ROOT_USER}" git lfs install
echo "[*] Cloning Haveno repo" echo "[*] Cloning Haveno repo"
sudo -H -i -u "${ROOT_USER}" git config --global advice.detachedHead false sudo -H -i -u "${ROOT_USER}" git config --global advice.detachedHead false
sudo -H -i -u "${ROOT_USER}" git clone --branch "${HAVENO_REPO_TAG}" "${HAVENO_REPO_URL}" "${ROOT_HOME}/${HAVENO_REPO_NAME}" sudo -H -i -u "${ROOT_USER}" git clone --branch "${HAVENO_REPO_TAG}" "${HAVENO_REPO_URL}" "${ROOT_HOME}/${HAVENO_REPO_NAME}"
echo "[*] Installing Tor" echo "[*] Installing Tor"
sudo -H -i -u "${ROOT_USER}" wget -qO- https://deb.torproject.org/torproject.org/A3C4F0F979CAA22CDBA8F512EE8CBC9E886DDD89.asc | gp sudo -H -i -u "${ROOT_USER}" wget -qO- https://deb.torproject.org/torproject.org/A3C4F0F979CAA22CDBA8F512EE8CBC9E886DDD89.asc | sudo gpg --dearmor | sudo tee /usr/share/keyrings/tor-archive-keyring.gpg >/dev/null
g --dearmor | tee /usr/share/keyrings/tor-archive-keyring.gpg >/dev/null echo "deb [arch=amd64 signed-by=/usr/share/keyrings/tor-archive-keyring.gpg] https://deb.torproject.org/torproject.org focal main" | sudo -H -i -u "${ROOT_USER}" tee /etc/apt/sources.list.d/tor.list
sudo -H -i -u "${ROOT_USER}" echo "deb [arch=amd64 signed-by=/usr/share/keyrings/tor-archive-keyring.gpg] https://deb.torproject.o
rg/torproject.org focal main" > /etc/apt/sources.list.d/tor.list
sudo -H -i -u "${ROOT_USER}" DEBIAN_FRONTEND=noninteractive apt-get update -q sudo -H -i -u "${ROOT_USER}" DEBIAN_FRONTEND=noninteractive apt-get update -q
sudo -H -i -u "${ROOT_USER}" DEBIAN_FRONTEND=noninteractive apt-get install -qq -y ${TOR_PKG} sudo -H -i -u "${ROOT_USER}" DEBIAN_FRONTEND=noninteractive apt-get install -qq -y ${TOR_PKG}
@ -128,17 +121,14 @@ echo "[*] Moving Haveno repo"
sudo -H -i -u "${ROOT_USER}" mv "${ROOT_HOME}/${HAVENO_REPO_NAME}" "${HAVENO_HOME}/${HAVENO_REPO_NAME}" sudo -H -i -u "${ROOT_USER}" mv "${ROOT_HOME}/${HAVENO_REPO_NAME}" "${HAVENO_HOME}/${HAVENO_REPO_NAME}"
sudo -H -i -u "${ROOT_USER}" chown -R "${HAVENO_USER}:${HAVENO_GROUP}" "${HAVENO_HOME}/${HAVENO_REPO_NAME}" sudo -H -i -u "${ROOT_USER}" chown -R "${HAVENO_USER}:${HAVENO_GROUP}" "${HAVENO_HOME}/${HAVENO_REPO_NAME}"
echo "[*] Installing OpenJDK 10.0.2 from Haveno repo"
sudo -H -i -u "${ROOT_USER}" "${HAVENO_HOME}/${HAVENO_REPO_NAME}/scripts/install_java.sh"
echo "[*] Installing Haveno init script" echo "[*] Installing Haveno init script"
sudo -H -i -u "${ROOT_USER}" install -c -o "${ROOT_USER}" -g "${ROOT_GROUP}" -m 644 "${HAVENO_HOME}/${HAVENO_REPO_NAME}/seednode/haveno.service" "${SYSTEMD_SERVICE_HOME}/haveno.service" sudo -H -i -u "${ROOT_USER}" install -c -o "${ROOT_USER}" -g "${ROOT_GROUP}" -m 644 "${HAVENO_HOME}/${HAVENO_REPO_NAME}/seednode/haveno-seednode.service" "${SYSTEMD_SERVICE_HOME}/haveno-seednode.service"
if [ "${BITCOIN_INSTALL}" = true ];then if [ "${BITCOIN_INSTALL}" = true ];then
sudo sed -i -e "s/#Requires=bitcoin.service/Requires=bitcoin.service/" "${SYSTEMD_SERVICE_HOME}/haveno.service" sudo sed -i -e "s/#Requires=bitcoin.service/Requires=bitcoin.service/" "${SYSTEMD_SERVICE_HOME}/haveno-seednode.service"
sudo sed -i -e "s/#BindsTo=bitcoin.service/BindsTo=bitcoin.service/" "${SYSTEMD_SERVICE_HOME}/haveno.service" sudo sed -i -e "s/#BindsTo=bitcoin.service/BindsTo=bitcoin.service/" "${SYSTEMD_SERVICE_HOME}/haveno-seednode.service"
fi fi
sudo sed -i -e "s/__HAVENO_REPO_NAME__/${HAVENO_REPO_NAME}/" "${SYSTEMD_SERVICE_HOME}/haveno.service" sudo sed -i -e "s/__HAVENO_REPO_NAME__/${HAVENO_REPO_NAME}/" "${SYSTEMD_SERVICE_HOME}/haveno-seednode.service"
sudo sed -i -e "s!__HAVENO_HOME__!${HAVENO_HOME}!" "${SYSTEMD_SERVICE_HOME}/haveno.service" sudo sed -i -e "s!__HAVENO_HOME__!${HAVENO_HOME}!" "${SYSTEMD_SERVICE_HOME}/haveno-seednode.service"
echo "[*] Installing Haveno environment file with Bitcoin RPC credentials" echo "[*] Installing Haveno environment file with Bitcoin RPC credentials"
sudo -H -i -u "${ROOT_USER}" install -c -o "${ROOT_USER}" -g "${ROOT_GROUP}" -m 644 "${HAVENO_HOME}/${HAVENO_REPO_NAME}/seednode/haveno.env" "${SYSTEMD_ENV_HOME}/haveno.env" sudo -H -i -u "${ROOT_USER}" install -c -o "${ROOT_USER}" -g "${ROOT_GROUP}" -m 644 "${HAVENO_HOME}/${HAVENO_REPO_NAME}/seednode/haveno.env" "${SYSTEMD_ENV_HOME}/haveno.env"
@ -154,16 +144,13 @@ sudo sed -i -e "s!__HAVENO_HOME__!${HAVENO_HOME}!" "${SYSTEMD_ENV_HOME}/haveno.e
echo "[*] Checking out Haveno ${HAVENO_LATEST_RELEASE}" echo "[*] Checking out Haveno ${HAVENO_LATEST_RELEASE}"
sudo -H -i -u "${HAVENO_USER}" sh -c "cd ${HAVENO_HOME}/${HAVENO_REPO_NAME} && git checkout ${HAVENO_LATEST_RELEASE}" sudo -H -i -u "${HAVENO_USER}" sh -c "cd ${HAVENO_HOME}/${HAVENO_REPO_NAME} && git checkout ${HAVENO_LATEST_RELEASE}"
echo "[*] Performing Git LFS pull"
sudo -H -i -u "${HAVENO_USER}" sh -c "cd ${HAVENO_HOME}/${HAVENO_REPO_NAME} && git lfs pull"
echo "[*] Building Haveno from source" echo "[*] Building Haveno from source"
sudo -H -i -u "${HAVENO_USER}" sh -c "cd ${HAVENO_HOME}/${HAVENO_REPO_NAME} && ./gradlew build -x test < /dev/null" # redirect from /dev/null is necessary to workaround gradlew non-interactive shell hanging issue sudo -H -i -u "${HAVENO_USER}" sh -c "cd ${HAVENO_HOME}/${HAVENO_REPO_NAME} && ./gradlew build -x test < /dev/null" # redirect from /dev/null is necessary to workaround gradlew non-interactive shell hanging issue
echo "[*] Updating systemd daemon configuration" echo "[*] Updating systemd daemon configuration"
sudo -H -i -u "${ROOT_USER}" systemctl daemon-reload sudo -H -i -u "${ROOT_USER}" systemctl daemon-reload
sudo -H -i -u "${ROOT_USER}" systemctl enable tor.service sudo -H -i -u "${ROOT_USER}" systemctl enable tor.service
sudo -H -i -u "${ROOT_USER}" systemctl enable haveno.service sudo -H -i -u "${ROOT_USER}" systemctl enable haveno-seednode.service
if [ "${BITCOIN_INSTALL}" = true ];then if [ "${BITCOIN_INSTALL}" = true ];then
sudo -H -i -u "${ROOT_USER}" systemctl enable bitcoin.service sudo -H -i -u "${ROOT_USER}" systemctl enable bitcoin.service
fi fi
@ -185,13 +172,13 @@ fi
echo "[*] Adding notes to motd" echo "[*] Adding notes to motd"
sudo -H -i -u "${ROOT_USER}" sh -c 'echo " " >> /etc/motd' sudo -H -i -u "${ROOT_USER}" sh -c 'echo " " >> /etc/motd'
sudo -H -i -u "${ROOT_USER}" sh -c 'echo "Haveno Seednode instructions:" >> /etc/motd' sudo -H -i -u "${ROOT_USER}" sh -c 'echo "Haveno Seednode instructions:" >> /etc/motd'
sudo -H -i -u "${ROOT_USER}" sh -c 'echo "https://github.com/bisq-network/bisq/tree/master/seednode" >> /etc/motd' sudo -H -i -u "${ROOT_USER}" sh -c 'echo "https://github.com/haveno-dex/haveno/tree/master/seednode" >> /etc/motd'
sudo -H -i -u "${ROOT_USER}" sh -c 'echo " " >> /etc/motd' sudo -H -i -u "${ROOT_USER}" sh -c 'echo " " >> /etc/motd'
sudo -H -i -u "${ROOT_USER}" sh -c 'echo "How to check logs for Haveno-Seednode service:" >> /etc/motd' sudo -H -i -u "${ROOT_USER}" sh -c 'echo "How to check logs for Haveno-Seednode service:" >> /etc/motd'
sudo -H -i -u "${ROOT_USER}" sh -c 'echo "sudo journalctl --no-pager --unit haveno" >> /etc/motd' sudo -H -i -u "${ROOT_USER}" sh -c 'echo "sudo journalctl --no-pager --unit haveno-seednode" >> /etc/motd'
sudo -H -i -u "${ROOT_USER}" sh -c 'echo " " >> /etc/motd' sudo -H -i -u "${ROOT_USER}" sh -c 'echo " " >> /etc/motd'
sudo -H -i -u "${ROOT_USER}" sh -c 'echo "How to restart Haveno-Seednode service:" >> /etc/motd' sudo -H -i -u "${ROOT_USER}" sh -c 'echo "How to restart Haveno-Seednode service:" >> /etc/motd'
sudo -H -i -u "${ROOT_USER}" sh -c 'echo "sudo service haveno restart" >> /etc/motd' sudo -H -i -u "${ROOT_USER}" sh -c 'echo "sudo service haveno-seednode restart" >> /etc/motd'
echo '[*] Done!' echo '[*] Done!'

View File

@ -3,9 +3,9 @@ echo "[*] Uninstalling Bitcoin and Haveno, will delete all data!!"
sleep 10 sleep 10
sudo rm -rf /root/haveno sudo rm -rf /root/haveno
sudo systemctl stop bitcoin sudo systemctl stop bitcoin
sudo systemctl stop haveno sudo systemctl stop haveno-seednode
sudo systemctl disable bitcoin sudo systemctl disable bitcoin
sudo systemctl disable haveno sudo systemctl disable haveno-seednode
sudo userdel -f -r haveno sudo userdel -f -r haveno
sudo userdel -f -r bitcoin sudo userdel -f -r bitcoin
echo "[*] Done!" echo "[*] Done!"