From 66d3a23ec25d8c4595bb8e506a6332c957ea4844 Mon Sep 17 00:00:00 2001 From: woodser Date: Mon, 15 May 2023 12:03:10 -0400 Subject: [PATCH] seller publishes trade statistic on deposit response --- Makefile | 2 +- .../main/java/haveno/core/trade/Trade.java | 7 +- .../core/trade/protocol/TradeProtocol.java | 7 +- .../tasks/SellerPublishTradeStatistics.java | 74 +++++++++++-------- 4 files changed, 51 insertions(+), 39 deletions(-) diff --git a/Makefile b/Makefile index 2d411185cc..bfb152904a 100644 --- a/Makefile +++ b/Makefile @@ -145,7 +145,7 @@ arbitrator-desktop-local: --apiPassword=apitest \ --apiPort=9998 -arbitrator-desktop2-local: +arbitrator2-desktop-local: # Arbitrator needs to be registered before making trades ./haveno-desktop$(APP_EXT) \ --baseCurrencyNetwork=XMR_LOCAL \ diff --git a/core/src/main/java/haveno/core/trade/Trade.java b/core/src/main/java/haveno/core/trade/Trade.java index fb2c563e26..a50652e7e5 100644 --- a/core/src/main/java/haveno/core/trade/Trade.java +++ b/core/src/main/java/haveno/core/trade/Trade.java @@ -1071,7 +1071,8 @@ public abstract class Trade implements Tradable, Model { if (depositId == null) return null; try { if (trader.getDepositTx() == null || !trader.getDepositTx().isConfirmed()) { - trader.setDepositTx(getDepositTxFromWalletOrDaemon(depositId)); + MoneroTx depositTx = getDepositTxFromWalletOrDaemon(depositId); + if (depositTx != null) trader.setDepositTx(depositTx); } return trader.getDepositTx(); } catch (MoneroError e) { @@ -1801,8 +1802,8 @@ public abstract class Trade implements Tradable, Model { if (tx.getHash().equals(processModel.getMaker().getDepositTxHash())) makerDepositTx = tx; if (tx.getHash().equals(processModel.getTaker().getDepositTxHash())) takerDepositTx = tx; } - getMaker().setDepositTx(makerDepositTx); - getTaker().setDepositTx(takerDepositTx); + if (makerDepositTx != null) getMaker().setDepositTx(makerDepositTx); + if (takerDepositTx != null) getTaker().setDepositTx(takerDepositTx); // skip if deposit txs not seen if (makerDepositTx == null || takerDepositTx == null) return; diff --git a/core/src/main/java/haveno/core/trade/protocol/TradeProtocol.java b/core/src/main/java/haveno/core/trade/protocol/TradeProtocol.java index c932c5c43d..0367081b8a 100644 --- a/core/src/main/java/haveno/core/trade/protocol/TradeProtocol.java +++ b/core/src/main/java/haveno/core/trade/protocol/TradeProtocol.java @@ -52,6 +52,7 @@ import haveno.core.trade.protocol.tasks.ProcessPaymentSentMessage; import haveno.core.trade.protocol.tasks.ProcessSignContractRequest; import haveno.core.trade.protocol.tasks.ProcessSignContractResponse; import haveno.core.trade.protocol.tasks.RemoveOffer; +import haveno.core.trade.protocol.tasks.SellerPublishTradeStatistics; import haveno.core.trade.protocol.tasks.MaybeResendDisputeClosedMessageWithPayout; import haveno.core.trade.protocol.tasks.TradeTask; import haveno.core.trade.protocol.tasks.VerifyPeersAccountAgeWitness; @@ -418,11 +419,11 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D processModel.setTradeMessage(response); expect(anyState(Trade.State.SENT_PUBLISH_DEPOSIT_TX_REQUEST, Trade.State.SAW_ARRIVED_PUBLISH_DEPOSIT_TX_REQUEST, Trade.State.ARBITRATOR_PUBLISHED_DEPOSIT_TXS, Trade.State.DEPOSIT_TXS_SEEN_IN_NETWORK) .with(response) - .from(sender)) // TODO (woodser): ensure this asserts sender == response.getSenderNodeAddress() + .from(sender)) .setup(tasks( - // TODO (woodser): validate request ProcessDepositResponse.class, - RemoveOffer.class) + RemoveOffer.class, + SellerPublishTradeStatistics.class) .using(new TradeTaskRunner(trade, () -> { stopTimeout(); diff --git a/core/src/main/java/haveno/core/trade/protocol/tasks/SellerPublishTradeStatistics.java b/core/src/main/java/haveno/core/trade/protocol/tasks/SellerPublishTradeStatistics.java index 32535b8dd7..af41cbe48e 100644 --- a/core/src/main/java/haveno/core/trade/protocol/tasks/SellerPublishTradeStatistics.java +++ b/core/src/main/java/haveno/core/trade/protocol/tasks/SellerPublishTradeStatistics.java @@ -17,10 +17,16 @@ package haveno.core.trade.protocol.tasks; +import haveno.common.app.Capability; import haveno.common.taskrunner.TaskRunner; +import haveno.core.trade.SellerTrade; import haveno.core.trade.Trade; +import haveno.core.trade.statistics.TradeStatistics3; +import haveno.network.p2p.network.TorNetworkNode; import lombok.extern.slf4j.Slf4j; +import static com.google.common.base.Preconditions.checkNotNull; + @Slf4j public class SellerPublishTradeStatistics extends TradeTask { public SellerPublishTradeStatistics(TaskRunner taskHandler, Trade trade) { @@ -29,37 +35,41 @@ public class SellerPublishTradeStatistics extends TradeTask { @Override protected void run() { - throw new RuntimeException("SellerPublishesTradeStatistics needs updated for XMR"); -// try { -// runInterceptHook(); -// -// checkNotNull(trade.getDepositTx()); -// -// processModel.getP2PService().findPeersCapabilities(trade.getTradePeer().getNodeAddress()) -// .filter(capabilities -> capabilities.containsAll(Capability.TRADE_STATISTICS_3)) -// .ifPresentOrElse(capabilities -> { -// // Our peer has updated, so as we are the seller we will publish the trade statistics. -// // The peer as buyer does not publish anymore with v.1.4.0 (where Capability.TRADE_STATISTICS_3 was added) -// -// String referralId = processModel.getReferralIdService().getOptionalReferralId().orElse(null); -// boolean isTorNetworkNode = model.getProcessModel().getP2PService().getNetworkNode() instanceof TorNetworkNode; -// TradeStatistics3 tradeStatistics = TradeStatistics3.from(trade, referralId, isTorNetworkNode); -// if (tradeStatistics.isValid()) { -// log.info("Publishing trade statistics"); -// processModel.getP2PService().addPersistableNetworkPayload(tradeStatistics, true); -// } else { -// log.warn("Trade statistics are invalid. We do not publish. {}", tradeStatistics); -// } -// -// complete(); -// }, -// () -> { -// log.info("Our peer does not has updated yet, so they will publish the trade statistics. " + -// "To avoid duplicates we do not publish from our side."); -// complete(); -// }); -// } catch (Throwable t) { -// failed(t); -// } + try { + runInterceptHook(); + + // skip if not seller + if (!(trade instanceof SellerTrade)) { + complete(); + return; + } + + checkNotNull(trade.getSeller().getDepositTx()); + processModel.getP2PService().findPeersCapabilities(trade.getTradePeer().getNodeAddress()) + .filter(capabilities -> capabilities.containsAll(Capability.TRADE_STATISTICS_3)) + .ifPresentOrElse(capabilities -> { + // Our peer has updated, so as we are the seller we will publish the trade statistics. + // The peer as buyer does not publish anymore with v.1.4.0 (where Capability.TRADE_STATISTICS_3 was added) + + String referralId = processModel.getReferralIdService().getOptionalReferralId().orElse(null); + boolean isTorNetworkNode = model.getProcessModel().getP2PService().getNetworkNode() instanceof TorNetworkNode; + TradeStatistics3 tradeStatistics = TradeStatistics3.from(trade, referralId, isTorNetworkNode); + if (tradeStatistics.isValid()) { + log.info("Publishing trade statistics"); + processModel.getP2PService().addPersistableNetworkPayload(tradeStatistics, true); + } else { + log.warn("Trade statistics are invalid. We do not publish. {}", tradeStatistics); + } + + complete(); + }, + () -> { + log.info("Our peer does not has updated yet, so they will publish the trade statistics. " + + "To avoid duplicates we do not publish from our side."); + complete(); + }); + } catch (Throwable t) { + failed(t); + } } }