Merging and adapting old bridges UI code to new bisq structure

Had to merge by hand because of the many changes in the new bisq
structure. Also removed the 'default bridges' concept because it's
discouraged to do that.
Open issues: UI screen is still WIP, and bitcoinj SOCKS proxy error
which makes that we can't connect to bitcoin nodes anymore.

Signed-off-by: Mike Rosseel <mike@eon-consult.be>
This commit is contained in:
Mike Rosseel 2017-11-02 15:50:06 +01:00
parent af39d00e6b
commit 0ec4b5edac
No known key found for this signature in database
GPG key ID: 1D9920AF2A8E6BF0
19 changed files with 688 additions and 491 deletions

View file

@ -1257,6 +1257,7 @@ message PreferencesPayload {
bool use_animations = 31;
PaymentAccount selectedPayment_account_for_createOffer = 32;
bool pay_fee_in_Btc = 33;
repeated string bridge_addresses = 34;
}

View file

@ -167,6 +167,11 @@ public class AppSetupWithP2P extends AppSetup {
public void onSetupFailed(Throwable throwable) {
log.error(throwable.toString());
}
@Override
public void onRequestCustomBridges(Runnable resultHandler) {
}
});
return p2pNetworkInitialized;

View file

@ -112,6 +112,11 @@ public class TradeStatisticsMigrationTool {
@Override
public void onSetupFailed(Throwable throwable) {
}
@Override
public void onRequestCustomBridges(Runnable resultHandler) {
}
});
}
}

View file

