Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add check for account age to apply restrictions #2801

Merged
merged 15 commits into from
May 3, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions common/src/main/java/bisq/common/app/Version.java
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ private static int getSubVersion(String version, int index) {

// The version no. of the current protocol. The offer holds that version.
// A taker will check the version of the offers to see if his version is compatible.
// Offers created with the old version will become invalid and have to be canceled.
// VERSION = 0.5.0 -> TRADE_PROTOCOL_VERSION = 1
public static final int TRADE_PROTOCOL_VERSION = 1;
private static int p2pMessageVersion;
Expand Down
25 changes: 21 additions & 4 deletions core/src/main/java/bisq/core/app/BisqSetup.java
Original file line number Diff line number Diff line change
Expand Up @@ -649,11 +649,28 @@ private void initDomainServices() {
filterManager.onAllServicesInitialized();
filterManager.addListener(filter -> {
if (filter != null && filterWarningHandler != null) {
if (filter.getSeedNodes() != null && !filter.getSeedNodes().isEmpty())
filterWarningHandler.accept(Res.get("popup.warning.nodeBanned", Res.get("popup.warning.seed")));
if (filter.getSeedNodes() != null && !filter.getSeedNodes().isEmpty()) {
log.warn(Res.get("popup.warning.nodeBanned", Res.get("popup.warning.seed")));
// Lets keep that more silent. Might be used in case a node is unstable and we don't want to confuse users.
// filterWarningHandler.accept(Res.get("popup.warning.nodeBanned", Res.get("popup.warning.seed")));
}

if (filter.getPriceRelayNodes() != null && !filter.getPriceRelayNodes().isEmpty()) {
log.warn(Res.get("popup.warning.nodeBanned", Res.get("popup.warning.priceRelay")));
// Lets keep that more silent. Might be used in case a node is unstable and we don't want to confuse users.
// filterWarningHandler.accept(Res.get("popup.warning.nodeBanned", Res.get("popup.warning.priceRelay")));
}

if (filter.getPriceRelayNodes() != null && !filter.getPriceRelayNodes().isEmpty())
filterWarningHandler.accept(Res.get("popup.warning.nodeBanned", Res.get("popup.warning.priceRelay")));
if (filterManager.requireUpdateToNewVersionForTrading()) {
filterWarningHandler.accept(Res.get("popup.warning.mandatoryUpdate.trading"));
}

if (filterManager.requireUpdateToNewVersionForDAO()) {
filterWarningHandler.accept(Res.get("popup.warning.mandatoryUpdate.dao"));
}
if (filter.isDisableDao()) {
filterWarningHandler.accept(Res.get("popup.warning.disable.dao"));
}
}
});

Expand Down
22 changes: 19 additions & 3 deletions core/src/main/java/bisq/core/arbitration/DisputeManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -878,10 +878,9 @@ private void onDisputeResultMessage(DisputeResultMessage disputeResultMessage) {
}
return;
}

Dispute dispute = disputeOptional.get();
try {
cleanupRetryMap(uid);
Dispute dispute = disputeOptional.get();
arbitratorsPubKeyRing = dispute.getArbitratorPubKeyRing();
DisputeCommunicationMessage disputeCommunicationMessage = disputeResult.getDisputeCommunicationMessage();
if (!dispute.getDisputeCommunicationMessages().contains(disputeCommunicationMessage))
Expand Down Expand Up @@ -997,7 +996,24 @@ public void onFailure(TxBroadcastException exception) {

success = true;
}
} catch (AddressFormatException | WalletException | TransactionVerificationException e) {
} catch (TransactionVerificationException e) {
e.printStackTrace();
errorMessage = "Error at traderSignAndFinalizeDisputedPayoutTx " + e.toString();
log.error(errorMessage);
success = false;

// We prefer to close the dispute in that case. If there was no deposit tx and a random tx was used
// we get a TransactionVerificationException. No reason to keep that dispute open...
if (tradeManager.getTradeById(dispute.getTradeId()).isPresent())
tradeManager.closeDisputedTrade(dispute.getTradeId());
else {
Optional<OpenOffer> openOfferOptional = openOfferManager.getOpenOfferById(dispute.getTradeId());
openOfferOptional.ifPresent(openOffer -> openOfferManager.closeOpenOffer(openOffer.getOffer()));
}
dispute.setIsClosed(true);

throw new RuntimeException(errorMessage);
} catch (AddressFormatException | WalletException e) {
e.printStackTrace();
errorMessage = "Error at traderSignAndFinalizeDisputedPayoutTx " + e.toString();
log.error(errorMessage);
Expand Down
16 changes: 15 additions & 1 deletion core/src/main/java/bisq/core/filter/FilterManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -350,7 +350,7 @@ public boolean isNodeAddressBanned(NodeAddress nodeAddress) {
.anyMatch(e -> e.equals(nodeAddress.getFullAddress()));
}

public boolean requireUpdateToNewVersion() {
public boolean requireUpdateToNewVersionForTrading() {
if (getFilter() == null) {
return false;
}
Expand All @@ -364,6 +364,20 @@ public boolean requireUpdateToNewVersion() {
return requireUpdateToNewVersion;
}

public boolean requireUpdateToNewVersionForDAO() {
if (getFilter() == null) {
return false;
}

boolean requireUpdateToNewVersion = false;
String disableDaoBelowVersion = getFilter().getDisableDaoBelowVersion();
if (disableDaoBelowVersion != null && !disableDaoBelowVersion.isEmpty()) {
requireUpdateToNewVersion = Version.isNewVersion(disableDaoBelowVersion);
}

return requireUpdateToNewVersion;
}

public boolean isPeersPaymentAccountDataAreBanned(PaymentAccountPayload paymentAccountPayload,
PaymentAccountFilter[] appliedPaymentAccountFilter) {
return getFilter() != null &&
Expand Down
15 changes: 15 additions & 0 deletions core/src/main/java/bisq/core/offer/OfferBookService.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
package bisq.core.offer;

import bisq.core.app.AppOptionKeys;
import bisq.core.filter.FilterManager;
import bisq.core.locale.Res;
import bisq.core.provider.price.PriceFeedService;

import bisq.network.p2p.BootstrapListener;
Expand Down Expand Up @@ -63,6 +65,7 @@ public interface OfferBookChangedListener {
private final P2PService p2PService;
private final PriceFeedService priceFeedService;
private final List<OfferBookChangedListener> offerBookChangedListeners = new LinkedList<>();
private final FilterManager filterManager;
private final JsonFileManager jsonFileManager;


Expand All @@ -73,10 +76,12 @@ public interface OfferBookChangedListener {
@Inject
public OfferBookService(P2PService p2PService,
PriceFeedService priceFeedService,
FilterManager filterManager,
@Named(Storage.STORAGE_DIR) File storageDir,
@Named(AppOptionKeys.DUMP_STATISTICS) boolean dumpStatistics) {
this.p2PService = p2PService;
this.priceFeedService = priceFeedService;
this.filterManager = filterManager;
jsonFileManager = new JsonFileManager(storageDir);

p2PService.addHashSetChangedListener(new HashMapChangedListener() {
Expand Down Expand Up @@ -132,6 +137,11 @@ public void onRemoved(Offer offer) {
///////////////////////////////////////////////////////////////////////////////////////////

public void addOffer(Offer offer, ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) {
if (filterManager.requireUpdateToNewVersionForTrading()) {
errorMessageHandler.handleErrorMessage(Res.get("popup.warning.mandatoryUpdate.trading"));
return;
}

boolean result = p2PService.addProtectedStorageEntry(offer.getOfferPayload(), true);
if (result) {
resultHandler.handleResult();
Expand All @@ -141,6 +151,11 @@ public void addOffer(Offer offer, ResultHandler resultHandler, ErrorMessageHandl
}

public void refreshTTL(OfferPayload offerPayload, ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) {
if (filterManager.requireUpdateToNewVersionForTrading()) {
errorMessageHandler.handleErrorMessage(Res.get("popup.warning.mandatoryUpdate.trading"));
return;
}

boolean result = p2PService.refreshTTL(offerPayload, true);
if (result) {
resultHandler.handleResult();
Expand Down
59 changes: 59 additions & 0 deletions core/src/main/java/bisq/core/offer/OfferRestrictions.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*
* This file is part of Bisq.
*
* Bisq is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bisq is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bisq. If not, see <http://www.gnu.org/licenses/>.
*/

package bisq.core.offer;

import bisq.core.payment.payload.PaymentMethod;
import bisq.core.trade.Trade;

import org.bitcoinj.core.Coin;

public class OfferRestrictions {
public static Coin TOLERATED_SMALL_TRADE_AMOUNT = Coin.parseCoin("0.01");

public static boolean isOfferRisky(Offer offer) {
return offer != null &&
offer.isBuyOffer() &&
PaymentMethod.hasChargebackRisk(offer.getPaymentMethod()) &&
isMinTradeAmountRisky(offer);
}

public static boolean isSellOfferRisky(Offer offer) {
return offer != null &&
PaymentMethod.hasChargebackRisk(offer.getPaymentMethod()) &&
isMinTradeAmountRisky(offer);
}

public static boolean isTradeRisky(Trade trade) {
if (trade == null)
return false;

Offer offer = trade.getOffer();
return offer != null &&
PaymentMethod.hasChargebackRisk(offer.getPaymentMethod()) &&
trade.getTradeAmount() != null &&
isAmountRisky(trade.getTradeAmount());
}

public static boolean isMinTradeAmountRisky(Offer offer) {
return isAmountRisky(offer.getMinAmount());
}

public static boolean isAmountRisky(Coin amount) {
return amount.isGreaterThan(TOLERATED_SMALL_TRADE_AMOUNT);
}
}
82 changes: 82 additions & 0 deletions core/src/main/java/bisq/core/payment/AccountAgeRestrictions.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/*
* This file is part of Bisq.
*
* Bisq is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bisq is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bisq. If not, see <http://www.gnu.org/licenses/>.
*/

package bisq.core.payment;

import bisq.core.offer.Offer;
import bisq.core.offer.OfferPayload;
import bisq.core.offer.OfferRestrictions;
import bisq.core.payment.payload.PaymentMethod;
import bisq.core.trade.Trade;

import bisq.common.util.Utilities;

import java.util.Date;
import java.util.GregorianCalendar;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class AccountAgeRestrictions {
public static final long SAFE_ACCOUNT_AGE_DATE = Utilities.getUTCDate(2019, GregorianCalendar.MARCH, 15).getTime();

public static boolean isMakersAccountAgeImmature(AccountAgeWitnessService accountAgeWitnessService, Offer offer) {
long accountCreationDate = new Date().getTime() - accountAgeWitnessService.getMakersAccountAge(offer, new Date());
return accountCreationDate > SAFE_ACCOUNT_AGE_DATE;
}

public static boolean isTradePeersAccountAgeImmature(AccountAgeWitnessService accountAgeWitnessService, Trade trade) {
long accountCreationDate = new Date().getTime() - accountAgeWitnessService.getTradingPeersAccountAge(trade);
return accountCreationDate > SAFE_ACCOUNT_AGE_DATE;
}

public static boolean isMyAccountAgeImmature(AccountAgeWitnessService accountAgeWitnessService, PaymentAccount myPaymentAccount) {
long accountCreationDate = new Date().getTime() - accountAgeWitnessService.getMyAccountAge(myPaymentAccount.getPaymentAccountPayload());
return accountCreationDate > SAFE_ACCOUNT_AGE_DATE;
}

public static long getMyTradeLimitAtCreateOffer(AccountAgeWitnessService accountAgeWitnessService,
PaymentAccount paymentAccount,
String currencyCode,
OfferPayload.Direction direction) {
if (direction == OfferPayload.Direction.BUY &&
PaymentMethod.hasChargebackRisk(paymentAccount.getPaymentMethod()) &&
AccountAgeRestrictions.isMyAccountAgeImmature(accountAgeWitnessService, paymentAccount)) {
return OfferRestrictions.TOLERATED_SMALL_TRADE_AMOUNT.value;
} else {
return accountAgeWitnessService.getMyTradeLimit(paymentAccount, currencyCode);
}
}

public static long getMyTradeLimitAtTakeOffer(AccountAgeWitnessService accountAgeWitnessService,
PaymentAccount paymentAccount,
Offer offer,
String currencyCode,
OfferPayload.Direction direction) {
if (direction == OfferPayload.Direction.BUY && PaymentMethod.hasChargebackRisk(paymentAccount.getPaymentMethod()) &&
AccountAgeRestrictions.isMakersAccountAgeImmature(accountAgeWitnessService, offer)) {
// Taker is seller
return OfferRestrictions.TOLERATED_SMALL_TRADE_AMOUNT.value;
} else if (direction == OfferPayload.Direction.SELL && PaymentMethod.hasChargebackRisk(paymentAccount.getPaymentMethod()) &&
AccountAgeRestrictions.isMyAccountAgeImmature(accountAgeWitnessService, paymentAccount)) {
// Taker is buyer
return OfferRestrictions.TOLERATED_SMALL_TRADE_AMOUNT.value;
} else {
return accountAgeWitnessService.getMyTradeLimit(paymentAccount, currencyCode);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
public class AccountAgeWitnessService {
private static final Date RELEASE = Utilities.getUTCDate(2017, GregorianCalendar.NOVEMBER, 11);
public static final Date FULL_ACTIVATION = Utilities.getUTCDate(2018, GregorianCalendar.FEBRUARY, 15);
public static final long SAFE_ACCOUNT_AGE_DATE = Utilities.getUTCDate(2019, GregorianCalendar.MARCH, 15).getTime();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should re-use the static from AccountAgeRestrictions


public enum AccountAge {
LESS_ONE_MONTH,
Expand Down
Loading