Source:
<code>private static void broadcastTx(String serviceAddress, String txIdToSend, String rawTx) { TxBroadcastHttpClient httpClient = new TxBroadcastHttpClient(socks5ProxyProvider); httpClient.setBaseUrl(serviceAddress); httpClient.setIgnoreSocks5Proxy(false); String url = httpClient.getBaseUrl(); log.info("We broadcast rawTx to {}", rawTx, url); ListenableFuture<String> future = executorService.submit(() -> { Thread.currentThread().setName("MemPoolSpaceTxBroadcaster @ " + url); return httpClient.post(rawTx, "User-Agent", "bisq/" + Version.VERSION); }); Futures.addCallback(future, new FutureCallback<>() { public void onSuccess(String txId) { if (txId.equals(txIdToSend)) { log.info("Broadcast of raw tx with txId to was successful. rawTx={}", txId, url, rawTx); } else { log.error("The txId we got returned from the service does not match " + "out tx of the sending tx. txId={}; txIdToSend={}", txId, txIdToSend); } } public void onFailure(@NotNull Throwable throwable) { Throwable cause = throwable.getCause(); if (cause instanceof HttpException) { int responseCode = ((HttpException) cause).getResponseCode(); String message = cause.getMessage(); <START> if (responseCode == 400 && message.equals("sendrawtransaction RPC error: {\"code\":-27,\"message\":\"Transaction already in block chain\"}")) { <END> log.info("Broadcast of raw tx to failed as transaction is already confirmed", serviceAddress, txIdToSend); } else { log.info("Broadcast of raw tx to failed for transaction {}. responseCode={}, error={}", serviceAddress, txIdToSend, responseCode, message); } } else { log.warn("Broadcast of raw tx with txId to failed. Error={}", txIdToSend, url, throwable.toString()); } } }, MoreExecutors.directExecutor()); }</code><technical_language>Instead of checking for exact message, checking for a substring of \"code\":-27 is better, exact string change in future releases of Bitcoin Core RPC</technical_language>

Target:
private static void broadcastTx(String serviceAddress, String txIdToSend, String rawTx) { TxBroadcastHttpClient httpClient = new TxBroadcastHttpClient(socks5ProxyProvider); httpClient.setBaseUrl(serviceAddress); httpClient.setIgnoreSocks5Proxy(false); log.info("We broadcast rawTx to {}", rawTx, serviceAddress); ListenableFuture<String> future = executorService.submit(() -> { Thread.currentThread().setName("MemPoolSpaceTxBroadcaster @ " + serviceAddress); return httpClient.post(rawTx, "User-Agent", "bisq/" + Version.VERSION); }); Futures.addCallback(future, new FutureCallback<>() { public void onSuccess(String txId) { if (txId.equals(txIdToSend)) { log.info("Broadcast of raw tx with txId to was successful. rawTx={}", txId, serviceAddress, rawTx); } else { log.error("The txId we got returned from the service does not match " + "out tx of the sending tx. txId={}; txIdToSend={}", txId, txIdToSend); } } public void onFailure(@NotNull Throwable throwable) { Throwable cause = throwable.getCause(); if (cause instanceof HttpException) { int responseCode = ((HttpException) cause).getResponseCode(); String message = cause.getMessage(); if (responseCode == 400 && message.contains("code\":-27")) { log.info("Broadcast of raw tx to failed as transaction is already confirmed", serviceAddress, txIdToSend); } else { log.info("Broadcast of raw tx to failed for transaction {}. responseCode={}, error={}", serviceAddress, txIdToSend, responseCode, message); } } else { log.warn("Broadcast of raw tx with txId to failed. Error={}", txIdToSend, serviceAddress, throwable.toString()); } } }, MoreExecutors.directExecutor()); }