mirror of
https://github.com/bisq-network/bisq.git
synced 2025-03-13 11:09:10 +01:00
Add publish statistics task for taker if offerer uses old version
This commit is contained in:
parent
38cc71c6aa
commit
ada3bd4dc3
17 changed files with 213 additions and 49 deletions
|
@ -10,12 +10,14 @@ import org.bitcoinj.core.Coin;
|
|||
import org.bitcoinj.utils.ExchangeRate;
|
||||
import org.bitcoinj.utils.Fiat;
|
||||
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
import java.security.PublicKey;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@Immutable
|
||||
public final class TradeStatistics implements StoragePayload, CapabilityRequiringPayload {
|
||||
@JsonExclude
|
||||
private static final long serialVersionUID = Version.P2P_NETWORK_VERSION;
|
||||
|
@ -86,9 +88,72 @@ public final class TradeStatistics implements StoragePayload, CapabilityRequirin
|
|||
}
|
||||
|
||||
public Fiat getTradeVolume() {
|
||||
if (getTradeAmount() != null && getTradePrice() != null)
|
||||
return new ExchangeRate(getTradePrice()).coinToFiat(getTradeAmount());
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
// We don't include the pubKeyRing as both traders might publish it if the offerer uses an old
|
||||
// version and update later (taker publishes first, then later offerer)
|
||||
// We also don't include the trade date as that is set locally and different for offerer and taker
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (!(o instanceof TradeStatistics)) return false;
|
||||
|
||||
TradeStatistics that = (TradeStatistics) o;
|
||||
|
||||
if (tradePrice != that.tradePrice) return false;
|
||||
if (tradeAmount != that.tradeAmount) return false;
|
||||
if (offerDate != that.offerDate) return false;
|
||||
if (useMarketBasedPrice != that.useMarketBasedPrice) return false;
|
||||
if (Double.compare(that.marketPriceMargin, marketPriceMargin) != 0) return false;
|
||||
if (offerAmount != that.offerAmount) return false;
|
||||
if (offerMinAmount != that.offerMinAmount) return false;
|
||||
if (currency != null ? !currency.equals(that.currency) : that.currency != null) return false;
|
||||
if (direction != that.direction) return false;
|
||||
if (paymentMethod != null ? !paymentMethod.equals(that.paymentMethod) : that.paymentMethod != null)
|
||||
return false;
|
||||
if (offerId != null ? !offerId.equals(that.offerId) : that.offerId != null) return false;
|
||||
return !(depositTxId != null ? !depositTxId.equals(that.depositTxId) : that.depositTxId != null);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result;
|
||||
long temp;
|
||||
result = currency != null ? currency.hashCode() : 0;
|
||||
result = 31 * result + (direction != null ? direction.hashCode() : 0);
|
||||
result = 31 * result + (int) (tradePrice ^ (tradePrice >>> 32));
|
||||
result = 31 * result + (int) (tradeAmount ^ (tradeAmount >>> 32));
|
||||
result = 31 * result + (paymentMethod != null ? paymentMethod.hashCode() : 0);
|
||||
result = 31 * result + (int) (offerDate ^ (offerDate >>> 32));
|
||||
result = 31 * result + (useMarketBasedPrice ? 1 : 0);
|
||||
temp = Double.doubleToLongBits(marketPriceMargin);
|
||||
result = 31 * result + (int) (temp ^ (temp >>> 32));
|
||||
result = 31 * result + (int) (offerAmount ^ (offerAmount >>> 32));
|
||||
result = 31 * result + (int) (offerMinAmount ^ (offerMinAmount >>> 32));
|
||||
result = 31 * result + (offerId != null ? offerId.hashCode() : 0);
|
||||
result = 31 * result + (depositTxId != null ? depositTxId.hashCode() : 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "TradeStatistics{" +
|
||||
"currency='" + currency + '\'' +
|
||||
", direction=" + direction +
|
||||
", tradePrice=" + tradePrice +
|
||||
", tradeAmount=" + tradeAmount +
|
||||
", tradeDate=" + tradeDate +
|
||||
", paymentMethod='" + paymentMethod + '\'' +
|
||||
", offerDate=" + offerDate +
|
||||
", useMarketBasedPrice=" + useMarketBasedPrice +
|
||||
", marketPriceMargin=" + marketPriceMargin +
|
||||
", offerAmount=" + offerAmount +
|
||||
", offerMinAmount=" + offerMinAmount +
|
||||
", offerId='" + offerId + '\'' +
|
||||
", depositTxId='" + depositTxId + '\'' +
|
||||
", pubKeyRing=" + pubKeyRing +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,7 +38,7 @@ public class TradeStatisticsManager {
|
|||
|
||||
HashSet<TradeStatistics> persisted = storage.initAndGetPersistedWithFileName("TradeStatistics");
|
||||
if (persisted != null)
|
||||
observableTradeStatisticsSet = FXCollections.observableSet(persisted);
|
||||
persisted.stream().forEach(e -> add(e));
|
||||
|
||||
p2PService.addHashSetChangedListener(new HashMapChangedListener() {
|
||||
@Override
|
||||
|
@ -57,9 +57,11 @@ public class TradeStatisticsManager {
|
|||
}
|
||||
|
||||
public void add(TradeStatistics tradeStatistics) {
|
||||
if (!observableTradeStatisticsSet.contains(tradeStatistics)) {
|
||||
observableTradeStatisticsSet.add(tradeStatistics);
|
||||
if (!tradeStatisticsSet.contains(tradeStatistics)) {
|
||||
boolean itemAlreadyAdded = tradeStatisticsSet.stream().filter(e -> (e.offerId.equals(tradeStatistics.offerId))).findAny().isPresent();
|
||||
if (!itemAlreadyAdded) {
|
||||
tradeStatisticsSet.add(tradeStatistics);
|
||||
observableTradeStatisticsSet.add(tradeStatistics);
|
||||
storage.queueUpForSave(tradeStatisticsSet, 2000);
|
||||
|
||||
if (dumpStatistics) {
|
||||
|
@ -75,6 +77,9 @@ public class TradeStatisticsManager {
|
|||
list.toArray(array);
|
||||
jsonStorage.queueUpForSave(Utilities.objectToJson(array), 5_000);
|
||||
}
|
||||
} else {
|
||||
log.error("We have already an item with the same offer ID. That might happen if both the offerer and the taker published the tradeStatistics");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -31,7 +31,6 @@ import io.bitsquare.trade.protocol.trade.messages.TradeMessage;
|
|||
import io.bitsquare.trade.protocol.trade.tasks.buyer.*;
|
||||
import io.bitsquare.trade.protocol.trade.tasks.offerer.*;
|
||||
import io.bitsquare.trade.protocol.trade.tasks.shared.BroadcastAfterLockTime;
|
||||
import io.bitsquare.trade.protocol.trade.tasks.shared.PublishTradeStatistics;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
|
|
@ -122,7 +122,8 @@ public class BuyerAsTakerProtocol extends TradeProtocol implements BuyerProtocol
|
|||
VerifyOffererAccount.class,
|
||||
VerifyAndSignContract.class,
|
||||
SignAndPublishDepositTxAsBuyer.class,
|
||||
SendDepositTxPublishedMessage.class
|
||||
SendDepositTxPublishedMessage.class,
|
||||
PublishTradeStatistics.class
|
||||
);
|
||||
taskRunner.run();
|
||||
}
|
||||
|
|
|
@ -29,7 +29,6 @@ import io.bitsquare.trade.protocol.trade.messages.*;
|
|||
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.PublishTradeStatistics;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
|
|
@ -132,7 +132,8 @@ public class SellerAsTakerProtocol extends TradeProtocol implements SellerProtoc
|
|||
VerifyOffererAccount.class,
|
||||
VerifyAndSignContract.class,
|
||||
SignAndPublishDepositTxAsSeller.class,
|
||||
SendDepositTxPublishedMessage.class
|
||||
SendDepositTxPublishedMessage.class,
|
||||
PublishTradeStatistics.class
|
||||
);
|
||||
taskRunner.run();
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package io.bitsquare.trade.protocol.trade.tasks.shared;
|
||||
package io.bitsquare.trade.protocol.trade.tasks.offerer;
|
||||
|
||||
import io.bitsquare.common.taskrunner.TaskRunner;
|
||||
import io.bitsquare.trade.Trade;
|
||||
|
@ -35,6 +35,7 @@ public class PublishTradeStatistics extends TradeTask {
|
|||
protected void run() {
|
||||
try {
|
||||
runInterceptHook();
|
||||
// Offerer publishes directly
|
||||
TradeStatistics tradeStatistics = new TradeStatistics(trade.getOffer(),
|
||||
trade.getTradePrice(),
|
||||
trade.getTradeAmount(),
|
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
* This file is part of Bitsquare.
|
||||
*
|
||||
* Bitsquare 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.
|
||||
*
|
||||
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package io.bitsquare.trade.protocol.trade.tasks.taker;
|
||||
|
||||
import io.bitsquare.common.taskrunner.TaskRunner;
|
||||
import io.bitsquare.trade.Trade;
|
||||
import io.bitsquare.trade.TradeStatistics;
|
||||
import io.bitsquare.trade.protocol.trade.tasks.TradeTask;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class PublishTradeStatistics extends TradeTask {
|
||||
private static final Logger log = LoggerFactory.getLogger(PublishTradeStatistics.class);
|
||||
|
||||
public PublishTradeStatistics(TaskRunner taskHandler, Trade trade) {
|
||||
super(taskHandler, trade);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void run() {
|
||||
try {
|
||||
runInterceptHook();
|
||||
// taker only publishes if the offerer uses an old version
|
||||
processModel.getP2PService().getNetworkNode().getConfirmedConnections()
|
||||
.stream()
|
||||
.filter(c -> c.getPeersNodeAddressOptional().isPresent() && c.getPeersNodeAddressOptional().get().equals(trade.getTradingPeerNodeAddress()))
|
||||
.findAny()
|
||||
.ifPresent(c -> {
|
||||
TradeStatistics tradeStatistics = new TradeStatistics(trade.getOffer(),
|
||||
trade.getTradePrice(),
|
||||
trade.getTradeAmount(),
|
||||
trade.getDate(),
|
||||
(trade.getDepositTx() != null ? trade.getDepositTx().getHashAsString() : ""),
|
||||
processModel.getPubKeyRing());
|
||||
|
||||
final List<Integer> requiredCapabilities = tradeStatistics.getRequiredCapabilities();
|
||||
final List<Integer> supportedCapabilities = c.getSupportedCapabilities();
|
||||
boolean matches = false;
|
||||
if (supportedCapabilities != null) {
|
||||
for (int messageCapability : requiredCapabilities) {
|
||||
for (int connectionCapability : supportedCapabilities) {
|
||||
if (messageCapability == connectionCapability) {
|
||||
matches = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!matches) {
|
||||
log.error("We publish tradeStatistics because the offerer does use an old version.");
|
||||
processModel.getP2PService().addData(tradeStatistics, true);
|
||||
} else {
|
||||
log.error("We do not publish tradeStatistics because the offerer support the capabilities.");
|
||||
}
|
||||
});
|
||||
complete();
|
||||
} catch (Throwable t) {
|
||||
failed(t);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -111,7 +111,8 @@ public final class Preferences implements Persistable {
|
|||
private boolean autoSelectArbitrators = true;
|
||||
private final Map<String, Boolean> dontShowAgainMap;
|
||||
private boolean tacAccepted;
|
||||
private boolean useTorForBitcoinJ = true;
|
||||
//TODO we set it to false for now as it is not ready yet
|
||||
private boolean useTorForBitcoinJ = false;
|
||||
private boolean showOwnOffersInOfferBook = true;
|
||||
private Locale preferredLocale;
|
||||
private TradeCurrency preferredTradeCurrency;
|
||||
|
|
|
@ -26,6 +26,6 @@
|
|||
xmlns:fx="http://javafx.com/fxml">
|
||||
|
||||
<Tab fx:id="chartsTab" text="Offer book" closable="false"/>
|
||||
<Tab fx:id="tradesTab" text="Trades" closable="false"/>
|
||||
<Tab fx:id="statisticsTab" text="Spreads" closable="false"/>
|
||||
<Tab fx:id="tradesTab" text="Trades" closable="false"/>
|
||||
</TabPane>
|
||||
|
|
|
@ -28,7 +28,6 @@ public class CandleData {
|
|||
public final long accumulatedVolume;
|
||||
public final boolean isBullish;
|
||||
|
||||
// public CandleStickExtraValues(double close, double high, double low, double average, double volume) {
|
||||
public CandleData(long tick, long open, long close, long high, long low, long average, long accumulatedAmount, long accumulatedVolume, boolean isBullish) {
|
||||
this.tick = tick;
|
||||
this.open = open;
|
||||
|
|
|
@ -190,6 +190,8 @@ public class CandleStickChart extends XYChart<Number, Number> {
|
|||
for (int j = 0; j < series.getData().size(); j++) {
|
||||
XYChart.Data item = series.getData().get(j);
|
||||
Node candle = createCandle(seriesIndex, item, j);
|
||||
|
||||
if (!getPlotChildren().contains(candle)) {
|
||||
getPlotChildren().add(candle);
|
||||
if (shouldAnimate()) {
|
||||
candle.setOpacity(0);
|
||||
|
@ -198,9 +200,12 @@ public class CandleStickChart extends XYChart<Number, Number> {
|
|||
ft.play();
|
||||
}
|
||||
}
|
||||
}
|
||||
Path seriesPath = new Path();
|
||||
seriesPath.getStyleClass().setAll("candlestick-average-line", "series" + seriesIndex);
|
||||
series.setNode(seriesPath);
|
||||
|
||||
if (!getPlotChildren().contains(seriesPath)) {
|
||||
getPlotChildren().add(seriesPath);
|
||||
if (shouldAnimate()) {
|
||||
seriesPath.setOpacity(0);
|
||||
|
@ -209,6 +214,7 @@ public class CandleStickChart extends XYChart<Number, Number> {
|
|||
ft.play();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void seriesRemoved(XYChart.Series<Number, Number> series) {
|
||||
|
|
|
@ -208,8 +208,8 @@ public class CreateOfferView extends ActivatableViewAndModel<AnchorPane, CreateO
|
|||
|
||||
balanceTextField.setTargetAmount(model.dataModel.totalToPayAsCoin.get());
|
||||
|
||||
if (DevFlags.STRESS_TEST_MODE)
|
||||
UserThread.runAfter(this::onShowPayFundsScreen, 200, TimeUnit.MILLISECONDS);
|
||||
// if (DevFlags.STRESS_TEST_MODE)
|
||||
// UserThread.runAfter(this::onShowPayFundsScreen, 200, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -268,7 +268,7 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
|
|||
// called form parent as the view does not get notified when the tab is closed
|
||||
public void onClose() {
|
||||
Coin balance = model.dataModel.balance.get();
|
||||
if (balance != null && balance.isPositive() && !model.takeOfferCompleted.get()) {
|
||||
if (balance != null && balance.isPositive() && !model.takeOfferCompleted.get() && !DevFlags.DEV_MODE) {
|
||||
model.dataModel.swapTradeToSavings();
|
||||
new Popup().information("You had already funded that offer.\n" +
|
||||
"Your funds have been moved to your local Bitsquare wallet and are available for " +
|
||||
|
@ -523,7 +523,6 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
|
|||
showTransactionPublishedScreenSubscription = EasyBind.subscribe(model.showTransactionPublishedScreen, newValue -> {
|
||||
if (newValue && DevFlags.DEV_MODE) {
|
||||
close();
|
||||
navigation.navigateTo(MainView.class, PortfolioView.class, PendingTradesView.class);
|
||||
} else if (newValue && model.getTrade() != null && model.getTrade().errorMessageProperty().get() == null) {
|
||||
String key = "takeOfferSuccessInfo";
|
||||
if (preferences.showAgain(key)) {
|
||||
|
|
|
@ -128,6 +128,8 @@ public class NetworkSettingsView extends ActivatableViewAndModel<GridPane, Activ
|
|||
|
||||
@Override
|
||||
public void activate() {
|
||||
// TODO we deactive atm as its not ready now
|
||||
useTorCheckBox.setDisable(true);
|
||||
useTorCheckBox.setSelected(preferences.getUseTorForBitcoinJ());
|
||||
useTorCheckBox.setOnAction(event -> {
|
||||
boolean selected = useTorCheckBox.isSelected();
|
||||
|
|
|
@ -35,9 +35,12 @@ public class SeedNodesRepository {
|
|||
new NodeAddress("b66vnevaljo6xt5a.onion:8000"),*/
|
||||
|
||||
// v0.4.2
|
||||
// ...128
|
||||
DevFlags.STRESS_TEST_MODE ? new NodeAddress("hlitt7z4bec4kdh4.onion:8000") : new NodeAddress("uadzuib66jupaept.onion:8000"),
|
||||
DevFlags.STRESS_TEST_MODE ? new NodeAddress("hlitt7z4bec4kdh4.onion:8000") : new NodeAddress("hbma455xxbqhcuqh.onion:8000"),
|
||||
DevFlags.STRESS_TEST_MODE ? new NodeAddress("hlitt7z4bec4kdh4.onion:8000") : new NodeAddress("wgthuiqn3aoiovbm.onion:8000"),
|
||||
|
||||
// ...188
|
||||
DevFlags.STRESS_TEST_MODE ? new NodeAddress("hlitt7z4bec4kdh4.onion:8000") : new NodeAddress("hbma455xxbqhcuqh.onion:8000"),
|
||||
DevFlags.STRESS_TEST_MODE ? new NodeAddress("hlitt7z4bec4kdh4.onion:8000") : new NodeAddress("2zxtnprnx5wqr7a3.onion:8000"),
|
||||
|
||||
// testnet
|
||||
|
@ -50,9 +53,9 @@ public class SeedNodesRepository {
|
|||
// 3. Shut down the seed node
|
||||
// 4. Rename the directory with your local onion address
|
||||
// 5. Edit here your found onion address (new NodeAddress("YOUR_ONION.onion:8002")
|
||||
new NodeAddress("rxdkppp3vicnbgqt.onion:8002"),
|
||||
new NodeAddress("brmbf6mf67d2hlm4.onion:8002"),
|
||||
new NodeAddress("mfla72c4igh5ta2t.onion:8002")
|
||||
DevFlags.STRESS_TEST_MODE ? new NodeAddress("hlitt7z4bec4kdh4.onion:8002") : new NodeAddress("rxdkppp3vicnbgqt.onion:8002"),
|
||||
DevFlags.STRESS_TEST_MODE ? new NodeAddress("hlitt7z4bec4kdh4.onion:8002") : new NodeAddress("brmbf6mf67d2hlm4.onion:8002"),
|
||||
DevFlags.STRESS_TEST_MODE ? new NodeAddress("hlitt7z4bec4kdh4.onion:8002") : new NodeAddress("mfla72c4igh5ta2t.onion:8002")
|
||||
);
|
||||
|
||||
// Addresses are used if the last digit of their port match the network id:
|
||||
|
|
|
@ -14,6 +14,7 @@ import io.bitsquare.common.handlers.ResultHandler;
|
|||
import io.bitsquare.common.util.Utilities;
|
||||
import io.bitsquare.p2p.P2PService;
|
||||
import io.bitsquare.p2p.P2PServiceListener;
|
||||
import io.bitsquare.trade.TradeStatisticsManager;
|
||||
import io.bitsquare.trade.offer.OpenOfferManager;
|
||||
import org.apache.commons.lang3.exception.ExceptionUtils;
|
||||
import org.bitcoinj.store.BlockStoreException;
|
||||
|
@ -30,6 +31,7 @@ public class SeedNode {
|
|||
private static Environment env;
|
||||
private final Injector injector;
|
||||
private final SeedNodeModule seedNodeModule;
|
||||
private final TradeStatisticsManager tradeStatisticsManager;
|
||||
|
||||
private P2PService p2pService;
|
||||
|
||||
|
@ -116,6 +118,9 @@ public class SeedNode {
|
|||
|
||||
}
|
||||
});
|
||||
|
||||
// Wee want to persist trade statistics so we need to instantiate the tradeStatisticsManager
|
||||
tradeStatisticsManager = injector.getInstance(TradeStatisticsManager.class);
|
||||
}
|
||||
|
||||
public void shutDown() {
|
||||
|
|
Loading…
Add table
Reference in a new issue