fix peer deleting unique payment sent, received, dispute messages

This commit is contained in:
woodser 2023-11-20 09:08:30 -05:00
parent 546e260cd0
commit fc396f7478
17 changed files with 103 additions and 110 deletions

View file

@ -365,7 +365,7 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup
UUID.randomUUID().toString(),
getSupportType(),
updatedMultisigHex,
trade.getProcessModel().getPaymentSentMessage());
trade.getArbitrator().getPaymentSentMessage());
log.info("Send {} to peer {}. tradeId={}, openNewDisputeMessage.uid={}, " +
"chatMessage.uid={}",
disputeOpenedMessage.getClass().getSimpleName(), agentNodeAddress,
@ -647,7 +647,7 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup
UUID.randomUUID().toString(),
getSupportType(),
updatedMultisigHex,
trade.getProcessModel().getPaymentSentMessage());
trade.getArbitrator().getPaymentSentMessage());
log.info("Send {} to peer {}. tradeId={}, peerOpenedDisputeMessage.uid={}, chatMessage.uid={}",
peerOpenedDisputeMessage.getClass().getSimpleName(), peersNodeAddress,

View file

@ -224,13 +224,13 @@ public final class ArbitrationManager extends DisputeManager<ArbitrationDisputeL
else DisputeSummaryVerification.verifySignature(summaryText, arbitratorManager); // verify using registered arbitrator (will fail is arbitrator is unregistered)
// save dispute closed message for reprocessing
trade.getProcessModel().setDisputeClosedMessage(disputeClosedMessage);
trade.getArbitrator().setDisputeClosedMessage(disputeClosedMessage);
requestPersistence();
// verify arbitrator does not receive DisputeClosedMessage
if (keyRing.getPubKeyRing().equals(dispute.getAgentPubKeyRing())) {
log.error("Arbitrator received disputeResultMessage. That should never happen.");
trade.getProcessModel().setDisputeClosedMessage(null); // don't reprocess
trade.getArbitrator().setDisputeClosedMessage(null); // don't reprocess
return;
}
@ -303,14 +303,14 @@ public final class ArbitrationManager extends DisputeManager<ArbitrationDisputeL
// nack bad message and do not reprocess
if (e instanceof IllegalArgumentException) {
trade.getProcessModel().setPaymentReceivedMessage(null); // message is processed
trade.getArbitrator().setDisputeClosedMessage(null); // message is processed
sendAckMessage(chatMessage, dispute.getAgentPubKeyRing(), false, e.getMessage());
requestPersistence();
throw e;
}
// schedule to reprocess message unless deleted
if (trade.getProcessModel().getDisputeClosedMessage() != null) {
if (trade.getArbitrator().getDisputeClosedMessage() != null) {
if (!reprocessDisputeClosedMessageCounts.containsKey(trade.getId())) reprocessDisputeClosedMessageCounts.put(trade.getId(), 0);
UserThread.runAfter(() -> {
reprocessDisputeClosedMessageCounts.put(trade.getId(), reprocessDisputeClosedMessageCounts.get(trade.getId()) + 1); // increment reprocess count
@ -325,12 +325,12 @@ public final class ArbitrationManager extends DisputeManager<ArbitrationDisputeL
synchronized (trade) {
// skip if no need to reprocess
if (trade.isArbitrator() || trade.getProcessModel().getDisputeClosedMessage() == null || trade.getProcessModel().getDisputeClosedMessage().getUnsignedPayoutTxHex() == null || trade.getDisputeState().ordinal() >= Trade.DisputeState.DISPUTE_CLOSED.ordinal()) {
if (trade.isArbitrator() || trade.getArbitrator().getDisputeClosedMessage() == null || trade.getArbitrator().getDisputeClosedMessage().getUnsignedPayoutTxHex() == null || trade.getDisputeState().ordinal() >= Trade.DisputeState.DISPUTE_CLOSED.ordinal()) {
return;
}
log.warn("Reprocessing dispute closed message for {} {}", trade.getClass().getSimpleName(), trade.getId());
new Thread(() -> handleDisputeClosedMessage(trade.getProcessModel().getDisputeClosedMessage(), reprocessOnError)).start();
new Thread(() -> handleDisputeClosedMessage(trade.getArbitrator().getDisputeClosedMessage(), reprocessOnError)).start();
}
}
@ -343,7 +343,7 @@ public final class ArbitrationManager extends DisputeManager<ArbitrationDisputeL
Dispute dispute = disputeOptional.get();
Contract contract = dispute.getContract();
DisputeResult disputeResult = dispute.getDisputeResultProperty().get();
String unsignedPayoutTxHex = trade.getProcessModel().getDisputeClosedMessage().getUnsignedPayoutTxHex();
String unsignedPayoutTxHex = trade.getArbitrator().getDisputeClosedMessage().getUnsignedPayoutTxHex();
// Offer offer = checkNotNull(trade.getOffer(), "offer must not be null");
// BigInteger sellerDepositAmount = multisigWallet.getTx(trade instanceof MakerTrade ? trade.getMaker().getDepositTxHash() : trade.getTaker().getDepositTxHash()).getIncomingAmount(); // TODO (woodser): use contract instead of trade to get deposit tx ids when contract has deposit tx ids
@ -420,10 +420,10 @@ public final class ArbitrationManager extends DisputeManager<ArbitrationDisputeL
// determine if we already signed dispute payout tx
// TODO: better way, such as by saving signed dispute payout tx hex in designated field instead of shared payoutTxHex field?
Set<String> nonSignedDisputePayoutTxHexes = new HashSet<String>();
if (trade.getProcessModel().getPaymentSentMessage() != null) nonSignedDisputePayoutTxHexes.add(trade.getProcessModel().getPaymentSentMessage().getPayoutTxHex());
if (trade.getProcessModel().getPaymentReceivedMessage() != null) {
nonSignedDisputePayoutTxHexes.add(trade.getProcessModel().getPaymentReceivedMessage().getUnsignedPayoutTxHex());
nonSignedDisputePayoutTxHexes.add(trade.getProcessModel().getPaymentReceivedMessage().getSignedPayoutTxHex());
if (trade.getTradePeer().getPaymentSentMessage() != null) nonSignedDisputePayoutTxHexes.add(trade.getTradePeer().getPaymentSentMessage().getPayoutTxHex());
if (trade.getTradePeer().getPaymentReceivedMessage() != null) {
nonSignedDisputePayoutTxHexes.add(trade.getTradePeer().getPaymentReceivedMessage().getUnsignedPayoutTxHex());
nonSignedDisputePayoutTxHexes.add(trade.getTradePeer().getPaymentReceivedMessage().getSignedPayoutTxHex());
}
boolean signed = trade.getPayoutTxHex() != null && !nonSignedDisputePayoutTxHexes.contains(trade.getPayoutTxHex());

View file

@ -1859,7 +1859,7 @@ public abstract class Trade implements Tradable, Model {
if (isDepositsUnlocked() && !isPayoutPublished()) wallet.rescanSpent();
// get txs from trade wallet
boolean payoutExpected = isPaymentReceived() || processModel.getPaymentReceivedMessage() != null || disputeState.ordinal() > DisputeState.ARBITRATOR_SENT_DISPUTE_CLOSED_MSG.ordinal() || processModel.getDisputeClosedMessage() != null;
boolean payoutExpected = isPaymentReceived() || getSeller().getPaymentReceivedMessage() != null || disputeState.ordinal() >= DisputeState.ARBITRATOR_SENT_DISPUTE_CLOSED_MSG.ordinal() || getArbitrator().getDisputeClosedMessage() != null;
boolean checkPool = !isDepositsConfirmed() || (!isPayoutConfirmed() && payoutExpected);
MoneroTxQuery query = new MoneroTxQuery().setIncludeOutputs(true);
if (!checkPool) query.setInTxPool(false); // avoid pool check if possible

View file

@ -18,7 +18,6 @@
package haveno.core.trade.protocol;
import com.google.protobuf.ByteString;
import haveno.common.app.Version;
import haveno.common.crypto.KeyRing;
import haveno.common.crypto.PubKeyRing;
import haveno.common.proto.ProtoUtil;
@ -34,12 +33,9 @@ import haveno.core.payment.payload.PaymentAccountPayload;
import haveno.core.proto.CoreProtoResolver;
import haveno.core.support.dispute.arbitration.arbitrator.ArbitratorManager;
import haveno.core.support.dispute.mediation.mediator.MediatorManager;
import haveno.core.support.dispute.messages.DisputeClosedMessage;
import haveno.core.support.dispute.refund.refundagent.RefundAgentManager;
import haveno.core.trade.Trade;
import haveno.core.trade.TradeManager;
import haveno.core.trade.messages.PaymentReceivedMessage;
import haveno.core.trade.messages.PaymentSentMessage;
import haveno.core.trade.messages.TradeMessage;
import haveno.core.trade.statistics.ReferralIdService;
import haveno.core.trade.statistics.TradeStatisticsManager;
@ -139,18 +135,6 @@ public class ProcessModel implements Model, PersistablePayload {
@Getter
@Setter
private String multisigAddress;
@Nullable
@Setter
@Getter
private PaymentSentMessage paymentSentMessage;
@Nullable
@Setter
@Getter
private PaymentReceivedMessage paymentReceivedMessage;
@Nullable
@Setter
@Getter
private DisputeClosedMessage disputeClosedMessage;
// 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.
@ -204,9 +188,6 @@ public class ProcessModel implements Model, PersistablePayload {
Optional.ofNullable(mediatedPayoutTxSignature).ifPresent(e -> builder.setMediatedPayoutTxSignature(ByteString.copyFrom(e)));
Optional.ofNullable(makerSignature).ifPresent(e -> builder.setMakerSignature(ByteString.copyFrom(e)));
Optional.ofNullable(multisigAddress).ifPresent(e -> builder.setMultisigAddress(multisigAddress));
Optional.ofNullable(paymentSentMessage).ifPresent(e -> builder.setPaymentSentMessage(paymentSentMessage.toProtoNetworkEnvelope().getPaymentSentMessage()));
Optional.ofNullable(paymentReceivedMessage).ifPresent(e -> builder.setPaymentReceivedMessage(paymentReceivedMessage.toProtoNetworkEnvelope().getPaymentReceivedMessage()));
Optional.ofNullable(disputeClosedMessage).ifPresent(e -> builder.setDisputeClosedMessage(disputeClosedMessage.toProtoNetworkEnvelope().getDisputeClosedMessage()));
return builder.build();
}
@ -232,9 +213,6 @@ public class ProcessModel implements Model, PersistablePayload {
MessageState paymentSentMessageState = ProtoUtil.enumFromProto(MessageState.class, paymentSentMessageStateString);
processModel.setPaymentSentMessageState(paymentSentMessageState);
processModel.setPaymentSentMessage(proto.hasPaymentSentMessage() ? PaymentSentMessage.fromProto(proto.getPaymentSentMessage(), Version.getP2PMessageVersion()) : null);
processModel.setPaymentReceivedMessage(proto.hasPaymentReceivedMessage() ? PaymentReceivedMessage.fromProto(proto.getPaymentReceivedMessage(), Version.getP2PMessageVersion()) : null);
processModel.setDisputeClosedMessage(proto.hasDisputeClosedMessage() ? DisputeClosedMessage.fromProto(proto.getDisputeClosedMessage(), Version.getP2PMessageVersion()) : null);
return processModel;
}

View file

@ -19,12 +19,16 @@ package haveno.core.trade.protocol;
import com.google.protobuf.ByteString;
import com.google.protobuf.Message;
import haveno.common.app.Version;
import haveno.common.crypto.PubKeyRing;
import haveno.common.proto.ProtoUtil;
import haveno.common.proto.persistable.PersistablePayload;
import haveno.core.account.witness.AccountAgeWitness;
import haveno.core.payment.payload.PaymentAccountPayload;
import haveno.core.proto.CoreProtoResolver;
import haveno.core.support.dispute.messages.DisputeClosedMessage;
import haveno.core.trade.messages.PaymentReceivedMessage;
import haveno.core.trade.messages.PaymentSentMessage;
import haveno.network.p2p.NodeAddress;
import lombok.Getter;
import lombok.Setter;
@ -79,6 +83,19 @@ public final class TradePeer implements PersistablePayload {
private String contractAsJson;
@Nullable
private byte[] contractSignature;
@Nullable
@Setter
@Getter
private PaymentSentMessage paymentSentMessage;
@Nullable
@Setter
@Getter
private PaymentReceivedMessage paymentReceivedMessage;
@Nullable
@Setter
@Getter
private DisputeClosedMessage disputeClosedMessage;
// added in v 0.6
@Nullable
@ -164,6 +181,9 @@ public final class TradePeer implements PersistablePayload {
Optional.ofNullable(accountAgeWitnessSignature).ifPresent(e -> builder.setAccountAgeWitnessSignature(ByteString.copyFrom(e)));
Optional.ofNullable(accountAgeWitness).ifPresent(e -> builder.setAccountAgeWitness(accountAgeWitness.toProtoAccountAgeWitness()));
Optional.ofNullable(mediatedPayoutTxSignature).ifPresent(e -> builder.setMediatedPayoutTxSignature(ByteString.copyFrom(e)));
Optional.ofNullable(paymentSentMessage).ifPresent(e -> builder.setPaymentSentMessage(paymentSentMessage.toProtoNetworkEnvelope().getPaymentSentMessage()));
Optional.ofNullable(paymentReceivedMessage).ifPresent(e -> builder.setPaymentReceivedMessage(paymentReceivedMessage.toProtoNetworkEnvelope().getPaymentReceivedMessage()));
Optional.ofNullable(disputeClosedMessage).ifPresent(e -> builder.setDisputeClosedMessage(disputeClosedMessage.toProtoNetworkEnvelope().getDisputeClosedMessage()));
Optional.ofNullable(reserveTxHash).ifPresent(e -> builder.setReserveTxHash(reserveTxHash));
Optional.ofNullable(reserveTxHex).ifPresent(e -> builder.setReserveTxHex(reserveTxHex));
Optional.ofNullable(reserveTxKey).ifPresent(e -> builder.setReserveTxKey(reserveTxKey));
@ -207,6 +227,9 @@ public final class TradePeer implements PersistablePayload {
tradePeer.setAccountAgeWitness(protoAccountAgeWitness.getHash().isEmpty() ? null : AccountAgeWitness.fromProto(protoAccountAgeWitness));
tradePeer.setCurrentDate(proto.getCurrentDate());
tradePeer.setMediatedPayoutTxSignature(ProtoUtil.byteArrayOrNullFromProto(proto.getMediatedPayoutTxSignature()));
tradePeer.setPaymentSentMessage(proto.hasPaymentSentMessage() ? PaymentSentMessage.fromProto(proto.getPaymentSentMessage(), Version.getP2PMessageVersion()) : null);
tradePeer.setPaymentReceivedMessage(proto.hasPaymentReceivedMessage() ? PaymentReceivedMessage.fromProto(proto.getPaymentReceivedMessage(), Version.getP2PMessageVersion()) : null);
tradePeer.setDisputeClosedMessage(proto.hasDisputeClosedMessage() ? DisputeClosedMessage.fromProto(proto.getDisputeClosedMessage(), Version.getP2PMessageVersion()) : null);
tradePeer.setReserveTxHash(ProtoUtil.stringOrNullFromProto(proto.getReserveTxHash()));
tradePeer.setReserveTxHex(ProtoUtil.stringOrNullFromProto(proto.getReserveTxHex()));
tradePeer.setReserveTxKey(ProtoUtil.stringOrNullFromProto(proto.getReserveTxKey()));

View file

@ -274,12 +274,12 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D
synchronized (trade) {
// skip if no need to reprocess
if (trade.isSeller() || trade.getProcessModel().getPaymentReceivedMessage() == null || trade.getState().ordinal() >= Trade.State.SELLER_SENT_PAYMENT_RECEIVED_MSG.ordinal()) {
if (trade.isSeller() || trade.getSeller().getPaymentReceivedMessage() == null || trade.getState().ordinal() >= Trade.State.SELLER_SENT_PAYMENT_RECEIVED_MSG.ordinal()) {
return;
}
log.warn("Reprocessing payment received message for {} {}", trade.getClass().getSimpleName(), trade.getId());
new Thread(() -> handle(trade.getProcessModel().getPaymentReceivedMessage(), trade.getProcessModel().getPaymentReceivedMessage().getSenderNodeAddress(), reprocessOnError)).start();
new Thread(() -> handle(trade.getSeller().getPaymentReceivedMessage(), trade.getSeller().getPaymentReceivedMessage().getSenderNodeAddress(), reprocessOnError)).start();
}
}
@ -552,7 +552,7 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D
processModel.getTradeManager().requestPersistence();
// schedule to reprocess message unless deleted
if (trade.getProcessModel().getPaymentReceivedMessage() != null) {
if (trade.getSeller().getPaymentReceivedMessage() != null) {
UserThread.runAfter(() -> {
reprocessPaymentReceivedMessageCount++;
maybeReprocessPaymentReceivedMessage(reprocessOnError);

View file

@ -45,9 +45,9 @@ public class BuyerPreparePaymentSentMessage extends TradeTask {
try {
runInterceptHook();
// skip if already created
if (processModel.getPaymentSentMessage() != null) {
log.warn("Skipping preparation of payment sent message since it's already created for {} {}", trade.getClass().getSimpleName(), trade.getId());
// skip if payout tx already created
if (trade.getPayoutTxHex() != null) {
log.warn("Skipping preparation of payment sent message because payout tx is already created for {} {}", trade.getClass().getSimpleName(), trade.getId());
complete();
return;
}

View file

@ -28,6 +28,7 @@ import haveno.core.trade.HavenoUtils;
import haveno.core.trade.Trade;
import haveno.core.trade.messages.PaymentSentMessage;
import haveno.core.trade.messages.TradeMailboxMessage;
import haveno.core.trade.protocol.TradePeer;
import haveno.core.util.JsonUtil;
import haveno.network.p2p.NodeAddress;
import javafx.beans.value.ChangeListener;
@ -56,9 +57,17 @@ public abstract class BuyerSendPaymentSentMessage extends SendMailboxMessageTask
super(taskHandler, trade);
}
protected abstract NodeAddress getReceiverNodeAddress();
protected abstract TradePeer getReceiver();
protected abstract PubKeyRing getReceiverPubKeyRing();
@Override
protected NodeAddress getReceiverNodeAddress() {
return getReceiver().getNodeAddress();
}
@Override
protected PubKeyRing getReceiverPubKeyRing() {
return getReceiver().getPubKeyRing();
}
@Override
protected void run() {
@ -72,7 +81,7 @@ public abstract class BuyerSendPaymentSentMessage extends SendMailboxMessageTask
@Override
protected TradeMailboxMessage getTradeMailboxMessage(String tradeId) {
if (processModel.getPaymentSentMessage() == null) {
if (getReceiver().getPaymentSentMessage() == null) {
// We do not use a real unique ID here as we want to be able to re-send the exact same message in case the
// peer does not respond with an ACK msg in a certain time interval. To avoid that we get dangling mailbox
@ -98,13 +107,13 @@ public abstract class BuyerSendPaymentSentMessage extends SendMailboxMessageTask
String messageAsJson = JsonUtil.objectToJson(message);
byte[] sig = HavenoUtils.sign(processModel.getP2PService().getKeyRing(), messageAsJson);
message.setBuyerSignature(sig);
processModel.setPaymentSentMessage(message);
getReceiver().setPaymentSentMessage(message);
trade.requestPersistence();
} catch (Exception e) {
throw new RuntimeException (e);
}
}
return processModel.getPaymentSentMessage();
return getReceiver().getPaymentSentMessage();
}
@Override

View file

@ -17,10 +17,9 @@
package haveno.core.trade.protocol.tasks;
import haveno.common.crypto.PubKeyRing;
import haveno.common.taskrunner.TaskRunner;
import haveno.core.trade.Trade;
import haveno.network.p2p.NodeAddress;
import haveno.core.trade.protocol.TradePeer;
import lombok.EqualsAndHashCode;
import lombok.extern.slf4j.Slf4j;
@ -32,12 +31,9 @@ public class BuyerSendPaymentSentMessageToArbitrator extends BuyerSendPaymentSen
super(taskHandler, trade);
}
protected NodeAddress getReceiverNodeAddress() {
return trade.getArbitrator().getNodeAddress();
}
protected PubKeyRing getReceiverPubKeyRing() {
return trade.getArbitrator().getPubKeyRing();
@Override
protected TradePeer getReceiver() {
return trade.getArbitrator();
}
@Override

View file

@ -17,11 +17,10 @@
package haveno.core.trade.protocol.tasks;
import haveno.common.crypto.PubKeyRing;
import haveno.common.taskrunner.TaskRunner;
import haveno.core.trade.Trade;
import haveno.core.trade.messages.TradeMessage;
import haveno.network.p2p.NodeAddress;
import haveno.core.trade.protocol.TradePeer;
import lombok.EqualsAndHashCode;
import lombok.extern.slf4j.Slf4j;
@ -33,12 +32,9 @@ public class BuyerSendPaymentSentMessageToSeller extends BuyerSendPaymentSentMes
super(taskHandler, trade);
}
protected NodeAddress getReceiverNodeAddress() {
return trade.getSeller().getNodeAddress();
}
protected PubKeyRing getReceiverPubKeyRing() {
return trade.getSeller().getPubKeyRing();
@Override
protected TradePeer getReceiver() {
return trade.getSeller();
}
// continue execution on fault so payment sent message is sent to arbitrator

View file

@ -26,6 +26,7 @@ import haveno.core.trade.BuyerTrade;
import haveno.core.trade.HavenoUtils;
import haveno.core.trade.Trade;
import haveno.core.trade.messages.PaymentReceivedMessage;
import haveno.core.trade.messages.PaymentSentMessage;
import haveno.core.util.Validator;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
@ -65,13 +66,13 @@ public class ProcessPaymentReceivedMessage extends TradeTask {
}
// save message for reprocessing
processModel.setPaymentReceivedMessage(message);
trade.requestPersistence();
trade.getSeller().setPaymentReceivedMessage(message);
// set state
trade.getSeller().setUpdatedMultisigHex(message.getUpdatedMultisigHex());
trade.getBuyer().setUpdatedMultisigHex(message.getPaymentSentMessage().getUpdatedMultisigHex());
trade.getBuyer().setAccountAgeWitness(message.getBuyerAccountAgeWitness());
trade.requestPersistence();
// close open disputes
if (trade.getDisputeState().ordinal() >= Trade.DisputeState.DISPUTE_REQUESTED.ordinal()) {
@ -100,7 +101,7 @@ public class ProcessPaymentReceivedMessage extends TradeTask {
// do not reprocess illegal argument
if (t instanceof IllegalArgumentException) {
processModel.setPaymentReceivedMessage(null); // do not reprocess
trade.getSeller().setPaymentReceivedMessage(null); // do not reprocess
trade.requestPersistence();
}
@ -134,8 +135,9 @@ public class ProcessPaymentReceivedMessage extends TradeTask {
trade.verifyPayoutTx(message.getSignedPayoutTxHex(), false, true);
} else {
try {
if (trade.getProcessModel().getPaymentSentMessage() == null) throw new RuntimeException("Process model does not have payment sent message for " + trade.getClass().getSimpleName() + " " + trade.getId());
if (StringUtils.equals(trade.getPayoutTxHex(), trade.getProcessModel().getPaymentSentMessage().getPayoutTxHex())) { // unsigned
PaymentSentMessage paymentSentMessage = (trade.isArbitrator() ? trade.getBuyer() : trade.getArbitrator()).getPaymentSentMessage();
if (paymentSentMessage == null) throw new RuntimeException("Process model does not have payment sent message for " + trade.getClass().getSimpleName() + " " + trade.getId());
if (StringUtils.equals(trade.getPayoutTxHex(), paymentSentMessage.getPayoutTxHex())) { // unsigned
log.info("{} {} verifying, signing, and publishing seller's payout tx", trade.getClass().getSimpleName(), trade.getId());
trade.verifyPayoutTx(message.getUnsignedPayoutTxHex(), true, true);
} else {

View file

@ -48,7 +48,7 @@ public class ProcessPaymentSentMessage extends TradeTask {
trade.getBuyer().setNodeAddress(processModel.getTempTradePeerNodeAddress());
// update state from message
processModel.setPaymentSentMessage(message);
trade.getBuyer().setPaymentSentMessage(message);
trade.setPayoutTxHex(message.getPayoutTxHex());
trade.getBuyer().setUpdatedMultisigHex(message.getUpdatedMultisigHex());
trade.getSeller().setAccountAgeWitness(message.getSellerAccountAgeWitness());

View file

@ -39,7 +39,7 @@ public class SellerPreparePaymentReceivedMessage extends TradeTask {
trade.checkDaemonConnection();
// handle first time preparation
if (processModel.getPaymentReceivedMessage() == null) {
if (trade.getArbitrator().getPaymentReceivedMessage() == null) {
// import multisig hex
trade.importMultisigHex();
@ -56,11 +56,11 @@ public class SellerPreparePaymentReceivedMessage extends TradeTask {
} else {
createUnsignedPayoutTx();
}
} else if (processModel.getPaymentReceivedMessage().getSignedPayoutTxHex() != null && !trade.isPayoutPublished()) {
} else if (trade.getArbitrator().getPaymentReceivedMessage().getSignedPayoutTxHex() != null && !trade.isPayoutPublished()) {
// republish payout tx from previous message
log.info("Seller re-verifying and publishing payout tx for trade {}", trade.getId());
trade.verifyPayoutTx(processModel.getPaymentReceivedMessage().getSignedPayoutTxHex(), false, true);
trade.verifyPayoutTx(trade.getArbitrator().getPaymentReceivedMessage().getSignedPayoutTxHex(), false, true);
}
processModel.getTradeManager().requestPersistence();

View file

@ -27,6 +27,7 @@ import haveno.core.trade.HavenoUtils;
import haveno.core.trade.Trade;
import haveno.core.trade.messages.PaymentReceivedMessage;
import haveno.core.trade.messages.TradeMailboxMessage;
import haveno.core.trade.protocol.TradePeer;
import haveno.core.util.JsonUtil;
import haveno.network.p2p.NodeAddress;
import lombok.EqualsAndHashCode;
@ -37,16 +38,23 @@ import static com.google.common.base.Preconditions.checkNotNull;
@Slf4j
@EqualsAndHashCode(callSuper = true)
public abstract class SellerSendPaymentReceivedMessage extends SendMailboxMessageTask {
PaymentReceivedMessage message = null;
SignedWitness signedWitness = null;
public SellerSendPaymentReceivedMessage(TaskRunner<Trade> taskHandler, Trade trade) {
super(taskHandler, trade);
}
protected abstract NodeAddress getReceiverNodeAddress();
protected abstract TradePeer getReceiver();
protected abstract PubKeyRing getReceiverPubKeyRing();
@Override
protected NodeAddress getReceiverNodeAddress() {
return getReceiver().getNodeAddress();
}
@Override
protected PubKeyRing getReceiverPubKeyRing() {
return getReceiver().getPubKeyRing();
}
@Override
protected void run() {
@ -61,7 +69,7 @@ public abstract class SellerSendPaymentReceivedMessage extends SendMailboxMessag
@Override
protected TradeMailboxMessage getTradeMailboxMessage(String tradeId) {
checkNotNull(trade.getPayoutTxHex(), "Payout tx must not be null");
if (message == null) {
if (getReceiver().getPaymentReceivedMessage() == null) {
// sign account witness
AccountAgeWitnessService accountAgeWitnessService = processModel.getAccountAgeWitnessService();
@ -75,7 +83,7 @@ public abstract class SellerSendPaymentReceivedMessage extends SendMailboxMessag
// messages where only the one which gets processed by the peer would be removed we use the same uid. All
// other data stays the same when we re-send the message at any time later.
String deterministicId = HavenoUtils.getDeterministicId(trade, PaymentReceivedMessage.class, getReceiverNodeAddress());
message = new PaymentReceivedMessage(
PaymentReceivedMessage message = new PaymentReceivedMessage(
tradeId,
processModel.getMyNodeAddress(),
deterministicId,
@ -85,7 +93,7 @@ public abstract class SellerSendPaymentReceivedMessage extends SendMailboxMessag
trade.getState().ordinal() >= Trade.State.SELLER_SAW_ARRIVED_PAYMENT_RECEIVED_MSG.ordinal(), // informs to expect payout
trade.getTradePeer().getAccountAgeWitness(),
signedWitness,
processModel.getPaymentSentMessage()
trade.getBuyer().getPaymentSentMessage()
);
// sign message
@ -93,13 +101,13 @@ public abstract class SellerSendPaymentReceivedMessage extends SendMailboxMessag
String messageAsJson = JsonUtil.objectToJson(message);
byte[] sig = Sig.sign(processModel.getP2PService().getKeyRing().getSignatureKeyPair().getPrivate(), messageAsJson.getBytes(Charsets.UTF_8));
message.setSellerSignature(sig);
processModel.setPaymentReceivedMessage(message);
getReceiver().setPaymentReceivedMessage(message);
trade.requestPersistence();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
return message;
return getReceiver().getPaymentReceivedMessage();
}
@Override

View file

@ -17,10 +17,9 @@
package haveno.core.trade.protocol.tasks;
import haveno.common.crypto.PubKeyRing;
import haveno.common.taskrunner.TaskRunner;
import haveno.core.trade.Trade;
import haveno.network.p2p.NodeAddress;
import haveno.core.trade.protocol.TradePeer;
import lombok.EqualsAndHashCode;
import lombok.extern.slf4j.Slf4j;
@ -32,11 +31,8 @@ public class SellerSendPaymentReceivedMessageToArbitrator extends SellerSendPaym
super(taskHandler, trade);
}
protected NodeAddress getReceiverNodeAddress() {
return trade.getArbitrator().getNodeAddress();
}
protected PubKeyRing getReceiverPubKeyRing() {
return trade.getArbitrator().getPubKeyRing();
@Override
protected TradePeer getReceiver() {
return trade.getArbitrator();
}
}

View file

@ -17,13 +17,10 @@
package haveno.core.trade.protocol.tasks;
import haveno.common.crypto.PubKeyRing;
import haveno.common.taskrunner.TaskRunner;
import haveno.core.trade.Trade;
import haveno.core.trade.messages.PaymentReceivedMessage;
import haveno.core.trade.messages.TradeMailboxMessage;
import haveno.core.trade.messages.TradeMessage;
import haveno.network.p2p.NodeAddress;
import haveno.core.trade.protocol.TradePeer;
import lombok.EqualsAndHashCode;
import lombok.extern.slf4j.Slf4j;
@ -35,21 +32,9 @@ public class SellerSendPaymentReceivedMessageToBuyer extends SellerSendPaymentRe
super(taskHandler, trade);
}
@Override
protected TradeMailboxMessage getTradeMailboxMessage(String tradeId) {
if (processModel.getPaymentReceivedMessage() == null) {
processModel.setPaymentReceivedMessage((PaymentReceivedMessage) super.getTradeMailboxMessage(tradeId)); // save payment received message for buyer
}
return processModel.getPaymentReceivedMessage();
}
protected NodeAddress getReceiverNodeAddress() {
return trade.getBuyer().getNodeAddress();
}
protected PubKeyRing getReceiverPubKeyRing() {
return trade.getBuyer().getPubKeyRing();
protected TradePeer getReceiver() {
return trade.getBuyer();
}
// continue execution on fault so payment received message is sent to arbitrator

View file

@ -1546,9 +1546,6 @@ message ProcessModel {
TradePeer arbitrator = 11;
NodeAddress temp_trade_peer_node_address = 12;
string multisig_address = 13;
PaymentSentMessage payment_sent_message = 14;
PaymentReceivedMessage payment_received_message = 15;
DisputeClosedMessage dispute_closed_message = 16;
bytes mediated_payout_tx_signature = 17; // placeholder if mediation used in future
int64 buyer_payout_amount_from_mediation = 18;
int64 seller_payout_amount_from_mediation = 19;
@ -1572,6 +1569,9 @@ message TradePeer {
AccountAgeWitness account_age_witness = 20;
int64 current_date = 21;
bytes mediated_payout_tx_signature = 22;
PaymentSentMessage payment_sent_message = 23;
PaymentReceivedMessage payment_received_message = 24;
DisputeClosedMessage dispute_closed_message = 25;
string reserve_tx_hash = 1001;
string reserve_tx_hex = 1002;