diff --git a/core/src/main/java/bisq/core/api/CoreOffersService.java b/core/src/main/java/bisq/core/api/CoreOffersService.java index 25933e218e..d42b427ce1 100644 --- a/core/src/main/java/bisq/core/api/CoreOffersService.java +++ b/core/src/main/java/bisq/core/api/CoreOffersService.java @@ -106,7 +106,7 @@ public class CoreOffersService { } Offer getOffer(String id) { - return offerBookService.getOffers().stream() + return new ArrayList<>(offerBookService.getOffers()).stream() .filter(o -> o.getId().equals(id)) .filter(o -> !o.isMyOffer(keyRing)) .filter(o -> { @@ -120,7 +120,7 @@ public class CoreOffersService { } Offer getMyOffer(String id) { - return openOfferManager.getObservableList().stream() + return new ArrayList<>(openOfferManager.getObservableList()).stream() .map(OpenOffer::getOffer) .filter(o -> o.getId().equals(id)) .filter(o -> o.isMyOffer(keyRing)) @@ -129,7 +129,7 @@ public class CoreOffersService { } List getOffers(String direction, String currencyCode) { - List offers = offerBookService.getOffers().stream() + List offers = new ArrayList<>(offerBookService.getOffers()).stream() .filter(o -> !o.isMyOffer(keyRing)) .filter(o -> offerMatchesDirectionAndCurrency(o, direction, currencyCode)) .filter(o -> { @@ -145,7 +145,7 @@ public class CoreOffersService { List getMyOffers(String direction, String currencyCode) { // get my open offers - List offers = openOfferManager.getObservableList().stream() + List offers = new ArrayList<>(openOfferManager.getObservableList()).stream() .map(OpenOffer::getOffer) .filter(o -> o.isMyOffer(keyRing)) .filter(o -> offerMatchesDirectionAndCurrency(o, direction, currencyCode)) diff --git a/core/src/main/java/bisq/core/btc/wallet/XmrWalletService.java b/core/src/main/java/bisq/core/btc/wallet/XmrWalletService.java index 8db7b01620..8b1dfe103e 100644 --- a/core/src/main/java/bisq/core/btc/wallet/XmrWalletService.java +++ b/core/src/main/java/bisq/core/btc/wallet/XmrWalletService.java @@ -166,6 +166,10 @@ public class XmrWalletService { return wallet; } + public void saveWallet() { + saveWallet(getWallet()); + } + public boolean isWalletReady() { try { return getWallet() != null; @@ -227,7 +231,21 @@ public class XmrWalletService { } } - public void saveWallet(MoneroWallet wallet) { + public void saveMultisigWallet(String tradeId) { + log.info("{}.saveMultisigWallet({})", getClass().getSimpleName(), tradeId); + initWalletLock(tradeId); + synchronized (walletLocks.get(tradeId)) { + String walletName = MONERO_MULTISIG_WALLET_PREFIX + tradeId; + if (!walletExists(walletName)) { + log.warn("Multisig wallet for trade {} does not exist"); + return; + } + if (!multisigWallets.containsKey(tradeId)) throw new RuntimeException("Multisig wallet to save was not previously opened for trade " + tradeId); + saveWallet(multisigWallets.get(tradeId)); + } + } + + private void saveWallet(MoneroWallet wallet) { wallet.save(); backupWallet(wallet.getPath()); } diff --git a/core/src/main/java/bisq/core/offer/OpenOfferManager.java b/core/src/main/java/bisq/core/offer/OpenOfferManager.java index 1ed30796da..65ce022a27 100644 --- a/core/src/main/java/bisq/core/offer/OpenOfferManager.java +++ b/core/src/main/java/bisq/core/offer/OpenOfferManager.java @@ -610,11 +610,11 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe } public Optional getOpenOfferById(String offerId) { - return openOffers.getObservableList().stream().filter(e -> e.getId().equals(offerId)).findFirst(); + return new ArrayList<>(openOffers.getObservableList()).stream().filter(e -> e.getId().equals(offerId)).findFirst(); } public Optional getSignedOfferById(String offerId) { - return signedOffers.getObservableList().stream().filter(e -> e.getOfferId().equals(offerId)).findFirst(); + return new ArrayList<>(signedOffers.getObservableList()).stream().filter(e -> e.getOfferId().equals(offerId)).findFirst(); } /////////////////////////////////////////////////////////////////////////////////////////// diff --git a/core/src/main/java/bisq/core/trade/Trade.java b/core/src/main/java/bisq/core/trade/Trade.java index 3d22f1046b..9dce37f2a7 100644 --- a/core/src/main/java/bisq/core/trade/Trade.java +++ b/core/src/main/java/bisq/core/trade/Trade.java @@ -931,7 +931,7 @@ public abstract class Trade implements Tradable, Model { } public void saveWallet() { - xmrWalletService.saveWallet(getWallet()); + xmrWalletService.saveMultisigWallet(getId()); } public void deleteWallet() { diff --git a/core/src/main/java/bisq/core/trade/protocol/SellerAsTakerProtocol.java b/core/src/main/java/bisq/core/trade/protocol/SellerAsTakerProtocol.java index 4745cdec5c..de1b4b90a9 100644 --- a/core/src/main/java/bisq/core/trade/protocol/SellerAsTakerProtocol.java +++ b/core/src/main/java/bisq/core/trade/protocol/SellerAsTakerProtocol.java @@ -54,7 +54,7 @@ public class SellerAsTakerProtocol extends SellerProtocol implements TakerProtoc @Override public void onTakeOffer(TradeResultHandler tradeResultHandler, ErrorMessageHandler errorMessageHandler) { - System.out.println(getClass().getCanonicalName() + ".onTakeOffer()"); + System.out.println(getClass().getSimpleName() + ".onTakeOffer()"); new Thread(() -> { synchronized (trade) { latchTrade(); diff --git a/core/src/main/java/bisq/core/trade/protocol/TradeProtocol.java b/core/src/main/java/bisq/core/trade/protocol/TradeProtocol.java index 836456936a..e13515241a 100644 --- a/core/src/main/java/bisq/core/trade/protocol/TradeProtocol.java +++ b/core/src/main/java/bisq/core/trade/protocol/TradeProtocol.java @@ -84,6 +84,7 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D protected final Trade trade; protected CountDownLatch tradeLatch; // to synchronize on trade private Timer timeoutTimer; + private Object timeoutTimerLock = new Object(); protected TradeResultHandler tradeResultHandler; protected ErrorMessageHandler errorMessageHandler; @@ -357,7 +358,7 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D latchTrade(); Validator.checkTradeId(processModel.getOfferId(), response); processModel.setTradeMessage(response); - expect(anyState(Trade.State.SAW_ARRIVED_PUBLISH_DEPOSIT_TX_REQUEST, Trade.State.ARBITRATOR_PUBLISHED_DEPOSIT_TXS, Trade.State.DEPOSIT_TXS_SEEN_IN_NETWORK) + 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() .setup(tasks( @@ -600,16 +601,20 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D /////////////////////////////////////////////////////////////////////////////////////////// protected synchronized void startTimeout(long timeoutSec) { - stopTimeout(); - timeoutTimer = UserThread.runAfter(() -> { - handleError("Timeout reached. Protocol did not complete in " + timeoutSec + " sec. TradeID=" + trade.getId() + ", state=" + trade.stateProperty().get()); - }, timeoutSec); + synchronized (timeoutTimerLock) { + stopTimeout(); + timeoutTimer = UserThread.runAfter(() -> { + handleError("Timeout reached. Protocol did not complete in " + timeoutSec + " sec. TradeID=" + trade.getId() + ", state=" + trade.stateProperty().get()); + }, timeoutSec); + } } protected synchronized void stopTimeout() { - if (timeoutTimer != null) { - timeoutTimer.stop(); - timeoutTimer = null; + synchronized (timeoutTimerLock) { + if (timeoutTimer != null) { + timeoutTimer.stop(); + timeoutTimer = null; + } } } diff --git a/core/src/main/java/bisq/core/trade/protocol/tasks/MaybeSendSignContractRequest.java b/core/src/main/java/bisq/core/trade/protocol/tasks/MaybeSendSignContractRequest.java index 076687dfdd..4b9f914b52 100644 --- a/core/src/main/java/bisq/core/trade/protocol/tasks/MaybeSendSignContractRequest.java +++ b/core/src/main/java/bisq/core/trade/protocol/tasks/MaybeSendSignContractRequest.java @@ -135,7 +135,7 @@ public class MaybeSendSignContractRequest extends TradeTask { private void completeAux() { trade.setState(State.CONTRACT_SIGNATURE_REQUESTED); processModel.getTradeManager().requestPersistence(); - processModel.getXmrWalletService().saveWallet(processModel.getXmrWalletService().getWallet()); + processModel.getXmrWalletService().saveWallet(); complete(); } } diff --git a/core/src/main/java/bisq/core/trade/protocol/tasks/ProcessInitMultisigRequest.java b/core/src/main/java/bisq/core/trade/protocol/tasks/ProcessInitMultisigRequest.java index b30c0c5667..1009a7d305 100644 --- a/core/src/main/java/bisq/core/trade/protocol/tasks/ProcessInitMultisigRequest.java +++ b/core/src/main/java/bisq/core/trade/protocol/tasks/ProcessInitMultisigRequest.java @@ -122,7 +122,7 @@ public class ProcessInitMultisigRequest extends TradeTask { log.info("Importing exchanged multisig hex for trade {}", trade.getId()); MoneroMultisigInitResult result = multisigWallet.exchangeMultisigKeys(Arrays.asList(peers[0].getExchangedMultisigHex(), peers[1].getExchangedMultisigHex()), xmrWalletService.getWalletPassword()); processModel.setMultisigAddress(result.getAddress()); - processModel.getProvider().getXmrWalletService().saveWallet(multisigWallet); // save multisig wallet once it's created + processModel.getProvider().getXmrWalletService().saveMultisigWallet(trade.getId()); // save multisig wallet once it's created trade.setStateIfValidTransitionTo(Trade.State.MULTISIG_COMPLETED); }