From ed5078c0f15589b2d75c5e87da643417200d33b8 Mon Sep 17 00:00:00 2001 From: chimp1984 Date: Sun, 30 Aug 2020 15:45:47 -0500 Subject: [PATCH] Add abstract AutoConfirmResult class to get better support if we want to add auto confirm for other currencies in the future. The generic part is only used where we would have issues with backward compatibility like in the protobuf objects. Most of the current classes are kept XMR specific and could be generalized once we add other assets, but that would be an internal refactoring without breaking any network or storage data. I think it would be premature to go further here as we don't know the details of other use cases. I added the methods used from clients to AutoConfirmResult, not sure if the API is well defined by that, but as said that could become subject of a future refactoring once another auto confirm feature gets added. Goal of that refactoring was to avoid that we need more fields for trade and the the UI would have to deal with lots of switch cases based on currency. Sorry that is a larger commit, would have been hard to break up... --- .../bisq/core/trade/AutoConfirmResult.java | 122 +++++----------- core/src/main/java/bisq/core/trade/Trade.java | 11 +- .../java/bisq/core/trade/TradeManager.java | 8 +- .../bisq/core/trade/XmrAutoConfirmResult.java | 136 ++++++++++++++++++ ...r.java => XmrAutoConfirmationManager.java} | 42 +++--- .../core/trade/asset/xmr/XmrProofInfo.java | 40 +++--- .../asset/xmr/XmrTransferProofRequester.java | 14 +- .../asset/xmr/XmrTransferProofService.java | 4 +- .../core/trade/protocol/ProcessModel.java | 8 +- ...CounterCurrencyTransferStartedMessage.java | 2 +- .../trade/asset/xmr/XmrProofInfoTest.java | 42 +++--- .../overlays/windows/TradeDetailsWindow.java | 4 +- .../steps/buyer/BuyerStep4View.java | 2 +- .../steps/seller/SellerStep3View.java | 7 +- proto/src/main/proto/pb.proto | 2 +- 15 files changed, 263 insertions(+), 181 deletions(-) create mode 100644 core/src/main/java/bisq/core/trade/XmrAutoConfirmResult.java rename core/src/main/java/bisq/core/trade/{AutoConfirmationManager.java => XmrAutoConfirmationManager.java} (88%) diff --git a/core/src/main/java/bisq/core/trade/AutoConfirmResult.java b/core/src/main/java/bisq/core/trade/AutoConfirmResult.java index 29f6bce8ac..bed7463d0f 100644 --- a/core/src/main/java/bisq/core/trade/AutoConfirmResult.java +++ b/core/src/main/java/bisq/core/trade/AutoConfirmResult.java @@ -17,115 +17,57 @@ package bisq.core.trade; -import bisq.core.locale.Res; - -import bisq.common.proto.ProtoUtil; - -import lombok.Value; -import lombok.extern.slf4j.Slf4j; +import lombok.EqualsAndHashCode; +import lombok.Getter; import javax.annotation.Nullable; -@Slf4j -@Value -public class AutoConfirmResult { - public enum State { - UNDEFINED, - FEATURE_DISABLED, - TX_NOT_FOUND, - TX_NOT_CONFIRMED, - PROOF_OK, - CONNECTION_FAIL, - API_FAILURE, - API_INVALID, - TX_KEY_REUSED, - TX_HASH_INVALID, - TX_KEY_INVALID, - ADDRESS_INVALID, - NO_MATCH_FOUND, - AMOUNT_NOT_MATCHING, - TRADE_LIMIT_EXCEEDED, - TRADE_DATE_NOT_MATCHING - } +/** + * Base class for AutoConfirm implementations + */ +@EqualsAndHashCode +@Getter +public abstract class AutoConfirmResult { - // Only state gets persisted - private final State state; - - private final transient int confirmCount; - private final transient int confirmsRequired; - - - /////////////////////////////////////////////////////////////////////////////////////////// - // Constructor - /////////////////////////////////////////////////////////////////////////////////////////// - - public AutoConfirmResult(State state) { - this(state, 0, 0); - } - - // alternate constructor for showing confirmation progress information - public AutoConfirmResult(State state, int confirmCount, int confirmsRequired) { - this.state = state; - this.confirmCount = confirmCount; - this.confirmsRequired = confirmsRequired; - } - - // alternate constructor for error scenarios - public AutoConfirmResult(State state, @Nullable String errorMsg) { - this(state, 0, 0); - - if (isErrorState()) { - log.error(errorMsg != null ? errorMsg : state.toString()); + public static AutoConfirmResult fromCurrencyCode(String currencyCode) { + switch (currencyCode) { + case "XMR": + return new XmrAutoConfirmResult(); + default: + return null; } } + private final String stateName; + + protected AutoConfirmResult(String stateName) { + this.stateName = stateName; + } + /////////////////////////////////////////////////////////////////////////////////////////// // PROTOBUF /////////////////////////////////////////////////////////////////////////////////////////// - public protobuf.AutoConfirmResult toProtoMessage() { - return protobuf.AutoConfirmResult.newBuilder().setStateName(state.name()).build(); + // We use fromProto as kind of factory method to get the specific AutoConfirmResult + @Nullable + static AutoConfirmResult fromProto(protobuf.AutoConfirmResult proto, String currencyCode) { + switch (currencyCode) { + case "XMR": + return XmrAutoConfirmResult.fromProto(proto); + default: + return null; + } } - public static AutoConfirmResult fromProto(protobuf.AutoConfirmResult proto) { - AutoConfirmResult.State state = ProtoUtil.enumFromProto(AutoConfirmResult.State.class, proto.getStateName()); - return state != null ? new AutoConfirmResult(state) : new AutoConfirmResult(State.UNDEFINED); - - } + public abstract protobuf.AutoConfirmResult toProtoMessage(); /////////////////////////////////////////////////////////////////////////////////////////// // API /////////////////////////////////////////////////////////////////////////////////////////// - public String getTextStatus() { - switch (state) { - case TX_NOT_CONFIRMED: - return Res.get("portfolio.pending.autoConfirmPending") - + " " + confirmCount - + "/" + confirmsRequired; - case TX_NOT_FOUND: - return Res.get("portfolio.pending.autoConfirmTxNotFound"); - case FEATURE_DISABLED: - return Res.get("portfolio.pending.autoConfirmDisabled"); - case PROOF_OK: - return Res.get("portfolio.pending.autoConfirmSuccess"); - default: - // any other statuses we display the enum name - return this.state.toString(); - } - } + abstract public boolean isSuccessState(); - public boolean isPendingState() { - return (state == State.TX_NOT_FOUND || state == State.TX_NOT_CONFIRMED); - } - - public boolean isSuccessState() { - return (state == State.PROOF_OK); - } - - public boolean isErrorState() { - return (!isPendingState() && !isSuccessState()); - } + abstract public String getTextStatus(); } diff --git a/core/src/main/java/bisq/core/trade/Trade.java b/core/src/main/java/bisq/core/trade/Trade.java index 5ca75ca76d..dc765d5200 100644 --- a/core/src/main/java/bisq/core/trade/Trade.java +++ b/core/src/main/java/bisq/core/trade/Trade.java @@ -435,7 +435,10 @@ public abstract class Trade implements Tradable, Model { @Setter private String counterCurrencyExtraData; - @Getter + public AutoConfirmResult getAutoConfirmResult() { + return autoConfirmResult != null ? autoConfirmResult : AutoConfirmResult.fromCurrencyCode(checkNotNull(offer).getCurrencyCode()); + } + @Nullable private AutoConfirmResult autoConfirmResult; @@ -595,7 +598,7 @@ public abstract class Trade implements Tradable, Model { trade.setLockTime(proto.getLockTime()); trade.setLastRefreshRequestDate(proto.getLastRefreshRequestDate()); trade.setCounterCurrencyExtraData(ProtoUtil.stringOrNullFromProto(proto.getCounterCurrencyExtraData())); - trade.setAutoConfirmResult(AutoConfirmResult.fromProto(proto.getAutoConfirmResult())); + trade.setAutoConfirmResult(AutoConfirmResult.fromProto(proto.getAutoConfirmResult(), checkNotNull(trade.getOffer()).getCurrencyCode())); trade.chatMessages.addAll(proto.getChatMessageList().stream() .map(ChatMessage::fromPayloadProto) @@ -625,7 +628,7 @@ public abstract class Trade implements Tradable, Model { User user, FilterManager filterManager, AccountAgeWitnessService accountAgeWitnessService, - AutoConfirmationManager autoConfirmationManager, + XmrAutoConfirmationManager xmrAutoConfirmationManager, TradeStatisticsManager tradeStatisticsManager, ArbitratorManager arbitratorManager, MediatorManager mediatorManager, @@ -645,7 +648,7 @@ public abstract class Trade implements Tradable, Model { user, filterManager, accountAgeWitnessService, - autoConfirmationManager, + xmrAutoConfirmationManager, tradeStatisticsManager, arbitratorManager, mediatorManager, diff --git a/core/src/main/java/bisq/core/trade/TradeManager.java b/core/src/main/java/bisq/core/trade/TradeManager.java index 3a7cd125b3..70ecd216c8 100644 --- a/core/src/main/java/bisq/core/trade/TradeManager.java +++ b/core/src/main/java/bisq/core/trade/TradeManager.java @@ -126,7 +126,7 @@ public class TradeManager implements PersistedDataHost { private final TradeStatisticsManager tradeStatisticsManager; private final ReferralIdService referralIdService; private final AccountAgeWitnessService accountAgeWitnessService; - private final AutoConfirmationManager autoConfirmationManager; + private final XmrAutoConfirmationManager xmrAutoConfirmationManager; private final ArbitratorManager arbitratorManager; private final MediatorManager mediatorManager; private final RefundAgentManager refundAgentManager; @@ -168,7 +168,7 @@ public class TradeManager implements PersistedDataHost { TradeStatisticsManager tradeStatisticsManager, ReferralIdService referralIdService, AccountAgeWitnessService accountAgeWitnessService, - AutoConfirmationManager autoConfirmationManager, + XmrAutoConfirmationManager xmrAutoConfirmationManager, ArbitratorManager arbitratorManager, MediatorManager mediatorManager, RefundAgentManager refundAgentManager, @@ -191,7 +191,7 @@ public class TradeManager implements PersistedDataHost { this.tradeStatisticsManager = tradeStatisticsManager; this.referralIdService = referralIdService; this.accountAgeWitnessService = accountAgeWitnessService; - this.autoConfirmationManager = autoConfirmationManager; + this.xmrAutoConfirmationManager = xmrAutoConfirmationManager; this.arbitratorManager = arbitratorManager; this.mediatorManager = mediatorManager; this.refundAgentManager = refundAgentManager; @@ -436,7 +436,7 @@ public class TradeManager implements PersistedDataHost { user, filterManager, accountAgeWitnessService, - autoConfirmationManager, + xmrAutoConfirmationManager, tradeStatisticsManager, arbitratorManager, mediatorManager, diff --git a/core/src/main/java/bisq/core/trade/XmrAutoConfirmResult.java b/core/src/main/java/bisq/core/trade/XmrAutoConfirmResult.java new file mode 100644 index 0000000000..4bce7bedf1 --- /dev/null +++ b/core/src/main/java/bisq/core/trade/XmrAutoConfirmResult.java @@ -0,0 +1,136 @@ +/* + * 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 . + */ + +package bisq.core.trade; + +import bisq.core.locale.Res; + +import bisq.common.proto.ProtoUtil; + +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; + +import javax.annotation.Nullable; + +@Slf4j +@Getter +@EqualsAndHashCode(callSuper = true) +public class XmrAutoConfirmResult extends AutoConfirmResult { + public enum State { + UNDEFINED, + FEATURE_DISABLED, + TX_NOT_FOUND, + TX_NOT_CONFIRMED, + PROOF_OK, + CONNECTION_FAIL, + API_FAILURE, + API_INVALID, + TX_KEY_REUSED, + TX_HASH_INVALID, + TX_KEY_INVALID, + ADDRESS_INVALID, + NO_MATCH_FOUND, + AMOUNT_NOT_MATCHING, + TRADE_LIMIT_EXCEEDED, + TRADE_DATE_NOT_MATCHING + } + + private final State state; + private final transient int confirmCount; + private final transient int confirmsRequired; + + + /////////////////////////////////////////////////////////////////////////////////////////// + // Constructor + /////////////////////////////////////////////////////////////////////////////////////////// + + public XmrAutoConfirmResult() { + this(State.UNDEFINED, 0, 0); + } + + public XmrAutoConfirmResult(State state) { + this(state, 0, 0); + } + + // alternate constructor for showing confirmation progress information + public XmrAutoConfirmResult(State state, int confirmCount, int confirmsRequired) { + super(state.name()); + this.state = state; + this.confirmCount = confirmCount; + this.confirmsRequired = confirmsRequired; + } + + // alternate constructor for error scenarios + public XmrAutoConfirmResult(State state, @Nullable String errorMsg) { + this(state, 0, 0); + + if (isErrorState()) { + log.error(errorMsg != null ? errorMsg : state.toString()); + } + } + + + /////////////////////////////////////////////////////////////////////////////////////////// + // PROTOBUF + /////////////////////////////////////////////////////////////////////////////////////////// + + @Override + public protobuf.AutoConfirmResult toProtoMessage() { + return protobuf.AutoConfirmResult.newBuilder().setStateName(state.name()).build(); + } + + public static XmrAutoConfirmResult fromProto(protobuf.AutoConfirmResult proto) { + XmrAutoConfirmResult.State state = ProtoUtil.enumFromProto(XmrAutoConfirmResult.State.class, proto.getStateName()); + return state != null ? new XmrAutoConfirmResult(state) : new XmrAutoConfirmResult(State.UNDEFINED); + } + + + /////////////////////////////////////////////////////////////////////////////////////////// + // API + /////////////////////////////////////////////////////////////////////////////////////////// + + public String getTextStatus() { + switch (state) { + case TX_NOT_CONFIRMED: + return Res.get("portfolio.pending.autoConfirmPending") + + " " + confirmCount + + "/" + confirmsRequired; + case TX_NOT_FOUND: + return Res.get("portfolio.pending.autoConfirmTxNotFound"); + case FEATURE_DISABLED: + return Res.get("portfolio.pending.autoConfirmDisabled"); + case PROOF_OK: + return Res.get("portfolio.pending.autoConfirmSuccess"); + default: + // any other statuses we display the enum name + return this.state.toString(); + } + } + + public boolean isPendingState() { + return (state == State.TX_NOT_FOUND || state == State.TX_NOT_CONFIRMED); + } + + public boolean isSuccessState() { + return (state == State.PROOF_OK); + } + + public boolean isErrorState() { + return (!isPendingState() && !isSuccessState()); + } +} diff --git a/core/src/main/java/bisq/core/trade/AutoConfirmationManager.java b/core/src/main/java/bisq/core/trade/XmrAutoConfirmationManager.java similarity index 88% rename from core/src/main/java/bisq/core/trade/AutoConfirmationManager.java rename to core/src/main/java/bisq/core/trade/XmrAutoConfirmationManager.java index 6f9f2bce8b..67a6bbeeab 100644 --- a/core/src/main/java/bisq/core/trade/AutoConfirmationManager.java +++ b/core/src/main/java/bisq/core/trade/XmrAutoConfirmationManager.java @@ -20,6 +20,7 @@ package bisq.core.trade; import bisq.core.account.witness.AccountAgeWitnessService; import bisq.core.btc.setup.WalletsSetup; import bisq.core.filter.FilterManager; +import bisq.core.monetary.Volume; import bisq.core.offer.Offer; import bisq.core.payment.payload.AssetsAccountPayload; import bisq.core.payment.payload.PaymentAccountPayload; @@ -49,7 +50,7 @@ import static com.google.common.base.Preconditions.checkNotNull; @Slf4j @Singleton -public class AutoConfirmationManager { +public class XmrAutoConfirmationManager { private final FilterManager filterManager; private final Preferences preferences; @@ -66,15 +67,15 @@ public class AutoConfirmationManager { /////////////////////////////////////////////////////////////////////////////////////////// @Inject - AutoConfirmationManager(FilterManager filterManager, - Preferences preferences, - XmrTransferProofService xmrTransferProofService, - ClosedTradableManager closedTradableManager, - FailedTradesManager failedTradesManager, - P2PService p2PService, - WalletsSetup walletsSetup, - AccountAgeWitnessService accountAgeWitnessService - ) { + XmrAutoConfirmationManager(FilterManager filterManager, + Preferences preferences, + XmrTransferProofService xmrTransferProofService, + ClosedTradableManager closedTradableManager, + FailedTradesManager failedTradesManager, + P2PService p2PService, + WalletsSetup walletsSetup, + AccountAgeWitnessService accountAgeWitnessService + ) { this.filterManager = filterManager; this.preferences = preferences; this.xmrTransferProofService = xmrTransferProofService; @@ -153,7 +154,7 @@ public class AutoConfirmationManager { if (alreadyUsed) { String message = "Peer used the XMR tx key already at another trade with trade ID " + t.getId() + ". This might be a scam attempt."; - trade.setAutoConfirmResult(new AutoConfirmResult(AutoConfirmResult.State.TX_KEY_REUSED, message)); + trade.setAutoConfirmResult(new XmrAutoConfirmResult(XmrAutoConfirmResult.State.TX_KEY_REUSED, message)); } return alreadyUsed; }); @@ -163,23 +164,24 @@ public class AutoConfirmationManager { } if (!preferences.getAutoConfirmSettings().enabled || this.isAutoConfDisabledByFilter()) { - trade.setAutoConfirmResult(new AutoConfirmResult(AutoConfirmResult.State.FEATURE_DISABLED, null)); + trade.setAutoConfirmResult(new XmrAutoConfirmResult(XmrAutoConfirmResult.State.FEATURE_DISABLED, null)); return; } Coin tradeAmount = trade.getTradeAmount(); Coin tradeLimit = Coin.valueOf(preferences.getAutoConfirmSettings().tradeLimit); - if (tradeAmount.isGreaterThan(tradeLimit)) { + if (tradeAmount != null && tradeAmount.isGreaterThan(tradeLimit)) { log.warn("Trade amount {} is higher than settings limit {}, will not attempt auto-confirm", tradeAmount.toFriendlyString(), tradeLimit.toFriendlyString()); - trade.setAutoConfirmResult(new AutoConfirmResult(AutoConfirmResult.State.TRADE_LIMIT_EXCEEDED, null)); + trade.setAutoConfirmResult(new XmrAutoConfirmResult(XmrAutoConfirmResult.State.TRADE_LIMIT_EXCEEDED, null)); return; } String address = sellersAssetsAccountPayload.getAddress(); // XMR satoshis have 12 decimal places vs. bitcoin's 8 - long amountXmr = offer.getVolumeByAmount(tradeAmount).getValue() * 10000L; + Volume volume = offer.getVolumeByAmount(tradeAmount); + long amountXmr = volume != null ? volume.getValue() * 10000L : 0L; int confirmsRequired = preferences.getAutoConfirmSettings().requiredConfirmations; - trade.setAutoConfirmResult(new AutoConfirmResult(AutoConfirmResult.State.TX_NOT_FOUND)); + trade.setAutoConfirmResult(new XmrAutoConfirmResult(XmrAutoConfirmResult.State.TX_NOT_FOUND)); List serviceAddresses = preferences.getAutoConfirmSettings().serviceAddresses; txProofResultsPending.put(trade.getId(), serviceAddresses.size()); // need result from each service address for (String serviceAddress : serviceAddresses) { @@ -204,7 +206,7 @@ public class AutoConfirmationManager { } } - private boolean handleProofResult(AutoConfirmResult result, Trade trade) { + private boolean handleProofResult(XmrAutoConfirmResult result, Trade trade) { boolean success = true; boolean failure = false; @@ -250,8 +252,10 @@ public class AutoConfirmationManager { } accountAgeWitnessService.maybeSignWitness(trade); // transition the trade to step 4: - ((SellerTrade) trade).onFiatPaymentReceived(() -> { }, - errorMessage -> { }); + ((SellerTrade) trade).onFiatPaymentReceived(() -> { + }, + errorMessage -> { + }); return success; } diff --git a/core/src/main/java/bisq/core/trade/asset/xmr/XmrProofInfo.java b/core/src/main/java/bisq/core/trade/asset/xmr/XmrProofInfo.java index 64a852a8c2..ebbbee968b 100644 --- a/core/src/main/java/bisq/core/trade/asset/xmr/XmrProofInfo.java +++ b/core/src/main/java/bisq/core/trade/asset/xmr/XmrProofInfo.java @@ -17,7 +17,7 @@ package bisq.core.trade.asset.xmr; -import bisq.core.trade.AutoConfirmResult; +import bisq.core.trade.XmrAutoConfirmResult; import bisq.asset.CryptoNoteAddressValidator; @@ -68,57 +68,57 @@ public class XmrProofInfo { return txHash + "|" + serviceAddress; } - public AutoConfirmResult checkApiResponse(String jsonTxt) { + public XmrAutoConfirmResult checkApiResponse(String jsonTxt) { try { JsonObject json = new Gson().fromJson(jsonTxt, JsonObject.class); if (json == null) { - return new AutoConfirmResult(AutoConfirmResult.State.API_INVALID, "Empty json"); + return new XmrAutoConfirmResult(XmrAutoConfirmResult.State.API_INVALID, "Empty json"); } // there should always be "data" and "status" at the top level if (json.get("data") == null || !json.get("data").isJsonObject() || json.get("status") == null) { - return new AutoConfirmResult(AutoConfirmResult.State.API_INVALID, "Missing data / status fields"); + return new XmrAutoConfirmResult(XmrAutoConfirmResult.State.API_INVALID, "Missing data / status fields"); } JsonObject jsonData = json.get("data").getAsJsonObject(); String jsonStatus = json.get("status").getAsString(); if (jsonStatus.matches("fail")) { // the API returns "fail" until the transaction has successfully reached the mempool. // we return TX_NOT_FOUND which will cause a retry later - return new AutoConfirmResult(AutoConfirmResult.State.TX_NOT_FOUND, null); + return new XmrAutoConfirmResult(XmrAutoConfirmResult.State.TX_NOT_FOUND, null); } else if (!jsonStatus.matches("success")) { - return new AutoConfirmResult(AutoConfirmResult.State.API_FAILURE, "Unhandled status value"); + return new XmrAutoConfirmResult(XmrAutoConfirmResult.State.API_FAILURE, "Unhandled status value"); } // validate that the address matches JsonElement jsonAddress = jsonData.get("address"); if (jsonAddress == null) { - return new AutoConfirmResult(AutoConfirmResult.State.API_INVALID, "Missing address field"); + return new XmrAutoConfirmResult(XmrAutoConfirmResult.State.API_INVALID, "Missing address field"); } else { String expectedAddressHex = CryptoNoteAddressValidator.convertToRawHex(this.recipientAddress); if (!jsonAddress.getAsString().equalsIgnoreCase(expectedAddressHex)) { log.warn("address {}, expected: {}", jsonAddress.getAsString(), expectedAddressHex); - return new AutoConfirmResult(AutoConfirmResult.State.ADDRESS_INVALID, null); + return new XmrAutoConfirmResult(XmrAutoConfirmResult.State.ADDRESS_INVALID, null); } } // validate that the txhash matches JsonElement jsonTxHash = jsonData.get("tx_hash"); if (jsonTxHash == null) { - return new AutoConfirmResult(AutoConfirmResult.State.API_INVALID, "Missing tx_hash field"); + return new XmrAutoConfirmResult(XmrAutoConfirmResult.State.API_INVALID, "Missing tx_hash field"); } else { if (!jsonTxHash.getAsString().equalsIgnoreCase(txHash)) { log.warn("txHash {}, expected: {}", jsonTxHash.getAsString(), txHash); - return new AutoConfirmResult(AutoConfirmResult.State.TX_HASH_INVALID, null); + return new XmrAutoConfirmResult(XmrAutoConfirmResult.State.TX_HASH_INVALID, null); } } // validate that the txkey matches JsonElement jsonViewkey = jsonData.get("viewkey"); if (jsonViewkey == null) { - return new AutoConfirmResult(AutoConfirmResult.State.API_INVALID, "Missing viewkey field"); + return new XmrAutoConfirmResult(XmrAutoConfirmResult.State.API_INVALID, "Missing viewkey field"); } else { if (!jsonViewkey.getAsString().equalsIgnoreCase(this.txKey)) { log.warn("viewkey {}, expected: {}", jsonViewkey.getAsString(), txKey); - return new AutoConfirmResult(AutoConfirmResult.State.TX_KEY_INVALID, null); + return new XmrAutoConfirmResult(XmrAutoConfirmResult.State.TX_KEY_INVALID, null); } } @@ -126,7 +126,7 @@ public class XmrProofInfo { // (except that in dev mode we let this check pass anyway) JsonElement jsonTimestamp = jsonData.get("tx_timestamp"); if (jsonTimestamp == null) { - return new AutoConfirmResult(AutoConfirmResult.State.API_INVALID, "Missing tx_timestamp field"); + return new XmrAutoConfirmResult(XmrAutoConfirmResult.State.API_INVALID, "Missing tx_timestamp field"); } else { long tradeDateSeconds = tradeDate.getTime() / 1000; long difference = tradeDateSeconds - jsonTimestamp.getAsLong(); @@ -134,7 +134,7 @@ public class XmrProofInfo { if (difference > TimeUnit.HOURS.toSeconds(2) && !DevEnv.isDevMode()) { log.warn("tx_timestamp {}, tradeDate: {}, difference {}", jsonTimestamp.getAsLong(), tradeDateSeconds, difference); - return new AutoConfirmResult(AutoConfirmResult.State.TRADE_DATE_NOT_MATCHING, null); + return new XmrAutoConfirmResult(XmrAutoConfirmResult.State.TRADE_DATE_NOT_MATCHING, null); } } @@ -142,7 +142,7 @@ public class XmrProofInfo { int confirmations; JsonElement jsonConfs = jsonData.get("tx_confirmations"); if (jsonConfs == null) { - return new AutoConfirmResult(AutoConfirmResult.State.API_INVALID, "Missing tx_confirmations field"); + return new XmrAutoConfirmResult(XmrAutoConfirmResult.State.API_INVALID, "Missing tx_confirmations field"); } else { confirmations = jsonConfs.getAsInt(); log.info("Confirmations: {}, xmr txHash: {}", confirmations, txHash); @@ -161,23 +161,23 @@ public class XmrProofInfo { if (jsonAmount == amount || DevEnv.isDevMode()) { // any amount ok in dev mode if (confirmations < confirmsRequired) // we return TX_NOT_CONFIRMED which will cause a retry later - return new AutoConfirmResult(AutoConfirmResult.State.TX_NOT_CONFIRMED, confirmations, confirmsRequired); + return new XmrAutoConfirmResult(XmrAutoConfirmResult.State.TX_NOT_CONFIRMED, confirmations, confirmsRequired); else - return new AutoConfirmResult(AutoConfirmResult.State.PROOF_OK, confirmations, confirmsRequired); + return new XmrAutoConfirmResult(XmrAutoConfirmResult.State.PROOF_OK, confirmations, confirmsRequired); } } } // None of the outputs had a match entry if (!anyMatchFound) { - return new AutoConfirmResult(AutoConfirmResult.State.NO_MATCH_FOUND, null); + return new XmrAutoConfirmResult(XmrAutoConfirmResult.State.NO_MATCH_FOUND, null); } // reaching this point means there was no matching amount - return new AutoConfirmResult(AutoConfirmResult.State.AMOUNT_NOT_MATCHING, null); + return new XmrAutoConfirmResult(XmrAutoConfirmResult.State.AMOUNT_NOT_MATCHING, null); } catch (JsonParseException | NullPointerException e) { - return new AutoConfirmResult(AutoConfirmResult.State.API_INVALID, e.toString()); + return new XmrAutoConfirmResult(XmrAutoConfirmResult.State.API_INVALID, e.toString()); } } } diff --git a/core/src/main/java/bisq/core/trade/asset/xmr/XmrTransferProofRequester.java b/core/src/main/java/bisq/core/trade/asset/xmr/XmrTransferProofRequester.java index 53b8293b1f..1003e05429 100644 --- a/core/src/main/java/bisq/core/trade/asset/xmr/XmrTransferProofRequester.java +++ b/core/src/main/java/bisq/core/trade/asset/xmr/XmrTransferProofRequester.java @@ -17,7 +17,7 @@ package bisq.core.trade.asset.xmr; -import bisq.core.trade.AutoConfirmResult; +import bisq.core.trade.XmrAutoConfirmResult; import bisq.network.Socks5ProxyProvider; @@ -50,7 +50,7 @@ public class XmrTransferProofRequester { "XmrTransferProofRequester", 3, 5, 10 * 60); private final XmrTxProofHttpClient httpClient; private final XmrProofInfo xmrProofInfo; - private final Consumer resultHandler; + private final Consumer resultHandler; private final FaultHandler faultHandler; private boolean terminated; @@ -63,7 +63,7 @@ public class XmrTransferProofRequester { XmrTransferProofRequester(@Nullable Socks5ProxyProvider socks5ProxyProvider, XmrProofInfo xmrProofInfo, - Consumer resultHandler, + Consumer resultHandler, FaultHandler faultHandler) { this.httpClient = new XmrTxProofHttpClient(socks5ProxyProvider); this.httpClient.setBaseUrl("http://" + xmrProofInfo.getServiceAddress()); @@ -94,7 +94,7 @@ public class XmrTransferProofRequester { log.info("Request() aborted, this object has been terminated. Service: {}", httpClient.getBaseUrl()); return; } - ListenableFuture future = executorService.submit(() -> { + ListenableFuture future = executorService.submit(() -> { Thread.currentThread().setName("XmrTransferProofRequest-" + xmrProofInfo.getKey()); String param = "/api/outputs?txhash=" + xmrProofInfo.getTxHash() + "&address=" + xmrProofInfo.getRecipientAddress() + @@ -102,13 +102,13 @@ public class XmrTransferProofRequester { "&txprove=1"; log.info("Requesting from {} with param {}", httpClient.getBaseUrl(), param); String json = httpClient.requestWithGET(param, "User-Agent", "bisq/" + Version.VERSION); - AutoConfirmResult autoConfirmResult = xmrProofInfo.checkApiResponse(json); + XmrAutoConfirmResult autoConfirmResult = xmrProofInfo.checkApiResponse(json); log.info("Response json {} resulted in autoConfirmResult {}", json, autoConfirmResult); return autoConfirmResult; }); Futures.addCallback(future, new FutureCallback<>() { - public void onSuccess(AutoConfirmResult result) { + public void onSuccess(XmrAutoConfirmResult result) { if (terminated) { log.info("API terminated from higher level: {}", httpClient.getBaseUrl()); return; @@ -127,7 +127,7 @@ public class XmrTransferProofRequester { String errorMessage = "Request to " + httpClient.getBaseUrl() + " failed"; faultHandler.handleFault(errorMessage, throwable); UserThread.execute(() -> resultHandler.accept( - new AutoConfirmResult(AutoConfirmResult.State.CONNECTION_FAIL, errorMessage))); + new XmrAutoConfirmResult(XmrAutoConfirmResult.State.CONNECTION_FAIL, errorMessage))); } }); } diff --git a/core/src/main/java/bisq/core/trade/asset/xmr/XmrTransferProofService.java b/core/src/main/java/bisq/core/trade/asset/xmr/XmrTransferProofService.java index 976fc70303..151463d81e 100644 --- a/core/src/main/java/bisq/core/trade/asset/xmr/XmrTransferProofService.java +++ b/core/src/main/java/bisq/core/trade/asset/xmr/XmrTransferProofService.java @@ -17,7 +17,7 @@ package bisq.core.trade.asset.xmr; -import bisq.core.trade.AutoConfirmResult; +import bisq.core.trade.XmrAutoConfirmResult; import bisq.network.Socks5ProxyProvider; @@ -48,7 +48,7 @@ public class XmrTransferProofService { } public void requestProof(XmrProofInfo xmrProofInfo, - Consumer resultHandler, + Consumer resultHandler, FaultHandler faultHandler) { String key = xmrProofInfo.getKey(); if (map.containsKey(key)) { diff --git a/core/src/main/java/bisq/core/trade/protocol/ProcessModel.java b/core/src/main/java/bisq/core/trade/protocol/ProcessModel.java index ed590b307c..51e0e08429 100644 --- a/core/src/main/java/bisq/core/trade/protocol/ProcessModel.java +++ b/core/src/main/java/bisq/core/trade/protocol/ProcessModel.java @@ -33,10 +33,10 @@ import bisq.core.proto.CoreProtoResolver; import bisq.core.support.dispute.arbitration.arbitrator.ArbitratorManager; import bisq.core.support.dispute.mediation.mediator.MediatorManager; import bisq.core.support.dispute.refund.refundagent.RefundAgentManager; -import bisq.core.trade.AutoConfirmationManager; import bisq.core.trade.MakerTrade; import bisq.core.trade.Trade; import bisq.core.trade.TradeManager; +import bisq.core.trade.XmrAutoConfirmationManager; import bisq.core.trade.messages.TradeMessage; import bisq.core.trade.statistics.ReferralIdService; import bisq.core.trade.statistics.TradeStatisticsManager; @@ -90,7 +90,7 @@ public class ProcessModel implements Model, PersistablePayload { transient private User user; transient private FilterManager filterManager; transient private AccountAgeWitnessService accountAgeWitnessService; - transient private AutoConfirmationManager autoConfirmationManager; + transient private XmrAutoConfirmationManager xmrAutoConfirmationManager; transient private TradeStatisticsManager tradeStatisticsManager; transient private ArbitratorManager arbitratorManager; transient private MediatorManager mediatorManager; @@ -247,7 +247,7 @@ public class ProcessModel implements Model, PersistablePayload { User user, FilterManager filterManager, AccountAgeWitnessService accountAgeWitnessService, - AutoConfirmationManager autoConfirmationManager, + XmrAutoConfirmationManager xmrAutoConfirmationManager, TradeStatisticsManager tradeStatisticsManager, ArbitratorManager arbitratorManager, MediatorManager mediatorManager, @@ -266,7 +266,7 @@ public class ProcessModel implements Model, PersistablePayload { this.user = user; this.filterManager = filterManager; this.accountAgeWitnessService = accountAgeWitnessService; - this.autoConfirmationManager = autoConfirmationManager; + this.xmrAutoConfirmationManager = xmrAutoConfirmationManager; this.tradeStatisticsManager = tradeStatisticsManager; this.arbitratorManager = arbitratorManager; this.mediatorManager = mediatorManager; diff --git a/core/src/main/java/bisq/core/trade/protocol/tasks/seller/SellerProcessCounterCurrencyTransferStartedMessage.java b/core/src/main/java/bisq/core/trade/protocol/tasks/seller/SellerProcessCounterCurrencyTransferStartedMessage.java index ba8ba8b8f7..2faa9fc335 100644 --- a/core/src/main/java/bisq/core/trade/protocol/tasks/seller/SellerProcessCounterCurrencyTransferStartedMessage.java +++ b/core/src/main/java/bisq/core/trade/protocol/tasks/seller/SellerProcessCounterCurrencyTransferStartedMessage.java @@ -58,7 +58,7 @@ public class SellerProcessCounterCurrencyTransferStartedMessage extends TradeTas String counterCurrencyExtraData = message.getCounterCurrencyExtraData(); if (counterCurrencyExtraData != null && counterCurrencyExtraData.length() < 100) { trade.setCounterCurrencyExtraData(counterCurrencyExtraData); - processModel.getAutoConfirmationManager().processCounterCurrencyExtraData( + processModel.getXmrAutoConfirmationManager().processCounterCurrencyExtraData( trade, processModel.getTradeManager().getTradableList().stream()); } processModel.removeMailboxMessageAfterProcessing(trade); diff --git a/core/src/test/java/bisq/core/trade/asset/xmr/XmrProofInfoTest.java b/core/src/test/java/bisq/core/trade/asset/xmr/XmrProofInfoTest.java index ab8d2a1b84..427a5cb9ba 100644 --- a/core/src/test/java/bisq/core/trade/asset/xmr/XmrProofInfoTest.java +++ b/core/src/test/java/bisq/core/trade/asset/xmr/XmrProofInfoTest.java @@ -1,6 +1,6 @@ package bisq.core.trade.asset.xmr; -import bisq.core.trade.AutoConfirmResult; +import bisq.core.trade.XmrAutoConfirmResult; import java.time.Instant; @@ -48,13 +48,13 @@ public class XmrProofInfoTest { public void testJsonRoot() { // checking what happens when bad input is provided assertTrue(xmrProofInfo.checkApiResponse( - "invalid json data").getState() == AutoConfirmResult.State.API_INVALID); + "invalid json data").getState() == XmrAutoConfirmResult.State.API_INVALID); assertTrue(xmrProofInfo.checkApiResponse( - "").getState() == AutoConfirmResult.State.API_INVALID); + "").getState() == XmrAutoConfirmResult.State.API_INVALID); assertTrue(xmrProofInfo.checkApiResponse( - "[]").getState() == AutoConfirmResult.State.API_INVALID); + "[]").getState() == XmrAutoConfirmResult.State.API_INVALID); assertTrue(xmrProofInfo.checkApiResponse( - "{}").getState() == AutoConfirmResult.State.API_INVALID); + "{}").getState() == XmrAutoConfirmResult.State.API_INVALID); } @Test @@ -62,34 +62,34 @@ public class XmrProofInfoTest { // testing the top level fields: data and status assertTrue(xmrProofInfo.checkApiResponse( "{'data':{'title':''},'status':'fail'}" ) - .getState() == AutoConfirmResult.State.TX_NOT_FOUND); + .getState() == XmrAutoConfirmResult.State.TX_NOT_FOUND); assertTrue(xmrProofInfo.checkApiResponse( "{'data':{'title':''},'missingstatus':'success'}" ) - .getState() == AutoConfirmResult.State.API_INVALID); + .getState() == XmrAutoConfirmResult.State.API_INVALID); assertTrue(xmrProofInfo.checkApiResponse( "{'missingdata':{'title':''},'status':'success'}" ) - .getState() == AutoConfirmResult.State.API_INVALID); + .getState() == XmrAutoConfirmResult.State.API_INVALID); } @Test public void testJsonAddress() { assertTrue(xmrProofInfo.checkApiResponse( "{'data':{'missingaddress':'irrelevant'},'status':'success'}" ) - .getState() == AutoConfirmResult.State.API_INVALID); + .getState() == XmrAutoConfirmResult.State.API_INVALID); assertTrue(xmrProofInfo.checkApiResponse( "{'data':{'address':'e957dac7'},'status':'success'}" ) - .getState() == AutoConfirmResult.State.ADDRESS_INVALID); + .getState() == XmrAutoConfirmResult.State.ADDRESS_INVALID); } @Test public void testJsonTxHash() { String missing_tx_hash = "{'data':{'address':'" + recipientAddressHex + "'}, 'status':'success'}"; assertTrue(xmrProofInfo.checkApiResponse(missing_tx_hash).getState() - == AutoConfirmResult.State.API_INVALID); + == XmrAutoConfirmResult.State.API_INVALID); String invalid_tx_hash = "{'data':{'address':'" + recipientAddressHex + "', 'tx_hash':'488e48'}, 'status':'success'}"; assertTrue(xmrProofInfo.checkApiResponse(invalid_tx_hash).getState() - == AutoConfirmResult.State.TX_HASH_INVALID); + == XmrAutoConfirmResult.State.TX_HASH_INVALID); } @Test @@ -97,13 +97,13 @@ public class XmrProofInfoTest { String missing_tx_key = "{'data':{'address':'" + recipientAddressHex + "', " + "'tx_hash':'" + txHash + "'}, 'status':'success'}"; assertTrue(xmrProofInfo.checkApiResponse(missing_tx_key).getState() - == AutoConfirmResult.State.API_INVALID); + == XmrAutoConfirmResult.State.API_INVALID); String invalid_tx_key = "{'data':{'address':'" + recipientAddressHex + "', " + "'tx_hash':'" + txHash + "', " + "'viewkey':'cdce04'}, 'status':'success'}"; assertTrue(xmrProofInfo.checkApiResponse(invalid_tx_key).getState() - == AutoConfirmResult.State.TX_KEY_INVALID); + == XmrAutoConfirmResult.State.TX_KEY_INVALID); } @Test @@ -112,14 +112,14 @@ public class XmrProofInfoTest { "'tx_hash':'" + txHash + "'," + "'viewkey':'" + txKey + "'}, 'status':'success'}"; assertTrue(xmrProofInfo.checkApiResponse(missing_tx_timestamp).getState() - == AutoConfirmResult.State.API_INVALID); + == XmrAutoConfirmResult.State.API_INVALID); String invalid_tx_timestamp = "{'data':{'address':'" + recipientAddressHex + "', " + "'tx_hash':'" + txHash + "', " + "'viewkey':'" + txKey + "'," + "'tx_timestamp':'12345'}, 'status':'success'}"; assertTrue(xmrProofInfo.checkApiResponse(invalid_tx_timestamp).getState() - == AutoConfirmResult.State.TRADE_DATE_NOT_MATCHING); + == XmrAutoConfirmResult.State.TRADE_DATE_NOT_MATCHING); } @Test @@ -137,25 +137,25 @@ public class XmrProofInfoTest { "'tx_timestamp':'" + Long.toString(epochDate) + "'}" + "}"; assertTrue(xmrProofInfo.checkApiResponse(json).getState() - == AutoConfirmResult.State.PROOF_OK); + == XmrAutoConfirmResult.State.PROOF_OK); json = json.replaceFirst("777", "0"); assertTrue(xmrProofInfo.checkApiResponse(json).getState() - == AutoConfirmResult.State.TX_NOT_CONFIRMED); + == XmrAutoConfirmResult.State.TX_NOT_CONFIRMED); json = json.replaceFirst("100000000000", "100000000001"); assertTrue(xmrProofInfo.checkApiResponse(json).getState() - == AutoConfirmResult.State.AMOUNT_NOT_MATCHING); + == XmrAutoConfirmResult.State.AMOUNT_NOT_MATCHING); // Revert change of amount json = json.replaceFirst("100000000001", "100000000000"); json = json.replaceFirst("'match':true", "'match':false"); assertTrue(xmrProofInfo.checkApiResponse(json).getState() - == AutoConfirmResult.State.NO_MATCH_FOUND); + == XmrAutoConfirmResult.State.NO_MATCH_FOUND); } @Test public void testJsonFail() { String failedJson = "{\"data\":null,\"message\":\"Cant parse tx hash: a\",\"status\":\"error\"}"; assertTrue(xmrProofInfo.checkApiResponse(failedJson).getState() - == AutoConfirmResult.State.API_INVALID); + == XmrAutoConfirmResult.State.API_INVALID); } } diff --git a/desktop/src/main/java/bisq/desktop/main/overlays/windows/TradeDetailsWindow.java b/desktop/src/main/java/bisq/desktop/main/overlays/windows/TradeDetailsWindow.java index d2babf8923..9e7d6a2cea 100644 --- a/desktop/src/main/java/bisq/desktop/main/overlays/windows/TradeDetailsWindow.java +++ b/desktop/src/main/java/bisq/desktop/main/overlays/windows/TradeDetailsWindow.java @@ -39,7 +39,6 @@ import bisq.core.util.coin.CoinFormatter; import bisq.network.p2p.NodeAddress; import bisq.common.UserThread; -import bisq.common.util.Utilities; import org.bitcoinj.core.Utils; @@ -160,8 +159,9 @@ public class TradeDetailsWindow extends Overlay { addConfirmationLabelLabel(gridPane, ++rowIndex, Res.get("shared.tradePrice"), FormattingUtils.formatPrice(trade.getTradePrice())); String methodText = Res.get(offer.getPaymentMethod().getId()); - if (trade.getAutoConfirmResult() != null && trade.getAutoConfirmResult().isSuccessState()) + if (trade.getAutoConfirmResult().isSuccessState()) { methodText += " (" + trade.getAutoConfirmResult().getTextStatus() + ")"; + } addConfirmationLabelLabel(gridPane, ++rowIndex, Res.get("shared.paymentMethod"), methodText); // second group diff --git a/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/steps/buyer/BuyerStep4View.java b/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/steps/buyer/BuyerStep4View.java index 0a945a7b73..83a5decfdd 100644 --- a/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/steps/buyer/BuyerStep4View.java +++ b/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/steps/buyer/BuyerStep4View.java @@ -117,7 +117,7 @@ public class BuyerStep4View extends TradeStepView { GridPane.setMargin(hBox2, new Insets(18, -10, -12, -10)); gridPane.getChildren().add(hBox2); GridPane.setRowSpan(hBox2, 5); - if (trade.getAutoConfirmResult() == null || !trade.getAutoConfirmResult().isSuccessState()) { + if (!trade.getAutoConfirmResult().isSuccessState()) { autoConfBadge.setVisible(false); } diff --git a/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/steps/seller/SellerStep3View.java b/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/steps/seller/SellerStep3View.java index c459c7ff3a..eb805a76a3 100644 --- a/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/steps/seller/SellerStep3View.java +++ b/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/steps/seller/SellerStep3View.java @@ -40,9 +40,9 @@ import bisq.core.payment.payload.SepaAccountPayload; import bisq.core.payment.payload.SepaInstantAccountPayload; import bisq.core.payment.payload.USPostalMoneyOrderAccountPayload; import bisq.core.payment.payload.WesternUnionAccountPayload; +import bisq.core.trade.AutoConfirmResult; import bisq.core.trade.Contract; import bisq.core.trade.Trade; -import bisq.core.trade.AutoConfirmResult; import bisq.core.user.DontShowAgainLookup; import bisq.common.Timer; @@ -154,10 +154,7 @@ public class SellerStep3View extends TradeStepView { if (autoConfirmStatusField != null) { trade.getAutoConfirmResultProperty().addListener(autoConfirmResultListener); // display the initial value, or FEATURE_DISABLED if there is none - AutoConfirmResult autoConfirmResult = trade.getAutoConfirmResult(); - if (autoConfirmResult == null) - autoConfirmResult = new AutoConfirmResult(AutoConfirmResult.State.FEATURE_DISABLED); - autoConfirmStatusField.setText(autoConfirmResult.getTextStatus()); + autoConfirmStatusField.setText(trade.getAutoConfirmResult().getTextStatus()); } } diff --git a/proto/src/main/proto/pb.proto b/proto/src/main/proto/pb.proto index 7b96a55f85..10a27fd375 100644 --- a/proto/src/main/proto/pb.proto +++ b/proto/src/main/proto/pb.proto @@ -1397,7 +1397,7 @@ message Trade { } message AutoConfirmResult { - string stateName = 1; // name of AutoConfirmResult.State enum + string stateName = 1; } message BuyerAsMakerTrade {