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;
import haveno.asset.Base58AddressValidator;
import haveno.asset.BitcoinAddressValidator;
import haveno.asset.Coin;
import haveno.asset.NetworkParametersAdapter;
public class Litecoin extends Coin {
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 LitecoinMainNetParams() {
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("LTuoeY6RBHV3n3cfhXVVTbJbxzxnXs9ofm");
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
@ -38,5 +49,14 @@ public class LitecoinTest extends AbstractAssetTest {
assertInvalidAddress("1LgfapHEPhZbRF9pMd5WPT35hFXcZS1USrW");
assertInvalidAddress("LgfapHEPhZbdRF9pMd5WPT35hFXcZS1USrW");
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'
guavaVersion = '32.1.1-jre'
guiceVersion = '7.0.0'
moneroJavaVersion = '0.8.10'
moneroJavaVersion = '0.8.11'
httpclient5Version = '5.0'
hamcrestVersion = '2.2'
httpclientVersion = '4.5.12'
@ -71,7 +71,7 @@ configure(subprojects) {
loggingVersion = '1.2'
lombokVersion = '1.18.30'
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'
protocVersion = protobufVersion
pushyVersion = '0.13.2'
@ -436,6 +436,11 @@ configure(project(':core')) {
systemProperty 'jdk.attach.allowAttachSelf', true
}
task generateKeypairs(type: JavaExec) {
mainClass = 'haveno.core.util.GenerateKeyPairs'
classpath = sourceSets.main.runtimeClasspath
}
task havenoDeps {
doLast {
// get monero binaries download url

View File

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

View File

@ -84,6 +84,7 @@ public class Config {
public static final String USE_TOR_FOR_XMR = "useTorForXmr";
public static final String TORRC_FILE = "torrcFile";
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_PASSWORD = "torControlPassword";
public static final String TOR_CONTROL_COOKIE_FILE = "torControlCookieFile";
@ -173,6 +174,7 @@ public class Config {
public final String socks5ProxyHttpAddress;
public final File torrcFile;
public final String torrcOptions;
public final String torControlHost;
public final int torControlPort;
public final String torControlPassword;
public final File torControlCookieFile;
@ -446,6 +448,11 @@ public class Config {
.withValuesConvertedBy(RegexMatcher.regex("^([^\\s,]+\\s[^,]+,?\\s*)+$"))
.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 =
parser.accepts(TOR_CONTROL_PORT,
"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.torrcFile = options.has(torrcFileOpt) ? options.valueOf(torrcFileOpt).toFile() : null;
this.torrcOptions = options.valueOf(torrcOptionsOpt);
this.torControlHost = options.valueOf(torControlHostOpt);
this.torControlPort = options.valueOf(torControlPortOpt);
this.torControlPassword = options.valueOf(torControlPasswordOpt);
this.torControlCookieFile = options.has(torControlCookieFileOpt) ?

View File

@ -19,16 +19,6 @@ package haveno.common.crypto;
import haveno.common.util.Hex;
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.IOException;
import java.security.InvalidKeyException;
@ -43,10 +33,17 @@ import java.security.spec.InvalidKeySpecException;
import java.security.spec.MGF1ParameterSpec;
import java.security.spec.X509EncodedKeySpec;
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 {
private static final Logger log = LoggerFactory.getLogger(Encryption.class);
public static final String ASYM_KEY_ALGO = "RSA";
private static final String ASYM_CIPHER = "RSA/ECB/OAEPWithSHA-256AndMGF1PADDING";

View File

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

View File

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

View File

@ -133,7 +133,6 @@ class CoreWalletsService {
verifyWalletCurrencyCodeIsValid(currencyCode);
verifyWalletsAreAvailable();
verifyEncryptedWalletIsUnlocked();
if (balances.getAvailableBalance().get() == null) throw new IllegalStateException("balance is not yet available");
switch (currencyCode.trim().toUpperCase()) {
case "":
@ -418,28 +417,8 @@ class CoreWalletsService {
private XmrBalanceInfo getXmrBalances() {
verifyWalletsAreAvailable();
verifyEncryptedWalletIsUnlocked();
var availableBalance = balances.getAvailableBalance().get();
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());
if (balances.getAvailableBalance() == null) throw new IllegalStateException("Balances are not yet available");
return balances.getBalances();
}
// Returns a Coin for the transfer amount string, or a RuntimeException if invalid.

View File

@ -1,10 +1,10 @@
package haveno.core.api.model;
import java.math.BigInteger;
import com.google.common.annotations.VisibleForTesting;
import haveno.common.Payload;
import lombok.Getter;
@Getter
public class XmrBalanceInfo implements Payload {
public static final XmrBalanceInfo EMPTY = new XmrBalanceInfo(-1,
@ -19,17 +19,19 @@ public class XmrBalanceInfo implements Payload {
private final long pendingBalance;
private final long reservedOfferBalance;
private final long reservedTradeBalance;
private final long reservedBalance;
public XmrBalanceInfo(long balance,
long unlockedBalance,
long lockedBalance,
long pendingBalance,
long reservedOfferBalance,
long reservedTradeBalance) {
this.balance = balance;
this.availableBalance = unlockedBalance;
this.pendingBalance = lockedBalance;
this.pendingBalance = pendingBalance;
this.reservedOfferBalance = reservedOfferBalance;
this.reservedTradeBalance = reservedTradeBalance;
this.reservedBalance = reservedOfferBalance + reservedTradeBalance;
}
@VisibleForTesting
@ -45,6 +47,30 @@ public class XmrBalanceInfo implements Payload {
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
///////////////////////////////////////////////////////////////////////////////////////////

View File

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

View File

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

View File

@ -12,29 +12,29 @@ import org.bitcoinj.core.Utils;
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.
*/
public class GenerateKeypairs {
public class GenerateKeyPairs {
public static void main(String[] args) {
// generate public/private keypairs
List<SecretKey> secretKeys = new ArrayList<SecretKey>();
// generate public/private key-pairs
List<SecretKey> secretKeys = new ArrayList<>();
for (int i = 0; i < 20; i++) {
secretKeys.add(Encryption.generateSecretKey(256));
}
// print keypairs
// print key-pairs
System.out.println("Private keys:");
for (SecretKey sk : secretKeys) {
String privKey = Utils.HEX.encode(sk.getEncoded());
System.out.println(privKey);
String privateKey = Utils.HEX.encode(sk.getEncoded());
System.out.println(privateKey);
}
System.out.println("Corresponding public keys:");
for (SecretKey sk : secretKeys) {
String privKey = Utils.HEX.encode(sk.getEncoded());
ECKey ecKey = ECKey.fromPrivate(new BigInteger(1, Utils.HEX.decode(privKey)));
String privateKey = Utils.HEX.encode(sk.getEncoded());
ECKey ecKey = ECKey.fromPrivate(new BigInteger(1, Utils.HEX.decode(privateKey)));
String pubKey = Utils.HEX.encode(ecKey.getPubKey());
System.out.println(pubKey);
}

View File

@ -37,6 +37,7 @@ package haveno.core.xmr;
import com.google.inject.Inject;
import haveno.common.ThreadUtils;
import haveno.common.UserThread;
import haveno.core.api.model.XmrBalanceInfo;
import haveno.core.offer.OpenOffer;
import haveno.core.offer.OpenOfferManager;
import haveno.core.support.dispute.Dispute;
@ -51,8 +52,8 @@ import haveno.core.xmr.wallet.XmrWalletService;
import java.math.BigInteger;
import java.util.List;
import java.util.stream.Collectors;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.collections.ListChangeListener;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
@ -67,15 +68,18 @@ public class Balances {
private final RefundManager refundManager;
@Getter
private final ObjectProperty<BigInteger> availableBalance = new SimpleObjectProperty<>();
private BigInteger availableBalance;
@Getter
private final ObjectProperty<BigInteger> pendingBalance = new SimpleObjectProperty<>();
private BigInteger pendingBalance;
@Getter
private final ObjectProperty<BigInteger> reservedOfferBalance = new SimpleObjectProperty<>();
private BigInteger reservedOfferBalance;
@Getter
private final ObjectProperty<BigInteger> reservedTradeBalance = new SimpleObjectProperty<>();
private BigInteger reservedTradeBalance;
@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
public Balances(TradeManager tradeManager,
@ -103,52 +107,57 @@ public class Balances {
updateBalances();
}
public XmrBalanceInfo getBalances() {
synchronized (this) {
return new XmrBalanceInfo(availableBalance.longValue() + pendingBalance.longValue(),
availableBalance.longValue(),
pendingBalance.longValue(),
reservedOfferBalance.longValue(),
reservedTradeBalance.longValue());
}
}
private void updateBalances() {
ThreadUtils.submitToPool(() -> doUpdateBalances());
}
private void doUpdateBalances() {
synchronized (this) {
// get wallet balances
BigInteger balance = xmrWalletService.getWallet() == null ? BigInteger.ZERO : xmrWalletService.getWallet().getBalance(0);
BigInteger unlockedBalance = xmrWalletService.getWallet() == null ? BigInteger.ZERO : xmrWalletService.getWallet().getUnlockedBalance(0);
// get wallet balances
BigInteger balance = xmrWalletService.getWallet() == null ? BigInteger.ZERO : xmrWalletService.getBalance();
availableBalance = xmrWalletService.getWallet() == null ? BigInteger.ZERO : xmrWalletService.getAvailableBalance();
// calculate pending balance by adding frozen trade balances - reserved amounts
BigInteger pendingBalance = balance.subtract(unlockedBalance);
List<Trade> trades = tradeManager.getTradesStreamWithFundsLockedIn().collect(Collectors.toList());
for (Trade trade : trades) {
if (trade.getFrozenAmount().equals(new BigInteger("0"))) continue;
BigInteger tradeFee = trade instanceof MakerTrade ? trade.getMakerFee() : trade.getTakerFee();
pendingBalance = pendingBalance.add(trade.getFrozenAmount()).subtract(trade.getReservedAmount()).subtract(tradeFee).subtract(trade.getSelf().getDepositTxFee());
// calculate pending balance by adding frozen trade balances - reserved amounts
pendingBalance = balance.subtract(availableBalance);
List<Trade> trades = tradeManager.getTradesStreamWithFundsLockedIn().collect(Collectors.toList());
for (Trade trade : trades) {
if (trade.getFrozenAmount().equals(new BigInteger("0"))) continue;
BigInteger tradeFee = trade instanceof MakerTrade ? trade.getMakerFee() : trade.getTakerFee();
pendingBalance = pendingBalance.add(trade.getFrozenAmount()).subtract(trade.getReservedAmount()).subtract(tradeFee).subtract(trade.getSelf().getDepositTxFee());
}
// calculate reserved offer balance
reservedOfferBalance = BigInteger.ZERO;
if (xmrWalletService.getWallet() != null) {
List<MoneroOutputWallet> frozenOutputs = xmrWalletService.getWallet().getOutputs(new MoneroOutputQuery().setIsFrozen(true).setIsSpent(false));
for (MoneroOutputWallet frozenOutput : frozenOutputs) reservedOfferBalance = reservedOfferBalance.add(frozenOutput.getAmount());
}
for (Trade trade : trades) {
reservedOfferBalance = reservedOfferBalance.subtract(trade.getFrozenAmount()); // subtract frozen trade balances
}
// calculate reserved trade balance
reservedTradeBalance = BigInteger.ZERO;
for (Trade trade : trades) {
reservedTradeBalance = reservedTradeBalance.add(trade.getReservedAmount());
}
// calculate reserved balance
reservedBalance = reservedOfferBalance.add(reservedTradeBalance);
// notify balance update
UserThread.execute(() -> updateCounter.set(updateCounter.get() + 1));
}
// calculate reserved offer balance
BigInteger reservedOfferBalance = BigInteger.ZERO;
if (xmrWalletService.getWallet() != null) {
List<MoneroOutputWallet> frozenOutputs = xmrWalletService.getWallet().getOutputs(new MoneroOutputQuery().setIsFrozen(true).setIsSpent(false));
for (MoneroOutputWallet frozenOutput : frozenOutputs) reservedOfferBalance = reservedOfferBalance.add(frozenOutput.getAmount());
}
for (Trade trade : trades) {
reservedOfferBalance = reservedOfferBalance.subtract(trade.getFrozenAmount()); // subtract frozen trade balances
}
// calculate reserved trade balance
BigInteger reservedTradeBalance = BigInteger.ZERO;
for (Trade trade : trades) {
reservedTradeBalance = reservedTradeBalance.add(trade.getReservedAmount());
}
// set balances
setBalances(balance, unlockedBalance, pendingBalance, reservedOfferBalance, reservedTradeBalance);
}
private void setBalances(BigInteger balance, BigInteger unlockedBalance, BigInteger pendingBalance, BigInteger reservedOfferBalance, BigInteger reservedTradeBalance) {
UserThread.execute(() -> {
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();
Future<MoneroSyncResult> future = syncWalletThreadPool.submit(task);
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) {
throw new MoneroError(e.getMessage());
}
@ -893,7 +895,7 @@ public class XmrWalletService {
}
// 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
public void postOffer(PostOfferRequest req,
StreamObserver<PostOfferReply> responseObserver) {
GrpcErrorMessageHandler errorMessageHandler =
new GrpcErrorMessageHandler(getPostOfferMethod().getFullMethodName(),
responseObserver,
exceptionHandler,
log);
GrpcErrorMessageHandler errorMessageHandler = new GrpcErrorMessageHandler(getPostOfferMethod().getFullMethodName(), responseObserver, exceptionHandler, log);
try {
coreApi.postOffer(
req.getCurrencyCode(),
@ -170,8 +166,7 @@ class GrpcOffersService extends OffersImplBase {
responseObserver.onCompleted();
},
errorMessage -> {
if (!errorMessageHandler.isErrorHandled())
errorMessageHandler.handleErrorMessage(errorMessage);
if (!errorMessageHandler.isErrorHandled()) errorMessageHandler.handleErrorMessage(errorMessage);
});
} catch (Throwable cause) {
exceptionHandler.handleException(log, cause, responseObserver);
@ -181,11 +176,15 @@ class GrpcOffersService extends OffersImplBase {
@Override
public void cancelOffer(CancelOfferRequest req,
StreamObserver<CancelOfferReply> responseObserver) {
GrpcErrorMessageHandler errorMessageHandler = new GrpcErrorMessageHandler(getCancelOfferMethod().getFullMethodName(), responseObserver, exceptionHandler, log);
try {
coreApi.cancelOffer(req.getId());
var reply = CancelOfferReply.newBuilder().build();
responseObserver.onNext(reply);
responseObserver.onCompleted();
coreApi.cancelOffer(req.getId(), () -> {
var reply = CancelOfferReply.newBuilder().build();
responseObserver.onNext(reply);
responseObserver.onCompleted();
}, errorMessage -> {
if (!errorMessageHandler.isErrorHandled()) errorMessageHandler.handleErrorMessage(errorMessage);
});
} catch (Throwable cause) {
exceptionHandler.handleException(log, cause, responseObserver);
}

View File

@ -236,203 +236,44 @@
<sha256 value="6306d89cfdb12bd0b6436390de71cef31879985da10d071a3bdad56bf287bbbb" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="com.github.bisq-network.netlayer" name="tor" version="6797461310f077bbea4f43a3a509c077b0ed8c34">
<artifact name="tor-6797461310f077bbea4f43a3a509c077b0ed8c34.jar">
<sha256 value="1536211d3f204059e2ad49c136978b36ebaa19e62103fcd46dcb926842fa0718" origin="Generated by Gradle"/>
</artifact>
<artifact name="tor-6797461310f077bbea4f43a3a509c077b0ed8c34.pom">
<sha256 value="7a0ccbecf1471f6be02fb034c006e36b7a6fd249544521c653fed09fbbcec0b1" origin="Generated by Gradle"/>
<component group="com.github.bisq-network.netlayer" name="tor" version="2b459dc">
<artifact name="tor-2b459dc.jar">
<sha256 value="d8aba69568795826bd1139b6854b479d9af9fc945eccf2b15d7f9ecb304c5cc4" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="com.github.bisq-network.netlayer" name="tor" version="8db4a13">
<artifact name="tor-8db4a13.jar">
<sha256 value="37198bc56e8fe112f8c80441544a2b9731929dae586bda841a4a926fdc04f457" origin="Generated by Gradle"/>
</artifact>
<artifact name="tor-8db4a13.pom">
<sha256 value="d1cb5d57710c43642771681d8b1c9039c722fb949bdc5a2022389f5a81501f42" origin="Generated by Gradle"/>
<component group="com.github.bisq-network.netlayer" name="tor.external" version="2b459dc">
<artifact name="tor.external-2b459dc.jar">
<sha256 value="6646b6ce9312a16f6b4b61ee91512b8725b55a2f7204aec29f64974207fd5015" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="com.github.bisq-network.netlayer" name="tor.external" version="0.7.2">
<artifact name="tor.external-0.7.2.jar">
<sha256 value="45daf9b30f753c49b62cf56226539e824886ce1ff430e03dbef1bddff919cbfc" origin="Generated by Gradle"/>
</artifact>
<artifact name="tor.external-0.7.2.pom">
<sha256 value="605e15f473aa7163c4dfa75b0fa17a96466d24c6e3d7a66925b29aadde98dfb4" origin="Generated by Gradle"/>
<component group="com.github.bisq-network.netlayer" name="tor.native" version="2b459dc">
<artifact name="tor.native-2b459dc.jar">
<sha256 value="dc5850e232f2c579d948213a3ea1ce536f56bcc49045a43d3bc63f1e065f1c94" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="com.github.bisq-network.netlayer" name="tor.external" version="6797461310f077bbea4f43a3a509c077b0ed8c34">
<artifact name="tor.external-6797461310f077bbea4f43a3a509c077b0ed8c34.jar">
<sha256 value="d79dee1380fcc912dd9f321e6689b99129a90c6b30085b3f86a0b81830ecee71" origin="Generated by Gradle"/>
</artifact>
<artifact name="tor.external-6797461310f077bbea4f43a3a509c077b0ed8c34.pom">
<sha256 value="949ab51a912ba5c126ffda083da2f0366bc9eda36afc5358183e040fee24d86f" origin="Generated by Gradle"/>
<component group="com.github.bisq-network.tor-binary" name="tor-binary-geoip" version="580d31bdcf1fabccd38456aa084044064d89d5c1">
<artifact name="tor-binary-geoip-580d31bdcf1fabccd38456aa084044064d89d5c1.jar">
<sha256 value="5a1795e95128e8c6fb3381d1c31ac39f2ec4e4fc3a0262f3f9ac3c7987e0c87e" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="com.github.bisq-network.netlayer" name="tor.external" version="8db4a13">
<artifact name="tor.external-8db4a13.jar">
<sha256 value="e1d6b8fe73891207701c6b14317be789fd4acd25f7b499425d2471598d9a22ac" origin="Generated by Gradle"/>
</artifact>
<artifact name="tor.external-8db4a13.pom">
<sha256 value="11918499210e0c12e9d517596eedb34b897021686cf8a1efd8ea87ae3b7e184d" origin="Generated by Gradle"/>
<component group="com.github.bisq-network.tor-binary" name="tor-binary-linux32" version="580d31bdcf1fabccd38456aa084044064d89d5c1">
<artifact name="tor-binary-linux32-580d31bdcf1fabccd38456aa084044064d89d5c1.jar">
<sha256 value="2516ce5549ef5687ef7f855db5940574fc9232ff3ba531fbc216275b8d51ae85" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="com.github.bisq-network.netlayer" name="tor.native" version="0.7.2">
<artifact name="tor.native-0.7.2.jar">
<sha256 value="ebb37e76fa14461be1ab2750daa3f8e5b78c8ff0d2adb72832ca0d38a1fb8f0d" origin="Generated by Gradle"/>
</artifact>
<artifact name="tor.native-0.7.2.pom">
<sha256 value="021ab6d438023653afee96c0fab1262eed6b7522fce76e114593d55e6d7d9928" origin="Generated by Gradle"/>
<component group="com.github.bisq-network.tor-binary" name="tor-binary-linux64" version="580d31bdcf1fabccd38456aa084044064d89d5c1">
<artifact name="tor-binary-linux64-580d31bdcf1fabccd38456aa084044064d89d5c1.jar">
<sha256 value="afc7ad5e1bc57e73aae55d9b022ff63f41f7c73a9a7603d4c24975288432daa1" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="com.github.bisq-network.netlayer" name="tor.native" version="6797461310f077bbea4f43a3a509c077b0ed8c34">
<artifact name="tor.native-6797461310f077bbea4f43a3a509c077b0ed8c34.jar">
<sha256 value="7ab70a9948fffea33da9fee161c5783a74aeb1531e3fda09995c47bb5e2de0f5" origin="Generated by Gradle"/>
</artifact>
<artifact name="tor.native-6797461310f077bbea4f43a3a509c077b0ed8c34.pom">
<sha256 value="17ba4bb22d00441e286dde286045d68190003e849f49871bdac96a5b41478533" origin="Generated by Gradle"/>
<component group="com.github.bisq-network.tor-binary" name="tor-binary-macos" version="580d31bdcf1fabccd38456aa084044064d89d5c1">
<artifact name="tor-binary-macos-580d31bdcf1fabccd38456aa084044064d89d5c1.jar">
<sha256 value="5bfb2eaf7efe5d280d6b68e222c910cc6ae2a925e3d06fa35c6b5295ebf94651" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="com.github.bisq-network.netlayer" name="tor.native" version="8db4a13">
<artifact name="tor.native-8db4a13.jar">
<sha256 value="aa3edf9c27071fdc2b7d55b00dbc7c6cd5dc9aa9f87aafa4be0805f818a466be" 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"/>
<component group="com.github.bisq-network.tor-binary" name="tor-binary-windows" version="580d31bdcf1fabccd38456aa084044064d89d5c1">
<artifact name="tor-binary-windows-580d31bdcf1fabccd38456aa084044064d89d5c1.jar">
<sha256 value="b5fbe9f9e2681b0cfdd0d8a26c7b216c38acfea74fe2103633fe7e81b6cc4bf7" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="com.github.johnrengelman" name="shadow" version="8.1.1">
@ -1005,9 +846,9 @@
<sha256 value="c92e2ca40a3f2474d61e56831aeb379cf8ae3dddeea61b4a828cee2d99f71f38" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="io.github.woodser" name="monero-java" version="0.8.10">
<artifact name="monero-java-0.8.10.jar">
<sha256 value="3ea921cb8122e9be4401479e7040055063b2132e8210f7129117b8b10472f773" origin="Generated by Gradle"/>
<component group="io.github.woodser" name="monero-java" version="0.8.11">
<artifact name="monero-java-0.8.11.jar">
<sha256 value="37c125a31463c44e43452bc3e18e74a05b65d1fbebb11adc5131521b29b48a6b" origin="Generated by Gradle"/>
</artifact>
</component>
<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,
@Nullable @Named(Config.TORRC_FILE) File torrcFile,
@Named(Config.TORRC_OPTIONS) String torrcOptions,
@Named(Config.TOR_CONTROL_HOST) String controlHost,
@Named(Config.TOR_CONTROL_PORT) int controlPort,
@Named(Config.TOR_CONTROL_PASSWORD) String password,
@Nullable @Named(Config.TOR_CONTROL_COOKIE_FILE) File cookieFile,
@ -59,11 +60,12 @@ public class NetworkNodeProvider implements Provider<NetworkNode> {
torDir,
torrcFile,
torrcOptions,
controlHost,
controlPort,
password,
cookieFile,
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,
@Nullable File torrcFile,
String torrcOptions,
String controlHost,
int controlPort,
String password,
@Nullable File cookieFile,
boolean useSafeCookieAuthentication) {
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);
}

View File

@ -19,8 +19,26 @@ package haveno.network.p2p;
import com.google.inject.Singleton;
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.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.http.HttpClient;
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.ProtectedDataStoreService;
import haveno.network.p2p.storage.persistence.ResourceDataStoreService;
import java.io.File;
import java.time.Clock;
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 P2PModule(Config config) {
@ -96,6 +95,7 @@ public class P2PModule extends AppModule {
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
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_PASSWORD)).to(config.torControlPassword);
bind(File.class).annotatedWith(named(TOR_CONTROL_COOKIE_FILE)).toProvider(of(config.torControlCookieFile));

View File

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

View File

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

View File

@ -51,7 +51,7 @@ public class TorNetworkNodeTest {
latch = new CountDownLatch(1);
int port = 9001;
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() {
@Override
public void onTorNodeReady() {
@ -78,7 +78,7 @@ public class TorNetworkNodeTest {
latch = new CountDownLatch(1);
int port2 = 9002;
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() {
@Override
public void onTorNodeReady() {
@ -136,7 +136,7 @@ public class TorNetworkNodeTest {
latch = new CountDownLatch(2);
int port = 9001;
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() {
@Override
public void onTorNodeReady() {
@ -162,7 +162,7 @@ public class TorNetworkNodeTest {
int port2 = 9002;
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() {
@Override
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
# 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 && \
apt update && \

View File

@ -1,11 +1,11 @@
# configuration for haveno service
# install in /etc/default/haveno.env
# java home, set to openjdk 10
JAVA_HOME=/usr/lib/jvm/openjdk-10.0.2
# java home, set to latest openjdk 21 from os repository
JAVA_HOME=/usr/lib/jvm/openjdk-21
# 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)
HAVENO_EXTERNAL_TOR_PORT=9051
@ -28,7 +28,7 @@ BITCOIN_RPC_BLOCKNOTIFY_PORT=5120
HAVENO_HOME=__HAVENO_HOME__
HAVENO_APP_NAME=haveno-seednode
HAVENO_ENTRYPOINT=haveno-seednode
HAVENO_BASE_CURRENCY=btc_mainnet
HAVENO_BASE_CURRENCY=xmr_mainnet
# haveno node settings
HAVENO_NODE_PORT=8000

View File

@ -7,22 +7,21 @@ echo "[*] Haveno Seednode installation script"
ROOT_USER=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
SYSTEMD_SERVICE_HOME=/etc/systemd/system
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_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_USER=haveno
# by default, this script will build and setup bitcoin fullnode
# if you want to use an existing bitcoin fullnode, see next section
BITCOIN_INSTALL=true
# by default, this script will not build and setup bitcoin full-node
BITCOIN_INSTALL=false
BITCOIN_REPO_URL=https://github.com/bitcoin/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)
@ -60,19 +59,13 @@ sudo -H -i -u "${ROOT_USER}" DEBIAN_FRONTEND=noninteractive apt-get upgrade -qq
echo "[*] Installing base packages"
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"
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}"
echo "[*] Installing Tor"
sudo -H -i -u "${ROOT_USER}" wget -qO- https://deb.torproject.org/torproject.org/A3C4F0F979CAA22CDBA8F512EE8CBC9E886DDD89.asc | gp
g --dearmor | tee /usr/share/keyrings/tor-archive-keyring.gpg >/dev/null
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}" wget -qO- https://deb.torproject.org/torproject.org/A3C4F0F979CAA22CDBA8F512EE8CBC9E886DDD89.asc | sudo gpg --dearmor | sudo 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}" DEBIAN_FRONTEND=noninteractive apt-get update -q
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}" 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"
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
sudo sed -i -e "s/#Requires=bitcoin.service/Requires=bitcoin.service/" "${SYSTEMD_SERVICE_HOME}/haveno.service"
sudo sed -i -e "s/#BindsTo=bitcoin.service/BindsTo=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-seednode.service"
fi
sudo sed -i -e "s/__HAVENO_REPO_NAME__/${HAVENO_REPO_NAME}/" "${SYSTEMD_SERVICE_HOME}/haveno.service"
sudo sed -i -e "s!__HAVENO_HOME__!${HAVENO_HOME}!" "${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-seednode.service"
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"
@ -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}"
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"
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"
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 haveno.service
sudo -H -i -u "${ROOT_USER}" systemctl enable haveno-seednode.service
if [ "${BITCOIN_INSTALL}" = true ];then
sudo -H -i -u "${ROOT_USER}" systemctl enable bitcoin.service
fi
@ -185,13 +172,13 @@ fi
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 "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 "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 "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!'

View File

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