Merge branch 'master_upstream' into Fix-small-P2P-network-issues

# Conflicts:
#	core/src/main/java/bisq/core/setup/CoreNetworkCapabilities.java
This commit is contained in:
chimp1984 2019-08-28 19:49:18 +02:00
commit a0e690997a
No known key found for this signature in database
GPG key ID: 9801B4EC591F90E3
17 changed files with 271 additions and 28 deletions

View file

@ -31,7 +31,7 @@ public enum Capability {
PROPOSAL, PROPOSAL,
BLIND_VOTE, BLIND_VOTE,
ACK_MSG, ACK_MSG,
BSQ_BLOCK, RECEIVE_BSQ_BLOCK,
DAO_STATE, DAO_STATE,
BUNDLE_OF_ENVELOPES, BUNDLE_OF_ENVELOPES,
SIGNED_ACCOUNT_AGE_WITNESS SIGNED_ACCOUNT_AGE_WITNESS

View file

@ -20,6 +20,11 @@ package bisq.core.account.sign;
import bisq.core.account.witness.AccountAgeWitness; import bisq.core.account.witness.AccountAgeWitness;
import bisq.core.account.witness.AccountAgeWitnessService; import bisq.core.account.witness.AccountAgeWitnessService;
import bisq.core.arbitration.ArbitratorManager; import bisq.core.arbitration.ArbitratorManager;
import bisq.core.arbitration.BuyerDataItem;
import bisq.core.arbitration.Dispute;
import bisq.core.arbitration.DisputeManager;
import bisq.core.arbitration.DisputeResult;
import bisq.core.payment.ChargeBackRisk;
import bisq.core.payment.payload.PaymentAccountPayload; import bisq.core.payment.payload.PaymentAccountPayload;
import bisq.network.p2p.P2PService; import bisq.network.p2p.P2PService;
@ -28,6 +33,7 @@ import bisq.network.p2p.storage.persistence.AppendOnlyDataStoreService;
import bisq.common.crypto.CryptoException; import bisq.common.crypto.CryptoException;
import bisq.common.crypto.KeyRing; import bisq.common.crypto.KeyRing;
import bisq.common.crypto.PubKeyRing;
import bisq.common.crypto.Sig; import bisq.common.crypto.Sig;
import bisq.common.util.Utilities; import bisq.common.util.Utilities;
@ -50,12 +56,16 @@ import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set; import java.util.Set;
import java.util.Stack; import java.util.Stack;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.Nullable;
@Slf4j @Slf4j
public class SignedWitnessService { public class SignedWitnessService {
public static final long CHARGEBACK_SAFETY_DAYS = 30; public static final long CHARGEBACK_SAFETY_DAYS = 30;
@ -64,6 +74,9 @@ public class SignedWitnessService {
private final P2PService p2PService; private final P2PService p2PService;
private final AccountAgeWitnessService accountAgeWitnessService; private final AccountAgeWitnessService accountAgeWitnessService;
private final ArbitratorManager arbitratorManager; private final ArbitratorManager arbitratorManager;
private final DisputeManager disputeManager;
private final ChargeBackRisk chargeBackRisk;
private final Map<P2PDataStorage.ByteArray, SignedWitness> signedWitnessMap = new HashMap<>(); private final Map<P2PDataStorage.ByteArray, SignedWitness> signedWitnessMap = new HashMap<>();
@ -77,11 +90,15 @@ public class SignedWitnessService {
AccountAgeWitnessService accountAgeWitnessService, AccountAgeWitnessService accountAgeWitnessService,
ArbitratorManager arbitratorManager, ArbitratorManager arbitratorManager,
SignedWitnessStorageService signedWitnessStorageService, SignedWitnessStorageService signedWitnessStorageService,
AppendOnlyDataStoreService appendOnlyDataStoreService) { AppendOnlyDataStoreService appendOnlyDataStoreService,
DisputeManager disputeManager,
ChargeBackRisk chargeBackRisk) {
this.keyRing = keyRing; this.keyRing = keyRing;
this.p2PService = p2PService; this.p2PService = p2PService;
this.accountAgeWitnessService = accountAgeWitnessService; this.accountAgeWitnessService = accountAgeWitnessService;
this.arbitratorManager = arbitratorManager; this.arbitratorManager = arbitratorManager;
this.disputeManager = disputeManager;
this.chargeBackRisk = chargeBackRisk;
// We need to add that early (before onAllServicesInitialized) as it will be used at startup. // We need to add that early (before onAllServicesInitialized) as it will be used at startup.
appendOnlyDataStoreService.addService(signedWitnessStorageService); appendOnlyDataStoreService.addService(signedWitnessStorageService);
@ -133,25 +150,29 @@ public class SignedWitnessService {
public SignedWitness signAccountAgeWitness(Coin tradeAmount, AccountAgeWitness accountAgeWitness, ECKey key, PublicKey peersPubKey) { public SignedWitness signAccountAgeWitness(Coin tradeAmount, AccountAgeWitness accountAgeWitness, ECKey key, PublicKey peersPubKey) {
String accountAgeWitnessHashAsHex = Utilities.encodeToHex(accountAgeWitness.getHash()); String accountAgeWitnessHashAsHex = Utilities.encodeToHex(accountAgeWitness.getHash());
String signatureBase64 = key.signMessage(accountAgeWitnessHashAsHex); String signatureBase64 = key.signMessage(accountAgeWitnessHashAsHex);
return new SignedWitness(true, SignedWitness signedWitness = new SignedWitness(true,
accountAgeWitness.getHash(), accountAgeWitness.getHash(),
signatureBase64.getBytes(Charsets.UTF_8), signatureBase64.getBytes(Charsets.UTF_8),
key.getPubKey(), key.getPubKey(),
peersPubKey.getEncoded(), peersPubKey.getEncoded(),
new Date().getTime(), new Date().getTime(),
tradeAmount.value); tradeAmount.value);
publishSignedWitness(signedWitness);
return signedWitness;
} }
// Any peer can sign with DSA key // Any peer can sign with DSA key
public SignedWitness signAccountAgeWitness(Coin tradeAmount, AccountAgeWitness accountAgeWitness, PublicKey peersPubKey) throws CryptoException { public SignedWitness signAccountAgeWitness(Coin tradeAmount, AccountAgeWitness accountAgeWitness, PublicKey peersPubKey) throws CryptoException {
byte[] signature = Sig.sign(keyRing.getSignatureKeyPair().getPrivate(), accountAgeWitness.getHash()); byte[] signature = Sig.sign(keyRing.getSignatureKeyPair().getPrivate(), accountAgeWitness.getHash());
return new SignedWitness(false, SignedWitness signedWitness = new SignedWitness(false,
accountAgeWitness.getHash(), accountAgeWitness.getHash(),
signature, signature,
keyRing.getSignatureKeyPair().getPublic().getEncoded(), keyRing.getSignatureKeyPair().getPublic().getEncoded(),
peersPubKey.getEncoded(), peersPubKey.getEncoded(),
new Date().getTime(), new Date().getTime(),
tradeAmount.value); tradeAmount.value);
publishSignedWitness(signedWitness);
return signedWitness;
} }
public boolean verifySignature(SignedWitness signedWitness) { public boolean verifySignature(SignedWitness signedWitness) {
@ -286,7 +307,6 @@ public class SignedWitnessService {
return signedWitnessDateMillis <= childSignedWitnessDateMinusChargebackPeriodMillis; return signedWitnessDateMillis <= childSignedWitnessDateMinusChargebackPeriodMillis;
} }
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Private // Private
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@ -295,4 +315,45 @@ public class SignedWitnessService {
void addToMap(SignedWitness signedWitness) { void addToMap(SignedWitness signedWitness) {
signedWitnessMap.putIfAbsent(signedWitness.getHashAsByteArray(), signedWitness); signedWitnessMap.putIfAbsent(signedWitness.getHashAsByteArray(), signedWitness);
} }
private void publishSignedWitness(SignedWitness signedWitness) {
if (!signedWitnessMap.containsKey(signedWitness.getHashAsByteArray())) {
p2PService.addPersistableNetworkPayload(signedWitness, false);
}
}
// Arbitrator signing
public List<BuyerDataItem> getBuyerPaymentAccounts(long safeDate) {
return disputeManager.getDisputesAsObservableList().stream()
.filter(this::hasChargebackRisk)
.filter(this::isBuyerWinner)
.map(this::getBuyerData)
.filter(Objects::nonNull)
.filter(buyerDataItem -> buyerDataItem.getAccountAgeWitness().getDate() < safeDate)
.distinct()
.collect(Collectors.toList());
}
private boolean hasChargebackRisk(Dispute dispute) {
return chargeBackRisk.hasChargebackRisk(dispute.getContract().getPaymentMethodId());
}
private boolean isBuyerWinner(Dispute dispute) {
return dispute.getDisputeResultProperty().get().getWinner() == DisputeResult.Winner.BUYER;
}
@Nullable
private BuyerDataItem getBuyerData(Dispute dispute) {
PubKeyRing buyerPubKeyRing = dispute.getContract().getBuyerPubKeyRing();
PaymentAccountPayload buyerPaymentAccountPaload = dispute.getContract().getBuyerPaymentAccountPayload();
Optional<AccountAgeWitness> optionalWitness = accountAgeWitnessService
.findWitness(buyerPaymentAccountPaload, buyerPubKeyRing);
return optionalWitness.map(witness -> new BuyerDataItem(
buyerPaymentAccountPaload,
witness,
dispute.getContract().getTradeAmount(),
dispute.getContract().getSellerPubKeyRing().getSignaturePubKey()))
.orElse(null);
}
} }

View file

@ -17,6 +17,7 @@
package bisq.core.app; package bisq.core.app;
import bisq.core.account.sign.SignedWitnessService;
import bisq.core.account.witness.AccountAgeWitnessService; import bisq.core.account.witness.AccountAgeWitnessService;
import bisq.core.alert.Alert; import bisq.core.alert.Alert;
import bisq.core.alert.AlertManager; import bisq.core.alert.AlertManager;
@ -143,6 +144,7 @@ public class BisqSetup {
private final KeyRing keyRing; private final KeyRing keyRing;
private final BisqEnvironment bisqEnvironment; private final BisqEnvironment bisqEnvironment;
private final AccountAgeWitnessService accountAgeWitnessService; private final AccountAgeWitnessService accountAgeWitnessService;
private final SignedWitnessService signedWitnessService;
private final MobileNotificationService mobileNotificationService; private final MobileNotificationService mobileNotificationService;
private final MyOfferTakenEvents myOfferTakenEvents; private final MyOfferTakenEvents myOfferTakenEvents;
private final TradeEvents tradeEvents; private final TradeEvents tradeEvents;
@ -221,6 +223,7 @@ public class BisqSetup {
KeyRing keyRing, KeyRing keyRing,
BisqEnvironment bisqEnvironment, BisqEnvironment bisqEnvironment,
AccountAgeWitnessService accountAgeWitnessService, AccountAgeWitnessService accountAgeWitnessService,
SignedWitnessService signedWitnessService,
MobileNotificationService mobileNotificationService, MobileNotificationService mobileNotificationService,
MyOfferTakenEvents myOfferTakenEvents, MyOfferTakenEvents myOfferTakenEvents,
TradeEvents tradeEvents, TradeEvents tradeEvents,
@ -261,6 +264,7 @@ public class BisqSetup {
this.keyRing = keyRing; this.keyRing = keyRing;
this.bisqEnvironment = bisqEnvironment; this.bisqEnvironment = bisqEnvironment;
this.accountAgeWitnessService = accountAgeWitnessService; this.accountAgeWitnessService = accountAgeWitnessService;
this.signedWitnessService = signedWitnessService;
this.mobileNotificationService = mobileNotificationService; this.mobileNotificationService = mobileNotificationService;
this.myOfferTakenEvents = myOfferTakenEvents; this.myOfferTakenEvents = myOfferTakenEvents;
this.tradeEvents = tradeEvents; this.tradeEvents = tradeEvents;
@ -647,6 +651,7 @@ public class BisqSetup {
assetService.onAllServicesInitialized(); assetService.onAllServicesInitialized();
accountAgeWitnessService.onAllServicesInitialized(); accountAgeWitnessService.onAllServicesInitialized();
signedWitnessService.onAllServicesInitialized();
priceFeedService.setCurrencyCodeOnInit(); priceFeedService.setCurrencyCodeOnInit();

View file

@ -17,6 +17,7 @@
package bisq.core.app.misc; package bisq.core.app.misc;
import bisq.core.account.sign.SignedWitnessService;
import bisq.core.account.witness.AccountAgeWitnessService; import bisq.core.account.witness.AccountAgeWitnessService;
import bisq.core.app.SetupUtils; import bisq.core.app.SetupUtils;
import bisq.core.app.TorSetup; import bisq.core.app.TorSetup;
@ -46,6 +47,7 @@ import lombok.extern.slf4j.Slf4j;
public class AppSetupWithP2P extends AppSetup { public class AppSetupWithP2P extends AppSetup {
protected final P2PService p2PService; protected final P2PService p2PService;
protected final AccountAgeWitnessService accountAgeWitnessService; protected final AccountAgeWitnessService accountAgeWitnessService;
private final SignedWitnessService signedWitnessService;
protected final FilterManager filterManager; protected final FilterManager filterManager;
private final TorSetup torSetup; private final TorSetup torSetup;
protected BooleanProperty p2pNetWorkReady; protected BooleanProperty p2pNetWorkReady;
@ -58,12 +60,14 @@ public class AppSetupWithP2P extends AppSetup {
P2PService p2PService, P2PService p2PService,
TradeStatisticsManager tradeStatisticsManager, TradeStatisticsManager tradeStatisticsManager,
AccountAgeWitnessService accountAgeWitnessService, AccountAgeWitnessService accountAgeWitnessService,
SignedWitnessService signedWitnessService,
FilterManager filterManager, FilterManager filterManager,
TorSetup torSetup) { TorSetup torSetup) {
super(encryptionService, keyRing); super(encryptionService, keyRing);
this.p2PService = p2PService; this.p2PService = p2PService;
this.tradeStatisticsManager = tradeStatisticsManager; this.tradeStatisticsManager = tradeStatisticsManager;
this.accountAgeWitnessService = accountAgeWitnessService; this.accountAgeWitnessService = accountAgeWitnessService;
this.signedWitnessService = signedWitnessService;
this.filterManager = filterManager; this.filterManager = filterManager;
this.torSetup = torSetup; this.torSetup = torSetup;
this.persistedDataHosts = new ArrayList<>(); this.persistedDataHosts = new ArrayList<>();
@ -184,6 +188,7 @@ public class AppSetupWithP2P extends AppSetup {
tradeStatisticsManager.onAllServicesInitialized(); tradeStatisticsManager.onAllServicesInitialized();
accountAgeWitnessService.onAllServicesInitialized(); accountAgeWitnessService.onAllServicesInitialized();
signedWitnessService.onAllServicesInitialized();
filterManager.onAllServicesInitialized(); filterManager.onAllServicesInitialized();
} }

View file

@ -17,6 +17,7 @@
package bisq.core.app.misc; package bisq.core.app.misc;
import bisq.core.account.sign.SignedWitnessService;
import bisq.core.account.witness.AccountAgeWitnessService; import bisq.core.account.witness.AccountAgeWitnessService;
import bisq.core.app.TorSetup; import bisq.core.app.TorSetup;
import bisq.core.dao.DaoOptionKeys; import bisq.core.dao.DaoOptionKeys;
@ -50,6 +51,7 @@ public class AppSetupWithP2PAndDAO extends AppSetupWithP2P {
P2PService p2PService, P2PService p2PService,
TradeStatisticsManager tradeStatisticsManager, TradeStatisticsManager tradeStatisticsManager,
AccountAgeWitnessService accountAgeWitnessService, AccountAgeWitnessService accountAgeWitnessService,
SignedWitnessService signedWitnessService,
FilterManager filterManager, FilterManager filterManager,
DaoSetup daoSetup, DaoSetup daoSetup,
MyVoteListService myVoteListService, MyVoteListService myVoteListService,
@ -65,6 +67,7 @@ public class AppSetupWithP2PAndDAO extends AppSetupWithP2P {
p2PService, p2PService,
tradeStatisticsManager, tradeStatisticsManager,
accountAgeWitnessService, accountAgeWitnessService,
signedWitnessService,
filterManager, filterManager,
torSetup); torSetup);

View file

@ -0,0 +1,48 @@
/*
* 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.arbitration;
import bisq.core.account.witness.AccountAgeWitness;
import bisq.core.payment.payload.PaymentAccountPayload;
import org.bitcoinj.core.Coin;
import java.security.PublicKey;
import lombok.EqualsAndHashCode;
import lombok.Getter;
@Getter
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
public class BuyerDataItem {
private final PaymentAccountPayload paymentAccountPayload;
@EqualsAndHashCode.Include
private final AccountAgeWitness accountAgeWitness;
private final Coin tradeAmount;
private final PublicKey sellerPubKey;
public BuyerDataItem(PaymentAccountPayload paymentAccountPayload,
AccountAgeWitness accountAgeWitness,
Coin tradeAmount,
PublicKey sellerPubKey) {
this.paymentAccountPayload = paymentAccountPayload;
this.accountAgeWitness = accountAgeWitness;
this.tradeAmount = tradeAmount;
this.sellerPubKey = sellerPubKey;
}
}

View file

@ -64,6 +64,6 @@ public final class NewBlockBroadcastMessage extends BroadcastMessage implements
@Override @Override
public Capabilities getRequiredCapabilities() { public Capabilities getRequiredCapabilities() {
return new Capabilities(Capability.BSQ_BLOCK); return new Capabilities(Capability.RECEIVE_BSQ_BLOCK);
} }
} }

View file

@ -0,0 +1,29 @@
/*
* 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.payment.payload.PaymentMethod;
import javax.inject.Singleton;
@Singleton
public class ChargeBackRisk {
public boolean hasChargebackRisk(String id) {
return PaymentMethod.hasChargebackRisk(id);
}
}

View file

@ -321,6 +321,10 @@ public final class PaymentMethod implements PersistablePayload, Comparable {
return false; return false;
String id = paymentMethod.getId(); String id = paymentMethod.getId();
return hasChargebackRisk(id);
}
public static boolean hasChargebackRisk(String id) {
return id.equals(PaymentMethod.SEPA_ID) || return id.equals(PaymentMethod.SEPA_ID) ||
id.equals(PaymentMethod.SEPA_INSTANT_ID) || id.equals(PaymentMethod.SEPA_INSTANT_ID) ||
id.equals(PaymentMethod.INTERAC_E_TRANSFER_ID) || id.equals(PaymentMethod.INTERAC_E_TRANSFER_ID) ||

View file

@ -40,7 +40,6 @@ public class CoreNetworkCapabilities {
Capabilities.app.addAll( Capabilities.app.addAll(
Capability.PROPOSAL, Capability.PROPOSAL,
Capability.BLIND_VOTE, Capability.BLIND_VOTE,
Capability.BSQ_BLOCK,
Capability.DAO_STATE Capability.DAO_STATE
); );
@ -56,6 +55,10 @@ public class CoreNetworkCapabilities {
if (isFullDaoNode != null && !isFullDaoNode.isEmpty() && isFullDaoNode.toLowerCase().equals("true")) { if (isFullDaoNode != null && !isFullDaoNode.isEmpty() && isFullDaoNode.toLowerCase().equals("true")) {
log.info("Set Capability.DAO_FULL_NODE"); log.info("Set Capability.DAO_FULL_NODE");
Capabilities.app.addAll(Capability.DAO_FULL_NODE); Capabilities.app.addAll(Capability.DAO_FULL_NODE);
} else {
// A lite node has the capability to receive bsq blocks. We do not want to send BSQ blocks to full nodes
// as they ignore them anyway.
Capabilities.app.addAll(Capability.RECEIVE_BSQ_BLOCK);
} }
} }
} }

View file

@ -2,7 +2,7 @@
5quyxpxheyvzmb2d.onion:8000 (@miker) 5quyxpxheyvzmb2d.onion:8000 (@miker)
s67qglwhkgkyvr74.onion:8000 (@emzy) s67qglwhkgkyvr74.onion:8000 (@emzy)
ef5qnzx6znifo3df.onion:8000 (@alexej996) ef5qnzx6znifo3df.onion:8000 (@alexej996)
jhgcy2won7xnslrb.onion:8000 (@wiz) jhgcy2won7xnslrb.onion:8000 (@wiz, @nicolasdorier)
3f3cu2yw7u457ztq.onion:8000 (@devinbileck) 3f3cu2yw7u457ztq.onion:8000 (@devinbileck)
723ljisnynbtdohi.onion:8000 (@emzy) 723ljisnynbtdohi.onion:8000 (@emzy)
rm7b56wbrcczpjvl.onion:8000 (@miker) rm7b56wbrcczpjvl.onion:8000 (@miker)

View file

@ -20,6 +20,7 @@ package bisq.core.account.sign;
import bisq.core.account.witness.AccountAgeWitness; import bisq.core.account.witness.AccountAgeWitness;
import bisq.core.arbitration.ArbitratorManager; import bisq.core.arbitration.ArbitratorManager;
import bisq.core.arbitration.DisputeManager;
import bisq.network.p2p.storage.persistence.AppendOnlyDataStoreService; import bisq.network.p2p.storage.persistence.AppendOnlyDataStoreService;
@ -74,8 +75,9 @@ public class SignedWitnessServiceTest {
public void setup() throws Exception { public void setup() throws Exception {
AppendOnlyDataStoreService appendOnlyDataStoreService = mock(AppendOnlyDataStoreService.class); AppendOnlyDataStoreService appendOnlyDataStoreService = mock(AppendOnlyDataStoreService.class);
ArbitratorManager arbitratorManager = mock(ArbitratorManager.class); ArbitratorManager arbitratorManager = mock(ArbitratorManager.class);
DisputeManager disputeManager = mock(DisputeManager.class);
when(arbitratorManager.isPublicKeyInList(any())).thenReturn(true); when(arbitratorManager.isPublicKeyInList(any())).thenReturn(true);
signedWitnessService = new SignedWitnessService(null, null, null, arbitratorManager, null, appendOnlyDataStoreService); signedWitnessService = new SignedWitnessService(null, null, null, arbitratorManager, null, appendOnlyDataStoreService, disputeManager, null);
account1DataHash = org.bitcoinj.core.Utils.sha256hash160(new byte[]{1}); account1DataHash = org.bitcoinj.core.Utils.sha256hash160(new byte[]{1});
account2DataHash = org.bitcoinj.core.Utils.sha256hash160(new byte[]{2}); account2DataHash = org.bitcoinj.core.Utils.sha256hash160(new byte[]{2});
account3DataHash = org.bitcoinj.core.Utils.sha256hash160(new byte[]{3}); account3DataHash = org.bitcoinj.core.Utils.sha256hash160(new byte[]{3});

View file

@ -0,0 +1,66 @@
package bisq.core.arbitration;
import bisq.core.account.witness.AccountAgeWitness;
import bisq.core.payment.payload.PaymentAccountPayload;
import org.bitcoinj.core.Coin;
import java.security.PublicKey;
import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.mockito.Mockito.mock;
/*
* 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/>.
*/
public class BuyerDataItemTest {
private BuyerDataItem buyerDataItem1;
private BuyerDataItem buyerDataItem2;
private BuyerDataItem buyerDataItem3;
private AccountAgeWitness accountAgeWitness1;
private AccountAgeWitness accountAgeWitness2;
private byte[] hash1 = "1".getBytes();
private byte[] hash2 = "2".getBytes();
@Before
public void setup() {
accountAgeWitness1 = new AccountAgeWitness(hash1, 123);
accountAgeWitness2 = new AccountAgeWitness(hash2, 124);
buyerDataItem1 = new BuyerDataItem(mock(PaymentAccountPayload.class), accountAgeWitness1, Coin.valueOf(546),
mock(PublicKey.class));
buyerDataItem2 = new BuyerDataItem(mock(PaymentAccountPayload.class), accountAgeWitness1, Coin.valueOf(547),
mock(PublicKey.class));
buyerDataItem3 = new BuyerDataItem(mock(PaymentAccountPayload.class), accountAgeWitness2, Coin.valueOf(548),
mock(PublicKey.class));
}
@Test
public void testEquals() {
assertEquals(buyerDataItem1, buyerDataItem2);
assertNotEquals(buyerDataItem1, buyerDataItem3);
assertNotEquals(buyerDataItem2, buyerDataItem3);
}
@Test
public void testHashCode() {
assertEquals(buyerDataItem1.hashCode(), buyerDataItem2.hashCode());
assertNotEquals(buyerDataItem1.hashCode(), buyerDataItem3.hashCode());
}
}

View file

@ -82,6 +82,7 @@ import java.sql.Date;
public class SupplyView extends ActivatableView<GridPane, Void> implements DaoStateListener { public class SupplyView extends ActivatableView<GridPane, Void> implements DaoStateListener {
private static final String MONTH = "month"; private static final String MONTH = "month";
private static final String DAY = "day";
private final DaoFacade daoFacade; private final DaoFacade daoFacade;
private DaoStateService daoStateService; private DaoStateService daoStateService;
@ -113,6 +114,7 @@ public class SupplyView extends ActivatableView<GridPane, Void> implements DaoSt
public void initialize() { public void initialize() {
ADJUSTERS.put(MONTH, TemporalAdjusters.firstDayOfMonth()); ADJUSTERS.put(MONTH, TemporalAdjusters.firstDayOfMonth());
ADJUSTERS.put(DAY, TemporalAdjusters.ofDateAdjuster(d -> d));
createSupplyIncreasedInformation(); createSupplyIncreasedInformation();
createSupplyReducedInformation(); createSupplyReducedInformation();
@ -161,7 +163,7 @@ public class SupplyView extends ActivatableView<GridPane, Void> implements DaoSt
seriesBSQIssued = new XYChart.Series<>(); seriesBSQIssued = new XYChart.Series<>();
createChart(seriesBSQIssued, Res.get("dao.factsAndFigures.supply.issued")); createChart(seriesBSQIssued, Res.get("dao.factsAndFigures.supply.issued"), "MMM uu");
} }
private void createSupplyReducedInformation() { private void createSupplyReducedInformation() {
@ -173,7 +175,7 @@ public class SupplyView extends ActivatableView<GridPane, Void> implements DaoSt
Res.get("dao.factsAndFigures.supply.invalidTxs"), Layout.FIRST_ROW_AND_GROUP_DISTANCE).second; Res.get("dao.factsAndFigures.supply.invalidTxs"), Layout.FIRST_ROW_AND_GROUP_DISTANCE).second;
seriesBSQBurnt = new XYChart.Series<>(); seriesBSQBurnt = new XYChart.Series<>();
createChart(seriesBSQBurnt, Res.get("dao.factsAndFigures.supply.burnt")); createChart(seriesBSQBurnt, Res.get("dao.factsAndFigures.supply.burnt"), "d MMM");
} }
private void createSupplyLockedInformation() { private void createSupplyLockedInformation() {
@ -193,7 +195,8 @@ public class SupplyView extends ActivatableView<GridPane, Void> implements DaoSt
Res.get("dao.factsAndFigures.supply.totalConfiscatedAmount")).second; Res.get("dao.factsAndFigures.supply.totalConfiscatedAmount")).second;
} }
private void createChart(XYChart.Series<Number, Number> series, String seriesLabel) { @SuppressWarnings("unchecked")
private void createChart(XYChart.Series<Number, Number> series, String seriesLabel, String datePattern) {
NumberAxis xAxis = new NumberAxis(); NumberAxis xAxis = new NumberAxis();
xAxis.setForceZeroInRange(false); xAxis.setForceZeroInRange(false);
xAxis.setAutoRanging(true); xAxis.setAutoRanging(true);
@ -205,7 +208,7 @@ public class SupplyView extends ActivatableView<GridPane, Void> implements DaoSt
public String toString(Number timestamp) { public String toString(Number timestamp) {
LocalDateTime localDateTime = LocalDateTime.ofEpochSecond(timestamp.longValue(), LocalDateTime localDateTime = LocalDateTime.ofEpochSecond(timestamp.longValue(),
0, OffsetDateTime.now(ZoneId.systemDefault()).getOffset()); 0, OffsetDateTime.now(ZoneId.systemDefault()).getOffset());
return localDateTime.format(DateTimeFormatter.ofPattern("MMM uu", GlobalSettings.getLocale())); return localDateTime.format(DateTimeFormatter.ofPattern(datePattern, GlobalSettings.getLocale()));
} }
@Override @Override
@ -296,15 +299,15 @@ public class SupplyView extends ActivatableView<GridPane, Void> implements DaoSt
Set<Tx> burntTxs = new HashSet<>(daoStateService.getBurntFeeTxs()); Set<Tx> burntTxs = new HashSet<>(daoStateService.getBurntFeeTxs());
burntTxs.addAll(daoStateService.getInvalidTxs()); burntTxs.addAll(daoStateService.getInvalidTxs());
Map<LocalDate, List<Tx>> burntBsqByMonth = burntTxs.stream() Map<LocalDate, List<Tx>> burntBsqByDay = burntTxs.stream()
.sorted(Comparator.comparing(Tx::getTime)) .sorted(Comparator.comparing(Tx::getTime))
.collect(Collectors.groupingBy(item -> new Date(item.getTime()).toLocalDate() .collect(Collectors.groupingBy(item -> new Date(item.getTime()).toLocalDate()
.with(ADJUSTERS.get(MONTH)))); .with(ADJUSTERS.get(DAY))));
List<XYChart.Data<Number, Number>> updatedBurntBsq = burntBsqByMonth.keySet().stream() List<XYChart.Data<Number, Number>> updatedBurntBsq = burntBsqByDay.keySet().stream()
.map(date -> { .map(date -> {
ZonedDateTime zonedDateTime = date.atStartOfDay(ZoneId.systemDefault()); ZonedDateTime zonedDateTime = date.atStartOfDay(ZoneId.systemDefault());
return new XYChart.Data<Number, Number>(zonedDateTime.toInstant().getEpochSecond(), burntBsqByMonth.get(date) return new XYChart.Data<Number, Number>(zonedDateTime.toInstant().getEpochSecond(), burntBsqByDay.get(date)
.stream() .stream()
.mapToDouble(Tx::getBurntBsq) .mapToDouble(Tx::getBurntBsq)
.sum() .sum()

View file

@ -32,6 +32,7 @@ import bisq.core.notifications.alerts.MyOfferTakenEvents;
import bisq.core.notifications.alerts.TradeEvents; import bisq.core.notifications.alerts.TradeEvents;
import bisq.core.notifications.alerts.market.MarketAlerts; import bisq.core.notifications.alerts.market.MarketAlerts;
import bisq.core.notifications.alerts.price.PriceAlert; import bisq.core.notifications.alerts.price.PriceAlert;
import bisq.core.payment.ChargeBackRisk;
import bisq.core.payment.TradeLimits; import bisq.core.payment.TradeLimits;
import bisq.core.proto.network.CoreNetworkProtoResolver; import bisq.core.proto.network.CoreNetworkProtoResolver;
import bisq.core.proto.persistable.CorePersistenceProtoResolver; import bisq.core.proto.persistable.CorePersistenceProtoResolver;
@ -131,6 +132,7 @@ public class GuiceSetupTest {
assertSingleton(TradeEvents.class); assertSingleton(TradeEvents.class);
assertSingleton(PriceAlert.class); assertSingleton(PriceAlert.class);
assertSingleton(MarketAlerts.class); assertSingleton(MarketAlerts.class);
assertSingleton(ChargeBackRisk.class);
assertNotSingleton(Storage.class); assertNotSingleton(Storage.class);
} }

View file

@ -201,8 +201,10 @@ public class P2PDataStorage implements MessageListener, ConnectionListener, Pers
// Batch processing can cause performance issues, so we give listeners a chance to deal with it by notifying // Batch processing can cause performance issues, so we give listeners a chance to deal with it by notifying
// about start and end of iteration. // about start and end of iteration.
hashMapChangedListeners.forEach(HashMapChangedListener::onBatchRemoveExpiredDataStarted); hashMapChangedListeners.forEach(HashMapChangedListener::onBatchRemoveExpiredDataStarted);
toRemoveSet.forEach(protectedDataToRemove -> hashMapChangedListeners.forEach( toRemoveSet.forEach(protectedStorageEntry -> {
listener -> listener.onRemoved(protectedDataToRemove))); hashMapChangedListeners.forEach(l -> l.onRemoved(protectedStorageEntry));
removeFromProtectedDataStore(protectedStorageEntry);
});
hashMapChangedListeners.forEach(HashMapChangedListener::onBatchRemoveExpiredDataCompleted); hashMapChangedListeners.forEach(HashMapChangedListener::onBatchRemoveExpiredDataCompleted);
if (sequenceNumberMap.size() > 1000) if (sequenceNumberMap.size() > 1000)
@ -483,6 +485,15 @@ public class P2PDataStorage implements MessageListener, ConnectionListener, Pers
broadcast(new RemoveDataMessage(protectedStorageEntry), sender, null, isDataOwner); broadcast(new RemoveDataMessage(protectedStorageEntry), sender, null, isDataOwner);
removeFromProtectedDataStore(protectedStorageEntry);
} else {
log.debug("remove failed");
}
return result;
}
private void removeFromProtectedDataStore(ProtectedStorageEntry protectedStorageEntry) {
ProtectedStoragePayload protectedStoragePayload = protectedStorageEntry.getProtectedStoragePayload();
if (protectedStoragePayload instanceof PersistablePayload) { if (protectedStoragePayload instanceof PersistablePayload) {
ByteArray compactHash = getCompactHashAsByteArray(protectedStoragePayload); ByteArray compactHash = getCompactHashAsByteArray(protectedStoragePayload);
ProtectedStorageEntry previous = protectedDataStoreService.remove(compactHash, protectedStorageEntry); ProtectedStorageEntry previous = protectedDataStoreService.remove(compactHash, protectedStorageEntry);
@ -492,10 +503,6 @@ public class P2PDataStorage implements MessageListener, ConnectionListener, Pers
log.info("We cannot remove the protectedStorageEntry from the persistedEntryMap as it does not exist."); log.info("We cannot remove the protectedStorageEntry from the persistedEntryMap as it does not exist.");
} }
} }
} else {
log.debug("remove failed");
}
return result;
} }
@SuppressWarnings("UnusedReturnValue") @SuppressWarnings("UnusedReturnValue")

View file

@ -3,6 +3,8 @@ package bisq.seednode;
import bisq.core.app.BisqEnvironment; import bisq.core.app.BisqEnvironment;
import bisq.core.app.misc.AppSetupWithP2PAndDAO; import bisq.core.app.misc.AppSetupWithP2PAndDAO;
import bisq.core.app.misc.ModuleForAppWithP2p; import bisq.core.app.misc.ModuleForAppWithP2p;
import bisq.core.locale.CurrencyUtil;
import bisq.core.locale.Res;
import org.springframework.mock.env.MockPropertySource; import org.springframework.mock.env.MockPropertySource;
@ -13,6 +15,9 @@ import org.junit.Test;
public class GuiceSetupTest { public class GuiceSetupTest {
@Test @Test
public void testGuiceSetup() { public void testGuiceSetup() {
Res.setup();
CurrencyUtil.setup();
ModuleForAppWithP2p module = new ModuleForAppWithP2p(new BisqEnvironment(new MockPropertySource())); ModuleForAppWithP2p module = new ModuleForAppWithP2p(new BisqEnvironment(new MockPropertySource()));
Guice.createInjector(module).getInstance(AppSetupWithP2PAndDAO.class); Guice.createInjector(module).getInstance(AppSetupWithP2PAndDAO.class);
} }