mirror of
https://github.com/bisq-network/bisq.git
synced 2025-02-24 23:18:17 +01:00
UI improvements, P2P network WIP
This commit is contained in:
parent
615f5570c3
commit
850b6d209c
54 changed files with 684 additions and 532 deletions
|
@ -1,7 +1,6 @@
|
|||
package io.bitsquare.btc.pricefeed;
|
||||
|
||||
import com.google.common.util.concurrent.*;
|
||||
import io.bitsquare.app.Log;
|
||||
import io.bitsquare.btc.pricefeed.providers.PriceProvider;
|
||||
import io.bitsquare.common.util.Utilities;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
@ -44,7 +43,7 @@ class GetPriceRequest {
|
|||
}
|
||||
|
||||
private SettableFuture<MarketPrice> requestPrice(String currencyCode, PriceProvider provider, SettableFuture<MarketPrice> resultFuture) {
|
||||
Log.traceCall(currencyCode);
|
||||
// Log.traceCall(currencyCode);
|
||||
ListenableFuture<MarketPrice> future = executorService.submit(() -> {
|
||||
Thread.currentThread().setName("requestPrice-" + provider.toString());
|
||||
return provider.getPrice(currencyCode);
|
||||
|
|
|
@ -4,7 +4,6 @@ import com.google.common.util.concurrent.FutureCallback;
|
|||
import com.google.common.util.concurrent.Futures;
|
||||
import com.google.common.util.concurrent.SettableFuture;
|
||||
import com.google.inject.Inject;
|
||||
import io.bitsquare.app.Log;
|
||||
import io.bitsquare.btc.pricefeed.providers.BitcoinAveragePriceProvider;
|
||||
import io.bitsquare.btc.pricefeed.providers.PoloniexPriceProvider;
|
||||
import io.bitsquare.btc.pricefeed.providers.PriceProvider;
|
||||
|
@ -140,7 +139,7 @@ public class MarketPriceFeed {
|
|||
if (priceConsumer != null && currencyCode != null && type != null) {
|
||||
if (cache.containsKey(currencyCode)) {
|
||||
MarketPrice marketPrice = cache.get(currencyCode);
|
||||
log.debug("applyPrice type=" + type);
|
||||
//log.debug("applyPrice type=" + type);
|
||||
priceConsumer.accept(marketPrice.getPrice(type));
|
||||
} else {
|
||||
String errorMessage = "We don't have a price for currencyCode " + currencyCode;
|
||||
|
@ -151,14 +150,14 @@ public class MarketPriceFeed {
|
|||
}
|
||||
|
||||
private void requestPrice(PriceProvider provider) {
|
||||
Log.traceCall();
|
||||
//Log.traceCall();
|
||||
GetPriceRequest getPriceRequest = new GetPriceRequest();
|
||||
SettableFuture<MarketPrice> future = getPriceRequest.requestPrice(currencyCode, provider);
|
||||
Futures.addCallback(future, new FutureCallback<MarketPrice>() {
|
||||
public void onSuccess(MarketPrice marketPrice) {
|
||||
UserThread.execute(() -> {
|
||||
cache.put(marketPrice.currencyCode, marketPrice);
|
||||
log.debug("marketPrice updated " + marketPrice);
|
||||
//log.debug("marketPrice updated " + marketPrice);
|
||||
priceConsumer.accept(marketPrice.getPrice(type));
|
||||
});
|
||||
}
|
||||
|
@ -170,7 +169,7 @@ public class MarketPriceFeed {
|
|||
}
|
||||
|
||||
private void requestAllPrices(PriceProvider provider, @Nullable Runnable resultHandler) {
|
||||
Log.traceCall();
|
||||
// Log.traceCall();
|
||||
GetPriceRequest getPriceRequest = new GetPriceRequest();
|
||||
SettableFuture<Map<String, MarketPrice>> future = getPriceRequest.requestAllPrices(provider);
|
||||
Futures.addCallback(future, new FutureCallback<Map<String, MarketPrice>>() {
|
||||
|
|
|
@ -4,7 +4,6 @@ import com.google.gson.Gson;
|
|||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import com.google.gson.internal.LinkedTreeMap;
|
||||
import io.bitsquare.app.Log;
|
||||
import io.bitsquare.btc.pricefeed.MarketPrice;
|
||||
import io.bitsquare.http.HttpClient;
|
||||
import io.bitsquare.http.HttpException;
|
||||
|
@ -45,7 +44,7 @@ public class BitcoinAveragePriceProvider implements PriceProvider {
|
|||
|
||||
@Override
|
||||
public MarketPrice getPrice(String currencyCode) throws IOException, HttpException {
|
||||
Log.traceCall("currencyCode=" + currencyCode);
|
||||
//Log.traceCall("currencyCode=" + currencyCode);
|
||||
JsonObject jsonObject = new JsonParser()
|
||||
.parse(httpClient.requestWithGET(currencyCode))
|
||||
.getAsJsonObject();
|
||||
|
|
|
@ -4,7 +4,6 @@ import com.google.gson.Gson;
|
|||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import com.google.gson.internal.LinkedTreeMap;
|
||||
import io.bitsquare.app.Log;
|
||||
import io.bitsquare.btc.pricefeed.MarketPrice;
|
||||
import io.bitsquare.http.HttpClient;
|
||||
import io.bitsquare.http.HttpException;
|
||||
|
@ -63,7 +62,7 @@ public class PoloniexPriceProvider implements PriceProvider {
|
|||
|
||||
@Override
|
||||
public MarketPrice getPrice(String currencyCode) throws IOException, HttpException {
|
||||
Log.traceCall("currencyCode=" + currencyCode);
|
||||
// Log.traceCall("currencyCode=" + currencyCode);
|
||||
JsonObject jsonObject = new JsonParser()
|
||||
.parse(httpClient.requestWithGET(currencyCode))
|
||||
.getAsJsonObject();
|
||||
|
|
|
@ -80,6 +80,10 @@ public class CountryUtil {
|
|||
return new Locale(LanguageUtil.getDefaultLanguage(), countryCode).getDisplayCountry();
|
||||
}
|
||||
|
||||
public static String getNameAndCode(String countryCode) {
|
||||
return getNameByCode(countryCode) + " (" + countryCode + ")";
|
||||
}
|
||||
|
||||
public static String getCodesString(List<String> countryCodes) {
|
||||
return countryCodes.stream().collect(Collectors.joining(", "));
|
||||
}
|
||||
|
|
|
@ -171,12 +171,6 @@ public class CurrencyUtil {
|
|||
result.add(new CryptoCurrency("ETH", "Ethereum"));
|
||||
result.add(new CryptoCurrency("LTC", "Litecoin"));
|
||||
result.add(new CryptoCurrency("NMC", "Namecoin"));
|
||||
// Unfortunately we cannot support CryptoNote coins yet as there is no way to proof the transaction. Payment ID helps only locate the tx but the
|
||||
// arbitrator cannot see if the receiving key matches the receivers address. They might add support for exposing the tx key, but that is not
|
||||
// implemented yet. To use the view key (also not available in GUI wallets) would reveal the complete wallet history for incoming payments, which is
|
||||
// not acceptable from privacy point of view.
|
||||
// result.add(new CryptoCurrency("XMR", "Monero"));
|
||||
// result.add(new CryptoCurrency("BCN", "Bytecoin"));
|
||||
result.add(new CryptoCurrency("DASH", "Dash"));
|
||||
result.add(new CryptoCurrency("NBT", "NuBits"));
|
||||
result.add(new CryptoCurrency("NSR", "NuShares"));
|
||||
|
@ -192,6 +186,13 @@ public class CurrencyUtil {
|
|||
result.add(new CryptoCurrency("BTS", "BitShares"));
|
||||
result.add(new CryptoCurrency("XCP", "Counterparty"));
|
||||
result.add(new CryptoCurrency("XRP", "Ripple"));
|
||||
|
||||
// Unfortunately we cannot support CryptoNote coins yet as there is no way to proof the transaction. Payment ID helps only locate the tx but the
|
||||
// arbitrator cannot see if the receiving key matches the receivers address. They might add support for exposing the tx key, but that is not
|
||||
// implemented yet. To use the view key (also not available in GUI wallets) would reveal the complete wallet history for incoming payments, which is
|
||||
// not acceptable from privacy point of view.
|
||||
// result.add(new CryptoCurrency("XMR", "Monero"));
|
||||
// result.add(new CryptoCurrency("BCN", "Bytecoin"));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -213,8 +214,8 @@ public class CurrencyUtil {
|
|||
try {
|
||||
return Currency.getInstance(currencyCode).getDisplayName(Preferences.getDefaultLocale());
|
||||
} catch (Throwable t) {
|
||||
// Seems that it is a crypto currency
|
||||
return getSortedCryptoCurrencies().stream().filter(e -> e.getCode().equals(currencyCode)).findFirst().get().getCodeAndName();
|
||||
// Seems that it is a cryptocurrency
|
||||
return getSortedCryptoCurrencies().stream().filter(e -> e.getCode().equals(currencyCode)).findFirst().get().getName();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -58,6 +58,10 @@ public class TradeCurrency implements Serializable {
|
|||
return symbol;
|
||||
}
|
||||
|
||||
public String getNameAndCode() {
|
||||
return name + " (" + code + ")";
|
||||
}
|
||||
|
||||
public String getCodeAndName() {
|
||||
return code + " (" + name + ")";
|
||||
}
|
||||
|
|
|
@ -44,6 +44,11 @@ public class AliPayAccountContractData extends PaymentAccountContractData implem
|
|||
return "AliPay - Account nr.: " + accountNr;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPaymentDetailsForTradePopup() {
|
||||
return getPaymentDetails();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "AliPayAccountContractData{" +
|
||||
|
|
|
@ -43,9 +43,14 @@ public class BlockChainAccountContractData extends PaymentAccountContractData im
|
|||
|
||||
@Override
|
||||
public String getPaymentDetails() {
|
||||
return "Address: " + address;
|
||||
return "Receivers cryptocurrency address: " + address;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPaymentDetailsForTradePopup() {
|
||||
return getPaymentDetails();
|
||||
}
|
||||
|
||||
public void setPaymentId(String paymentId) {
|
||||
this.paymentId = paymentId;
|
||||
}
|
||||
|
|
|
@ -44,5 +44,8 @@ public class OKPayAccountContractData extends PaymentAccountContractData impleme
|
|||
return "OKPay - Account nr.: " + accountNr;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getPaymentDetailsForTradePopup() {
|
||||
return getPaymentDetails();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -72,6 +72,8 @@ public abstract class PaymentAccountContractData implements Serializable {
|
|||
|
||||
abstract public String getPaymentDetails();
|
||||
|
||||
abstract public String getPaymentDetailsForTradePopup();
|
||||
|
||||
public int getMaxTradePeriod() {
|
||||
return maxTradePeriod;
|
||||
}
|
||||
|
|
|
@ -44,4 +44,9 @@ public class PerfectMoneyAccountContractData extends PaymentAccountContractData
|
|||
return "PerfectMoney - Account nr.: " + accountNr;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPaymentDetailsForTradePopup() {
|
||||
return getPaymentDetails();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -89,4 +89,12 @@ public class SepaAccountContractData extends PaymentAccountContractData implemen
|
|||
public String getPaymentDetails() {
|
||||
return "SEPA - Holder name: " + holderName + ", IBAN: " + iban + ", BIC: " + bic + ", country code: " + getCountryCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPaymentDetailsForTradePopup() {
|
||||
return "Holder name: " + holderName + "\n" +
|
||||
"IBAN: " + iban + "\n" +
|
||||
"BIC: " + bic + "\n" +
|
||||
"Country of bank: " + CountryUtil.getNameAndCode(getCountryCode());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,4 +53,9 @@ public class SwishAccountContractData extends PaymentAccountContractData impleme
|
|||
return "Swish - Holder name: " + holderName + ", mobile nr.: " + mobileNr;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPaymentDetailsForTradePopup() {
|
||||
return "Holder name: " + holderName + "\n" +
|
||||
"Mobile nr.: " + mobileNr;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -146,7 +146,7 @@ abstract public class Trade implements Tradable, Model, Serializable {
|
|||
|
||||
// Mutable
|
||||
private DecryptedMsgWithPubKey decryptedMsgWithPubKey;
|
||||
private Date takeOfferDate = new Date(0); // in some error cases the date is not set and cause null pointers, so we set a default
|
||||
private Date takeOfferDate;
|
||||
private int takeOfferDateAsBlockHeight;
|
||||
private Coin tradeAmount;
|
||||
private NodeAddress tradingPeerNodeAddress;
|
||||
|
@ -180,6 +180,7 @@ abstract public class Trade implements Tradable, Model, Serializable {
|
|||
protected Trade(Offer offer, Storage<? extends TradableList> storage) {
|
||||
this.offer = offer;
|
||||
this.storage = storage;
|
||||
this.takeOfferDate = new Date();
|
||||
|
||||
processModel = new ProcessModel();
|
||||
tradeVolumeProperty = new SimpleObjectProperty<>();
|
||||
|
@ -199,6 +200,7 @@ abstract public class Trade implements Tradable, Model, Serializable {
|
|||
this.tradingPeerNodeAddress = tradingPeerNodeAddress;
|
||||
tradeAmountProperty.set(tradeAmount);
|
||||
tradeVolumeProperty.set(getTradeVolume());
|
||||
this.takeOfferDate = new Date();
|
||||
}
|
||||
|
||||
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
|
||||
|
@ -411,9 +413,9 @@ abstract public class Trade implements Tradable, Model, Serializable {
|
|||
return takeOfferDate;
|
||||
}
|
||||
|
||||
public void setTakeOfferDate(Date takeOfferDate) {
|
||||
/*public void setTakeOfferDate(Date takeOfferDate) {
|
||||
this.takeOfferDate = takeOfferDate;
|
||||
}
|
||||
}*/
|
||||
|
||||
public int getTakeOfferDateAsBlockHeight() {
|
||||
return takeOfferDateAsBlockHeight;
|
||||
|
|
|
@ -59,7 +59,6 @@ import org.spongycastle.crypto.params.KeyParameter;
|
|||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import java.io.File;
|
||||
import java.util.Date;
|
||||
import java.util.Optional;
|
||||
|
||||
import static io.bitsquare.util.Validator.nonEmptyStringOf;
|
||||
|
@ -98,7 +97,6 @@ public class TradeManager {
|
|||
ArbitratorManager arbitratorManager,
|
||||
P2PService p2PService,
|
||||
@Named("storage.dir") File storageDir) {
|
||||
Log.traceCall();
|
||||
this.user = user;
|
||||
this.keyRing = keyRing;
|
||||
this.walletService = walletService;
|
||||
|
@ -280,7 +278,7 @@ public class TradeManager {
|
|||
else
|
||||
trade = new BuyerAsTakerTrade(offer, amount, model.getPeerNodeAddress(), tradableListStorage);
|
||||
|
||||
trade.setTakeOfferDate(new Date());
|
||||
//trade.setTakeOfferDate(new Date());
|
||||
trade.setTakeOfferDateAsBlockHeight(tradeWalletService.getBestChainHeight());
|
||||
trade.setTakerPaymentAccountId(paymentAccountId);
|
||||
|
||||
|
@ -312,8 +310,8 @@ public class TradeManager {
|
|||
public void onSuccess(@javax.annotation.Nullable Transaction transaction) {
|
||||
if (transaction != null) {
|
||||
log.info("onWithdraw onSuccess tx ID:" + transaction.getHashAsString());
|
||||
trade.setState(Trade.State.WITHDRAW_COMPLETED);
|
||||
addTradeToClosedTrades(trade);
|
||||
trade.setState(Trade.State.WITHDRAW_COMPLETED);
|
||||
resultHandler.handleResult();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ import io.bitsquare.trade.TradableList;
|
|||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
|
@ -55,6 +56,18 @@ public class OpenOffer implements Tradable, Serializable {
|
|||
this.storage = storage;
|
||||
}
|
||||
|
||||
private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
|
||||
try {
|
||||
in.defaultReadObject();
|
||||
|
||||
// If we have a reserved state from the local db we reset it
|
||||
if (state == State.RESERVED)
|
||||
setState(State.AVAILABLE);
|
||||
|
||||
} catch (Throwable t) {
|
||||
log.error("Cannot be deserialized." + t.getMessage());
|
||||
}
|
||||
}
|
||||
public Date getDate() {
|
||||
return offer.getDate();
|
||||
}
|
||||
|
@ -98,7 +111,7 @@ public class OpenOffer implements Tradable, Serializable {
|
|||
stopTimeout();
|
||||
|
||||
timeoutTimer = UserThread.runAfter(() -> {
|
||||
log.info("Timeout reached");
|
||||
log.info("Timeout for resettin State.RESERVED reached");
|
||||
if (state == State.RESERVED)
|
||||
setState(State.AVAILABLE);
|
||||
}, TIMEOUT_SEC);
|
||||
|
|
|
@ -47,13 +47,13 @@ public class ProcessFinalizePayoutTxRequest extends TradeTask {
|
|||
processModel.tradingPeer.setPayoutAddressString(nonEmptyStringOf(message.sellerPayoutAddress));
|
||||
trade.setLockTimeAsBlockHeight(nonNegativeLongOf(message.lockTimeAsBlockHeight));
|
||||
|
||||
trade.setState(Trade.State.FIAT_PAYMENT_RECEIPT_MSG_RECEIVED);
|
||||
|
||||
// update to the latest peer address of our peer if the message is correct
|
||||
trade.setTradingPeerNodeAddress(processModel.getTempTradingPeerNodeAddress());
|
||||
|
||||
removeMailboxMessageAfterProcessing();
|
||||
|
||||
trade.setState(Trade.State.FIAT_PAYMENT_RECEIPT_MSG_RECEIVED);
|
||||
|
||||
complete();
|
||||
} catch (Throwable t) {
|
||||
failed(t);
|
||||
|
|
|
@ -27,8 +27,6 @@ import org.jetbrains.annotations.NotNull;
|
|||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
public class SignAndPublishDepositTxAsBuyer extends TradeTask {
|
||||
private static final Logger log = LoggerFactory.getLogger(SignAndPublishDepositTxAsBuyer.class);
|
||||
|
||||
|
@ -64,7 +62,7 @@ public class SignAndPublishDepositTxAsBuyer extends TradeTask {
|
|||
log.trace("takerSignAndPublishTx succeeded " + transaction);
|
||||
|
||||
trade.setDepositTx(transaction);
|
||||
trade.setTakeOfferDate(new Date());
|
||||
//trade.setTakeOfferDate(new Date());
|
||||
trade.setTakeOfferDateAsBlockHeight(processModel.getTradeWalletService().getBestChainHeight());
|
||||
trade.setState(Trade.State.DEPOSIT_PUBLISHED);
|
||||
|
||||
|
|
|
@ -26,8 +26,6 @@ import org.bitcoinj.core.Transaction;
|
|||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static io.bitsquare.util.Validator.checkTradeId;
|
||||
|
@ -53,11 +51,10 @@ public class ProcessDepositTxPublishedMessage extends TradeTask {
|
|||
Transaction transactionFromSerializedTx = processModel.getWalletService().getTransactionFromSerializedTx(message.depositTx);
|
||||
// update with full tx
|
||||
trade.setDepositTx(processModel.getTradeWalletService().addTransactionToWallet(transactionFromSerializedTx));
|
||||
|
||||
trade.setState(Trade.State.DEPOSIT_PUBLISHED_MSG_RECEIVED);
|
||||
trade.setTakeOfferDate(new Date());
|
||||
trade.setTakeOfferDateAsBlockHeight(processModel.getTradeWalletService().getBestChainHeight());
|
||||
|
||||
//trade.setTakeOfferDate(new Date());
|
||||
trade.setTakeOfferDateAsBlockHeight(processModel.getTradeWalletService().getBestChainHeight());
|
||||
|
||||
if (trade instanceof OffererTrade)
|
||||
processModel.getOpenOfferManager().closeOpenOffer(trade.getOffer());
|
||||
|
||||
|
@ -65,6 +62,8 @@ public class ProcessDepositTxPublishedMessage extends TradeTask {
|
|||
trade.setTradingPeerNodeAddress(processModel.getTempTradingPeerNodeAddress());
|
||||
|
||||
removeMailboxMessageAfterProcessing();
|
||||
|
||||
trade.setState(Trade.State.DEPOSIT_PUBLISHED_MSG_RECEIVED);
|
||||
|
||||
complete();
|
||||
} catch (Throwable t) {
|
||||
|
|
|
@ -36,7 +36,6 @@ public class SendPublishDepositTxRequest extends TradeTask {
|
|||
protected void run() {
|
||||
try {
|
||||
runInterceptHook();
|
||||
trade.setState(Trade.State.DEPOSIT_PUBLISH_REQUESTED);
|
||||
PublishDepositTxRequest tradeMessage = new PublishDepositTxRequest(
|
||||
processModel.getId(),
|
||||
processModel.getPaymentAccountContractData(trade),
|
||||
|
@ -69,6 +68,9 @@ public class SendPublishDepositTxRequest extends TradeTask {
|
|||
}
|
||||
}
|
||||
);
|
||||
|
||||
//TODO should it be in success handler?
|
||||
trade.setState(Trade.State.DEPOSIT_PUBLISH_REQUESTED);
|
||||
} catch (Throwable t) {
|
||||
failed(t);
|
||||
}
|
||||
|
|
|
@ -46,13 +46,13 @@ public class ProcessFiatTransferStartedMessage extends TradeTask {
|
|||
|
||||
processModel.tradingPeer.setPayoutAddressString(nonEmptyStringOf(message.buyerPayoutAddress));
|
||||
|
||||
trade.setState(Trade.State.FIAT_PAYMENT_STARTED_MSG_RECEIVED);
|
||||
|
||||
// update to the latest peer address of our peer if the message is correct
|
||||
trade.setTradingPeerNodeAddress(processModel.getTempTradingPeerNodeAddress());
|
||||
|
||||
removeMailboxMessageAfterProcessing();
|
||||
|
||||
trade.setState(Trade.State.FIAT_PAYMENT_STARTED_MSG_RECEIVED);
|
||||
|
||||
complete();
|
||||
} catch (Throwable t) {
|
||||
failed(t);
|
||||
|
|
|
@ -46,13 +46,13 @@ public class ProcessPayoutTxFinalizedMessage extends TradeTask {
|
|||
checkArgument(message.payoutTx != null);
|
||||
trade.setPayoutTx(processModel.getWalletService().getTransactionFromSerializedTx(message.payoutTx));
|
||||
|
||||
trade.setState(Trade.State.PAYOUT_TX_RECEIVED);
|
||||
|
||||
// update to the latest peer address of our peer if the message is correct
|
||||
trade.setTradingPeerNodeAddress(processModel.getTempTradingPeerNodeAddress());
|
||||
|
||||
removeMailboxMessageAfterProcessing();
|
||||
|
||||
|
||||
trade.setState(Trade.State.PAYOUT_TX_RECEIVED);
|
||||
|
||||
complete();
|
||||
} catch (Throwable t) {
|
||||
failed(t);
|
||||
|
|
|
@ -27,8 +27,6 @@ import org.jetbrains.annotations.NotNull;
|
|||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
public class SignAndPublishDepositTxAsSeller extends TradeTask {
|
||||
private static final Logger log = LoggerFactory.getLogger(SignAndPublishDepositTxAsSeller.class);
|
||||
|
||||
|
@ -62,7 +60,7 @@ public class SignAndPublishDepositTxAsSeller extends TradeTask {
|
|||
log.trace("takerSignAndPublishTx succeeded " + transaction);
|
||||
|
||||
trade.setDepositTx(transaction);
|
||||
trade.setTakeOfferDate(new Date());
|
||||
//trade.setTakeOfferDate(new Date());
|
||||
trade.setTakeOfferDateAsBlockHeight(processModel.getTradeWalletService().getBestChainHeight());
|
||||
trade.setState(Trade.State.DEPOSIT_PUBLISHED);
|
||||
|
||||
|
|
|
@ -634,49 +634,6 @@ textfield */
|
|||
-fx-base: #dd0000;
|
||||
}
|
||||
|
||||
#trade-notification-warning {
|
||||
-fx-font-size: 14;
|
||||
-fx-base: -bs-red-soft;
|
||||
}
|
||||
|
||||
#trade-notification-information {
|
||||
-fx-font-size: 14;
|
||||
-fx-outer-border: linear-gradient(to bottom, #ffb34b, #ff9200);
|
||||
}
|
||||
|
||||
#trade-notification-dispute {
|
||||
-fx-font-size: 14;
|
||||
-fx-base: -bs-error-red;
|
||||
}
|
||||
|
||||
#trade-notification-support {
|
||||
-fx-font-size: 14;
|
||||
-fx-base: -bs-orange;
|
||||
}
|
||||
|
||||
#support-info-label {
|
||||
-fx-font-size: 14;
|
||||
-fx-text-fill: -bs-red-soft;
|
||||
}
|
||||
|
||||
#titled-group-bg-warn {
|
||||
-fx-body-color: linear-gradient(to bottom, -bs-content-bg-grey, #F0F0F0);
|
||||
-fx-outer-border: linear-gradient(to bottom, #ffb34b, #ff9200);
|
||||
-fx-background-color: -fx-shadow-highlight-color,
|
||||
-fx-outer-border,
|
||||
-fx-inner-border,
|
||||
-fx-body-color;
|
||||
-fx-background-insets: 0 0 -1 0, 0, 1, 2;
|
||||
-fx-background-radius: 3px, 3px, 2px, 1px;
|
||||
}
|
||||
|
||||
#titled-group-bg-label-warn {
|
||||
-fx-font-weight: bold;
|
||||
-fx-font-size: 14;
|
||||
-fx-text-fill: #ff9200;
|
||||
-fx-background-color: -bs-content-bg-grey;
|
||||
}
|
||||
|
||||
/* TitledGroupBg */
|
||||
#titled-group-bg-label {
|
||||
-fx-font-weight: bold;
|
||||
|
|
|
@ -93,6 +93,10 @@ public class TextFieldWithCopyIcon extends AnchorPane {
|
|||
this.text.set(text);
|
||||
}
|
||||
|
||||
public void setTooltip(Tooltip toolTip) {
|
||||
textField.setTooltip(toolTip);
|
||||
}
|
||||
|
||||
public void setCopyWithoutCurrencyPostFix(boolean copyWithoutCurrencyPostFix) {
|
||||
this.copyWithoutCurrencyPostFix = copyWithoutCurrencyPostFix;
|
||||
}
|
||||
|
|
|
@ -75,12 +75,15 @@ public class TxIdTextField extends AnchorPane {
|
|||
copyIcon = new Label();
|
||||
copyIcon.setLayoutY(3);
|
||||
copyIcon.getStyleClass().add("copy-icon");
|
||||
Tooltip.install(copyIcon, new Tooltip("Copy transaction ID to clipboard"));
|
||||
copyIcon.setTooltip(new Tooltip("Copy transaction ID to clipboard"));
|
||||
AwesomeDude.setIcon(copyIcon, AwesomeIcon.COPY);
|
||||
AnchorPane.setRightAnchor(copyIcon, 30.0);
|
||||
|
||||
Tooltip tooltip = new Tooltip("Open a blockchain explorer with that transactions ID");
|
||||
|
||||
blockExplorerIcon = new Label();
|
||||
blockExplorerIcon.getStyleClass().add("external-link-icon");
|
||||
blockExplorerIcon.setTooltip(tooltip);
|
||||
AwesomeDude.setIcon(blockExplorerIcon, AwesomeIcon.EXTERNAL_LINK);
|
||||
blockExplorerIcon.setMinWidth(20);
|
||||
AnchorPane.setRightAnchor(blockExplorerIcon, 52.0);
|
||||
|
@ -89,7 +92,7 @@ public class TxIdTextField extends AnchorPane {
|
|||
textField = new TextField();
|
||||
textField.setId("address-text-field");
|
||||
textField.setEditable(false);
|
||||
Tooltip.install(textField, new Tooltip("Open a blockchain explorer with that transactions ID"));
|
||||
textField.setTooltip(tooltip);
|
||||
AnchorPane.setRightAnchor(textField, 80.0);
|
||||
AnchorPane.setLeftAnchor(textField, 0.0);
|
||||
textField.focusTraversableProperty().set(focusTraversableProperty().get());
|
||||
|
|
|
@ -63,7 +63,7 @@ public class AliPayForm extends PaymentMethodForm {
|
|||
updateFromInputs();
|
||||
});
|
||||
|
||||
addLabelTextField(gridPane, ++gridRow, "Currency:", aliPayAccount.getSingleTradeCurrency().getCodeAndName());
|
||||
addLabelTextField(gridPane, ++gridRow, "Currency:", aliPayAccount.getSingleTradeCurrency().getNameAndCode());
|
||||
addAllowedPeriod();
|
||||
addAccountNameTextFieldWithAutoFillCheckBox();
|
||||
}
|
||||
|
@ -85,7 +85,7 @@ public class AliPayForm extends PaymentMethodForm {
|
|||
addLabelTextField(gridPane, ++gridRow, "Payment method:", BSResources.get(aliPayAccount.getPaymentMethod().getId()));
|
||||
TextField field = addLabelTextField(gridPane, ++gridRow, "Account nr.:", aliPayAccount.getAccountNr()).second;
|
||||
field.setMouseTransparent(false);
|
||||
addLabelTextField(gridPane, ++gridRow, "Currency:", aliPayAccount.getSingleTradeCurrency().getCodeAndName());
|
||||
addLabelTextField(gridPane, ++gridRow, "Currency:", aliPayAccount.getSingleTradeCurrency().getNameAndCode());
|
||||
addAllowedPeriod();
|
||||
}
|
||||
|
||||
|
|
|
@ -49,7 +49,7 @@ public class BlockChainForm extends PaymentMethodForm {
|
|||
private ComboBox<TradeCurrency> currencyComboBox;
|
||||
|
||||
public static int addFormForBuyer(GridPane gridPane, int gridRow, PaymentAccountContractData paymentAccountContractData) {
|
||||
addLabelTextFieldWithCopyIcon(gridPane, ++gridRow, "Address:", ((BlockChainAccountContractData) paymentAccountContractData).getAddress());
|
||||
addLabelTextFieldWithCopyIcon(gridPane, ++gridRow, "Cryptocurrency address:", ((BlockChainAccountContractData) paymentAccountContractData).getAddress());
|
||||
if (paymentAccountContractData instanceof BlockChainAccountContractData &&
|
||||
((BlockChainAccountContractData) paymentAccountContractData).getPaymentId() != null)
|
||||
addLabelTextFieldWithCopyIcon(gridPane, ++gridRow, "Payment ID:", ((BlockChainAccountContractData) paymentAccountContractData).getPaymentId());
|
||||
|
@ -70,7 +70,7 @@ public class BlockChainForm extends PaymentMethodForm {
|
|||
|
||||
addTradeCurrencyComboBox();
|
||||
currencyComboBox.setPrefWidth(250);
|
||||
addressInputTextField = addLabelInputTextField(gridPane, ++gridRow, "Receiving altcoin address:").second;
|
||||
addressInputTextField = addLabelInputTextField(gridPane, ++gridRow, "Cryptocurrency address:").second;
|
||||
addressInputTextField.setValidator(altCoinAddressValidator);
|
||||
|
||||
addressInputTextField.textProperty().addListener((ov, oldValue, newValue) -> {
|
||||
|
@ -98,9 +98,9 @@ public class BlockChainForm extends PaymentMethodForm {
|
|||
gridRowFrom = gridRow;
|
||||
addLabelTextField(gridPane, gridRow, "Account name:", blockChainAccount.getAccountName(), Layout.FIRST_ROW_AND_GROUP_DISTANCE);
|
||||
addLabelTextField(gridPane, ++gridRow, "Payment method:", BSResources.get(blockChainAccount.getPaymentMethod().getId()));
|
||||
TextField field = addLabelTextField(gridPane, ++gridRow, "Receiving altcoin address:", blockChainAccount.getAddress()).second;
|
||||
TextField field = addLabelTextField(gridPane, ++gridRow, "Cryptocurrency address:", blockChainAccount.getAddress()).second;
|
||||
field.setMouseTransparent(false);
|
||||
addLabelTextField(gridPane, ++gridRow, "Crypto currency:", blockChainAccount.getSingleTradeCurrency().getCodeAndName());
|
||||
addLabelTextField(gridPane, ++gridRow, "Crypto currency:", blockChainAccount.getSingleTradeCurrency().getNameAndCode());
|
||||
addAllowedPeriod();
|
||||
}
|
||||
|
||||
|
@ -114,13 +114,13 @@ public class BlockChainForm extends PaymentMethodForm {
|
|||
@Override
|
||||
protected void addTradeCurrencyComboBox() {
|
||||
currencyComboBox = addLabelComboBox(gridPane, ++gridRow, "Crypto currency:").second;
|
||||
currencyComboBox.setPromptText("Select crypto currency");
|
||||
currencyComboBox.setPromptText("Select cryptocurrency");
|
||||
currencyComboBox.setItems(FXCollections.observableArrayList(CurrencyUtil.getSortedCryptoCurrencies()));
|
||||
currencyComboBox.setVisibleRowCount(Math.min(currencyComboBox.getItems().size(), 20));
|
||||
currencyComboBox.setConverter(new StringConverter<TradeCurrency>() {
|
||||
@Override
|
||||
public String toString(TradeCurrency tradeCurrency) {
|
||||
return tradeCurrency.getCodeAndName();
|
||||
return tradeCurrency.getNameAndCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -65,7 +65,7 @@ public abstract class PaymentMethodForm {
|
|||
currencyComboBox.setConverter(new StringConverter<TradeCurrency>() {
|
||||
@Override
|
||||
public String toString(TradeCurrency tradeCurrency) {
|
||||
return tradeCurrency.getCodeAndName();
|
||||
return tradeCurrency.getNameAndCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -111,7 +111,7 @@ public abstract class PaymentMethodForm {
|
|||
displayText = hours / 24 + " days";
|
||||
|
||||
|
||||
addLabelTextField(gridPane, gridRow, "Trade period/end date:", displayText + " / " + dateFromBlocks);
|
||||
addLabelTextField(gridPane, gridRow, "Max. allowed trade period / date:", displayText + " / " + dateFromBlocks);
|
||||
}
|
||||
|
||||
protected void addAllowedPeriod() {
|
||||
|
@ -126,7 +126,7 @@ public abstract class PaymentMethodForm {
|
|||
|
||||
displayText += " (Max. permitted period until the trade has to be completed)";
|
||||
|
||||
addLabelTextField(gridPane, ++gridRow, "Allowed trade period:", displayText);
|
||||
addLabelTextField(gridPane, ++gridRow, "Max. allowed trade period:", displayText);
|
||||
}
|
||||
|
||||
abstract protected void autoFillNameTextField();
|
||||
|
|
|
@ -64,7 +64,7 @@ public class PerfectMoneyForm extends PaymentMethodForm {
|
|||
updateFromInputs();
|
||||
});
|
||||
|
||||
addLabelTextField(gridPane, ++gridRow, "Currency:", perfectMoneyAccount.getSingleTradeCurrency().getCodeAndName());
|
||||
addLabelTextField(gridPane, ++gridRow, "Currency:", perfectMoneyAccount.getSingleTradeCurrency().getNameAndCode());
|
||||
addAllowedPeriod();
|
||||
addAccountNameTextFieldWithAutoFillCheckBox();
|
||||
}
|
||||
|
@ -87,7 +87,7 @@ public class PerfectMoneyForm extends PaymentMethodForm {
|
|||
addLabelTextField(gridPane, ++gridRow, "Payment method:", BSResources.get(perfectMoneyAccount.getPaymentMethod().getId()));
|
||||
TextField field = addLabelTextField(gridPane, ++gridRow, "Account nr.:", perfectMoneyAccount.getAccountNr()).second;
|
||||
field.setMouseTransparent(false);
|
||||
addLabelTextField(gridPane, ++gridRow, "Currency:", perfectMoneyAccount.getSingleTradeCurrency().getCodeAndName());
|
||||
addLabelTextField(gridPane, ++gridRow, "Currency:", perfectMoneyAccount.getSingleTradeCurrency().getNameAndCode());
|
||||
addAllowedPeriod();
|
||||
}
|
||||
|
||||
|
|
|
@ -59,7 +59,7 @@ public class SepaForm extends PaymentMethodForm {
|
|||
|
||||
public static int addFormForBuyer(GridPane gridPane, int gridRow, PaymentAccountContractData paymentAccountContractData) {
|
||||
addLabelTextFieldWithCopyIcon(gridPane, ++gridRow, "Account holder name:", ((SepaAccountContractData) paymentAccountContractData).getHolderName());
|
||||
addLabelTextFieldWithCopyIcon(gridPane, ++gridRow, "Country of bank:", CountryUtil.getNameByCode(paymentAccountContractData.getCountryCode()));
|
||||
addLabelTextFieldWithCopyIcon(gridPane, ++gridRow, "Country of bank:", CountryUtil.getNameAndCode(paymentAccountContractData.getCountryCode()));
|
||||
addLabelTextFieldWithCopyIcon(gridPane, ++gridRow, "IBAN:", ((SepaAccountContractData) paymentAccountContractData).getIban());
|
||||
addLabelTextFieldWithCopyIcon(gridPane, ++gridRow, "BIC/SWIFT:", ((SepaAccountContractData) paymentAccountContractData).getBic());
|
||||
return gridRow;
|
||||
|
@ -107,7 +107,7 @@ public class SepaForm extends PaymentMethodForm {
|
|||
countryComboBox.setConverter(new StringConverter<Country>() {
|
||||
@Override
|
||||
public String toString(Country country) {
|
||||
return country.code + " (" + country.name + ")";
|
||||
return country.name + " (" + country.code + ")";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -120,7 +120,7 @@ public class SepaForm extends PaymentMethodForm {
|
|||
sepaAccount.setCountry(selectedItem);
|
||||
TradeCurrency currency = CurrencyUtil.getCurrencyByCountryCode(selectedItem.code);
|
||||
sepaAccount.setSingleTradeCurrency(currency);
|
||||
currencyTextField.setText("Currency: " + currency.getCodeAndName());
|
||||
currencyTextField.setText("Currency: " + currency.getNameAndCode());
|
||||
updateCountriesSelection(true, euroCountryCheckBoxes);
|
||||
updateCountriesSelection(true, nonEuroCountryCheckBoxes);
|
||||
updateFromInputs();
|
||||
|
@ -138,7 +138,7 @@ public class SepaForm extends PaymentMethodForm {
|
|||
sepaAccount.setCountry(country);
|
||||
TradeCurrency currency = CurrencyUtil.getCurrencyByCountryCode(country.code);
|
||||
sepaAccount.setSingleTradeCurrency(currency);
|
||||
currencyTextField.setText("Currency: " + currency.getCodeAndName());
|
||||
currencyTextField.setText("Currency: " + currency.getNameAndCode());
|
||||
}
|
||||
|
||||
updateFromInputs();
|
||||
|
@ -256,7 +256,7 @@ public class SepaForm extends PaymentMethodForm {
|
|||
TextField bicField = addLabelTextField(gridPane, ++gridRow, "BIC/SWIFT:", sepaAccount.getBic()).second;
|
||||
bicField.setMouseTransparent(false);
|
||||
addLabelTextField(gridPane, ++gridRow, "Location of Bank:", sepaAccount.getCountry().name);
|
||||
addLabelTextField(gridPane, ++gridRow, "Currency:", sepaAccount.getSingleTradeCurrency().getCodeAndName());
|
||||
addLabelTextField(gridPane, ++gridRow, "Currency:", sepaAccount.getSingleTradeCurrency().getNameAndCode());
|
||||
String countries;
|
||||
Tooltip tooltip = null;
|
||||
if (CountryUtil.containsAllSepaEuroCountries(sepaAccount.getAcceptedCountryCodes())) {
|
||||
|
|
|
@ -72,7 +72,7 @@ public class SwishForm extends PaymentMethodForm {
|
|||
updateFromInputs();
|
||||
});
|
||||
|
||||
addLabelTextField(gridPane, ++gridRow, "Currency:", swishAccount.getSingleTradeCurrency().getCodeAndName());
|
||||
addLabelTextField(gridPane, ++gridRow, "Currency:", swishAccount.getSingleTradeCurrency().getNameAndCode());
|
||||
addAllowedPeriod();
|
||||
addAccountNameTextFieldWithAutoFillCheckBox();
|
||||
}
|
||||
|
@ -95,7 +95,7 @@ public class SwishForm extends PaymentMethodForm {
|
|||
addLabelTextField(gridPane, ++gridRow, "Account holder name:", swishAccount.getHolderName());
|
||||
TextField field = addLabelTextField(gridPane, ++gridRow, "Mobile nr.:", swishAccount.getMobileNr()).second;
|
||||
field.setMouseTransparent(false);
|
||||
addLabelTextField(gridPane, ++gridRow, "Currency:", swishAccount.getSingleTradeCurrency().getCodeAndName());
|
||||
addLabelTextField(gridPane, ++gridRow, "Currency:", swishAccount.getSingleTradeCurrency().getNameAndCode());
|
||||
addAllowedPeriod();
|
||||
}
|
||||
|
||||
|
|
|
@ -35,9 +35,9 @@ import io.bitsquare.trade.protocol.trade.SellerAsTakerProtocol;
|
|||
import io.bitsquare.trade.protocol.trade.tasks.buyer.*;
|
||||
import io.bitsquare.trade.protocol.trade.tasks.offerer.*;
|
||||
import io.bitsquare.trade.protocol.trade.tasks.seller.*;
|
||||
import io.bitsquare.trade.protocol.trade.tasks.shared.BroadcastAfterLockTime;
|
||||
import io.bitsquare.trade.protocol.trade.tasks.shared.CommitPayoutTx;
|
||||
import io.bitsquare.trade.protocol.trade.tasks.shared.InitWaitPeriodForOpenDispute;
|
||||
import io.bitsquare.trade.protocol.trade.tasks.shared.SetupPayoutTxLockTimeReachedListener;
|
||||
import io.bitsquare.trade.protocol.trade.tasks.taker.*;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ObservableList;
|
||||
|
@ -99,7 +99,7 @@ public class DebugView extends InitializableView {
|
|||
SignAndFinalizePayoutTx.class,
|
||||
CommitPayoutTx.class,
|
||||
SendPayoutTxFinalizedMessage.class,
|
||||
SetupPayoutTxLockTimeReachedListener.class,
|
||||
BroadcastAfterLockTime.class,
|
||||
Boolean.class, /* used as seperator*/
|
||||
|
||||
|
||||
|
@ -125,7 +125,7 @@ public class DebugView extends InitializableView {
|
|||
|
||||
ProcessPayoutTxFinalizedMessage.class,
|
||||
CommitPayoutTx.class,
|
||||
SetupPayoutTxLockTimeReachedListener.class,
|
||||
BroadcastAfterLockTime.class,
|
||||
Boolean.class /* used as seperator*/
|
||||
)
|
||||
);
|
||||
|
@ -152,7 +152,7 @@ public class DebugView extends InitializableView {
|
|||
SignAndFinalizePayoutTx.class,
|
||||
CommitPayoutTx.class,
|
||||
SendPayoutTxFinalizedMessage.class,
|
||||
SetupPayoutTxLockTimeReachedListener.class,
|
||||
BroadcastAfterLockTime.class,
|
||||
Boolean.class, /* used as seperator*/
|
||||
|
||||
|
||||
|
@ -177,7 +177,7 @@ public class DebugView extends InitializableView {
|
|||
|
||||
ProcessPayoutTxFinalizedMessage.class,
|
||||
CommitPayoutTx.class,
|
||||
SetupPayoutTxLockTimeReachedListener.class,
|
||||
BroadcastAfterLockTime.class,
|
||||
Boolean.class /* used as seperator*/
|
||||
)
|
||||
);
|
||||
|
|
|
@ -86,7 +86,7 @@ public class MarketsChartsView extends ActivatableViewAndModel<VBox, MarketsChar
|
|||
currencyComboBox.setConverter(new StringConverter<TradeCurrency>() {
|
||||
@Override
|
||||
public String toString(TradeCurrency tradeCurrency) {
|
||||
return tradeCurrency.getCodeAndName();
|
||||
return tradeCurrency.getNameAndCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -289,7 +289,7 @@ public class CreateOfferView extends ActivatableViewAndModel<AnchorPane, CreateO
|
|||
|
||||
model.onPaymentAccountSelected(paymentAccount);
|
||||
} else {
|
||||
currencyTextField.setText(paymentAccount.getSingleTradeCurrency().getCodeAndName());
|
||||
currencyTextField.setText(paymentAccount.getSingleTradeCurrency().getNameAndCode());
|
||||
model.onPaymentAccountSelected(paymentAccount);
|
||||
model.onCurrencySelected(paymentAccount.getSingleTradeCurrency());
|
||||
}
|
||||
|
@ -588,7 +588,7 @@ public class CreateOfferView extends ActivatableViewAndModel<AnchorPane, CreateO
|
|||
currencyComboBox.setConverter(new StringConverter<TradeCurrency>() {
|
||||
@Override
|
||||
public String toString(TradeCurrency tradeCurrency) {
|
||||
return tradeCurrency.getCodeAndName();
|
||||
return tradeCurrency.getNameAndCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -673,7 +673,7 @@ public class CreateOfferView extends ActivatableViewAndModel<AnchorPane, CreateO
|
|||
balanceTextField = balanceTuple.second;
|
||||
balanceTextField.setVisible(false);
|
||||
|
||||
Tuple3<Button, ProgressIndicator, Label> placeOfferTuple = addButtonWithStatus(gridPane, ++gridRow,
|
||||
Tuple3<Button, ProgressIndicator, Label> placeOfferTuple = addButtonWithStatusAfterGroup(gridPane, ++gridRow,
|
||||
BSResources.get("createOffer.fundsBox.placeOffer"));
|
||||
placeOfferButton = placeOfferTuple.first;
|
||||
placeOfferButton.setVisible(false);
|
||||
|
|
|
@ -89,7 +89,7 @@ public class OfferBookView extends ActivatableViewAndModel<GridPane, OfferBookVi
|
|||
currencyComboBox.setConverter(new StringConverter<TradeCurrency>() {
|
||||
@Override
|
||||
public String toString(TradeCurrency tradeCurrency) {
|
||||
return tradeCurrency.getCodeAndName();
|
||||
return tradeCurrency.getNameAndCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -160,6 +160,8 @@ public class OfferBookView extends ActivatableViewAndModel<GridPane, OfferBookVi
|
|||
currencyComboBox.setOnAction(e -> model.onSetTradeCurrency(currencyComboBox.getSelectionModel().getSelectedItem()));
|
||||
paymentMethodComboBox.setOnAction(e -> model.onSetPaymentMethod(paymentMethodComboBox.getSelectionModel().getSelectedItem()));
|
||||
createOfferButton.setOnAction(e -> onCreateOffer());
|
||||
priceColumn.textProperty().bind(createStringBinding(
|
||||
() -> "Price in " + model.tradeCurrencyCode.get() + "/BTC", model.tradeCurrencyCode));
|
||||
volumeColumn.textProperty().bind(createStringBinding(
|
||||
() -> "Amount in " + model.tradeCurrencyCode.get() + " (Min.)", model.tradeCurrencyCode));
|
||||
model.getOfferList().comparatorProperty().bind(tableView.comparatorProperty());
|
||||
|
|
|
@ -317,7 +317,7 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
|
|||
paymentMethodLabel.setManaged(!showComboBox);
|
||||
if (!showComboBox)
|
||||
paymentMethodTextField.setText(BSResources.get(model.getPaymentMethod().getId()));
|
||||
currencyTextField.setText(model.getTradeCurrency().getCodeAndName());
|
||||
currencyTextField.setText(model.getTradeCurrency().getNameAndCode());
|
||||
buyLabel.setText(model.getDirectionLabel());
|
||||
amountDescriptionLabel.setText(model.getAmountDescription());
|
||||
amountRangeTextField.setText(model.getAmountRange());
|
||||
|
@ -553,7 +553,7 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
|
|||
balanceTextField = balanceTuple.second;
|
||||
balanceTextField.setVisible(false);
|
||||
|
||||
Tuple3<Button, ProgressIndicator, Label> takeOfferTuple = addButtonWithStatus(gridPane, ++gridRow, BSResources.get("takeOffer.fundsBox.takeOffer"));
|
||||
Tuple3<Button, ProgressIndicator, Label> takeOfferTuple = addButtonWithStatusAfterGroup(gridPane, ++gridRow, BSResources.get("takeOffer.fundsBox.takeOffer"));
|
||||
takeOfferButton = takeOfferTuple.first;
|
||||
takeOfferButton.setVisible(false);
|
||||
takeOfferButton.setOnAction(e -> onTakeOffer());
|
||||
|
|
|
@ -87,7 +87,7 @@ public class PreferencesView extends ActivatableViewAndModel<GridPane, Preferenc
|
|||
tradeCurrencyComboBox.setConverter(new StringConverter<TradeCurrency>() {
|
||||
@Override
|
||||
public String toString(TradeCurrency tradeCurrency) {
|
||||
return tradeCurrency.getCodeAndName();
|
||||
return tradeCurrency.getNameAndCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -148,7 +148,8 @@ public class OfferDetailsPopup extends Popup {
|
|||
addLabelTextField(gridPane, ++rowIndex, "Payment method:", BSResources.get(offer.getPaymentMethod().getId()));
|
||||
|
||||
rows = 3;
|
||||
if (offer.getPaymentMethodCountryCode() != null)
|
||||
String paymentMethodCountryCode = offer.getPaymentMethodCountryCode();
|
||||
if (paymentMethodCountryCode != null)
|
||||
rows++;
|
||||
if (offer.getOfferFeePaymentTxID() != null)
|
||||
rows++;
|
||||
|
@ -161,8 +162,9 @@ public class OfferDetailsPopup extends Popup {
|
|||
addLabelTextField(gridPane, rowIndex, "Offer ID:", offer.getId(), Layout.FIRST_ROW_AND_GROUP_DISTANCE);
|
||||
addLabelTextField(gridPane, ++rowIndex, "Creation date:", formatter.formatDateTime(offer.getDate()));
|
||||
|
||||
if (offer.getPaymentMethodCountryCode() != null)
|
||||
addLabelTextField(gridPane, ++rowIndex, "Offerers country of bank:", offer.getPaymentMethodCountryCode());
|
||||
if (paymentMethodCountryCode != null)
|
||||
addLabelTextField(gridPane, ++rowIndex, "Offerers country of bank:",
|
||||
CountryUtil.getNameAndCode(paymentMethodCountryCode));
|
||||
if (offer.getAcceptedCountryCodes() != null) {
|
||||
String countries;
|
||||
Tooltip tooltip = null;
|
||||
|
|
|
@ -129,6 +129,7 @@ public class FormBuilder {
|
|||
return label;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Label + TextField
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -672,9 +673,9 @@ public class FormBuilder {
|
|||
// Button + ProgressIndicator + Label
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public static Tuple3<Button, ProgressIndicator, Label> addButtonWithStatus(GridPane gridPane,
|
||||
int rowIndex,
|
||||
String buttonTitle) {
|
||||
public static Tuple3<Button, ProgressIndicator, Label> addButtonWithStatusAfterGroup(GridPane gridPane,
|
||||
int rowIndex,
|
||||
String buttonTitle) {
|
||||
return addButtonWithStatus(gridPane, rowIndex, buttonTitle, 15);
|
||||
}
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ public class HttpClient implements Serializable {
|
|||
connection = (HttpURLConnection) url.openConnection();
|
||||
connection.setRequestMethod("GET");
|
||||
connection.setConnectTimeout(10000);
|
||||
connection.setReadTimeout(10000);
|
||||
|
||||
if (connection.getResponseCode() == 200) {
|
||||
return convertInputStreamToString(connection.getInputStream());
|
||||
|
|
|
@ -16,10 +16,7 @@ import io.bitsquare.crypto.EncryptionService;
|
|||
import io.bitsquare.crypto.PrefixedSealedAndSignedMessage;
|
||||
import io.bitsquare.p2p.messaging.*;
|
||||
import io.bitsquare.p2p.network.*;
|
||||
import io.bitsquare.p2p.peers.Broadcaster;
|
||||
import io.bitsquare.p2p.peers.PeerExchangeManager;
|
||||
import io.bitsquare.p2p.peers.PeerManager;
|
||||
import io.bitsquare.p2p.peers.RequestDataManager;
|
||||
import io.bitsquare.p2p.peers.*;
|
||||
import io.bitsquare.p2p.seed.SeedNodesRepository;
|
||||
import io.bitsquare.p2p.storage.HashMapChangedListener;
|
||||
import io.bitsquare.p2p.storage.P2PDataStorage;
|
||||
|
@ -81,6 +78,7 @@ public class P2PService implements SetupListener, MessageListener, ConnectionLis
|
|||
private Subscription networkReadySubscription;
|
||||
private boolean isBootstrapped;
|
||||
private ChangeListener<Number> numOfBroadcastsChangeListener;
|
||||
private MaintenanceManager maintenanceManager;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -128,6 +126,9 @@ public class P2PService implements SetupListener, MessageListener, ConnectionLis
|
|||
|
||||
peerExchangeManager = new PeerExchangeManager(networkNode, peerManager, seedNodeAddresses);
|
||||
|
||||
maintenanceManager = new MaintenanceManager(networkNode, peerManager, seedNodeAddresses);
|
||||
|
||||
|
||||
// We need to have both the initial data delivered and the hidden service published
|
||||
networkReadyBinding = EasyBind.combine(hiddenServicePublished, preliminaryDataReceived,
|
||||
(hiddenServicePublished, preliminaryDataReceived)
|
||||
|
@ -170,6 +171,9 @@ public class P2PService implements SetupListener, MessageListener, ConnectionLis
|
|||
if (peerExchangeManager != null)
|
||||
peerExchangeManager.shutDown();
|
||||
|
||||
if (maintenanceManager != null)
|
||||
maintenanceManager.shutDown();
|
||||
|
||||
if (networkNode != null)
|
||||
networkNode.shutDown(() -> {
|
||||
shutDownResultHandlers.stream().forEach(Runnable::run);
|
||||
|
@ -222,6 +226,8 @@ public class P2PService implements SetupListener, MessageListener, ConnectionLis
|
|||
hiddenServicePublished.set(true);
|
||||
|
||||
p2pServiceListeners.stream().forEach(SetupListener::onHiddenServicePublished);
|
||||
|
||||
maintenanceManager.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -62,7 +62,7 @@ public class Connection implements MessageListener {
|
|||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private final Socket socket;
|
||||
private final MessageListener messageListener;
|
||||
// private final MessageListener messageListener;
|
||||
private final ConnectionListener connectionListener;
|
||||
private final String portInfo;
|
||||
private final String uid = UUID.randomUUID().toString();
|
||||
|
@ -85,6 +85,8 @@ public class Connection implements MessageListener {
|
|||
private PeerType peerType;
|
||||
private final ObjectProperty<NodeAddress> nodeAddressProperty = new SimpleObjectProperty<>();
|
||||
private List<Long> messageTimeStamps = new ArrayList<>();
|
||||
private final CopyOnWriteArraySet<MessageListener> messageListeners = new CopyOnWriteArraySet<>();
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Constructor
|
||||
|
@ -93,9 +95,11 @@ public class Connection implements MessageListener {
|
|||
Connection(Socket socket, MessageListener messageListener, ConnectionListener connectionListener,
|
||||
@Nullable NodeAddress peersNodeAddress) {
|
||||
this.socket = socket;
|
||||
this.messageListener = messageListener;
|
||||
//this.messageListener = messageListener;
|
||||
this.connectionListener = connectionListener;
|
||||
|
||||
addMessageListener(messageListener);
|
||||
|
||||
sharedModel = new SharedModel(this, socket);
|
||||
|
||||
if (socket.getLocalPort() == 0)
|
||||
|
@ -143,7 +147,6 @@ public class Connection implements MessageListener {
|
|||
// API
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
// Called form various threads
|
||||
public void sendMessage(Message message) {
|
||||
if (!stopped) {
|
||||
|
@ -190,6 +193,19 @@ public class Connection implements MessageListener {
|
|||
}
|
||||
}
|
||||
|
||||
public void addMessageListener(MessageListener messageListener) {
|
||||
boolean isNewEntry = messageListeners.add(messageListener);
|
||||
if (!isNewEntry)
|
||||
log.warn("Try to add a messageListener which was already added.");
|
||||
}
|
||||
|
||||
public void removeMessageListener(MessageListener messageListener) {
|
||||
boolean contained = messageListeners.remove(messageListener);
|
||||
if (!contained)
|
||||
log.debug("Try to remove a messageListener which was never added.\n\t" +
|
||||
"That might happen because of async behaviour of CopyOnWriteArraySet");
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public void reportIllegalRequest(RuleViolation ruleViolation) {
|
||||
sharedModel.reportInvalidRequest(ruleViolation);
|
||||
|
@ -224,11 +240,11 @@ public class Connection implements MessageListener {
|
|||
// MessageListener implementation
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Only get non - CloseConnectionMessage messages
|
||||
// Only receive non - CloseConnectionMessage messages
|
||||
@Override
|
||||
public void onMessage(Message message, Connection connection) {
|
||||
// connection is null as we get called from InputHandler, which does not hold a reference to Connection
|
||||
UserThread.execute(() -> messageListener.onMessage(message, this));
|
||||
checkArgument(connection.equals(this));
|
||||
UserThread.execute(() -> messageListeners.stream().forEach(e -> e.onMessage(message, connection)));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,122 @@
|
|||
package io.bitsquare.p2p.peers;
|
||||
|
||||
import com.google.common.util.concurrent.FutureCallback;
|
||||
import com.google.common.util.concurrent.Futures;
|
||||
import com.google.common.util.concurrent.SettableFuture;
|
||||
import io.bitsquare.app.Log;
|
||||
import io.bitsquare.common.UserThread;
|
||||
import io.bitsquare.p2p.network.CloseConnectionReason;
|
||||
import io.bitsquare.p2p.network.Connection;
|
||||
import io.bitsquare.p2p.network.NetworkNode;
|
||||
import io.bitsquare.p2p.peers.messages.peers.GetPeersRequest;
|
||||
import io.bitsquare.p2p.peers.messages.peers.GetPeersResponse;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.Timer;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
|
||||
public class GetPeersRequestHandler {
|
||||
private static final Logger log = LoggerFactory.getLogger(GetPeersRequestHandler.class);
|
||||
|
||||
private static final long TIME_OUT_SEC = 20;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Listener
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public interface Listener {
|
||||
void onComplete();
|
||||
|
||||
void onFault(String errorMessage, Connection connection);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Class fields
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private final NetworkNode networkNode;
|
||||
private final PeerManager peerManager;
|
||||
private final Listener listener;
|
||||
private Timer timeoutTimer;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Constructor
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public GetPeersRequestHandler(NetworkNode networkNode, PeerManager peerManager, Listener listener) {
|
||||
this.networkNode = networkNode;
|
||||
this.peerManager = peerManager;
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// API
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public void process(GetPeersRequest getPeersRequest, final Connection connection) {
|
||||
Log.traceCall("getPeersRequest=" + getPeersRequest + "\n\tconnection=" + connection + "\n\tthis=" + this);
|
||||
|
||||
checkArgument(connection.getPeersNodeAddressOptional().isPresent(),
|
||||
"The peers address must have been already set at the moment");
|
||||
GetPeersResponse getPeersResponse = new GetPeersResponse(getPeersRequest.nonce,
|
||||
peerManager.getConnectedPeersNonSeedNodes(connection.getPeersNodeAddressOptional().get()));
|
||||
SettableFuture<Connection> future = networkNode.sendMessage(connection,
|
||||
getPeersResponse);
|
||||
Futures.addCallback(future, new FutureCallback<Connection>() {
|
||||
@Override
|
||||
public void onSuccess(Connection connection) {
|
||||
log.trace("GetPeersResponse sent successfully");
|
||||
cleanup();
|
||||
listener.onComplete();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(@NotNull Throwable throwable) {
|
||||
String errorMessage = "Sending getPeersRequest to " + connection +
|
||||
" failed. That is expected if the peer is offline. getPeersRequest=" + getPeersRequest + "." +
|
||||
"Exception: " + throwable.getMessage();
|
||||
log.info(errorMessage);
|
||||
handleFault(errorMessage, CloseConnectionReason.SEND_MSG_FAILURE, connection);
|
||||
}
|
||||
});
|
||||
|
||||
checkArgument(timeoutTimer == null, "onGetPeersRequest must not be called twice.");
|
||||
timeoutTimer = UserThread.runAfter(() -> {
|
||||
String errorMessage = "A timeout occurred at sending getPeersResponse:" + getPeersResponse + " on connection:" + connection;
|
||||
log.info(errorMessage + " / PeerExchangeHandshake=" +
|
||||
GetPeersRequestHandler.this);
|
||||
log.info("timeoutTimer called. this=" + this);
|
||||
handleFault(errorMessage, CloseConnectionReason.SEND_MSG_TIMEOUT, connection);
|
||||
},
|
||||
TIME_OUT_SEC, TimeUnit.SECONDS);
|
||||
|
||||
peerManager.addToReportedPeers(getPeersRequest.reportedPeers, connection);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Private
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private void handleFault(String errorMessage, CloseConnectionReason sendMsgFailure, Connection connection) {
|
||||
// TODO retry
|
||||
cleanup();
|
||||
peerManager.shutDownConnection(connection, sendMsgFailure);
|
||||
listener.onFault(errorMessage, connection);
|
||||
}
|
||||
|
||||
private void cleanup() {
|
||||
if (timeoutTimer != null) {
|
||||
timeoutTimer.cancel();
|
||||
timeoutTimer = null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -117,11 +117,8 @@ public class MaintenanceHandshake implements MessageListener {
|
|||
Log.traceCall("getPeersRequest=" + getPeersRequest + "\n\tconnection=" + connection + "\n\tthis=" + this);
|
||||
|
||||
HashSet<ReportedPeer> reportedPeers = getPeersRequest.reportedPeers;
|
||||
|
||||
/* StringBuilder result = new StringBuilder("Received peers:");
|
||||
reportedPeers.stream().forEach(e -> result.append("\n\t").append(e));
|
||||
log.trace(result.toString());*/
|
||||
log.trace("reportedPeers.size=" + reportedPeers.size());
|
||||
|
||||
peerManager.printReportedPeers(reportedPeers);
|
||||
|
||||
checkArgument(connection.getPeersNodeAddressOptional().isPresent(),
|
||||
"The peers address must have been already set at the moment");
|
||||
|
|
|
@ -7,7 +7,6 @@ import io.bitsquare.common.util.Utilities;
|
|||
import io.bitsquare.p2p.Message;
|
||||
import io.bitsquare.p2p.NodeAddress;
|
||||
import io.bitsquare.p2p.network.*;
|
||||
import io.bitsquare.p2p.peers.messages.peers.GetPeersRequest;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
@ -18,16 +17,17 @@ import java.util.concurrent.TimeUnit;
|
|||
import java.util.stream.Collectors;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
public class MaintenanceManager implements MessageListener, ConnectionListener {
|
||||
private static final Logger log = LoggerFactory.getLogger(MaintenanceManager.class);
|
||||
|
||||
private static final int MAINTENANCE_DELAY_SEC = 5 * 60;
|
||||
|
||||
private final NetworkNode networkNode;
|
||||
private final PeerManager peerManager;
|
||||
private final Set<NodeAddress> seedNodeAddresses;
|
||||
private final ScheduledThreadPoolExecutor executor;
|
||||
private final Map<NodeAddress, PeerExchangeHandshake> peerExchangeHandshakeMap = new HashMap<>();
|
||||
private ScheduledThreadPoolExecutor executor;
|
||||
private final Map<NodeAddress, PeerExchangeHandler> peerExchangeHandshakeMap = new HashMap<>();
|
||||
private Timer connectToMorePeersTimer, maintainConnectionsTimer;
|
||||
private boolean shutDownInProgress;
|
||||
|
||||
|
@ -42,7 +42,6 @@ public class MaintenanceManager implements MessageListener, ConnectionListener {
|
|||
checkArgument(!seedNodeAddresses.isEmpty(), "seedNodeAddresses must not be empty");
|
||||
this.seedNodeAddresses = new HashSet<>(seedNodeAddresses);
|
||||
|
||||
executor = Utilities.getScheduledThreadPoolExecutor("PeerExchangeManager", 1, 10, 5);
|
||||
networkNode.addMessageListener(this);
|
||||
}
|
||||
|
||||
|
@ -53,8 +52,10 @@ public class MaintenanceManager implements MessageListener, ConnectionListener {
|
|||
networkNode.removeMessageListener(this);
|
||||
stopConnectToMorePeersTimer();
|
||||
stopMaintainConnectionsTimer();
|
||||
peerExchangeHandshakeMap.values().stream().forEach(PeerExchangeHandshake::closeHandshake);
|
||||
MoreExecutors.shutdownAndAwaitTermination(executor, 500, TimeUnit.MILLISECONDS);
|
||||
peerExchangeHandshakeMap.values().stream().forEach(PeerExchangeHandler::cleanup);
|
||||
|
||||
if (executor != null)
|
||||
MoreExecutors.shutdownAndAwaitTermination(executor, 100, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
|
||||
|
@ -62,19 +63,15 @@ public class MaintenanceManager implements MessageListener, ConnectionListener {
|
|||
// API
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public void requestReportedPeersFromSeedNodes(NodeAddress nodeAddress) {
|
||||
checkNotNull(networkNode.getNodeAddress(), "My node address must not be null at requestReportedPeers");
|
||||
ArrayList<NodeAddress> remainingNodeAddresses = new ArrayList<>(seedNodeAddresses);
|
||||
remainingNodeAddresses.remove(nodeAddress);
|
||||
Collections.shuffle(remainingNodeAddresses);
|
||||
requestReportedPeers(nodeAddress, remainingNodeAddresses);
|
||||
|
||||
int delay = new Random().nextInt(60) + 60 * 3; // 3-4 min
|
||||
executor.scheduleAtFixedRate(() -> UserThread.execute(this::maintainConnections),
|
||||
delay, delay, TimeUnit.SECONDS);
|
||||
public void start() {
|
||||
if (executor == null) {
|
||||
executor = Utilities.getScheduledThreadPoolExecutor("MaintenanceManager", 1, 2, 5);
|
||||
int delay = new Random().nextInt(120) + MAINTENANCE_DELAY_SEC; // add 1-2 min. randomness
|
||||
executor.scheduleAtFixedRate(() -> UserThread.execute(this::maintainConnections),
|
||||
delay, delay, TimeUnit.SECONDS);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// ConnectionListener implementation
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -85,13 +82,13 @@ public class MaintenanceManager implements MessageListener, ConnectionListener {
|
|||
|
||||
@Override
|
||||
public void onDisconnect(CloseConnectionReason closeConnectionReason, Connection connection) {
|
||||
// We use a timer to throttle if we get a series of disconnects
|
||||
/* // We use a timer to throttle if we get a series of disconnects
|
||||
// The more connections we have the more relaxed we are with a checkConnections
|
||||
stopMaintainConnectionsTimer();
|
||||
int size = networkNode.getAllConnections().size();
|
||||
int delay = 10 + 2 * size * size; // 12 sec - 210 sec (3.5 min)
|
||||
maintainConnectionsTimer = UserThread.runAfter(this::maintainConnections,
|
||||
delay, TimeUnit.SECONDS);
|
||||
delay, TimeUnit.SECONDS);*/
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -105,7 +102,7 @@ public class MaintenanceManager implements MessageListener, ConnectionListener {
|
|||
|
||||
@Override
|
||||
public void onMessage(Message message, Connection connection) {
|
||||
if (message instanceof GetPeersRequest) {
|
||||
/* if (message instanceof GetPeersRequest) {
|
||||
Log.traceCall(message.toString() + "\n\tconnection=" + connection);
|
||||
PeerExchangeHandshake peerExchangeHandshake = new PeerExchangeHandshake(networkNode,
|
||||
peerManager,
|
||||
|
@ -123,7 +120,7 @@ public class MaintenanceManager implements MessageListener, ConnectionListener {
|
|||
}
|
||||
});
|
||||
peerExchangeHandshake.onGetPeersRequest((GetPeersRequest) message, connection);
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
|
||||
|
@ -134,9 +131,9 @@ public class MaintenanceManager implements MessageListener, ConnectionListener {
|
|||
private void requestReportedPeers(NodeAddress nodeAddress, List<NodeAddress> remainingNodeAddresses) {
|
||||
Log.traceCall("nodeAddress=" + nodeAddress);
|
||||
if (!peerExchangeHandshakeMap.containsKey(nodeAddress)) {
|
||||
PeerExchangeHandshake peerExchangeHandshake = new PeerExchangeHandshake(networkNode,
|
||||
PeerExchangeHandler peerExchangeHandler = new PeerExchangeHandler(networkNode,
|
||||
peerManager,
|
||||
new PeerExchangeHandshake.Listener() {
|
||||
new PeerExchangeHandler.Listener() {
|
||||
@Override
|
||||
public void onComplete() {
|
||||
log.trace("PeerExchangeHandshake of outbound connection complete. nodeAddress={}", nodeAddress);
|
||||
|
@ -167,8 +164,8 @@ public class MaintenanceManager implements MessageListener, ConnectionListener {
|
|||
}
|
||||
}
|
||||
});
|
||||
peerExchangeHandshakeMap.put(nodeAddress, peerExchangeHandshake);
|
||||
peerExchangeHandshake.requestConnectedPeers(nodeAddress);
|
||||
peerExchangeHandshakeMap.put(nodeAddress, peerExchangeHandler);
|
||||
peerExchangeHandler.requestConnectedPeers(nodeAddress);
|
||||
} else {
|
||||
//TODO check when that happens
|
||||
log.warn("We have started already a peerExchangeHandshake. " +
|
||||
|
|
|
@ -0,0 +1,158 @@
|
|||
package io.bitsquare.p2p.peers;
|
||||
|
||||
import com.google.common.util.concurrent.FutureCallback;
|
||||
import com.google.common.util.concurrent.Futures;
|
||||
import com.google.common.util.concurrent.SettableFuture;
|
||||
import io.bitsquare.app.Log;
|
||||
import io.bitsquare.common.UserThread;
|
||||
import io.bitsquare.p2p.Message;
|
||||
import io.bitsquare.p2p.NodeAddress;
|
||||
import io.bitsquare.p2p.network.CloseConnectionReason;
|
||||
import io.bitsquare.p2p.network.Connection;
|
||||
import io.bitsquare.p2p.network.MessageListener;
|
||||
import io.bitsquare.p2p.network.NetworkNode;
|
||||
import io.bitsquare.p2p.peers.messages.peers.GetPeersRequest;
|
||||
import io.bitsquare.p2p.peers.messages.peers.GetPeersResponse;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Random;
|
||||
import java.util.Timer;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
public class PeerExchangeHandler implements MessageListener {
|
||||
private static final Logger log = LoggerFactory.getLogger(PeerExchangeHandler.class);
|
||||
|
||||
private static final long TIME_OUT_SEC = 20;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Listener
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public interface Listener {
|
||||
void onComplete();
|
||||
|
||||
void onFault(String errorMessage, @Nullable Connection connection);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Class fields
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private final NetworkNode networkNode;
|
||||
private final PeerManager peerManager;
|
||||
private final Listener listener;
|
||||
private final long nonce = new Random().nextLong();
|
||||
private Timer timeoutTimer;
|
||||
public Connection connection;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Constructor
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public PeerExchangeHandler(NetworkNode networkNode, PeerManager peerManager, Listener listener) {
|
||||
this.networkNode = networkNode;
|
||||
this.peerManager = peerManager;
|
||||
this.listener = listener;
|
||||
|
||||
//networkNode.addMessageListener(this);
|
||||
}
|
||||
|
||||
public void cleanup() {
|
||||
if (connection != null)
|
||||
connection.removeMessageListener(this);
|
||||
|
||||
if (timeoutTimer != null) {
|
||||
timeoutTimer.cancel();
|
||||
timeoutTimer = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// API
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public void requestConnectedPeers(NodeAddress nodeAddress) {
|
||||
Log.traceCall("nodeAddress=" + nodeAddress + " / this=" + this);
|
||||
checkNotNull(networkNode.getNodeAddress(), "PeerExchangeHandshake.requestReportedPeers: My node address must " +
|
||||
"not be null at requestReportedPeers");
|
||||
GetPeersRequest getPeersRequest = new GetPeersRequest(networkNode.getNodeAddress(), nonce, peerManager.getConnectedPeersNonSeedNodes(nodeAddress));
|
||||
SettableFuture<Connection> future = networkNode.sendMessage(nodeAddress, getPeersRequest);
|
||||
Futures.addCallback(future, new FutureCallback<Connection>() {
|
||||
@Override
|
||||
public void onSuccess(Connection connection) {
|
||||
PeerExchangeHandler.this.connection = connection;
|
||||
connection.addMessageListener(PeerExchangeHandler.this);
|
||||
log.trace("Send " + getPeersRequest + " to " + nodeAddress + " succeeded.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(@NotNull Throwable throwable) {
|
||||
String errorMessage = "Sending getPeersRequest to " + nodeAddress +
|
||||
" failed. That is expected if the peer is offline.\n\tgetPeersRequest=" + getPeersRequest +
|
||||
".\n\tException=" + throwable.getMessage();
|
||||
log.info(errorMessage);
|
||||
handleFault(errorMessage, CloseConnectionReason.SEND_MSG_FAILURE, nodeAddress);
|
||||
}
|
||||
});
|
||||
|
||||
checkArgument(timeoutTimer == null, "requestReportedPeers must not be called twice.");
|
||||
timeoutTimer = UserThread.runAfter(() -> {
|
||||
String errorMessage = "A timeout occurred at sending getPeersRequest:" + getPeersRequest + " for nodeAddress:" + nodeAddress;
|
||||
log.info(errorMessage + " / PeerExchangeHandshake=" +
|
||||
PeerExchangeHandler.this);
|
||||
log.info("timeoutTimer called on " + this);
|
||||
handleFault(errorMessage, CloseConnectionReason.SEND_MSG_TIMEOUT, nodeAddress);
|
||||
},
|
||||
TIME_OUT_SEC, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// MessageListener implementation
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
public void onMessage(Message message, Connection connection) {
|
||||
if (message instanceof GetPeersResponse) {
|
||||
GetPeersResponse getPeersResponse = (GetPeersResponse) message;
|
||||
// Check if the response is for our request
|
||||
if (getPeersResponse.requestNonce == nonce) {
|
||||
Log.traceCall(message.toString() + "\n\tconnection=" + connection);
|
||||
Log.traceCall("this=" + this);
|
||||
peerManager.addToReportedPeers(getPeersResponse.reportedPeers, connection);
|
||||
|
||||
cleanup();
|
||||
listener.onComplete();
|
||||
} else {
|
||||
log.trace("Nonce not matching. That message is not intended for us.\n\t" +
|
||||
"We drop that message. nonce={} / requestNonce={}",
|
||||
nonce, getPeersResponse.requestNonce);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Private
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private void handleFault(String errorMessage, CloseConnectionReason sendMsgFailure, NodeAddress nodeAddress) {
|
||||
// TODO retry
|
||||
cleanup();
|
||||
if (connection == null)
|
||||
peerManager.shutDownConnection(nodeAddress, sendMsgFailure);
|
||||
else
|
||||
peerManager.shutDownConnection(connection, sendMsgFailure);
|
||||
|
||||
listener.onFault(errorMessage, connection);
|
||||
}
|
||||
}
|
|
@ -1,219 +0,0 @@
|
|||
package io.bitsquare.p2p.peers;
|
||||
|
||||
import com.google.common.util.concurrent.FutureCallback;
|
||||
import com.google.common.util.concurrent.Futures;
|
||||
import com.google.common.util.concurrent.SettableFuture;
|
||||
import io.bitsquare.app.Log;
|
||||
import io.bitsquare.common.UserThread;
|
||||
import io.bitsquare.p2p.Message;
|
||||
import io.bitsquare.p2p.NodeAddress;
|
||||
import io.bitsquare.p2p.network.CloseConnectionReason;
|
||||
import io.bitsquare.p2p.network.Connection;
|
||||
import io.bitsquare.p2p.network.MessageListener;
|
||||
import io.bitsquare.p2p.network.NetworkNode;
|
||||
import io.bitsquare.p2p.peers.messages.peers.GetPeersRequest;
|
||||
import io.bitsquare.p2p.peers.messages.peers.GetPeersResponse;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.HashSet;
|
||||
import java.util.Random;
|
||||
import java.util.Timer;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
public class PeerExchangeHandshake implements MessageListener {
|
||||
private static final Logger log = LoggerFactory.getLogger(PeerExchangeHandshake.class);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Listener
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public interface Listener {
|
||||
void onComplete();
|
||||
|
||||
void onFault(String errorMessage, @Nullable Connection connection);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Class fields
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private final NetworkNode networkNode;
|
||||
private final PeerManager peerManager;
|
||||
private final Listener listener;
|
||||
private final long nonce = new Random().nextLong();
|
||||
private Timer timeoutTimer;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Constructor
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public PeerExchangeHandshake(NetworkNode networkNode, PeerManager peerManager, Listener listener) {
|
||||
this.networkNode = networkNode;
|
||||
this.peerManager = peerManager;
|
||||
this.listener = listener;
|
||||
|
||||
networkNode.addMessageListener(this);
|
||||
}
|
||||
|
||||
public void closeHandshake() {
|
||||
networkNode.removeMessageListener(this);
|
||||
stopTimeoutTimer();
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// API
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public void requestConnectedPeers(NodeAddress nodeAddress) {
|
||||
Log.traceCall("nodeAddress=" + nodeAddress + " / this=" + this);
|
||||
checkNotNull(networkNode.getNodeAddress(), "PeerExchangeHandshake.requestReportedPeers: My node address must " +
|
||||
"not be null at requestReportedPeers");
|
||||
GetPeersRequest getPeersRequest = new GetPeersRequest(networkNode.getNodeAddress(), nonce, getConnectedPeers(nodeAddress));
|
||||
SettableFuture<Connection> future = networkNode.sendMessage(nodeAddress, getPeersRequest);
|
||||
Futures.addCallback(future, new FutureCallback<Connection>() {
|
||||
@Override
|
||||
public void onSuccess(Connection connection) {
|
||||
log.trace("Send " + getPeersRequest + " to " + nodeAddress + " succeeded.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(@NotNull Throwable throwable) {
|
||||
String errorMessage = "Sending getPeersRequest to " + nodeAddress +
|
||||
" failed. That is expected if the peer is offline.\n\tgetPeersRequest=" + getPeersRequest +
|
||||
".\n\tException=" + throwable.getMessage();
|
||||
log.info(errorMessage);
|
||||
|
||||
peerManager.shutDownConnection(nodeAddress, CloseConnectionReason.SEND_MSG_FAILURE);
|
||||
closeHandshake();
|
||||
listener.onFault(errorMessage, null);
|
||||
}
|
||||
});
|
||||
|
||||
checkArgument(timeoutTimer == null, "requestReportedPeers must not be called twice.");
|
||||
timeoutTimer = UserThread.runAfter(() -> {
|
||||
String errorMessage = "A timeout occurred at sending getPeersRequest:" + getPeersRequest + " for nodeAddress:" + nodeAddress;
|
||||
log.info(errorMessage + " / PeerExchangeHandshake=" +
|
||||
PeerExchangeHandshake.this);
|
||||
|
||||
log.info("timeoutTimer called on " + this);
|
||||
peerManager.shutDownConnection(nodeAddress, CloseConnectionReason.SEND_MSG_TIMEOUT);
|
||||
closeHandshake();
|
||||
listener.onFault(errorMessage, null);
|
||||
},
|
||||
20, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
public void onGetPeersRequest(GetPeersRequest getPeersRequest, final Connection connection) {
|
||||
Log.traceCall("getPeersRequest=" + getPeersRequest + "\n\tconnection=" + connection + "\n\tthis=" + this);
|
||||
|
||||
HashSet<ReportedPeer> reportedPeers = getPeersRequest.reportedPeers;
|
||||
|
||||
/* StringBuilder result = new StringBuilder("Received peers:");
|
||||
reportedPeers.stream().forEach(e -> result.append("\n\t").append(e));
|
||||
log.trace(result.toString());*/
|
||||
log.trace("reportedPeers.size=" + reportedPeers.size());
|
||||
|
||||
checkArgument(connection.getPeersNodeAddressOptional().isPresent(),
|
||||
"The peers address must have been already set at the moment");
|
||||
GetPeersResponse getPeersResponse = new GetPeersResponse(getPeersRequest.nonce,
|
||||
getConnectedPeers(connection.getPeersNodeAddressOptional().get()));
|
||||
SettableFuture<Connection> future = networkNode.sendMessage(connection,
|
||||
getPeersResponse);
|
||||
Futures.addCallback(future, new FutureCallback<Connection>() {
|
||||
@Override
|
||||
public void onSuccess(Connection connection) {
|
||||
log.trace("GetPeersResponse sent successfully");
|
||||
closeHandshake();
|
||||
listener.onComplete();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(@NotNull Throwable throwable) {
|
||||
String errorMessage = "Sending getPeersRequest to " + connection +
|
||||
" failed. That is expected if the peer is offline. getPeersRequest=" + getPeersRequest + "." +
|
||||
"Exception: " + throwable.getMessage();
|
||||
log.info(errorMessage);
|
||||
|
||||
peerManager.shutDownConnection(connection, CloseConnectionReason.SEND_MSG_FAILURE);
|
||||
closeHandshake();
|
||||
listener.onFault(errorMessage, connection);
|
||||
}
|
||||
});
|
||||
|
||||
checkArgument(timeoutTimer == null, "onGetPeersRequest must not be called twice.");
|
||||
timeoutTimer = UserThread.runAfter(() -> {
|
||||
String errorMessage = "A timeout occurred at sending getPeersResponse:" + getPeersResponse + " on connection:" + connection;
|
||||
log.info(errorMessage + " / PeerExchangeHandshake=" +
|
||||
PeerExchangeHandshake.this);
|
||||
|
||||
log.info("timeoutTimer called. this=" + this);
|
||||
peerManager.shutDownConnection(connection, CloseConnectionReason.SEND_MSG_TIMEOUT);
|
||||
closeHandshake();
|
||||
listener.onFault(errorMessage, connection);
|
||||
},
|
||||
20, TimeUnit.SECONDS);
|
||||
|
||||
peerManager.addToReportedPeers(reportedPeers, connection);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// MessageListener implementation
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
public void onMessage(Message message, Connection connection) {
|
||||
if (message instanceof GetPeersResponse) {
|
||||
Log.traceCall(message.toString() + "\n\tconnection=" + connection);
|
||||
Log.traceCall("this=" + this);
|
||||
GetPeersResponse getPeersResponse = (GetPeersResponse) message;
|
||||
if (getPeersResponse.requestNonce == nonce) {
|
||||
stopTimeoutTimer();
|
||||
|
||||
HashSet<ReportedPeer> reportedPeers = getPeersResponse.reportedPeers;
|
||||
StringBuilder result = new StringBuilder("Received peers:");
|
||||
reportedPeers.stream().forEach(e -> result.append("\n\t").append(e));
|
||||
log.trace(result.toString());
|
||||
peerManager.addToReportedPeers(reportedPeers, connection);
|
||||
|
||||
closeHandshake();
|
||||
listener.onComplete();
|
||||
} else {
|
||||
log.debug("Nonce not matching. That can happen rarely if we get a response after a canceled handshake " +
|
||||
"(timeout causes connection close but peer might have sent a msg before connection " +
|
||||
"was closed).\n\tWe drop that message. nonce={} / requestNonce={}",
|
||||
nonce, getPeersResponse.requestNonce);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Private
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private HashSet<ReportedPeer> getConnectedPeers(NodeAddress receiverNodeAddress) {
|
||||
return new HashSet<>(peerManager.getConnectedPeers().stream()
|
||||
.filter(e -> !peerManager.isSeedNode(e) &&
|
||||
!e.nodeAddress.equals(receiverNodeAddress)
|
||||
)
|
||||
.collect(Collectors.toSet()));
|
||||
}
|
||||
|
||||
private void stopTimeoutTimer() {
|
||||
if (timeoutTimer != null) {
|
||||
timeoutTimer.cancel();
|
||||
timeoutTimer = null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,16 +1,20 @@
|
|||
package io.bitsquare.p2p.peers;
|
||||
|
||||
import com.google.common.util.concurrent.MoreExecutors;
|
||||
import io.bitsquare.app.Log;
|
||||
import io.bitsquare.common.UserThread;
|
||||
import io.bitsquare.common.util.Utilities;
|
||||
import io.bitsquare.p2p.Message;
|
||||
import io.bitsquare.p2p.NodeAddress;
|
||||
import io.bitsquare.p2p.network.*;
|
||||
import io.bitsquare.p2p.peers.messages.peers.GetPeersRequest;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
|
@ -19,13 +23,17 @@ import static com.google.common.base.Preconditions.checkNotNull;
|
|||
public class PeerExchangeManager implements MessageListener, ConnectionListener {
|
||||
private static final Logger log = LoggerFactory.getLogger(PeerExchangeManager.class);
|
||||
|
||||
private static final long RETRY_DELAY_SEC = 60;
|
||||
private static final long MAINTENANCE_DELAY_SEC = 5;
|
||||
|
||||
private final NetworkNode networkNode;
|
||||
private final PeerManager peerManager;
|
||||
private final Set<NodeAddress> seedNodeAddresses;
|
||||
private final Map<NodeAddress, PeerExchangeHandshake> peerExchangeHandshakeMap = new HashMap<>();
|
||||
private final Map<NodeAddress, PeerExchangeHandler> peerExchangeHandlerMap = new HashMap<>();
|
||||
private Timer connectToMorePeersTimer;
|
||||
private boolean shutDownInProgress;
|
||||
|
||||
private ScheduledThreadPoolExecutor executor;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Constructor
|
||||
|
@ -38,15 +46,19 @@ public class PeerExchangeManager implements MessageListener, ConnectionListener
|
|||
this.seedNodeAddresses = new HashSet<>(seedNodeAddresses);
|
||||
|
||||
networkNode.addMessageListener(this);
|
||||
networkNode.addConnectionListener(this);
|
||||
}
|
||||
|
||||
public void shutDown() {
|
||||
Log.traceCall();
|
||||
shutDownInProgress = true;
|
||||
|
||||
networkNode.removeMessageListener(this);
|
||||
networkNode.removeConnectionListener(this);
|
||||
stopConnectToMorePeersTimer();
|
||||
peerExchangeHandshakeMap.values().stream().forEach(PeerExchangeHandshake::closeHandshake);
|
||||
peerExchangeHandlerMap.values().stream().forEach(PeerExchangeHandler::cleanup);
|
||||
|
||||
if (executor != null)
|
||||
MoreExecutors.shutdownAndAwaitTermination(executor, 100, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
|
||||
|
@ -60,8 +72,13 @@ public class PeerExchangeManager implements MessageListener, ConnectionListener
|
|||
remainingNodeAddresses.remove(nodeAddress);
|
||||
Collections.shuffle(remainingNodeAddresses);
|
||||
requestReportedPeers(nodeAddress, remainingNodeAddresses);
|
||||
}
|
||||
|
||||
if (executor == null) {
|
||||
executor = Utilities.getScheduledThreadPoolExecutor("PeerExchangeManager", 1, 2, 5);
|
||||
executor.scheduleAtFixedRate(() -> UserThread.execute(this::requestAgain),
|
||||
MAINTENANCE_DELAY_SEC, MAINTENANCE_DELAY_SEC, TimeUnit.SECONDS);
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// ConnectionListener implementation
|
||||
|
@ -73,6 +90,12 @@ public class PeerExchangeManager implements MessageListener, ConnectionListener
|
|||
|
||||
@Override
|
||||
public void onDisconnect(CloseConnectionReason closeConnectionReason, Connection connection) {
|
||||
if (connectToMorePeersTimer == null)
|
||||
connectToMorePeersTimer = UserThread.runAfter(() -> {
|
||||
log.trace("ConnectToMorePeersTimer called from onDisconnect code path");
|
||||
stopConnectToMorePeersTimer();
|
||||
requestWithAvailablePeers();
|
||||
}, RETRY_DELAY_SEC);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -88,41 +111,41 @@ public class PeerExchangeManager implements MessageListener, ConnectionListener
|
|||
public void onMessage(Message message, Connection connection) {
|
||||
if (message instanceof GetPeersRequest) {
|
||||
Log.traceCall(message.toString() + "\n\tconnection=" + connection);
|
||||
PeerExchangeHandshake peerExchangeHandshake = new PeerExchangeHandshake(networkNode,
|
||||
GetPeersRequestHandler getPeersRequestHandler = new GetPeersRequestHandler(networkNode,
|
||||
peerManager,
|
||||
new PeerExchangeHandshake.Listener() {
|
||||
new GetPeersRequestHandler.Listener() {
|
||||
@Override
|
||||
public void onComplete() {
|
||||
log.trace("PeerExchangeHandshake of inbound connection complete.\n\tConnection={}", connection);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFault(String errorMessage, @Nullable Connection connection) {
|
||||
public void onFault(String errorMessage, Connection connection) {
|
||||
log.trace("PeerExchangeHandshake of outbound connection failed.\n\terrorMessage={}\n\t" +
|
||||
"connection={}", errorMessage, connection);
|
||||
peerManager.handleConnectionFault(connection);
|
||||
}
|
||||
});
|
||||
peerExchangeHandshake.onGetPeersRequest((GetPeersRequest) message, connection);
|
||||
getPeersRequestHandler.process((GetPeersRequest) message, connection);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Private
|
||||
// Request
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private void requestReportedPeers(NodeAddress nodeAddress, List<NodeAddress> remainingNodeAddresses) {
|
||||
Log.traceCall("nodeAddress=" + nodeAddress);
|
||||
if (!peerExchangeHandshakeMap.containsKey(nodeAddress)) {
|
||||
PeerExchangeHandshake peerExchangeHandshake = new PeerExchangeHandshake(networkNode,
|
||||
if (!peerExchangeHandlerMap.containsKey(nodeAddress)) {
|
||||
PeerExchangeHandler peerExchangeHandler = new PeerExchangeHandler(networkNode,
|
||||
peerManager,
|
||||
new PeerExchangeHandshake.Listener() {
|
||||
new PeerExchangeHandler.Listener() {
|
||||
@Override
|
||||
public void onComplete() {
|
||||
log.trace("PeerExchangeHandshake of outbound connection complete. nodeAddress={}", nodeAddress);
|
||||
peerExchangeHandshakeMap.remove(nodeAddress);
|
||||
connectToMorePeers();
|
||||
peerExchangeHandlerMap.remove(nodeAddress);
|
||||
requestWithAvailablePeers();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -130,26 +153,36 @@ public class PeerExchangeManager implements MessageListener, ConnectionListener
|
|||
log.trace("PeerExchangeHandshake of outbound connection failed.\n\terrorMessage={}\n\t" +
|
||||
"nodeAddress={}", errorMessage, nodeAddress);
|
||||
|
||||
peerExchangeHandshakeMap.remove(nodeAddress);
|
||||
peerExchangeHandlerMap.remove(nodeAddress);
|
||||
peerManager.handleConnectionFault(nodeAddress, connection);
|
||||
if (!shutDownInProgress) {
|
||||
if (!remainingNodeAddresses.isEmpty()) {
|
||||
log.info("There are remaining nodes available for requesting peers. " +
|
||||
"We will try getReportedPeers again.");
|
||||
requestReportedPeersFromRandomPeer(remainingNodeAddresses);
|
||||
if (!peerManager.hasSufficientConnections()) {
|
||||
log.info("There are remaining nodes available for requesting peers. " +
|
||||
"We will try getReportedPeers again.");
|
||||
NodeAddress nextCandidate = remainingNodeAddresses.get(new Random().nextInt(remainingNodeAddresses.size()));
|
||||
remainingNodeAddresses.remove(nextCandidate);
|
||||
requestReportedPeers(nextCandidate, remainingNodeAddresses);
|
||||
} else {
|
||||
// That path will rarely be reached
|
||||
log.info("We have already sufficient connections.");
|
||||
}
|
||||
} else {
|
||||
log.info("There is no remaining node available for requesting peers. " +
|
||||
"That is expected if no other node is online.\n\t" +
|
||||
"We will try again after a random pause.");
|
||||
"We will try again after a pause.");
|
||||
if (connectToMorePeersTimer == null)
|
||||
connectToMorePeersTimer = UserThread.runAfterRandomDelay(
|
||||
PeerExchangeManager.this::connectToMorePeers, 20, 30);
|
||||
connectToMorePeersTimer = UserThread.runAfter(() -> {
|
||||
log.trace("ConnectToMorePeersTimer called from requestReportedPeers code path");
|
||||
stopConnectToMorePeersTimer();
|
||||
requestWithAvailablePeers();
|
||||
}, RETRY_DELAY_SEC);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
peerExchangeHandshakeMap.put(nodeAddress, peerExchangeHandshake);
|
||||
peerExchangeHandshake.requestConnectedPeers(nodeAddress);
|
||||
peerExchangeHandlerMap.put(nodeAddress, peerExchangeHandler);
|
||||
peerExchangeHandler.requestConnectedPeers(nodeAddress);
|
||||
} else {
|
||||
//TODO check when that happens
|
||||
log.warn("We have started already a peerExchangeHandshake. " +
|
||||
|
@ -158,59 +191,86 @@ public class PeerExchangeManager implements MessageListener, ConnectionListener
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
private void connectToMorePeers() {
|
||||
private void requestWithAvailablePeers() {
|
||||
Log.traceCall();
|
||||
|
||||
stopConnectToMorePeersTimer();
|
||||
|
||||
if (!peerManager.hasSufficientConnections()) {
|
||||
// We create a new list of not connected candidates
|
||||
// 1. reported sorted by most recent lastActivityDate
|
||||
// 2. persisted sorted by most recent lastActivityDate
|
||||
// 3. seenNodes
|
||||
List<NodeAddress> list = new ArrayList<>(getFilteredAndSortedList(peerManager.getReportedPeers(), new ArrayList<>()));
|
||||
list.addAll(getFilteredAndSortedList(peerManager.getPersistedPeers(), list));
|
||||
ArrayList<NodeAddress> seedNodeAddresses = new ArrayList<>(this.seedNodeAddresses);
|
||||
Collections.shuffle(seedNodeAddresses);
|
||||
list.addAll(seedNodeAddresses.stream()
|
||||
.filter(e -> !list.contains(e) &&
|
||||
!peerManager.isSelf(e) &&
|
||||
!peerManager.isConfirmed(e))
|
||||
.collect(Collectors.toSet()));
|
||||
log.info("Sorted and filtered list: list.size()=" + list.size());
|
||||
log.trace("Sorted and filtered list: list=" + list);
|
||||
// 1. reported shuffled peers
|
||||
// 2. persisted shuffled peers
|
||||
// 3. Add as last shuffled seedNodes (least priority)
|
||||
List<NodeAddress> list = getFilteredNonSeedNodeList(getNodeAddresses(peerManager.getReportedPeers()), new ArrayList<>());
|
||||
Collections.shuffle(list);
|
||||
|
||||
List<NodeAddress> filteredPersistedPeers = getFilteredNonSeedNodeList(getNodeAddresses(peerManager.getPersistedPeers()), list);
|
||||
Collections.shuffle(filteredPersistedPeers);
|
||||
list.addAll(filteredPersistedPeers);
|
||||
|
||||
List<NodeAddress> filteredSeedNodeAddresses = getFilteredList(new ArrayList<>(seedNodeAddresses), list);
|
||||
Collections.shuffle(filteredSeedNodeAddresses);
|
||||
list.addAll(filteredSeedNodeAddresses);
|
||||
|
||||
log.info("Number of peers in list for connectToMorePeers: {}", list.size());
|
||||
log.trace("Filtered connectToMorePeers list: list=" + list);
|
||||
if (!list.isEmpty()) {
|
||||
// Dont shuffle as we want the seed nodes at the last entries
|
||||
NodeAddress nextCandidate = list.get(0);
|
||||
list.remove(nextCandidate);
|
||||
requestReportedPeers(nextCandidate, list);
|
||||
} else {
|
||||
log.info("No more peers are available for requestReportedPeers.");
|
||||
log.info("No more peers are available for requestReportedPeers. We will try again after a pause.");
|
||||
if (connectToMorePeersTimer == null)
|
||||
connectToMorePeersTimer = UserThread.runAfter(() -> {
|
||||
log.trace("ConnectToMorePeersTimer called from requestWithAvailablePeers code path");
|
||||
stopConnectToMorePeersTimer();
|
||||
requestWithAvailablePeers();
|
||||
}, RETRY_DELAY_SEC);
|
||||
}
|
||||
} else {
|
||||
log.info("We have already sufficient connections.");
|
||||
}
|
||||
}
|
||||
|
||||
// sorted by most recent lastActivityDate
|
||||
private List<NodeAddress> getFilteredAndSortedList(Set<ReportedPeer> set, List<NodeAddress> list) {
|
||||
return set.stream()
|
||||
.filter(e -> !list.contains(e.nodeAddress) &&
|
||||
!peerManager.isSeedNode(e) &&
|
||||
!peerManager.isSelf(e) &&
|
||||
!peerManager.isConfirmed(e))
|
||||
.collect(Collectors.toList())
|
||||
.stream()
|
||||
.filter(e -> e.lastActivityDate != null)
|
||||
.sorted((o1, o2) -> o2.lastActivityDate.compareTo(o1.lastActivityDate))
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Maintenance
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private void requestAgain() {
|
||||
checkNotNull(networkNode.getNodeAddress(), "My node address must not be null at sendUpdateRequest");
|
||||
Set<NodeAddress> candidates = new HashSet<>(getNodeAddresses(peerManager.getReportedPeers()));
|
||||
candidates.addAll(getNodeAddresses(peerManager.getPersistedPeers()));
|
||||
candidates.addAll(seedNodeAddresses);
|
||||
candidates.remove(networkNode.getNodeAddress());
|
||||
ArrayList<NodeAddress> list = new ArrayList<>(candidates);
|
||||
Collections.shuffle(list);
|
||||
NodeAddress candidate = list.remove(0);
|
||||
requestReportedPeers(candidate, list);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Utils
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private List<NodeAddress> getNodeAddresses(Collection<ReportedPeer> collection) {
|
||||
return collection.stream()
|
||||
.map(e -> e.nodeAddress)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private void requestReportedPeersFromRandomPeer(List<NodeAddress> remainingNodeAddresses) {
|
||||
NodeAddress nextCandidate = remainingNodeAddresses.get(new Random().nextInt(remainingNodeAddresses.size()));
|
||||
remainingNodeAddresses.remove(nextCandidate);
|
||||
requestReportedPeers(nextCandidate, remainingNodeAddresses);
|
||||
private List<NodeAddress> getFilteredList(Collection<NodeAddress> collection, List<NodeAddress> list) {
|
||||
return collection.stream()
|
||||
.filter(e -> !list.contains(e) &&
|
||||
!peerManager.isSelf(e) &&
|
||||
!peerManager.isConfirmed(e))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private List<NodeAddress> getFilteredNonSeedNodeList(Collection<NodeAddress> collection, List<NodeAddress> list) {
|
||||
return getFilteredList(collection, list).stream()
|
||||
.filter(e -> !peerManager.isSeedNode(e))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private void stopConnectToMorePeersTimer() {
|
||||
|
|
|
@ -15,7 +15,6 @@ import javax.annotation.Nullable;
|
|||
import java.io.File;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
|
@ -32,6 +31,7 @@ public class PeerManager implements ConnectionListener, MessageListener {
|
|||
private static int MAX_CONNECTIONS_EXTENDED_1;
|
||||
private static int MAX_CONNECTIONS_EXTENDED_2;
|
||||
private static int MAX_CONNECTIONS_EXTENDED_3;
|
||||
private boolean printReportedPeersDetails = true;
|
||||
|
||||
public static void setMaxConnections(int maxConnections) {
|
||||
MAX_CONNECTIONS = maxConnections;
|
||||
|
@ -271,87 +271,48 @@ public class PeerManager implements ConnectionListener, MessageListener {
|
|||
}
|
||||
|
||||
public void addToReportedPeers(HashSet<ReportedPeer> reportedPeersToAdd, Connection connection) {
|
||||
// we disconnect misbehaving nodes trying to send too many peers
|
||||
// reported peers include the connected peers which is normally max. 10 but we give some headroom
|
||||
// for safety
|
||||
if (reportedPeersToAdd.size() > (MAX_REPORTED_PEERS + PeerManager.MIN_CONNECTIONS * 3)) {
|
||||
// Will trigger a shutdown after 2nd time sending too much
|
||||
connection.reportIllegalRequest(RuleViolation.TOO_MANY_REPORTED_PEERS_SENT);
|
||||
} else {
|
||||
// In case we have one of the peers already we adjust the lastActivityDate by adjusting the date to the mid
|
||||
// of the lastActivityDate of our already stored peer and the reported one
|
||||
Map<ReportedPeer, ReportedPeer> reportedPeersMap = reportedPeers.stream()
|
||||
.collect(Collectors.toMap(e -> e, Function.identity()));
|
||||
HashSet<ReportedPeer> adjustedReportedPeers = new HashSet<>();
|
||||
reportedPeersToAdd.stream()
|
||||
.filter(e -> e.nodeAddress != null &&
|
||||
!e.nodeAddress.equals(networkNode.getNodeAddress()) &&
|
||||
!getConnectedPeers().contains(e))
|
||||
.forEach(e -> {
|
||||
if (reportedPeersMap.containsKey(e)) {
|
||||
if (e.lastActivityDate != null && reportedPeersMap.get(e).lastActivityDate != null) {
|
||||
long adjustedTime = (e.lastActivityDate.getTime() +
|
||||
reportedPeersMap.get(e).lastActivityDate.getTime()) / 2;
|
||||
adjustedReportedPeers.add(new ReportedPeer(e.nodeAddress,
|
||||
new Date(adjustedTime)));
|
||||
} else if (e.lastActivityDate == null) {
|
||||
adjustedReportedPeers.add(reportedPeersMap.get(e));
|
||||
} else if (reportedPeersMap.get(e).lastActivityDate == null) {
|
||||
adjustedReportedPeers.add(e);
|
||||
}
|
||||
} else {
|
||||
adjustedReportedPeers.add(e);
|
||||
}
|
||||
});
|
||||
|
||||
reportedPeers.addAll(adjustedReportedPeers);
|
||||
printReportedPeers(reportedPeersToAdd);
|
||||
|
||||
// We check if the reported msg is not violating our rules
|
||||
if (reportedPeersToAdd.size() <= (MAX_REPORTED_PEERS + PeerManager.MAX_CONNECTIONS_EXTENDED_3 + 10)) {
|
||||
reportedPeers.addAll(reportedPeersToAdd);
|
||||
purgeReportedPeersIfExceeds();
|
||||
|
||||
persistedPeers.addAll(reportedPeersToAdd);
|
||||
persistedPeers.addAll(new HashSet<>(getConnectedPeers()));
|
||||
|
||||
// We remove if we exceeds MAX_PERSISTED_PEERS limit
|
||||
int toRemove = persistedPeers.size() - MAX_PERSISTED_PEERS;
|
||||
if (toRemove > 0) {
|
||||
int toRemove1 = toRemove / 2;
|
||||
if (toRemove1 > 0) {
|
||||
// we remove the first half randomly to avoid attack vectors with lastActivityDate
|
||||
List<ReportedPeer> list = new ArrayList<>(persistedPeers);
|
||||
for (int i = 0; i < toRemove1; i++) {
|
||||
persistedPeers.remove(list.get(i));
|
||||
}
|
||||
int toRemove2 = toRemove - toRemove1;
|
||||
if (toRemove2 > 0) {
|
||||
// now we remove second half with a list sorted by oldest lastActivityDate
|
||||
list = new ArrayList<>(persistedPeers);
|
||||
list = list.stream().filter(e -> e.lastActivityDate != null).collect(Collectors.toList());
|
||||
list.sort((o1, o2) -> o1.lastActivityDate.compareTo(o2.lastActivityDate));
|
||||
for (int i = 0; i < toRemove2; i++) {
|
||||
persistedPeers.remove(list.get(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
purgePersistedPeersIfExceeds();
|
||||
if (dbStorage != null)
|
||||
dbStorage.queueUpForSave(persistedPeers, 2000);
|
||||
}
|
||||
|
||||
printReportedPeers();
|
||||
printReportedPeers();
|
||||
} else {
|
||||
// If a node is trying to send too many peers we treat it as rule violation.
|
||||
// Reported peers include the connected peers. We use the max value and give some extra headroom.
|
||||
// Will trigger a shutdown after 2nd time sending too much
|
||||
connection.reportIllegalRequest(RuleViolation.TOO_MANY_REPORTED_PEERS_SENT);
|
||||
}
|
||||
}
|
||||
|
||||
private void printReportedPeers() {
|
||||
if (!reportedPeers.isEmpty()) {
|
||||
StringBuilder result = new StringBuilder("\n\n------------------------------------------------------------\n" +
|
||||
"Reported peers:");
|
||||
reportedPeers.stream().forEach(e -> result.append("\n").append(e));
|
||||
result.append("\n------------------------------------------------------------\n");
|
||||
//log.trace(result.toString());
|
||||
log.info("Number of reported peers: {}", reportedPeers.size());
|
||||
if (printReportedPeersDetails) {
|
||||
StringBuilder result = new StringBuilder("\n\n------------------------------------------------------------\n" +
|
||||
"Collected reported peers:");
|
||||
reportedPeers.stream().forEach(e -> result.append("\n").append(e));
|
||||
result.append("\n------------------------------------------------------------\n");
|
||||
log.info(result.toString());
|
||||
}
|
||||
log.info("Number of collected reported peers: {}", reportedPeers.size());
|
||||
}
|
||||
}
|
||||
|
||||
public void printReportedPeers(HashSet<ReportedPeer> reportedPeers) {
|
||||
if (printReportedPeersDetails) {
|
||||
StringBuilder result = new StringBuilder("We received now reportedPeers:");
|
||||
reportedPeers.stream().forEach(e -> result.append("\n\t").append(e));
|
||||
log.info(result.toString());
|
||||
}
|
||||
log.info("Number of new arrived reported peers: {}", reportedPeers.size());
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Persisted peers
|
||||
|
@ -455,6 +416,7 @@ public class PeerManager implements ConnectionListener, MessageListener {
|
|||
return isConfirmed(reportedPeer.nodeAddress);
|
||||
}
|
||||
|
||||
// Checks if that connection has the peers node address
|
||||
public boolean isConfirmed(NodeAddress nodeAddress) {
|
||||
return networkNode.getNodeAddressesOfConfirmedConnections().contains(nodeAddress);
|
||||
}
|
||||
|
@ -480,22 +442,41 @@ public class PeerManager implements ConnectionListener, MessageListener {
|
|||
private void purgeReportedPeersIfExceeds() {
|
||||
Log.traceCall();
|
||||
int size = getReportedPeers().size();
|
||||
if (size > MAX_REPORTED_PEERS) {
|
||||
log.trace("We have more then {} reported peers. size={}. " +
|
||||
"We remove random peers from the reported peers list.", MAX_REPORTED_PEERS, size);
|
||||
int diff = size - MAX_REPORTED_PEERS;
|
||||
int limit = MAX_REPORTED_PEERS - MAX_CONNECTIONS_EXTENDED_3;
|
||||
if (size > limit) {
|
||||
log.trace("We have already {} reported peers which exceeds our limit of {}." +
|
||||
"We remove random peers from the reported peers list.", size, limit);
|
||||
int diff = size - limit;
|
||||
List<ReportedPeer> list = new ArrayList<>(getReportedPeers());
|
||||
// we dont use sorting by lastActivityDate to avoid attack vectors and keep it more random
|
||||
for (int i = 0; i < diff; i++) {
|
||||
ReportedPeer toRemove = getAndRemoveRandomReportedPeer(list);
|
||||
removeReportedPeer(toRemove);
|
||||
removePersistedPeer(toRemove);
|
||||
}
|
||||
} else {
|
||||
log.trace("No need to purge reported peers.\n\tWe don't have more then {} reported peers yet.", MAX_REPORTED_PEERS);
|
||||
}
|
||||
}
|
||||
|
||||
private void purgePersistedPeersIfExceeds() {
|
||||
Log.traceCall();
|
||||
int size = getPersistedPeers().size();
|
||||
int limit = MAX_REPORTED_PEERS - MAX_CONNECTIONS_EXTENDED_3;
|
||||
if (size > limit) {
|
||||
log.trace("We have already {} persisted peers which exceeds our limit of {}." +
|
||||
"We remove random peers from the persisted peers list.", size, limit);
|
||||
int diff = size - limit;
|
||||
List<ReportedPeer> list = new ArrayList<>(getReportedPeers());
|
||||
// we dont use sorting by lastActivityDate to avoid attack vectors and keep it more random
|
||||
for (int i = 0; i < diff; i++) {
|
||||
ReportedPeer toRemove = getAndRemoveRandomReportedPeer(list);
|
||||
removePersistedPeer(toRemove);
|
||||
}
|
||||
} else {
|
||||
log.trace("No need to purge persisted peers.\n\tWe don't have more then {} persisted peers yet.", MAX_REPORTED_PEERS);
|
||||
}
|
||||
}
|
||||
|
||||
private ReportedPeer getAndRemoveRandomReportedPeer(List<ReportedPeer> list) {
|
||||
checkArgument(!list.isEmpty(), "List must not be empty");
|
||||
return list.remove(new Random().nextInt(list.size()));
|
||||
|
@ -509,6 +490,18 @@ public class PeerManager implements ConnectionListener, MessageListener {
|
|||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
public HashSet<ReportedPeer> getConnectedPeersNonSeedNodes() {
|
||||
return new HashSet<>(getConnectedPeers().stream()
|
||||
.filter(e -> !isSeedNode(e))
|
||||
.collect(Collectors.toSet()));
|
||||
}
|
||||
|
||||
public HashSet<ReportedPeer> getConnectedPeersNonSeedNodes(NodeAddress excludedNodeAddress) {
|
||||
return new HashSet<>(getConnectedPeersNonSeedNodes().stream()
|
||||
.filter(e -> !e.nodeAddress.equals(excludedNodeAddress))
|
||||
.collect(Collectors.toSet()));
|
||||
}
|
||||
|
||||
private void stopCheckMaxConnectionsTimer() {
|
||||
if (checkMaxConnectionsTimer != null) {
|
||||
checkMaxConnectionsTimer.cancel();
|
||||
|
|
|
@ -22,6 +22,9 @@ import static com.google.common.base.Preconditions.checkArgument;
|
|||
public class RequestDataManager implements MessageListener {
|
||||
private static final Logger log = LoggerFactory.getLogger(RequestDataManager.class);
|
||||
|
||||
private static final long RETRY_DELAY_SEC = 10;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Listener
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -193,7 +196,7 @@ public class RequestDataManager implements MessageListener {
|
|||
|
||||
// try again after a pause
|
||||
stopRequestDataTimer();
|
||||
requestDataTimer = UserThread.runAfterRandomDelay(() -> {
|
||||
requestDataTimer = UserThread.runAfter(() -> {
|
||||
log.trace("requestDataAfterDelayTimer called");
|
||||
// We want to keep it sorted but avoid duplicates
|
||||
// We don't filter out already established connections for seed nodes as it might be that
|
||||
|
@ -208,7 +211,7 @@ public class RequestDataManager implements MessageListener {
|
|||
list.remove(nextCandidate);
|
||||
requestData(nextCandidate, list);
|
||||
},
|
||||
10, 15, TimeUnit.SECONDS);
|
||||
RETRY_DELAY_SEC, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
requestDataHandshakeMap.remove(nodeAddress);
|
||||
|
|
|
@ -32,14 +32,12 @@ public class SeedNodesRepository {
|
|||
new NodeAddress("izs5oz7i5ta7c2ir.onion:8000"),*/
|
||||
|
||||
// v0.3.5
|
||||
new NodeAddress("que4ysbd2qazkb7d.onion:8000"),
|
||||
new NodeAddress("h2crs2j5huhclkc6.onion:8000"),
|
||||
new NodeAddress("7a3sj4j6yw5oukai.onion:8000"),
|
||||
new NodeAddress("hulvbm5xjn7b7ku4.onion:8000"),
|
||||
new NodeAddress("3efgjjbdvhbvck3x.onion:8000"),
|
||||
new NodeAddress("3unfcshgwipxhxfm.onion:8000"),
|
||||
|
||||
// testnet
|
||||
new NodeAddress("znmy44wcstn2rkva.onion:8001"),
|
||||
/* new NodeAddress("zvn7umikgxml6x6h.onion:8001"),
|
||||
new NodeAddress("wnfxmrmsyeeos2dy.onion:8001"),*/
|
||||
|
||||
// regtest
|
||||
// For development you need to change that to your local onion addresses
|
||||
|
|
|
@ -15,7 +15,10 @@ public class ProtectedData implements Serializable {
|
|||
private static final Logger log = LoggerFactory.getLogger(P2PDataStorage.class);
|
||||
|
||||
public final ExpirableMessage expirableMessage;
|
||||
|
||||
//TODO check if that field make sense as it is in expirableMessage.getTTL()
|
||||
transient public long ttl;
|
||||
|
||||
public final PublicKey ownerPubKey;
|
||||
public final int sequenceNumber;
|
||||
public final byte[] signature;
|
||||
|
|
Loading…
Add table
Reference in a new issue