diff --git a/core/src/main/java/bisq/core/trade/Trade.java b/core/src/main/java/bisq/core/trade/Trade.java index 468f87658c..a00fe2dca8 100644 --- a/core/src/main/java/bisq/core/trade/Trade.java +++ b/core/src/main/java/bisq/core/trade/Trade.java @@ -597,7 +597,13 @@ public abstract class Trade implements Tradable, Model { trade.setLockTime(proto.getLockTime()); trade.setLastRefreshRequestDate(proto.getLastRefreshRequestDate()); trade.setCounterCurrencyExtraData(ProtoUtil.stringOrNullFromProto(proto.getCounterCurrencyExtraData())); - trade.setAssetTxProofResult(ProtoUtil.enumFromProto(AssetTxProofResult.class, proto.getAssetTxProofResult())); + + AssetTxProofResult persistedAssetTxProofResult = ProtoUtil.enumFromProto(AssetTxProofResult.class, proto.getAssetTxProofResult()); + // We do not want to show the user the last pending state when he starts up the app again, so we clear it. + if (persistedAssetTxProofResult == AssetTxProofResult.PENDING) { + persistedAssetTxProofResult = null; + } + trade.setAssetTxProofResult(persistedAssetTxProofResult); trade.chatMessages.addAll(proto.getChatMessageList().stream() .map(ChatMessage::fromPayloadProto) @@ -884,6 +890,7 @@ public abstract class Trade implements Tradable, Model { public void setAssetTxProofResult(@Nullable AssetTxProofResult assetTxProofResult) { this.assetTxProofResult = assetTxProofResult; assetTxProofResultUpdateProperty.set(assetTxProofResultUpdateProperty.get() + 1); + persist(); } diff --git a/core/src/main/java/bisq/core/trade/txproof/xmr/DevTestXmrTxProofHttpClient.java b/core/src/main/java/bisq/core/trade/txproof/xmr/DevTestXmrTxProofHttpClient.java new file mode 100644 index 0000000000..cd9825187c --- /dev/null +++ b/core/src/main/java/bisq/core/trade/txproof/xmr/DevTestXmrTxProofHttpClient.java @@ -0,0 +1,199 @@ +/* + * 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.txproof.xmr; + +import bisq.core.trade.txproof.AssetTxProofHttpClient; + +import bisq.network.Socks5ProxyProvider; +import bisq.network.http.HttpClientImpl; + +import bisq.common.app.DevEnv; + +import javax.inject.Inject; + +import java.io.IOException; + +import java.util.Date; + +import lombok.extern.slf4j.Slf4j; + +import javax.annotation.Nullable; + +import static bisq.core.trade.txproof.xmr.XmrTxProofParser.MAX_DATE_TOLERANCE; + +/** + * This should help to test error scenarios in dev testing the app. This is additional to unit test which test the + * correct data but do not test the context of the results and how it behaves in the UI. + * + * You have to change the binding in TradeModule to + * bind(AssetTxProofHttpClient.class).to(DevTestXmrTxProofHttpClient.class); to use that class. + * + * This class can be removed once done testing, but as multiple devs are testing its useful to share it for now. + */ +@Slf4j +public class DevTestXmrTxProofHttpClient extends HttpClientImpl implements AssetTxProofHttpClient { + enum ApiInvalidDetails { + EMPTY_JSON, + MISSING_DATA, + MISSING_STATUS, + UNHANDLED_STATUS, + MISSING_ADDRESS, + MISSING_TX_ID, + MISSING_VIEW_KEY, + MISSING_TS, + MISSING_CONF, + EXCEPTION + } + + @Inject + public DevTestXmrTxProofHttpClient(@Nullable Socks5ProxyProvider socks5ProxyProvider) { + super(socks5ProxyProvider); + } + + static int counter; + + @Override + public String requestWithGET(String param, + @Nullable String headerKey, + @Nullable String headerValue) throws IOException { + + XmrTxProofRequest.Result result = XmrTxProofRequest.Result.PENDING; + XmrTxProofRequest.Detail detail = XmrTxProofRequest.Detail.TX_NOT_FOUND; + ApiInvalidDetails apiInvalidDetails = ApiInvalidDetails.EXCEPTION; + + int delay = counter == 0 ? 2000 : 100; + try { + Thread.sleep(delay); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + if (counter >= 2) { + detail = XmrTxProofRequest.Detail.PENDING_CONFIRMATIONS.numConfirmations(counter - 2); + } + counter++; + switch (result) { + case PENDING: + switch (detail) { + case TX_NOT_FOUND: + return validJson().replace("success", + "fail"); + case PENDING_CONFIRMATIONS: + return validJson().replace("201287", + String.valueOf(detail.getNumConfirmations())); + } + break; + case SUCCESS: + return validJson(); + case FAILED: + switch (detail) { + case TX_HASH_INVALID: + return validJson().replace("5e665addf6d7c6300670e8a89564ed12b5c1a21c336408e2835668f9a6a0d802", + "-"); + case TX_KEY_INVALID: + return validJson().replace("f3ce66c9d395e5e460c8802b2c3c1fff04e508434f9738ee35558aac4678c906", + "-"); + case ADDRESS_INVALID: + return validJson().replace("5e665addf6d7c6300670e8a89564ed12b5c1a21c336408e2835668f9a6a0d802", + "-"); + case NO_MATCH_FOUND: + return validJson().replace("match\": true", + "match\": false"); + case AMOUNT_NOT_MATCHING: + return validJson().replace("8902597360000", + "18902597360000"); + case TRADE_DATE_NOT_MATCHING: + DevEnv.setDevMode(false); + long date = (new Date(1574922644 * 1000L).getTime() - (MAX_DATE_TOLERANCE * 1000L + 1)) / 1000; + String replace = validJson().replace("1574922644", + String.valueOf(date)); + return replace; + } + case ERROR: + switch (detail) { + /* case CONNECTION_FAILURE: + break;*/ + case API_INVALID: + switch (apiInvalidDetails) { + case EMPTY_JSON: + return null; + case MISSING_DATA: + return validJson().replace("data", + "missing"); + case MISSING_STATUS: + return validJson().replace("status", + "missing"); + case UNHANDLED_STATUS: + return validJson().replace("success", + "missing"); + case MISSING_ADDRESS: + return validJson().replace("address", + "missing"); + case MISSING_TX_ID: + return validJson().replace("tx_hash", + "missing"); + case MISSING_VIEW_KEY: + return validJson().replace("viewkey", + "missing"); + case MISSING_TS: + return validJson().replace("tx_timestamp", + "missing"); + case MISSING_CONF: + return validJson().replace("tx_confirmations", + "missing"); + case EXCEPTION: + return validJson().replace("} ", + ""); + } + break; + /* case NO_RESULTS_TIMEOUT: + break;*/ + } + } + return validJson(); + } + + private String validJson() { + return "{\n" + + " \"data\": {\n" + + " \"address\": \"590f7263428051068bb45cdfcf93407c15b6e291d20c92d0251fcfbf53cc745cdf53319f7d6d7a8e21ea39041aabf31d220a32a875e3ca2087a777f1201c0571\",\n" + + " \"outputs\": [\n" + + " {\n" + + " \"amount\": 8902597360000,\n" + + " \"match\": true,\n" + + " \"output_idx\": 0,\n" + + " \"output_pubkey\": \"2b6d2296f2591c198cd1aa47de9a5d74270963412ed30bbcc63b8eff29f0d43e\"\n" + + " },\n" + + " {\n" + + " \"amount\": 0,\n" + + " \"match\": false,\n" + + " \"output_idx\": 1,\n" + + " \"output_pubkey\": \"f53271624847507d80b746e91e689e88bc41678d55246275f5ad3c0f7e8a9ced\"\n" + + " }\n" + + " ],\n" + + " \"tx_confirmations\": 201287,\n" + + " \"tx_hash\": \"5e665addf6d7c6300670e8a89564ed12b5c1a21c336408e2835668f9a6a0d802\",\n" + + " \"tx_prove\": true,\n" + + " \"tx_timestamp\": 1574922644,\n" + + " \"viewkey\": \"f3ce66c9d395e5e460c8802b2c3c1fff04e508434f9738ee35558aac4678c906\"\n" + + " },\n" + + " \"status\": \"success\"\n" + + "} "; + } + +} diff --git a/core/src/main/java/bisq/core/trade/txproof/xmr/XmrTxProofParser.java b/core/src/main/java/bisq/core/trade/txproof/xmr/XmrTxProofParser.java index ae223d2269..dda5f924c8 100644 --- a/core/src/main/java/bisq/core/trade/txproof/xmr/XmrTxProofParser.java +++ b/core/src/main/java/bisq/core/trade/txproof/xmr/XmrTxProofParser.java @@ -35,6 +35,8 @@ import lombok.extern.slf4j.Slf4j; @Slf4j public class XmrTxProofParser implements AssetTxProofParser { + public static final long MAX_DATE_TOLERANCE = TimeUnit.HOURS.toSeconds(2); + XmrTxProofParser() { } @@ -110,7 +112,7 @@ public class XmrTxProofParser implements AssetTxProofParser TimeUnit.HOURS.toSeconds(2) && !DevEnv.isDevMode()) { + if (difference > MAX_DATE_TOLERANCE && !DevEnv.isDevMode()) { log.warn("tx_timestamp {}, tradeDate: {}, difference {}", jsonTimestamp.getAsLong(), tradeDateSeconds, difference); return XmrTxProofRequest.Result.FAILED.with(XmrTxProofRequest.Detail.TRADE_DATE_NOT_MATCHING); diff --git a/core/src/main/java/bisq/core/trade/txproof/xmr/XmrTxProofRequest.java b/core/src/main/java/bisq/core/trade/txproof/xmr/XmrTxProofRequest.java index f0b84d6060..c853af2410 100644 --- a/core/src/main/java/bisq/core/trade/txproof/xmr/XmrTxProofRequest.java +++ b/core/src/main/java/bisq/core/trade/txproof/xmr/XmrTxProofRequest.java @@ -87,7 +87,6 @@ class XmrTxProofRequest implements AssetTxProofRequest // Error states CONNECTION_FAILURE, - API_FAILURE, API_INVALID, // Failure states @@ -194,8 +193,13 @@ class XmrTxProofRequest implements AssetTxProofRequest "&txprove=1"; log.info("Param {} for {}", param, this); String json = httpClient.requestWithGET(param, "User-Agent", "bisq/" + Version.VERSION); - String prettyJson = new GsonBuilder().setPrettyPrinting().create().toJson(new JsonParser().parse(json)); - log.info("Response json from {}\n{}", this, prettyJson); + try { + String prettyJson = new GsonBuilder().setPrettyPrinting().create().toJson(new JsonParser().parse(json)); + log.info("Response json from {}\n{}", this, prettyJson); + } catch (Throwable error) { + log.error("Pretty rint caused a {}}: raw josn={}", error, json); + } + Result result = parser.parse(model, json); log.info("Result from {}\n{}", this, result); return result; diff --git a/core/src/main/java/bisq/core/trade/txproof/xmr/test/DevTestXmrTxProofHttpClient.java b/core/src/main/java/bisq/core/trade/txproof/xmr/test/DevTestXmrTxProofHttpClient.java deleted file mode 100644 index 48de7c2750..0000000000 --- a/core/src/main/java/bisq/core/trade/txproof/xmr/test/DevTestXmrTxProofHttpClient.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * 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.txproof.xmr.test; - -import bisq.core.trade.txproof.AssetTxProofHttpClient; - -import bisq.network.Socks5ProxyProvider; -import bisq.network.http.HttpClientImpl; - -import javax.inject.Inject; - -import java.io.IOException; - -import lombok.extern.slf4j.Slf4j; - -import javax.annotation.Nullable; - -/** - * This should help to test error scenarios in dev testing the app. This is additional to unit test which test the - * correct data but do not test the context of the results and how it behaves in the UI. - * - * You have to change the binding in TradeModule to - * bind(AssetTxProofHttpClient.class).to(DevTestXmrTxProofHttpClient.class); to use that class. - * - * This class can be removed once done testing, but as multiple devs are testing its useful to share it for now. - */ -@Slf4j -public class DevTestXmrTxProofHttpClient extends HttpClientImpl implements AssetTxProofHttpClient { - enum TestCase { - SUCCESS, - INVALID_ADDRESS, - STATUS_FAIL - } - - @Inject - public DevTestXmrTxProofHttpClient(@Nullable Socks5ProxyProvider socks5ProxyProvider) { - super(socks5ProxyProvider); - } - - @Override - public String requestWithGET(String param, - @Nullable String headerKey, - @Nullable String headerValue) throws IOException { - TestCase testCase = TestCase.SUCCESS; - switch (testCase) { - case SUCCESS: - return validJson(); - case INVALID_ADDRESS: - return validJson().replace("590f7263428051068bb45cdfcf93407c15b6e291d20c92d0251fcfbf53cc745cdf53319f7d6d7a8e21ea39041aabf31d220a32a875e3ca2087a777f1201c0571", - "invalidAddress"); - case STATUS_FAIL: - return validJson().replace("success", - "fail"); - default: - return testCase.toString(); - } - } - - private String validJson() { - return "{\n" + - " \"data\": {\n" + - " \"address\": \"590f7263428051068bb45cdfcf93407c15b6e291d20c92d0251fcfbf53cc745cdf53319f7d6d7a8e21ea39041aabf31d220a32a875e3ca2087a777f1201c0571\",\n" + - " \"outputs\": [\n" + - " {\n" + - " \"amount\": 8902597360000,\n" + - " \"match\": true,\n" + - " \"output_idx\": 0,\n" + - " \"output_pubkey\": \"2b6d2296f2591c198cd1aa47de9a5d74270963412ed30bbcc63b8eff29f0d43e\"\n" + - " },\n" + - " {\n" + - " \"amount\": 0,\n" + - " \"match\": false,\n" + - " \"output_idx\": 1,\n" + - " \"output_pubkey\": \"f53271624847507d80b746e91e689e88bc41678d55246275f5ad3c0f7e8a9ced\"\n" + - " }\n" + - " ],\n" + - " \"tx_confirmations\": 201287,\n" + - " \"tx_hash\": \"5e665addf6d7c6300670e8a89564ed12b5c1a21c336408e2835668f9a6a0d802\",\n" + - " \"tx_prove\": true,\n" + - " \"tx_timestamp\": 1574922644,\n" + - " \"viewkey\": \"f3ce66c9d395e5e460c8802b2c3c1fff04e508434f9738ee35558aac4678c906\"\n" + - " },\n" + - " \"status\": \"success\"\n" + - "} "; - } - -}