diff --git a/core/src/main/java/haveno/core/trade/Trade.java b/core/src/main/java/haveno/core/trade/Trade.java index 18e2ba1004..6e9086e1ef 100644 --- a/core/src/main/java/haveno/core/trade/Trade.java +++ b/core/src/main/java/haveno/core/trade/Trade.java @@ -143,6 +143,7 @@ public abstract class Trade extends XmrWalletBase implements Tradable, Model { private static final long DELETE_AFTER_NUM_BLOCKS = 2; // if deposit requested but not published private static final long EXTENDED_RPC_TIMEOUT = 600000; // 10 minutes private static final long DELETE_AFTER_MS = TradeProtocol.TRADE_STEP_TIMEOUT_SECONDS; + private static final int NUM_CONFIRMATIONS_FOR_SCHEDULED_IMPORT = 10; protected final Object pollLock = new Object(); protected static final Object importMultisigLock = new Object(); private boolean pollInProgress; @@ -741,6 +742,11 @@ public abstract class Trade extends XmrWalletBase implements Tradable, Model { } } + // handle confirmations + walletHeight.addListener((observable, oldValue, newValue) -> { + importMultisigHexIfScheduled(); + }); + // trade is initialized isInitialized = true; @@ -1077,6 +1083,26 @@ public abstract class Trade extends XmrWalletBase implements Tradable, Model { } } + public void scheduleImportMultisigHex() { + processModel.setImportMultisigHexScheduled(true); + requestPersistence(); + } + + private void importMultisigHexIfScheduled() { + if (!isInitialized || isShutDownStarted) return; + if (!isDepositsConfirmed() || getMaker().getDepositTx() == null) return; + if (walletHeight.get() - getMaker().getDepositTx().getHeight() < NUM_CONFIRMATIONS_FOR_SCHEDULED_IMPORT) return; + ThreadUtils.execute(() -> { + if (!isInitialized || isShutDownStarted) return; + synchronized (getLock()) { + if (processModel.isImportMultisigHexScheduled()) { + processModel.setImportMultisigHexScheduled(false); + ThreadUtils.submitToPool(() -> importMultisigHex()); + } + } + }, getId()); + } + public void importMultisigHex() { synchronized (walletLock) { synchronized (HavenoUtils.getDaemonLock()) { // lock on daemon because import calls full refresh @@ -1141,6 +1167,9 @@ public abstract class Trade extends XmrWalletBase implements Tradable, Model { if (removed) wallet.importMultisigHex(multisigHexes.toArray(new String[0])); if (wallet.isMultisigImportNeeded()) throw new IllegalStateException(errorMessage); } + + // remove scheduled import + processModel.setImportMultisigHexScheduled(false); } catch (MoneroError e) { // import multisig hex individually if one is invalid @@ -2345,7 +2374,12 @@ public abstract class Trade extends XmrWalletBase implements Tradable, Model { return tradeAmountTransferred(); } - public boolean tradeAmountTransferred() { + + /////////////////////////////////////////////////////////////////////////////////////////// + // Private + /////////////////////////////////////////////////////////////////////////////////////////// + + private boolean tradeAmountTransferred() { return isPaymentReceived() || (getDisputeResult() != null && getDisputeResult().getWinner() == DisputeResult.Winner.SELLER); } @@ -2361,11 +2395,6 @@ public abstract class Trade extends XmrWalletBase implements Tradable, Model { } } - - /////////////////////////////////////////////////////////////////////////////////////////// - // Private - /////////////////////////////////////////////////////////////////////////////////////////// - // lazy initialization private ObjectProperty<BigInteger> getAmountProperty() { if (tradeAmountProperty == null) diff --git a/core/src/main/java/haveno/core/trade/protocol/ProcessModel.java b/core/src/main/java/haveno/core/trade/protocol/ProcessModel.java index d81c4f476a..8521174ca8 100644 --- a/core/src/main/java/haveno/core/trade/protocol/ProcessModel.java +++ b/core/src/main/java/haveno/core/trade/protocol/ProcessModel.java @@ -158,6 +158,9 @@ public class ProcessModel implements Model, PersistablePayload { @Getter @Setter private long tradeProtocolErrorHeight; + @Getter + @Setter + private boolean importMultisigHexScheduled; // We want to indicate the user the state of the message delivery of the // PaymentSentMessage. As well we do an automatic re-send in case it was not ACKed yet. @@ -207,7 +210,8 @@ public class ProcessModel implements Model, PersistablePayload { .setPaymentSentMessageStateArbitrator(paymentSentMessageStatePropertyArbitrator.get().name()) .setBuyerPayoutAmountFromMediation(buyerPayoutAmountFromMediation) .setSellerPayoutAmountFromMediation(sellerPayoutAmountFromMediation) - .setTradeProtocolErrorHeight(tradeProtocolErrorHeight); + .setTradeProtocolErrorHeight(tradeProtocolErrorHeight) + .setImportMultisigHexScheduled(importMultisigHexScheduled); Optional.ofNullable(maker).ifPresent(e -> builder.setMaker((protobuf.TradePeer) maker.toProtoMessage())); Optional.ofNullable(taker).ifPresent(e -> builder.setTaker((protobuf.TradePeer) taker.toProtoMessage())); Optional.ofNullable(arbitrator).ifPresent(e -> builder.setArbitrator((protobuf.TradePeer) arbitrator.toProtoMessage())); @@ -231,6 +235,7 @@ public class ProcessModel implements Model, PersistablePayload { processModel.setBuyerPayoutAmountFromMediation(proto.getBuyerPayoutAmountFromMediation()); processModel.setSellerPayoutAmountFromMediation(proto.getSellerPayoutAmountFromMediation()); processModel.setTradeProtocolErrorHeight(proto.getTradeProtocolErrorHeight()); + processModel.setImportMultisigHexScheduled(proto.getImportMultisigHexScheduled()); // nullable processModel.setPayoutTxSignature(ProtoUtil.byteArrayOrNullFromProto(proto.getPayoutTxSignature())); diff --git a/core/src/main/java/haveno/core/trade/protocol/tasks/ProcessDepositsConfirmedMessage.java b/core/src/main/java/haveno/core/trade/protocol/tasks/ProcessDepositsConfirmedMessage.java index c11df74fae..7e0c85af2d 100644 --- a/core/src/main/java/haveno/core/trade/protocol/tasks/ProcessDepositsConfirmedMessage.java +++ b/core/src/main/java/haveno/core/trade/protocol/tasks/ProcessDepositsConfirmedMessage.java @@ -18,7 +18,6 @@ package haveno.core.trade.protocol.tasks; -import haveno.common.ThreadUtils; import haveno.common.taskrunner.TaskRunner; import haveno.core.trade.Trade; import haveno.core.trade.messages.DepositsConfirmedMessage; @@ -63,17 +62,7 @@ public class ProcessDepositsConfirmedMessage extends TradeTask { // update multisig hex if (sender.getUpdatedMultisigHex() == null) { sender.setUpdatedMultisigHex(request.getUpdatedMultisigHex()); - - // try to import multisig hex (retry later) - if (!trade.isPayoutPublished()) { - ThreadUtils.submitToPool(() -> { - try { - trade.importMultisigHex(); - } catch (Exception e) { - log.warn("Error importing multisig hex on deposits confirmed for trade " + trade.getId() + ": " + e.getMessage() + "\n", e); - } - }); - } + trade.scheduleImportMultisigHex(); } // persist diff --git a/proto/src/main/proto/pb.proto b/proto/src/main/proto/pb.proto index 6436052333..9bca09b668 100644 --- a/proto/src/main/proto/pb.proto +++ b/proto/src/main/proto/pb.proto @@ -1581,6 +1581,7 @@ message ProcessModel { int64 seller_payout_amount_from_mediation = 17; int64 trade_protocol_error_height = 18; string trade_fee_address = 19; + bool import_multisig_hex_scheduled = 20; } message TradePeer {