@ -10,6 +10,7 @@ import io.bisq.core.btc.BaseCurrencyNetwork;
import io.bisq.core.btc.BtcOptionKeys;
import io.bisq.core.btc.Restrictions;
import io.bisq.core.payment.PaymentAccount;
import io.bisq.network.BridgeProvider;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.LongProperty;
import javafx.beans.property.SimpleBooleanProperty;
@ -175,6 +176,7 @@ public final class Preferences implements PersistedDataHost {
setPreferredTradeCurrency(preferredTradeCurrency);
setFiatCurrencies(prefPayload.getFiatCurrencies());
setCryptoCurrencies(prefPayload.getCryptoCurrencies());
setBridgeAddresses(prefPayload.getBridgeAddresses());
} else {
prefPayload = new PreferencesPayload();
@ -474,6 +476,13 @@ public final class Preferences implements PersistedDataHost {
storage.queueUpForSave(prefPayload, 1);
}
public void setBridgeAddresses(List<String> bridgeAddresses) {
prefPayload.setBridgeAddresses(bridgeAddresses);
BridgeProvider.setBridges(bridgeAddresses);
// We call that before shutdown so we dont want a delay here
storage.queueUpForSave(prefPayload, 1);
}
// Only used from PB but keep it explicit as maybe it get used from the client and then we want to persist
public void setPeerTagMap(Map<String, String> peerTagMap) {
prefPayload.setPeerTagMap(peerTagMap);
@ -650,5 +659,7 @@ public final class Preferences implements PersistedDataHost {
void setDontShowAgainMap(Map<String, Boolean> dontShowAgainMap);
void setPeerTagMap(Map<String, String> peerTagMap);
void setBridgeAddresses(List<String> bridgeAddresses);
}
}

View file

@ -12,6 +12,7 @@ import io.bisq.core.btc.Restrictions;
import io.bisq.core.payment.PaymentAccount;
import io.bisq.core.proto.CoreProtoResolver;
import io.bisq.generated.protobuffer.PB;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
@ -21,6 +22,7 @@ import java.util.stream.Collectors;
@Slf4j
@Data
@AllArgsConstructor
public final class PreferencesPayload implements PersistableEnvelope {
private String userLanguage;
private Country userCountry;
@ -64,6 +66,8 @@ public final class PreferencesPayload implements PersistableEnvelope {
@Nullable
private PaymentAccount selectedPaymentAccountForCreateOffer;
private boolean payFeeInBtc = true;
@Nullable
private List<String> bridgeAddresses = new ArrayList<>();
///////////////////////////////////////////////////////////////////////////////////////////
@ -78,74 +82,6 @@ public final class PreferencesPayload implements PersistableEnvelope {
// PROTO BUFFER
///////////////////////////////////////////////////////////////////////////////////////////
private PreferencesPayload(String userLanguage,
Country userCountry,
List<FiatCurrency> fiatCurrencies,
List<CryptoCurrency> cryptoCurrencies,
BlockChainExplorer blockChainExplorerMainNet,
BlockChainExplorer blockChainExplorerTestNet,
BlockChainExplorer bsqBlockChainExplorer,
@Nullable String backupDirectory,
boolean autoSelectArbitrators,
Map<String, Boolean> dontShowAgainMap,
boolean tacAccepted,
boolean useTorForBitcoinJ,
boolean showOwnOffersInOfferBook,
@Nullable TradeCurrency preferredTradeCurrency,
long withdrawalTxFeeInBytes,
boolean useCustomWithdrawalTxFee,
double maxPriceDistanceInPercent,
@Nullable String offerBookChartScreenCurrencyCode,
@Nullable String tradeChartsScreenCurrencyCode,
@Nullable String buyScreenCurrencyCode,
@Nullable String sellScreenCurrencyCode,
int tradeStatisticsTickUnitIndex,
boolean resyncSpvRequested,
boolean sortMarketCurrenciesNumerically,
boolean usePercentageBasedPrice,
Map<String, String> peerTagMap,
String bitcoinNodes,
List<String> ignoreTradersList,
String directoryChooserPath,
long buyerSecurityDepositAsLong,
boolean useAnimations,
@Nullable PaymentAccount selectedPaymentAccountForCreateOffer,
boolean payFeeInBtc) {
this.userLanguage = userLanguage;
this.userCountry = userCountry;
this.fiatCurrencies = fiatCurrencies;
this.cryptoCurrencies = cryptoCurrencies;
this.blockChainExplorerMainNet = blockChainExplorerMainNet;
this.blockChainExplorerTestNet = blockChainExplorerTestNet;
this.bsqBlockChainExplorer = bsqBlockChainExplorer;
this.backupDirectory = backupDirectory;
this.autoSelectArbitrators = autoSelectArbitrators;
this.dontShowAgainMap = dontShowAgainMap;
this.tacAccepted = tacAccepted;
this.useTorForBitcoinJ = useTorForBitcoinJ;
this.showOwnOffersInOfferBook = showOwnOffersInOfferBook;
this.preferredTradeCurrency = preferredTradeCurrency;
this.withdrawalTxFeeInBytes = withdrawalTxFeeInBytes;
this.useCustomWithdrawalTxFee = useCustomWithdrawalTxFee;
this.maxPriceDistanceInPercent = maxPriceDistanceInPercent;
this.offerBookChartScreenCurrencyCode = offerBookChartScreenCurrencyCode;
this.tradeChartsScreenCurrencyCode = tradeChartsScreenCurrencyCode;
this.buyScreenCurrencyCode = buyScreenCurrencyCode;
this.sellScreenCurrencyCode = sellScreenCurrencyCode;
this.tradeStatisticsTickUnitIndex = tradeStatisticsTickUnitIndex;
this.resyncSpvRequested = resyncSpvRequested;
this.sortMarketCurrenciesNumerically = sortMarketCurrenciesNumerically;
this.usePercentageBasedPrice = usePercentageBasedPrice;
this.peerTagMap = peerTagMap;
this.bitcoinNodes = bitcoinNodes;
this.ignoreTradersList = ignoreTradersList;
this.directoryChooserPath = directoryChooserPath;
this.buyerSecurityDepositAsLong = buyerSecurityDepositAsLong;
this.useAnimations = useAnimations;
this.selectedPaymentAccountForCreateOffer = selectedPaymentAccountForCreateOffer;
this.payFeeInBtc = payFeeInBtc;
}
@Override
public Message toProtoMessage() {
PB.PreferencesPayload.Builder builder = PB.PreferencesPayload.newBuilder()
@ -178,8 +114,8 @@ public final class PreferencesPayload implements PersistableEnvelope {
.setDirectoryChooserPath(directoryChooserPath)
.setBuyerSecurityDepositAsLong(buyerSecurityDepositAsLong)
.setUseAnimations(useAnimations)
.setPayFeeInBtc(payFeeInBtc);
.setPayFeeInBtc(payFeeInBtc)
.addAllBridgeAddresses(bridgeAddresses);
Optional.ofNullable(backupDirectory).ifPresent(builder::setBackupDirectory);
Optional.ofNullable(preferredTradeCurrency).ifPresent(e -> builder.setPreferredTradeCurrency((PB.TradeCurrency) e.toProtoMessage()));
Optional.ofNullable(offerBookChartScreenCurrencyCode).ifPresent(builder::setOfferBookChartScreenCurrencyCode);
@ -188,7 +124,6 @@ public final class PreferencesPayload implements PersistableEnvelope {
Optional.ofNullable(sellScreenCurrencyCode).ifPresent(builder::setSellScreenCurrencyCode);
Optional.ofNullable(selectedPaymentAccountForCreateOffer).ifPresent(
account -> builder.setSelectedPaymentAccountForCreateOffer(selectedPaymentAccountForCreateOffer.toProtoMessage()));
return PB.PersistableEnvelope.newBuilder().setPreferencesPayload(builder).build();
}
@ -199,44 +134,45 @@ public final class PreferencesPayload implements PersistableEnvelope {
paymentAccount = PaymentAccount.fromProto(proto.getSelectedPaymentAccountForCreateOffer(), coreProtoResolver);
return new PreferencesPayload(
proto.getUserLanguage(),
Country.fromProto(userCountry),
proto.getFiatCurrenciesList().isEmpty() ? new ArrayList<>() :
new ArrayList<>(proto.getFiatCurrenciesList().stream()
.map(FiatCurrency::fromProto)
.collect(Collectors.toList())),
proto.getCryptoCurrenciesList().isEmpty() ? new ArrayList<>() :
new ArrayList<>(proto.getCryptoCurrenciesList().stream()
.map(CryptoCurrency::fromProto)
.collect(Collectors.toList())),
BlockChainExplorer.fromProto(proto.getBlockChainExplorerMainNet()),
BlockChainExplorer.fromProto(proto.getBlockChainExplorerTestNet()),
BlockChainExplorer.fromProto(proto.getBsqBlockChainExplorer()),
ProtoUtil.stringOrNullFromProto(proto.getBackupDirectory()),
proto.getAutoSelectArbitrators(),
Maps.newHashMap(proto.getDontShowAgainMapMap()),
proto.getTacAccepted(),
proto.getUseTorForBitcoinJ(),
proto.getShowOwnOffersInOfferBook(),
proto.hasPreferredTradeCurrency() ? TradeCurrency.fromProto(proto.getPreferredTradeCurrency()) : null,
proto.getWithdrawalTxFeeInBytes(),
proto.getUseCustomWithdrawalTxFee(),
proto.getMaxPriceDistanceInPercent(),
ProtoUtil.stringOrNullFromProto(proto.getOfferBookChartScreenCurrencyCode()),
ProtoUtil.stringOrNullFromProto(proto.getTradeChartsScreenCurrencyCode()),
ProtoUtil.stringOrNullFromProto(proto.getBuyScreenCurrencyCode()),
ProtoUtil.stringOrNullFromProto(proto.getSellScreenCurrencyCode()),
proto.getTradeStatisticsTickUnitIndex(),
proto.getResyncSpvRequested(),
proto.getSortMarketCurrenciesNumerically(),
proto.getUsePercentageBasedPrice(),
Maps.newHashMap(proto.getPeerTagMapMap()),
proto.getBitcoinNodes(),
proto.getIgnoreTradersListList(),
proto.getDirectoryChooserPath(),
proto.getBuyerSecurityDepositAsLong(),
proto.getUseAnimations(),
paymentAccount,
proto.getPayFeeInBtc());
proto.getUserLanguage(),
Country.fromProto(userCountry),
proto.getFiatCurrenciesList().isEmpty() ? new ArrayList<>() :
new ArrayList<>(proto.getFiatCurrenciesList().stream()
.map(FiatCurrency::fromProto)
.collect(Collectors.toList())),
proto.getCryptoCurrenciesList().isEmpty() ? new ArrayList<>() :
new ArrayList<>(proto.getCryptoCurrenciesList().stream()
.map(CryptoCurrency::fromProto)
.collect(Collectors.toList())),
BlockChainExplorer.fromProto(proto.getBlockChainExplorerMainNet()),
BlockChainExplorer.fromProto(proto.getBlockChainExplorerTestNet()),
BlockChainExplorer.fromProto(proto.getBsqBlockChainExplorer()),
ProtoUtil.stringOrNullFromProto(proto.getBackupDirectory()),
proto.getAutoSelectArbitrators(),
Maps.newHashMap(proto.getDontShowAgainMapMap()),
proto.getTacAccepted(),
proto.getUseTorForBitcoinJ(),
proto.getShowOwnOffersInOfferBook(),
proto.hasPreferredTradeCurrency() ? TradeCurrency.fromProto(proto.getPreferredTradeCurrency()) : null,
proto.getWithdrawalTxFeeInBytes(),
proto.getUseCustomWithdrawalTxFee(),
proto.getMaxPriceDistanceInPercent(),
ProtoUtil.stringOrNullFromProto(proto.getOfferBookChartScreenCurrencyCode()),
ProtoUtil.stringOrNullFromProto(proto.getTradeChartsScreenCurrencyCode()),
ProtoUtil.stringOrNullFromProto(proto.getBuyScreenCurrencyCode()),
ProtoUtil.stringOrNullFromProto(proto.getSellScreenCurrencyCode()),
proto.getTradeStatisticsTickUnitIndex(),
proto.getResyncSpvRequested(),
proto.getSortMarketCurrenciesNumerically(),
proto.getUsePercentageBasedPrice(),
Maps.newHashMap(proto.getPeerTagMapMap()),
proto.getBitcoinNodes(),
proto.getIgnoreTradersListList(),
proto.getDirectoryChooserPath(),
proto.getBuyerSecurityDepositAsLong(),
proto.getUseAnimations(),
paymentAccount,
proto.getPayFeeInBtc(),
proto.getBridgeAddressesList());
}
}

View file

@ -72,12 +72,14 @@ import io.bisq.gui.components.BalanceWithConfirmationTextField;
import io.bisq.gui.components.TxIdTextField;
import io.bisq.gui.main.overlays.notifications.NotificationCenter;
import io.bisq.gui.main.overlays.popups.Popup;
import io.bisq.gui.main.overlays.windows.AddBridgeEntriesWindow;
import io.bisq.gui.main.overlays.windows.DisplayAlertMessageWindow;
import io.bisq.gui.main.overlays.windows.TacWindow;
import io.bisq.gui.main.overlays.windows.WalletPasswordWindow;
import io.bisq.gui.main.overlays.windows.downloadupdate.DisplayUpdateDownloadWindow;
import io.bisq.gui.util.BSFormatter;
import io.bisq.gui.util.GUIUtil;
import io.bisq.gui.util.Transitions;
import io.bisq.network.crypto.DecryptedDataTuple;
import io.bisq.network.crypto.EncryptionService;
import io.bisq.network.p2p.BootstrapListener;
@ -251,7 +253,7 @@ public class MainViewModel implements ViewModel {
this.formatter = formatter;
btcNetworkAsString = Res.get(BisqEnvironment.getBaseCurrencyNetwork().name()) +
(preferences.getUseTorForBitcoinJ() ? (" " + Res.get("mainView.footer.usingTor")) : "");
(preferences.getUseTorForBitcoinJ() ? (" " + Res.get("mainView.footer.usingTor")) : "");
TxIdTextField.setPreferences(preferences);
@ -284,10 +286,10 @@ public class MainViewModel implements ViewModel {
private void readMapsFromResources() {
readMapsFromResourcesBinding = EasyBind.combine(SetupUtils.readPersistableNetworkPayloadMapFromResources(p2PService),
SetupUtils.readEntryMapFromResources(p2PService),
(result1, result2) -> {
return result1 && result2;
});
SetupUtils.readEntryMapFromResources(p2PService),
(result1, result2) -> {
return result1 && result2;
});
readMapsFromResourcesBindingSubscription = readMapsFromResourcesBinding.subscribe((observable, oldValue, newValue) -> {
if (newValue)
startBasicServices();
@ -324,12 +326,12 @@ public class MainViewModel implements ViewModel {
// need to store it to not get garbage collected
allServicesDone = EasyBind.combine(walletInitialized, p2pNetWorkReady,
(a, b) -> {
log.debug("\nwalletInitialized={}\n" +
"p2pNetWorkReady={}",
a, b);
return a && b;
});
(a, b) -> {
log.debug("\nwalletInitialized={}\n" +
"p2pNetWorkReady={}",
a, b);
return a && b;
});
allServicesDone.subscribe((observable, oldValue, newValue) -> {
if (newValue) {
startupTimeout.stop();
@ -354,8 +356,8 @@ public class MainViewModel implements ViewModel {
}
startupTimeoutPopup = new Popup<>();
startupTimeoutPopup.warning(Res.get("popup.warning.startupFailed.timeout", details))
.useShutDownButton()
.show();
.useShutDownButton()
.show();
}
@ -372,22 +374,22 @@ public class MainViewModel implements ViewModel {
BooleanProperty initialP2PNetworkDataReceived = new SimpleBooleanProperty();
p2PNetworkInfoBinding = EasyBind.combine(bootstrapState, bootstrapWarning, p2PService.getNumConnectedPeers(), hiddenServicePublished, initialP2PNetworkDataReceived,
(state, warning, numPeers, hiddenService, dataReceived) -> {
String result = "";
int peers = (int) numPeers;
if (warning != null && peers == 0) {
result = warning;
} else {
String p2pInfo = Res.get("mainView.footer.p2pInfo", numPeers);
if (dataReceived && hiddenService) {
result = p2pInfo;
} else if (peers == 0)
result = state;
else
result = state + " / " + p2pInfo;
}
return result;
});
(state, warning, numPeers, hiddenService, dataReceived) -> {
String result = "";
int peers = (int) numPeers;
if (warning != null && peers == 0) {
result = warning;
} else {
String p2pInfo = Res.get("mainView.footer.p2pInfo", numPeers);
if (dataReceived && hiddenService) {
result = p2pInfo;
} else if (peers == 0)
result = state;
else
result = state + " / " + p2pInfo;
}
return result;
});
p2PNetworkInfoBinding.subscribe((observable, oldValue, newValue) -> {
p2PNetworkInfo.set(newValue);
});
@ -404,7 +406,7 @@ public class MainViewModel implements ViewModel {
// We only check at seed nodes as they are running the latest version
// Other disconnects might be caused by peers running an older version
if (connection.getPeerType() == Connection.PeerType.SEED_NODE &&
closeConnectionReason == CloseConnectionReason.RULE_VIOLATION) {
closeConnectionReason == CloseConnectionReason.RULE_VIOLATION) {
log.warn("RULE_VIOLATION onDisconnect closeConnectionReason=" + closeConnectionReason);
log.warn("RULE_VIOLATION onDisconnect connection=" + connection);
}
@ -485,6 +487,13 @@ public class MainViewModel implements ViewModel {
bootstrapWarning.set(Res.get("mainView.bootstrapWarning.bootstrappingToP2PFailed"));
p2pNetworkLabelId.set("splash-error-state-msg");
}
@Override
public void onRequestCustomBridges(Runnable resultHandler) {
AddBridgeEntriesWindow addBridgeEntriesWindow = new AddBridgeEntriesWindow(preferences)
.onAction(resultHandler::run);
UserThread.execute(addBridgeEntriesWindow::show);
}
});
return p2pNetworkInitialized;
@ -495,99 +504,99 @@ public class MainViewModel implements ViewModel {
ObjectProperty<Throwable> walletServiceException = new SimpleObjectProperty<>();
btcInfoBinding = EasyBind.combine(walletsSetup.downloadPercentageProperty(), walletsSetup.numPeersProperty(), walletServiceException,
(downloadPercentage, numPeers, exception) -> {
String result = "";
if (exception == null) {
double percentage = (double) downloadPercentage;
int peers = (int) numPeers;
btcSyncProgress.set(percentage);
if (percentage == 1) {
result = Res.get("mainView.footer.btcInfo",
peers,
Res.get("mainView.footer.btcInfo.synchronizedWith"),
btcNetworkAsString);
btcSplashSyncIconId.set("image-connection-synced");
(downloadPercentage, numPeers, exception) -> {
String result = "";
if (exception == null) {
double percentage = (double) downloadPercentage;
int peers = (int) numPeers;
btcSyncProgress.set(percentage);
if (percentage == 1) {
result = Res.get("mainView.footer.btcInfo",
peers,
Res.get("mainView.footer.btcInfo.synchronizedWith"),
btcNetworkAsString);
btcSplashSyncIconId.set("image-connection-synced");
if (allBasicServicesInitialized)
checkForLockedUpFunds();
} else if (percentage > 0.0) {
result = Res.get("mainView.footer.btcInfo",
peers,
Res.get("mainView.footer.btcInfo.synchronizedWith"),
btcNetworkAsString + ": " + formatter.formatToPercentWithSymbol(percentage));
} else {
result = Res.get("mainView.footer.btcInfo",
peers,
Res.get("mainView.footer.btcInfo.connectingTo"),
btcNetworkAsString);
}
} else {
result = Res.get("mainView.footer.btcInfo",
numBtcPeers,
Res.get("mainView.footer.btcInfo.connectionFailed"),
btcNetworkAsString);
log.error(exception.getMessage());
if (exception instanceof TimeoutException) {
walletServiceErrorMsg.set(Res.get("mainView.walletServiceErrorMsg.timeout"));
} else if (exception.getCause() instanceof BlockStoreException) {
if (exception.getCause().getCause() instanceof ChainFileLockedException) {
new Popup<>().warning(Res.get("popup.warning.startupFailed.twoInstances"))
.useShutDownButton()
.show();
if (allBasicServicesInitialized)
checkForLockedUpFunds();
} else if (percentage > 0.0) {
result = Res.get("mainView.footer.btcInfo",
peers,
Res.get("mainView.footer.btcInfo.synchronizedWith"),
btcNetworkAsString + ": " + formatter.formatToPercentWithSymbol(percentage));
} else {
new Popup<>().warning(Res.get("error.spvFileCorrupted",
exception.getMessage()))
.actionButtonText(Res.get("settings.net.reSyncSPVChainButton"))
.onAction(() -> {
if (walletsSetup.reSyncSPVChain())
new Popup<>().feedback(Res.get("settings.net.reSyncSPVSuccess"))
.useShutDownButton().show();
else
new Popup<>().error(Res.get("settings.net.reSyncSPVFailed")).show();
})
.show();
result = Res.get("mainView.footer.btcInfo",
peers,
Res.get("mainView.footer.btcInfo.connectingTo"),
btcNetworkAsString);
}
} else {
walletServiceErrorMsg.set(Res.get("mainView.walletServiceErrorMsg.connectionError", exception.toString()));
result = Res.get("mainView.footer.btcInfo",
numBtcPeers,
Res.get("mainView.footer.btcInfo.connectionFailed"),
btcNetworkAsString);
log.error(exception.getMessage());
if (exception instanceof TimeoutException) {
walletServiceErrorMsg.set(Res.get("mainView.walletServiceErrorMsg.timeout"));
} else if (exception.getCause() instanceof BlockStoreException) {
if (exception.getCause().getCause() instanceof ChainFileLockedException) {
new Popup<>().warning(Res.get("popup.warning.startupFailed.twoInstances"))
.useShutDownButton()
.show();
} else {
new Popup<>().warning(Res.get("error.spvFileCorrupted",
exception.getMessage()))
.actionButtonText(Res.get("settings.net.reSyncSPVChainButton"))
.onAction(() -> {
if (walletsSetup.reSyncSPVChain())
new Popup<>().feedback(Res.get("settings.net.reSyncSPVSuccess"))
.useShutDownButton().show();
else
new Popup<>().error(Res.get("settings.net.reSyncSPVFailed")).show();
})
.show();
}
} else {
walletServiceErrorMsg.set(Res.get("mainView.walletServiceErrorMsg.connectionError", exception.toString()));
}
}
}
return result;
return result;
});
});
btcInfoBinding.subscribe((observable, oldValue, newValue) -> {
btcInfo.set(newValue);
});
walletsSetup.initialize(null,
() -> {
log.debug("walletsSetup.onInitialized");
numBtcPeers = walletsSetup.numPeersProperty().get();
() -> {
log.debug("walletsSetup.onInitialized");
numBtcPeers = walletsSetup.numPeersProperty().get();
// We only check one as we apply encryption to all or none
if (walletsManager.areWalletsEncrypted()) {
if (p2pNetWorkReady.get())
splashP2PNetworkAnimationVisible.set(false);
// We only check one as we apply encryption to all or none
if (walletsManager.areWalletsEncrypted()) {
if (p2pNetWorkReady.get())
splashP2PNetworkAnimationVisible.set(false);
walletPasswordWindow
.onAesKey(aesKey -> {
walletsManager.setAesKey(aesKey);
if (preferences.isResyncSpvRequested()) {
showFirstPopupIfResyncSPVRequested();
} else {
walletInitialized.set(true);
}
})
.hideCloseButton()
.show();
} else {
if (preferences.isResyncSpvRequested()) {
showFirstPopupIfResyncSPVRequested();
walletPasswordWindow
.onAesKey(aesKey -> {
walletsManager.setAesKey(aesKey);
if (preferences.isResyncSpvRequested()) {
showFirstPopupIfResyncSPVRequested();
} else {
walletInitialized.set(true);
}
})
.hideCloseButton()
.show();
} else {
walletInitialized.set(true);
if (preferences.isResyncSpvRequested()) {
showFirstPopupIfResyncSPVRequested();
} else {
walletInitialized.set(true);
}
}
}
},
walletServiceException::set);
},
walletServiceException::set);
}
private void onBasicServicesInitialized() {
@ -617,8 +626,8 @@ public class MainViewModel implements ViewModel {
applyTradePeriodState();
});
tradeManager.setTakeOfferRequestErrorMessageHandler(errorMessage -> new Popup<>()
.warning(Res.get("popup.error.takeOfferRequestFailed", errorMessage))
.show());
.warning(Res.get("popup.error.takeOfferRequestFailed", errorMessage))
.show());
// walletService
btcWalletService.addBalanceListener(new BalanceListener() {
@ -680,9 +689,9 @@ public class MainViewModel implements ViewModel {
user.getPaymentAccountsAsObservable().addListener((SetChangeListener<PaymentAccount>) change -> {
if (!walletsManager.areWalletsEncrypted() && preferences.showAgain(key) && change.wasAdded()) {
new Popup<>().headLine(Res.get("popup.securityRecommendation.headline"))
.information(Res.get("popup.securityRecommendation.msg"))
.dontShowAgainId(key)
.show();
.information(Res.get("popup.securityRecommendation.msg"))
.dontShowAgainId(key)
.show();
}
});
@ -711,9 +720,9 @@ public class MainViewModel implements ViewModel {
firstPopup.hide();
preferences.setResyncSpvRequested(false);
new Popup<>().information(Res.get("settings.net.reSyncSPVAfterRestartCompleted"))
.hideCloseButton()
.useShutDownButton()
.show();
.hideCloseButton()
.useShutDownButton()
.show();
}
private void checkIfLocalHostNodeIsRunning() {
@ -725,7 +734,7 @@ public class MainViewModel implements ViewModel {
try {
socket = new Socket();
socket.connect(new InetSocketAddress(InetAddresses.forString("127.0.0.1"),
BisqEnvironment.getBaseCurrencyNetwork().getParameters().getPort()), 5000);
BisqEnvironment.getBaseCurrencyNetwork().getParameters().getPort()), 5000);
log.info("Localhost peer detected.");
UserThread.execute(() -> {
bisqEnvironment.setBitcoinLocalhostNodeRunning(true);
@ -763,11 +772,11 @@ public class MainViewModel implements ViewModel {
// just use any simple dummy msg
Ping payload = new Ping(1, 1);
SealedAndSigned sealedAndSigned = EncryptionService.encryptHybridWithSignature(payload,
keyRing.getSignatureKeyPair(), keyRing.getPubKeyRing().getEncryptionPubKey());
keyRing.getSignatureKeyPair(), keyRing.getPubKeyRing().getEncryptionPubKey());
DecryptedDataTuple tuple = encryptionService.decryptHybridWithSignature(sealedAndSigned, keyRing.getEncryptionKeyPair().getPrivate());
if (tuple.getNetworkEnvelope() instanceof Ping &&
((Ping) tuple.getNetworkEnvelope()).getNonce() == payload.getNonce() &&
((Ping) tuple.getNetworkEnvelope()).getLastRoundTripTime() == payload.getLastRoundTripTime()) {
((Ping) tuple.getNetworkEnvelope()).getNonce() == payload.getNonce() &&
((Ping) tuple.getNetworkEnvelope()).getLastRoundTripTime() == payload.getLastRoundTripTime()) {
log.debug("Crypto test succeeded");
if (Security.getProvider("BC") != null) {
@ -783,9 +792,9 @@ public class MainViewModel implements ViewModel {
String msg = Res.get("popup.warning.cryptoTestFailed", e.getMessage());
log.error(msg);
UserThread.execute(() -> new Popup<>().warning(msg)
.useShutDownButton()
.useReportBugButton()
.show());
.useShutDownButton()
.useReportBugButton()
.show());
}
}
};
@ -794,20 +803,20 @@ public class MainViewModel implements ViewModel {
private void checkIfOpenOffersMatchTradeProtocolVersion() {
List<OpenOffer> outDatedOffers = openOfferManager.getObservableList()
.stream()
.filter(e -> e.getOffer().getProtocolVersion() != Version.TRADE_PROTOCOL_VERSION)
.collect(Collectors.toList());
.stream()
.filter(e -> e.getOffer().getProtocolVersion() != Version.TRADE_PROTOCOL_VERSION)
.collect(Collectors.toList());
if (!outDatedOffers.isEmpty()) {
String offers = outDatedOffers.stream()
.map(e -> e.getId() + "\n")
.collect(Collectors.toList()).toString()
.replace("[", "").replace("]", "");
.map(e -> e.getId() + "\n")
.collect(Collectors.toList()).toString()
.replace("[", "").replace("]", "");
new Popup<>()
.warning(Res.get("popup.warning.oldOffers.msg", offers))
.actionButtonText(Res.get("popup.warning.oldOffers.buttonText"))
.onAction(() -> openOfferManager.removeOpenOffers(outDatedOffers, null))
.useShutDownButton()
.show();
.warning(Res.get("popup.warning.oldOffers.msg", offers))
.actionButtonText(Res.get("popup.warning.oldOffers.buttonText"))
.onAction(() -> openOfferManager.removeOpenOffers(outDatedOffers, null))
.useShutDownButton()
.show();
}
}
@ -869,9 +878,9 @@ public class MainViewModel implements ViewModel {
if (DontShowAgainLookup.showAgain(key)) {
DontShowAgainLookup.dontShowAgain(key, true);
new Popup<>().warning(Res.get("popup.warning.tradePeriod.halfReached",
trade.getShortId(),
formatter.formatDateTime(maxTradePeriodDate)))
.show();
trade.getShortId(),
formatter.formatDateTime(maxTradePeriodDate)))
.show();
}
break;
case TRADE_PERIOD_OVER:
@ -879,9 +888,9 @@ public class MainViewModel implements ViewModel {
if (DontShowAgainLookup.showAgain(key)) {
DontShowAgainLookup.dontShowAgain(key, true);
new Popup<>().warning(Res.get("popup.warning.tradePeriod.ended",
trade.getShortId(),
formatter.formatDateTime(maxTradePeriodDate)))
.show();
trade.getShortId(),
formatter.formatDateTime(maxTradePeriodDate)))
.show();
}
break;
}
@ -948,11 +957,11 @@ public class MainViewModel implements ViewModel {
private void setupMarketPriceFeed() {
priceFeedService.requestPriceFeed(price -> marketPrice.set(formatter.formatMarketPrice(price, priceFeedService.getCurrencyCode())),
(errorMessage, throwable) -> marketPrice.set(Res.get("shared.na")));
(errorMessage, throwable) -> marketPrice.set(Res.get("shared.na")));
marketPriceBinding = EasyBind.combine(
marketPriceCurrencyCode, marketPrice,
(currencyCode, price) -> formatter.getCurrencyPair(currencyCode) + ": " + price);
marketPriceCurrencyCode, marketPrice,
(currencyCode, price) -> formatter.getCurrencyPair(currencyCode) + ": " + price);
marketPriceBinding.subscribe((observable, oldValue, newValue) -> {
if (newValue != null && !newValue.equals(oldValue)) {
@ -1016,12 +1025,12 @@ public class MainViewModel implements ViewModel {
selectedPriceFeedComboBoxItemProperty.set(itemOptional.get());
else
findPriceFeedComboBoxItem(preferences.getPreferredTradeCurrency().getCode())
.ifPresent(selectedPriceFeedComboBoxItemProperty::set);
.ifPresent(selectedPriceFeedComboBoxItemProperty::set);
priceFeedService.setCurrencyCode(item.currencyCode);
} else {
findPriceFeedComboBoxItem(preferences.getPreferredTradeCurrency().getCode())
.ifPresent(selectedPriceFeedComboBoxItemProperty::set);
.ifPresent(selectedPriceFeedComboBoxItemProperty::set);
}
// Need a delay a bit as we get item.isPriceAvailable() set after that call.
@ -1039,15 +1048,15 @@ public class MainViewModel implements ViewModel {
private Optional<PriceFeedComboBoxItem> findPriceFeedComboBoxItem(String currencyCode) {
return priceFeedComboBoxItems.stream()
.filter(item -> item.currencyCode.equals(currencyCode))
.findAny();
.filter(item -> item.currencyCode.equals(currencyCode))
.findAny();
}
private void fillPriceFeedComboBoxItems() {
List<PriceFeedComboBoxItem> currencyItems = preferences.getTradeCurrenciesAsObservable()
.stream()
.map(tradeCurrency -> new PriceFeedComboBoxItem(tradeCurrency.getCode()))
.collect(Collectors.toList());
.stream()
.map(tradeCurrency -> new PriceFeedComboBoxItem(tradeCurrency.getCode()))
.collect(Collectors.toList());
priceFeedComboBoxItems.setAll(currencyItems);
}
@ -1066,20 +1075,20 @@ public class MainViewModel implements ViewModel {
private void displayPrivateNotification(PrivateNotificationPayload privateNotification) {
new Popup<>().headLine(Res.get("popup.privateNotification.headline"))
.attention(privateNotification.getMessage())
.setHeadlineStyle("-fx-text-fill: -bs-error-red; -fx-font-weight: bold; -fx-font-size: 16;")
.onClose(privateNotificationManager::removePrivateNotification)
.useIUnderstandButton()
.show();
.attention(privateNotification.getMessage())
.setHeadlineStyle("-fx-text-fill: -bs-error-red; -fx-font-weight: bold; -fx-font-size: 16;")
.onClose(privateNotificationManager::removePrivateNotification)
.useIUnderstandButton()
.show();
}
private void swapPendingOfferFundingEntries() {
tradeManager.getAddressEntriesForAvailableBalanceStream()
.filter(addressEntry -> addressEntry.getOfferId() != null)
.forEach(addressEntry -> {
log.debug("swapPendingOfferFundingEntries, offerId={}, OFFER_FUNDING", addressEntry.getOfferId());
btcWalletService.swapTradeEntryToAvailableEntry(addressEntry.getOfferId(), AddressEntry.Context.OFFER_FUNDING);
});
.filter(addressEntry -> addressEntry.getOfferId() != null)
.forEach(addressEntry -> {
log.debug("swapPendingOfferFundingEntries, offerId={}, OFFER_FUNDING", addressEntry.getOfferId());
btcWalletService.swapTradeEntryToAvailableEntry(addressEntry.getOfferId(), AddressEntry.Context.OFFER_FUNDING);
});
}
private void updateBalance() {
@ -1094,8 +1103,8 @@ public class MainViewModel implements ViewModel {
private void updateAvailableBalance() {
Coin totalAvailableBalance = Coin.valueOf(tradeManager.getAddressEntriesForAvailableBalanceStream()
.mapToLong(addressEntry -> btcWalletService.getBalanceForAddress(addressEntry.getAddress()).getValue())
.sum());
.mapToLong(addressEntry -> btcWalletService.getBalanceForAddress(addressEntry.getAddress()).getValue())
.sum());
String value = formatter.formatCoinWithCode(totalAvailableBalance);
// If we get full precision the BTC postfix breaks layout so we omit it
if (value.length() > 11)
@ -1105,18 +1114,18 @@ public class MainViewModel implements ViewModel {
private void updateReservedBalance() {
Coin sum = Coin.valueOf(openOfferManager.getObservableList().stream()
.map(openOffer -> {
final Optional<AddressEntry> addressEntryOptional = btcWalletService.getAddressEntry(openOffer.getId(), AddressEntry.Context.RESERVED_FOR_TRADE);
if (addressEntryOptional.isPresent()) {
Address address = addressEntryOptional.get().getAddress();
return btcWalletService.getBalanceForAddress(address);
} else {
return null;
}
})
.filter(e -> e != null)
.mapToLong(Coin::getValue)
.sum());
.map(openOffer -> {
final Optional<AddressEntry> addressEntryOptional = btcWalletService.getAddressEntry(openOffer.getId(), AddressEntry.Context.RESERVED_FOR_TRADE);
if (addressEntryOptional.isPresent()) {
Address address = addressEntryOptional.get().getAddress();
return btcWalletService.getBalanceForAddress(address);
} else {
return null;
}
})
.filter(e -> e != null)
.mapToLong(Coin::getValue)
.sum());
reservedBalance.set(formatter.formatCoinWithCode(sum));
}
@ -1125,42 +1134,42 @@ public class MainViewModel implements ViewModel {
Stream<Trade> lockedTrades = Stream.concat(closedTradableManager.getLockedTradesStream(), failedTradesManager.getLockedTradesStream());
lockedTrades = Stream.concat(lockedTrades, tradeManager.getLockedTradesStream());
Coin sum = Coin.valueOf(lockedTrades
.mapToLong(trade -> {
final Optional<AddressEntry> addressEntryOptional = btcWalletService.getAddressEntry(trade.getId(), AddressEntry.Context.MULTI_SIG);
if (addressEntryOptional.isPresent())
return addressEntryOptional.get().getCoinLockedInMultiSig().getValue();
else
return 0;
})
.sum());
.mapToLong(trade -> {
final Optional<AddressEntry> addressEntryOptional = btcWalletService.getAddressEntry(trade.getId(), AddressEntry.Context.MULTI_SIG);
if (addressEntryOptional.isPresent())
return addressEntryOptional.get().getCoinLockedInMultiSig().getValue();
else
return 0;
})
.sum());
lockedBalance.set(formatter.formatCoinWithCode(sum));
}
private void checkForLockedUpFunds() {
Set<String> tradesIdSet = tradeManager.getLockedTradesStream()
.filter(Trade::hasFailed)
.map(Trade::getId)
.collect(Collectors.toSet());
.filter(Trade::hasFailed)
.map(Trade::getId)
.collect(Collectors.toSet());
tradesIdSet.addAll(failedTradesManager.getLockedTradesStream()
.map(Trade::getId)
.collect(Collectors.toSet()));
.map(Trade::getId)
.collect(Collectors.toSet()));
tradesIdSet.addAll(closedTradableManager.getLockedTradesStream()
.map(e -> {
log.warn("We found a closed trade with locked up funds. " +
"That should never happen. trade ID=" + e.getId());
return e.getId();
})
.collect(Collectors.toSet()));
.map(e -> {
log.warn("We found a closed trade with locked up funds. " +
"That should never happen. trade ID=" + e.getId());
return e.getId();
})
.collect(Collectors.toSet()));
btcWalletService.getAddressEntriesForTrade().stream()
.filter(e -> tradesIdSet.contains(e.getOfferId()) && e.getContext() == AddressEntry.Context.MULTI_SIG)
.forEach(e -> {
final Coin balance = e.getCoinLockedInMultiSig();
final String message = Res.get("popup.warning.lockedUpFunds",
formatter.formatCoinWithCode(balance), e.getAddressString(), e.getOfferId());
log.warn(message);
new Popup<>().warning(message).show();
});
.filter(e -> tradesIdSet.contains(e.getOfferId()) && e.getContext() == AddressEntry.Context.MULTI_SIG)
.forEach(e -> {
final Coin balance = e.getCoinLockedInMultiSig();
final String message = Res.get("popup.warning.lockedUpFunds",
formatter.formatCoinWithCode(balance), e.getAddressString(), e.getOfferId());
log.warn(message);
new Popup<>().warning(message).show();
});
}
@ -1177,20 +1186,20 @@ public class MainViewModel implements ViewModel {
addedList.stream().forEach(dispute -> {
String id = dispute.getId();
Subscription disputeStateSubscription = EasyBind.subscribe(dispute.isClosedProperty(),
isClosed -> {
// We get event before list gets updated, so we execute on next frame
UserThread.execute(() -> {
int openDisputes = disputeManager.getDisputesAsObservableList().stream()
.filter(e -> !e.isClosed())
.collect(Collectors.toList()).size();
if (openDisputes > 0)
numOpenDisputesAsString.set(String.valueOf(openDisputes));
if (openDisputes > 9)
numOpenDisputesAsString.set("");
isClosed -> {
// We get event before list gets updated, so we execute on next frame
UserThread.execute(() -> {
int openDisputes = disputeManager.getDisputesAsObservableList().stream()
.filter(e -> !e.isClosed())
.collect(Collectors.toList()).size();
if (openDisputes > 0)
numOpenDisputesAsString.set(String.valueOf(openDisputes));
if (openDisputes > 9)
numOpenDisputesAsString.set("");
showOpenDisputesNotification.set(openDisputes > 0);
showOpenDisputesNotification.set(openDisputes > 0);
});
});
});
disputeIsClosedSubscriptionsMap.put(id, disputeStateSubscription);
});
}
@ -1208,21 +1217,21 @@ public class MainViewModel implements ViewModel {
private void removeOffersWithoutAccountAgeWitness() {
if (new Date().after(AccountAgeWitnessService.FULL_ACTIVATION)) {
openOfferManager.getObservableList().stream()
.filter(e -> CurrencyUtil.isFiatCurrency(e.getOffer().getCurrencyCode()))
.filter(e -> !e.getOffer().getAccountAgeWitnessHashAsHex().isPresent())
.forEach(e -> {
new Popup<>().warning(Res.get("popup.warning.offerWithoutAccountAgeWitness", e.getId()))
.actionButtonText(Res.get("popup.warning.offerWithoutAccountAgeWitness.confirm"))
.onAction(() -> {
openOfferManager.removeOffer(e.getOffer(),
() -> {
log.info("Offer with ID {} is removed", e.getId());
},
log::error);
})
.hideCloseButton()
.show();
});
.filter(e -> CurrencyUtil.isFiatCurrency(e.getOffer().getCurrencyCode()))
.filter(e -> !e.getOffer().getAccountAgeWitnessHashAsHex().isPresent())
.forEach(e -> {
new Popup<>().warning(Res.get("popup.warning.offerWithoutAccountAgeWitness", e.getId()))
.actionButtonText(Res.get("popup.warning.offerWithoutAccountAgeWitness.confirm"))
.onAction(() -> {
openOfferManager.removeOffer(e.getOffer(),
() -> {
log.info("Offer with ID {} is removed", e.getId());
},
log::error);
})
.hideCloseButton()
.show();
});
}
}

View file

@ -0,0 +1,173 @@
/*
* This file is part of bisq.
*
* bisq is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* bisq is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with bisq. If not, see <http://www.gnu.org/licenses/>.
*/
/** This file is part of bisq.
*
* bisq is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* bisq is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bisq.gui.main.overlays.windows;
import io.bisq.common.util.Tuple2;
import io.bisq.common.util.Utilities;
import io.bisq.core.alert.Alert;
import io.bisq.core.user.Preferences;
import io.bisq.gui.main.overlays.Overlay;
import javafx.geometry.HPos;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextArea;
import javafx.scene.input.KeyCode;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import javafx.scene.layout.Priority;
import lombok.extern.slf4j.Slf4j;
import javax.inject.Inject;
import java.io.IOException;
import java.net.URI;
import java.util.Arrays;
import java.util.List;
import static io.bisq.gui.util.FormBuilder.addLabel;
import static io.bisq.gui.util.FormBuilder.addLabelTextArea;
@Slf4j
public class AddBridgeEntriesWindow extends Overlay<AddBridgeEntriesWindow> {
private TextArea bridgeEntriesTextArea;
private final Preferences preferences;
@Inject
public AddBridgeEntriesWindow(Preferences preferences) {
this.preferences = preferences;
type = Type.Attention;
}
///////////////////////////////////////////////////////////////////////////////////////////
// Public API
///////////////////////////////////////////////////////////////////////////////////////////
public void show() {
if (headLine == null)
headLine = "Add Tor bridge entries";
width = 900;
createGridPane();
addHeadLine();
addSeparator();
addContent();
addCloseButton();
applyStyles();
display();
}
protected void addCloseButton() {
closeButton = new Button(closeButtonText == null ? "Close" : closeButtonText);
closeButton.setOnAction(event -> doClose());
if (actionHandlerOptional.isPresent() || actionButtonText != null) {
actionButton = new Button("Save and retry");
actionButton.setDefaultButton(true);
//TODO app wide focus
//actionButton.requestFocus();
actionButton.setOnAction(event -> save());
Button urlButton = new Button("Open Tor project web page");
urlButton.setOnAction(event -> {
try {
Utilities.openURI(URI.create("https://bridges.torproject.org/bridges"));
} catch (IOException e) {
e.printStackTrace();
}
});
Pane spacer = new Pane();
HBox hBox = new HBox();
hBox.setSpacing(10);
hBox.getChildren().addAll(spacer, closeButton, urlButton, actionButton);
HBox.setHgrow(spacer, Priority.ALWAYS);
GridPane.setHalignment(hBox, HPos.RIGHT);
GridPane.setRowIndex(hBox, rowIndex);
GridPane.setColumnSpan(hBox, 2);
GridPane.setMargin(hBox, new Insets(buttonDistance, 0, 0, 0));
gridPane.getChildren().add(hBox);
} else if (!hideCloseButton) {
closeButton.setDefaultButton(true);
GridPane.setHalignment(closeButton, HPos.RIGHT);
GridPane.setMargin(closeButton, new Insets(buttonDistance, 0, 0, 0));
GridPane.setRowIndex(closeButton, rowIndex);
GridPane.setColumnIndex(closeButton, 1);
gridPane.getChildren().add(closeButton);
}
}
///////////////////////////////////////////////////////////////////////////////////////////
// Protected
///////////////////////////////////////////////////////////////////////////////////////////
@Override
protected void setupKeyHandler(Scene scene) {
if (!hideCloseButton) {
scene.setOnKeyPressed(e -> {
if (e.getCode() == KeyCode.ESCAPE) {
e.consume();
doClose();
} else if (e.getCode() == KeyCode.ENTER) {
e.consume();
save();
}
});
}
}
private void addContent() {
Label label = addLabel(gridPane, ++rowIndex, "We could not connect to the Tor network.\n" +
"If Tor is blocked at your internet provider, you can try to add Tor bridge address entries from the Tor project:\n" +
"https://bridges.torproject.org/bridges\n\n" +
"Add one address entry in each line.\n");
GridPane.setColumnIndex(label, 0);
GridPane.setColumnSpan(label, 2);
GridPane.setHalignment(label, HPos.LEFT);
Tuple2<Label, TextArea> labelTextAreaTuple2 = addLabelTextArea(gridPane, rowIndex, "Bridge entries:", "");
bridgeEntriesTextArea = labelTextAreaTuple2.second;
}
private void save() {
if (!bridgeEntriesTextArea.getText().isEmpty()) {
List<String> list = Arrays.asList(bridgeEntriesTextArea.getText().split("\\n"));
preferences.setBridgeAddresses(list);
actionHandlerOptional.ifPresent(Runnable::run);
hide();
}
}
}

View file

@ -9,24 +9,25 @@
<root level="TRACE">
<appender-ref ref="CONSOLE_APPENDER"/>
</root>
<!--
<logger name="com.neemre.btcdcli4j" level="WARN"/>
<logger name="com.neemre.btcdcli4j" level="WARN"/>
<logger name="com.msopentech.thali.toronionproxy.OnionProxyManagerEventHandler" level="INFO"/>
<logger name="com.msopentech.thali.toronionproxy.OnionProxyManagerEventHandler" level="INFO"/>
<logger name="org.bitcoinj.core.AbstractBlockChain" level="WARN"/>
<logger name="org.bitcoinj.net.BlockingClient" level="WARN"/>
<logger name="org.bitcoinj.core.PeerGroup" level="WARN"/>
<logger name="org.bitcoinj.core.Peer" level="WARN"/>
<logger name="org.bitcoinj.core.Context" level="WARN"/>
<logger name="org.bitcoinj.wallet.WalletFiles" level="WARN"/>
<logger name="org.bitcoinj.core.listeners.DownloadProgressTracker" level="WARN"/>
<logger name="org.bitcoinj.core.PeerSocketHandler" level="WARN"/>
<logger name="org.bitcoinj.net.NioClientManager" level="WARN"/>
-->
<logger name="org.bitcoinj.core.AbstractBlockChain" level="WARN"/>
<logger name="org.bitcoinj.net.BlockingClient" level="WARN"/>
<logger name="org.bitcoinj.core.PeerGroup" level="WARN"/>
<logger name="org.bitcoinj.core.Peer" level="WARN"/>
<logger name="org.bitcoinj.core.Context" level="WARN"/>
<logger name="org.bitcoinj.wallet.WalletFiles" level="WARN"/>
<logger name="org.bitcoinj.core.listeners.DownloadProgressTracker" level="WARN"/>
<logger name="org.bitcoinj.core.PeerSocketHandler" level="WARN"/>
<logger name="org.bitcoinj.net.NioClientManager" level="WARN"/>
<!-- We get too many errors logged from connection issues-->
<!-- We get too many errors logged from connection issues
<logger name="org.bitcoinj.net.BlockingClient" level="OFF"/>
-->
<!--
<logger name="org.bitcoinj.net.ConnectionHandler" level="WARN"/>

View file

@ -0,0 +1,23 @@
package io.bisq.network;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* This class exists because the TorNetworkNode in module 'network' can't access the preferences
* in 'core' directly, so we use this provider.
*/
@Slf4j
public class BridgeProvider {
@Setter
@Getter
static List<String> bridges = new ArrayList<>();
}

View file

@ -28,4 +28,8 @@ public abstract class BootstrapListener implements P2PServiceListener {
@Override
abstract public void onBootstrapComplete();
@Override
public void onRequestCustomBridges(Runnable resultHandler) {
}
}

View file

@ -48,7 +48,7 @@ import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
public class P2PService implements SetupListener, MessageListener, ConnectionListener, RequestDataManager.Listener,
HashMapChangedListener, PersistedDataHost {
HashMapChangedListener, PersistedDataHost {
private static final Logger log = LoggerFactory.getLogger(P2PService.class);
public static final int MAX_CONNECTIONS_DEFAULT = 12;
@ -99,7 +99,7 @@ public class P2PService implements SetupListener, MessageListener, ConnectionLis
SeedNodesRepository seedNodesRepository,
Socks5ProxyProvider socks5ProxyProvider,
EncryptionService encryptionService,
KeyRing keyRing ) {
KeyRing keyRing) {
this.networkNode = networkNode;
this.peerManager = peerManager;
this.p2PDataStorage = p2PDataStorage;
@ -119,8 +119,8 @@ public class P2PService implements SetupListener, MessageListener, ConnectionLis
// We need to have both the initial data delivered and the hidden service published
networkReadyBinding = EasyBind.combine(hiddenServicePublished, preliminaryDataReceived,
(hiddenServicePublished, preliminaryDataReceived)
-> hiddenServicePublished && preliminaryDataReceived);
(hiddenServicePublished, preliminaryDataReceived)
-> hiddenServicePublished && preliminaryDataReceived);
networkReadySubscription = networkReadyBinding.subscribe((observable, oldValue, newValue) -> {
if (newValue)
onNetworkReady();
@ -272,6 +272,12 @@ public class P2PService implements SetupListener, MessageListener, ConnectionLis
p2pServiceListeners.stream().forEach(e -> e.onSetupFailed(throwable));
}
@Override
public void onRequestCustomBridges(Runnable resultHandler) {
Log.traceCall();
p2pServiceListeners.stream().forEach(e -> e.onRequestCustomBridges(resultHandler));
}
// Called from networkReadyBinding
private void onNetworkReady() {
Log.traceCall();
@ -279,7 +285,7 @@ public class P2PService implements SetupListener, MessageListener, ConnectionLis
Optional<NodeAddress> seedNodeOfPreliminaryDataRequest = requestDataManager.getNodeAddressOfPreliminaryDataRequest();
checkArgument(seedNodeOfPreliminaryDataRequest.isPresent(),
"seedNodeOfPreliminaryDataRequest must be present");
"seedNodeOfPreliminaryDataRequest must be present");
requestDataManager.requestUpdateData();
}
@ -299,7 +305,7 @@ public class P2PService implements SetupListener, MessageListener, ConnectionLis
public void onUpdatedDataReceived() {
Optional<NodeAddress> seedNodeOfPreliminaryDataRequest = requestDataManager.getNodeAddressOfPreliminaryDataRequest();
checkArgument(seedNodeOfPreliminaryDataRequest.isPresent(),
"seedNodeOfPreliminaryDataRequest must be present");
"seedNodeOfPreliminaryDataRequest must be present");
peerExchangeManager.requestReportedPeersFromSeedNodes(seedNodeOfPreliminaryDataRequest.get());
if (!isBootstrapped) {
@ -367,14 +373,14 @@ public class P2PService implements SetupListener, MessageListener, ConnectionLis
log.debug("Try to decrypt...");
DecryptedMessageWithPubKey decryptedMessageWithPubKey = encryptionService.decryptAndVerify(
prefixedSealedAndSignedMessage.getSealedAndSigned());
prefixedSealedAndSignedMessage.getSealedAndSigned());
log.debug("\n\nDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD\n" +
"Decrypted SealedAndSignedMessage:\ndecryptedMsgWithPubKey={}"
+ "\nDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD\n", decryptedMessageWithPubKey);
"Decrypted SealedAndSignedMessage:\ndecryptedMsgWithPubKey={}"
+ "\nDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD\n", decryptedMessageWithPubKey);
if (connection.getPeersNodeAddressOptional().isPresent())
decryptedDirectMessageListeners.stream().forEach(
e -> e.onDirectMessage(decryptedMessageWithPubKey, connection.getPeersNodeAddressOptional().get()));
e -> e.onDirectMessage(decryptedMessageWithPubKey, connection.getPeersNodeAddressOptional().get()));
else
log.error("peersNodeAddress is not available at onMessage.");
} else {
@ -384,7 +390,7 @@ public class P2PService implements SetupListener, MessageListener, ConnectionLis
log.debug(networkEnvelop.toString());
log.debug(e.toString());
log.debug("Decryption of prefixedSealedAndSignedMessage.sealedAndSigned failed. " +
"That is expected if the message is not intended for us.");
"That is expected if the message is not intended for us.");
}
}
}
@ -427,13 +433,13 @@ public class P2PService implements SetupListener, MessageListener, ConnectionLis
checkNotNull(networkNode.getNodeAddress(), "My node address must not be null at doSendEncryptedDirectMessage");
try {
log.debug("\n\nEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n" +
"Encrypt message:\nmessage={}"
+ "\nEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n", message);
"Encrypt message:\nmessage={}"
+ "\nEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n", message);
PrefixedSealedAndSignedMessage prefixedSealedAndSignedMessage = new PrefixedSealedAndSignedMessage(
networkNode.getNodeAddress(),
encryptionService.encryptAndSign(pubKeyRing, message),
peersNodeAddress.getAddressPrefixHash(),
UUID.randomUUID().toString());
networkNode.getNodeAddress(),
encryptionService.encryptAndSign(pubKeyRing, message),
peersNodeAddress.getAddressPrefixHash(),
UUID.randomUUID().toString());
SettableFuture<Connection> future = networkNode.sendMessage(peersNodeAddress, prefixedSealedAndSignedMessage);
Futures.addCallback(future, new FutureCallback<Connection>() {
@Override
@ -471,7 +477,7 @@ public class P2PService implements SetupListener, MessageListener, ConnectionLis
if (verifyAddressPrefixHash(prefixedSealedAndSignedMessage)) {
try {
DecryptedMessageWithPubKey decryptedMessageWithPubKey = encryptionService.decryptAndVerify(
prefixedSealedAndSignedMessage.getSealedAndSigned());
prefixedSealedAndSignedMessage.getSealedAndSigned());
if (decryptedMessageWithPubKey.getNetworkEnvelope() instanceof MailboxMessage) {
MailboxMessage mailboxMessage = (MailboxMessage) decryptedMessageWithPubKey.getNetworkEnvelope();
NodeAddress senderNodeAddress = mailboxMessage.getSenderNodeAddress();
@ -479,17 +485,17 @@ public class P2PService implements SetupListener, MessageListener, ConnectionLis
mailboxMap.put(mailboxMessage.getUid(), protectedMailboxStorageEntry);
log.trace("Decryption of SealedAndSignedMessage succeeded. senderAddress="
+ senderNodeAddress + " / my address=" + getAddress());
+ senderNodeAddress + " / my address=" + getAddress());
decryptedMailboxListeners.stream().forEach(
e -> e.onMailboxMessageAdded(decryptedMessageWithPubKey, senderNodeAddress));
e -> e.onMailboxMessageAdded(decryptedMessageWithPubKey, senderNodeAddress));
} else {
log.warn("tryDecryptMailboxData: Expected MailboxMessage but got other type. " +
"decryptedMsgWithPubKey.message=", decryptedMessageWithPubKey.getNetworkEnvelope());
"decryptedMsgWithPubKey.message=", decryptedMessageWithPubKey.getNetworkEnvelope());
}
} catch (CryptoException e) {
log.debug(e.toString());
log.debug("Decryption of prefixedSealedAndSignedMessage.sealedAndSigned failed. " +
"That is expected if the message is not intended for us.");
"That is expected if the message is not intended for us.");
}
} else {
log.debug("Wrong blurredAddressHash. The message is not intended for us.");
@ -502,23 +508,23 @@ public class P2PService implements SetupListener, MessageListener, ConnectionLis
SendMailboxMessageListener sendMailboxMessageListener) {
Log.traceCall("message " + message);
checkNotNull(peersNodeAddress,
"PeerAddress must not be null (sendEncryptedMailboxMessage)");
"PeerAddress must not be null (sendEncryptedMailboxMessage)");
checkNotNull(networkNode.getNodeAddress(),
"My node address must not be null at sendEncryptedMailboxMessage");
"My node address must not be null at sendEncryptedMailboxMessage");
checkArgument(!keyRing.getPubKeyRing().equals(peersPubKeyRing),
"We got own keyring instead of that from peer");
"We got own keyring instead of that from peer");
if (isBootstrapped()) {
if (!networkNode.getAllConnections().isEmpty()) {
try {
log.debug("\n\nEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n" +
"Encrypt message:\nmessage={}"
+ "\nEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n", message);
"Encrypt message:\nmessage={}"
+ "\nEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n", message);
PrefixedSealedAndSignedMessage prefixedSealedAndSignedMessage = new PrefixedSealedAndSignedMessage(
networkNode.getNodeAddress(),
encryptionService.encryptAndSign(peersPubKeyRing, message),
peersNodeAddress.getAddressPrefixHash(),
UUID.randomUUID().toString());
networkNode.getNodeAddress(),
encryptionService.encryptAndSign(peersPubKeyRing, message),
peersNodeAddress.getAddressPrefixHash(),
UUID.randomUUID().toString());
SettableFuture<Connection> future = networkNode.sendMessage(peersNodeAddress, prefixedSealedAndSignedMessage);
Futures.addCallback(future, new FutureCallback<Connection>() {
@Override
@ -535,10 +541,10 @@ public class P2PService implements SetupListener, MessageListener, ConnectionLis
log.trace("create MailboxEntry with peerAddress " + peersNodeAddress);
PublicKey receiverStoragePublicKey = peersPubKeyRing.getSignaturePubKey();
addMailboxData(new MailboxStoragePayload(prefixedSealedAndSignedMessage,
keyRing.getSignatureKeyPair().getPublic(),
receiverStoragePublicKey),
receiverStoragePublicKey,
sendMailboxMessageListener);
keyRing.getSignatureKeyPair().getPublic(),
receiverStoragePublicKey),
receiverStoragePublicKey,
sendMailboxMessageListener);
}
});
} catch (CryptoException e) {
@ -548,7 +554,7 @@ public class P2PService implements SetupListener, MessageListener, ConnectionLis
}
} else {
sendMailboxMessageListener.onFault("There are no P2P network nodes connected. " +
"Please check your internet connection.");
"Please check your internet connection.");
}
} else {
throw new NetworkNotReadyException();
@ -565,9 +571,9 @@ public class P2PService implements SetupListener, MessageListener, ConnectionLis
if (!networkNode.getAllConnections().isEmpty()) {
try {
ProtectedMailboxStorageEntry protectedMailboxStorageEntry = p2PDataStorage.getMailboxDataWithSignedSeqNr(
expirableMailboxStoragePayload,
keyRing.getSignatureKeyPair(),
receiversPublicKey);
expirableMailboxStoragePayload,
keyRing.getSignatureKeyPair(),
receiversPublicKey);
BroadcastHandler.Listener listener = new BroadcastHandler.Listener() {
@Override
@ -579,7 +585,7 @@ public class P2PService implements SetupListener, MessageListener, ConnectionLis
// The reason for that check was to separate different callback for different send calls.
// We only want to notify our sendMailboxMessageListener for the calls he is interested in.
if (message instanceof AddDataMessage &&
((AddDataMessage) message).getProtectedStorageEntry().equals(protectedMailboxStorageEntry)) {
((AddDataMessage) message).getProtectedStorageEntry().equals(protectedMailboxStorageEntry)) {
// We delay a bit to give more time for sufficient propagation in the P2P network.
// This should help to avoid situations where a user closes the app too early and the msg
// does not arrive.
@ -597,7 +603,7 @@ public class P2PService implements SetupListener, MessageListener, ConnectionLis
@Override
public void onBroadcastCompleted(BroadcastMessage message, int numOfCompletedBroadcasts, int numOfFailedBroadcasts) {
log.info("Broadcast completed: Sent to {} peers (failed: {}). Message = {}",
numOfCompletedBroadcasts, numOfFailedBroadcasts, Utilities.toTruncatedString(message));
numOfCompletedBroadcasts, numOfFailedBroadcasts, Utilities.toTruncatedString(message));
if (numOfCompletedBroadcasts == 0)
sendMailboxMessageListener.onFault("Broadcast completed without any successful broadcast");
}
@ -622,7 +628,7 @@ public class P2PService implements SetupListener, MessageListener, ConnectionLis
}
} else {
sendMailboxMessageListener.onFault("There are no P2P network nodes connected. " +
"Please check your internet connection.");
"Please check your internet connection.");
}
} else {
throw new NetworkNotReadyException();
@ -649,12 +655,12 @@ public class P2PService implements SetupListener, MessageListener, ConnectionLis
MailboxStoragePayload expirableMailboxStoragePayload = (MailboxStoragePayload) mailboxData.getProtectedStoragePayload();
PublicKey receiversPubKey = mailboxData.getReceiversPubKey();
checkArgument(receiversPubKey.equals(keyRing.getSignatureKeyPair().getPublic()),
"receiversPubKey is not matching with our key. That must not happen.");
"receiversPubKey is not matching with our key. That must not happen.");
try {
ProtectedMailboxStorageEntry protectedMailboxStorageEntry = p2PDataStorage.getMailboxDataWithSignedSeqNr(
expirableMailboxStoragePayload,
keyRing.getSignatureKeyPair(),
receiversPubKey);
expirableMailboxStoragePayload,
keyRing.getSignatureKeyPair(),
receiversPubKey);
p2PDataStorage.removeMailboxData(protectedMailboxStorageEntry, networkNode.getNodeAddress(), true);
} catch (CryptoException e) {
log.error("Signing at getDataWithSignedSeqNr failed. That should never happen.");
@ -665,7 +671,7 @@ public class P2PService implements SetupListener, MessageListener, ConnectionLis
}
} else {
log.warn("uid for mailbox entry not found in mailboxMap. That should never happen." +
"\n\tuid={}\n\tmailboxMap={}\n\tmailboxMessage={}", uid, mailboxMap, mailboxMessage);
"\n\tuid={}\n\tmailboxMap={}\n\tmailboxMessage={}", uid, mailboxMap, mailboxMessage);
}
} else {
throw new NetworkNotReadyException();
@ -809,7 +815,7 @@ public class P2PService implements SetupListener, MessageListener, ConnectionLis
if (networkNode.getNodeAddress() != null) {
byte[] blurredAddressHash = networkNode.getNodeAddress().getAddressPrefixHash();
return blurredAddressHash != null &&
Arrays.equals(blurredAddressHash, prefixedSealedAndSignedMessage.getAddressPrefixHash());
Arrays.equals(blurredAddressHash, prefixedSealedAndSignedMessage.getAddressPrefixHash());
} else {
log.debug("myOnionAddress is null at verifyAddressPrefixHash. That is expected at startup.");
return false;

View file

@ -7,4 +7,6 @@ public interface SetupListener {
@SuppressWarnings("unused")
void onSetupFailed(Throwable throwable);
void onRequestCustomBridges(Runnable resultHandler);
}

View file

@ -11,6 +11,7 @@ import io.bisq.common.app.Log;
import io.bisq.common.proto.network.NetworkProtoResolver;
import io.bisq.common.storage.FileUtil;
import io.bisq.common.util.Utilities;
import io.bisq.network.BridgeProvider;
import io.bisq.network.p2p.NodeAddress;
import io.bisq.network.p2p.Utils;
import javafx.beans.property.BooleanProperty;
@ -31,7 +32,7 @@ import java.nio.file.Paths;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import static com.google.common.base.Preconditions.checkArgument;
@ -41,6 +42,7 @@ public class TorNetworkNode extends NetworkNode {
private static final int MAX_RESTART_ATTEMPTS = 5;
private static final long SHUT_DOWN_TIMEOUT_SEC = 5;
private static final int WAIT_BEFORE_RESTART = 2000;
private HiddenServiceSocket hiddenServiceSocket;
private final File torDir;
@ -48,8 +50,6 @@ public class TorNetworkNode extends NetworkNode {
private int restartCounter;
@SuppressWarnings("FieldCanBeLocal")
private MonadicBinding<Boolean> allShutDown;
@Setter
private List<String> bridgeLines = null;
///////////////////////////////////////////////////////////////////////////////////////////
@ -76,8 +76,7 @@ public class TorNetworkNode extends NetworkNode {
createExecutorService();
// Create the tor node (takes about 6 sec.)
//createTorNode(torDir, (nativeTor) -> createHiddenService(Utils.findFreeSystemPort(), servicePort, bridgeLines));
createTorAndHiddenService(torDir, Utils.findFreeSystemPort(), servicePort, bridgeLines);
createTorAndHiddenService(torDir, Utils.findFreeSystemPort(), servicePort, BridgeProvider.getBridges());
}
@Override
@ -170,8 +169,25 @@ public class TorNetworkNode extends NetworkNode {
private void restartTor(String errorMessage) {
Log.traceCall();
log.warn("Restarting Tor");
restartCounter++;
if (restartCounter > MAX_RESTART_ATTEMPTS) {
if (restartCounter <= MAX_RESTART_ATTEMPTS) {
// If we failed we try with custom bridges
if (restartCounter == 1) {
setupListeners.stream().forEach(e -> e.onRequestCustomBridges(() -> {
log.warn("Tor restart after custom bridges.");
start(null);
}));
log.warn("We stop tor as starting tor with the default bridges failed. We request user to add custom bridges.");
shutDown(null);
} else {
shutDown(() -> UserThread.runAfter(() -> {
log.warn("We restart tor using custom bridges.");
log.warn("Bridges: " + BridgeProvider.getBridges());
start(null);
}, WAIT_BEFORE_RESTART, TimeUnit.MILLISECONDS));
}
} else {
String msg = "We tried to restart Tor " + restartCounter +
" times, but it continued to fail with error message:\n" +
errorMessage + "\n\n" +
@ -186,99 +202,21 @@ public class TorNetworkNode extends NetworkNode {
// create tor
///////////////////////////////////////////////////////////////////////////////////////////
private void createTorNode(final File torDir, final Consumer<NativeTor> resultHandler) {
Log.traceCall();
ListenableFuture<NativeTor> future = executorService.submit(() -> {
Utilities.setThreadName("TorNetworkNode:CreateTorNode");
long ts = System.currentTimeMillis();
if (torDir.mkdirs())
log.trace("Created directory for tor at {}", torDir.getAbsolutePath());
NativeTor nativeTor = null;
try {
nativeTor = new NativeTor(torDir, bridgeLines);
} catch (TorCtlException e) {
throw new Exception(e);
}
log.debug("\n\n############################################################\n" +
"TorNode created:" +
"\nTook " + (System.currentTimeMillis() - ts) + " ms"
+ "\n############################################################\n");
return nativeTor;
});
Futures.addCallback(future, new FutureCallback<NativeTor>() {
public void onSuccess(NativeTor torNode) {
Tor.setDefault(torNode);
UserThread.execute(() -> resultHandler.accept(torNode));
}
public void onFailure(@NotNull Throwable throwable) {
UserThread.execute(() -> {
log.error("TorNode creation failed with exception: " + throwable.getMessage());
restartTor(throwable.getMessage());
});
}
});
}
private void createHiddenService(int localPort, int servicePort, List<String> bridgeLines) {
Log.traceCall();
ListenableFuture<Object> future = executorService.submit(() -> {
Utilities.setThreadName("TorNetworkNode:CreateHiddenService");
{
long ts = System.currentTimeMillis();
// TODO backup has to be taken from ./hiddenservice, not ./
hiddenServiceSocket = new HiddenServiceSocket(localPort, "hiddenservice", servicePort);
hiddenServiceSocket.addReadyListener(socket -> {
Socket con;
try {
log.info("Hidden Service " + socket + " is ready");
new Thread() {
@Override
public void run() {
try {
Log.traceCall("hiddenService created");
nodeAddressProperty.set(new NodeAddress(hiddenServiceSocket.getServiceName() + ":" + hiddenServiceSocket.getHiddenServicePort()));
startServer(socket);
UserThread.execute(() -> setupListeners.stream().forEach(SetupListener::onHiddenServicePublished));
} catch (final Exception e1) {
e1.printStackTrace();
}
}
}.start();
} catch (final Exception e) {
e.printStackTrace();
}
return null;
});
log.info("It will take some time for the HS to be reachable (~40 seconds). You will be notified about this");
return null;
}
});
Futures.addCallback(future, new FutureCallback<Object>() {
public void onSuccess(Object hiddenServiceDescriptor) {
log.debug("HiddenServiceDescriptor created. Wait for publishing.");
}
public void onFailure(@NotNull Throwable throwable) {
UserThread.execute(() -> {
log.error("Hidden service creation failed");
restartTor(throwable.getMessage());
});
}
});
}
private void createTorAndHiddenService(final File torDir, int localPort, int servicePort, List<String> bridgeLines) {
Log.traceCall();
log.debug("Using bridges: {}", bridgeLines.stream().collect(Collectors.joining(",")));
if(restartCounter == 0) {
log.error("Doing fake restart to get to the bridges");
restartTor("error message here...");
return;
}
ListenableFuture<Object> future = (ListenableFuture<Object>) executorService.submit(() -> {
try {
Tor.setDefault(new NativeTor(torDir, bridgeLines));
} catch (TorCtlException e) {
log.error("Tor node creation failed", e);
restartTor(e.getMessage());
return;
}
UserThread.execute(() -> setupListeners.stream().forEach(SetupListener::onTorNodeReady));

View file

@ -117,6 +117,10 @@ public class PeerServiceTest {
@Override
public void onSetupFailed(Throwable throwable) {
}
@Override
public void onRequestCustomBridges(Runnable resultHandler) {
}
});
}
Thread.sleep(30_000);
@ -208,6 +212,11 @@ public class PeerServiceTest {
@Override
public void onSetupFailed(Throwable throwable) {
}
@Override
public void onRequestCustomBridges(Runnable resultHandler) {
}
});
P2PService p2PService1 = seedNode1.getSeedNodeP2PService();
@ -245,6 +254,11 @@ public class PeerServiceTest {
@Override
public void onSetupFailed(Throwable throwable) {
}
@Override
public void onRequestCustomBridges(Runnable resultHandler) {
}
});
P2PService p2PService2 = seedNode2.getSeedNodeP2PService();
latch.await();
@ -480,6 +494,10 @@ public class PeerServiceTest {
@Override
public void onSetupFailed(Throwable throwable) {
}
@Override
public void onRequestCustomBridges(Runnable resultHandler) {
}
});
latch.await();
Thread.sleep(sleepTime);

View file

@ -80,6 +80,11 @@ public class TestUtils {
@Override
public void onSetupFailed(Throwable throwable) {
}
@Override
public void onRequestCustomBridges(Runnable resultHandler) {
}
});
latch.await();
Thread.sleep(sleepTime);

View file

@ -52,6 +52,11 @@ public class LocalhostNetworkNodeTest {
public void onSetupFailed(Throwable throwable) {
log.debug("onSetupFailed");
}
@Override
public void onRequestCustomBridges(Runnable resultHandler) {
}
});
LocalhostNetworkNode node2 = new LocalhostNetworkNode(9002, TestUtils.getNetworkProtoResolver());
@ -75,6 +80,11 @@ public class LocalhostNetworkNodeTest {
public void onSetupFailed(Throwable throwable) {
log.debug("onSetupFailed 2");
}
@Override
public void onRequestCustomBridges(Runnable resultHandler) {
}
});
startupLatch.await();

View file

@ -416,6 +416,11 @@ public class NetworkStressTest {
localServicesFailed.set(true);
localServicesLatch.countDown();
}
@Override
public void onRequestCustomBridges(Runnable resultHandler) {
}
}
private class SeedServiceListener extends TestSetupListener implements P2PServiceListener {
@ -802,6 +807,11 @@ public class NetworkStressTest {
@Override
public void onSetupFailed(Throwable throwable) {
}
@Override
public void onRequestCustomBridges(Runnable resultHandler) {
}
}
}

View file

@ -53,6 +53,11 @@ public class TorNetworkNodeTest {
@Override
public void onSetupFailed(Throwable throwable) {
}
@Override
public void onRequestCustomBridges(Runnable resultHandler) {
}
});
latch.await();
@ -75,6 +80,11 @@ public class TorNetworkNodeTest {
@Override
public void onSetupFailed(Throwable throwable) {
}
@Override
public void onRequestCustomBridges(Runnable resultHandler) {
}
});
latch.await();
@ -127,6 +137,11 @@ public class TorNetworkNodeTest {
public void onSetupFailed(Throwable throwable) {
}
@Override
public void onRequestCustomBridges(Runnable resultHandler) {
}
});
int port2 = 9002;
@ -146,6 +161,11 @@ public class TorNetworkNodeTest {
@Override
public void onSetupFailed(Throwable throwable) {
}
@Override
public void onRequestCustomBridges(Runnable resultHandler) {
}
});
latch.await();

View file

@ -117,6 +117,11 @@ public class PeerManagerTest {
public void onSetupFailed(Throwable throwable) {
}
@Override
public void onRequestCustomBridges(Runnable resultHandler) {
}
});
P2PService p2PService1 = seedNode1.getSeedNodeP2PService();
latch.await();
@ -168,6 +173,11 @@ public class PeerManagerTest {
@Override
public void onSetupFailed(Throwable throwable) {
}
@Override
public void onRequestCustomBridges(Runnable resultHandler) {
}
});
P2PService p2PService1 = seedNode1.getSeedNodeP2PService();
@ -205,6 +215,11 @@ public class PeerManagerTest {
@Override
public void onSetupFailed(Throwable throwable) {
}
@Override
public void onRequestCustomBridges(Runnable resultHandler) {
}
});
P2PService p2PService2 = seedNode2.getSeedNodeP2PService();
latch.await();
@ -439,6 +454,11 @@ public class PeerManagerTest {
@Override
public void onSetupFailed(Throwable throwable) {
}
@Override
public void onRequestCustomBridges(Runnable resultHandler) {
}
});
latch.await();
Thread.sleep(sleepTime);