fix not enough signers on process payout tx

This commit is contained in:
woodser 2024-09-25 09:41:25 -04:00
parent 60b91d3d23
commit 3e3f3085f8
7 changed files with 30 additions and 20 deletions

View file

@ -199,7 +199,7 @@ public abstract class SupportManager {
if (dispute.isClosed()) dispute.reOpen(); if (dispute.isClosed()) dispute.reOpen();
trade.advanceDisputeState(Trade.DisputeState.DISPUTE_OPENED); trade.advanceDisputeState(Trade.DisputeState.DISPUTE_OPENED);
} else if (dispute.isClosed()) { } else if (dispute.isClosed()) {
trade.pollWalletNormallyForMs(30000); // sync to check for payout trade.pollWalletNormallyForMs(60000); // sync to check for payout
} }
} }
} }

View file

@ -854,7 +854,7 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup
// the state, as that is displayed to the user and we only persist that msg // the state, as that is displayed to the user and we only persist that msg
disputeResult.getChatMessage().setArrived(true); disputeResult.getChatMessage().setArrived(true);
trade.advanceDisputeState(Trade.DisputeState.ARBITRATOR_SAW_ARRIVED_DISPUTE_CLOSED_MSG); trade.advanceDisputeState(Trade.DisputeState.ARBITRATOR_SAW_ARRIVED_DISPUTE_CLOSED_MSG);
trade.pollWalletNormallyForMs(30000); trade.pollWalletNormallyForMs(60000);
requestPersistence(trade); requestPersistence(trade);
resultHandler.handleResult(); resultHandler.handleResult();
} }

View file

@ -361,7 +361,7 @@ public final class ArbitrationManager extends DisputeManager<ArbitrationDisputeL
requestPersistence(trade); requestPersistence(trade);
// nack bad message and do not reprocess // nack bad message and do not reprocess
if (e instanceof IllegalArgumentException || e instanceof IllegalStateException) { if (HavenoUtils.isIllegal(e)) {
trade.getArbitrator().setDisputeClosedMessage(null); // message is processed trade.getArbitrator().setDisputeClosedMessage(null); // message is processed
trade.setDisputeState(Trade.DisputeState.DISPUTE_CLOSED); trade.setDisputeState(Trade.DisputeState.DISPUTE_CLOSED);
String warningMsg = "Error processing dispute closed message: " + e.getMessage() + "\n\nOpen another dispute to try again (ctrl+o)."; String warningMsg = "Error processing dispute closed message: " + e.getMessage() + "\n\nOpen another dispute to try again (ctrl+o).";

View file

@ -510,19 +510,27 @@ public class HavenoUtils {
havenoSetup.getTopErrorMsg().set(msg); havenoSetup.getTopErrorMsg().set(msg);
} }
public static boolean isConnectionRefused(Exception e) { public static boolean isConnectionRefused(Throwable e) {
return e != null && e.getMessage().contains("Connection refused"); return e != null && e.getMessage().contains("Connection refused");
} }
public static boolean isReadTimeout(Exception e) { public static boolean isReadTimeout(Throwable e) {
return e != null && e.getMessage().contains("Read timed out"); return e != null && e.getMessage().contains("Read timed out");
} }
public static boolean isUnresponsive(Exception e) { public static boolean isUnresponsive(Throwable e) {
return isConnectionRefused(e) || isReadTimeout(e); return isConnectionRefused(e) || isReadTimeout(e);
} }
public static boolean isNotEnoughSigners(Exception e) { public static boolean isNotEnoughSigners(Throwable e) {
return e != null && e.getMessage().contains("Not enough signers"); return e != null && e.getMessage().contains("Not enough signers");
} }
public static boolean isTransactionRejected(Throwable e) {
return e != null && e.getMessage().contains("was rejected");
}
public static boolean isIllegal(Throwable e) {
return e instanceof IllegalArgumentException || e instanceof IllegalStateException;
}
} }

View file

@ -1158,7 +1158,7 @@ public abstract class Trade extends XmrWalletBase implements Tradable, Model {
private void handleWalletError(Exception e, MoneroRpcConnection sourceConnection) { private void handleWalletError(Exception e, MoneroRpcConnection sourceConnection) {
if (HavenoUtils.isUnresponsive(e)) forceCloseWallet(); // wallet can be stuck a while if (HavenoUtils.isUnresponsive(e)) forceCloseWallet(); // wallet can be stuck a while
if (xmrConnectionService.isConnected()) requestSwitchToNextBestConnection(sourceConnection); if (!HavenoUtils.isIllegal(e) && xmrConnectionService.isConnected()) requestSwitchToNextBestConnection(sourceConnection);
getWallet(); // re-open wallet getWallet(); // re-open wallet
} }
@ -1278,7 +1278,7 @@ public abstract class Trade extends XmrWalletBase implements Tradable, Model {
} catch (IllegalArgumentException | IllegalStateException e) { } catch (IllegalArgumentException | IllegalStateException e) {
throw e; throw e;
} catch (Exception e) { } catch (Exception e) {
log.warn("Failed to process payout tx, tradeId={}, attempt={}/{}, error={}", getShortId(), i + 1, TradeProtocol.MAX_ATTEMPTS, e.getMessage()); log.warn("Failed to process payout tx, tradeId={}, attempt={}/{}, error={}", getShortId(), i + 1, TradeProtocol.MAX_ATTEMPTS, e.getMessage(), e);
handleWalletError(e, sourceConnection); handleWalletError(e, sourceConnection);
if (i == TradeProtocol.MAX_ATTEMPTS - 1) throw e; if (i == TradeProtocol.MAX_ATTEMPTS - 1) throw e;
HavenoUtils.waitFor(TradeProtocol.REPROCESS_DELAY_MS); // wait before retrying HavenoUtils.waitFor(TradeProtocol.REPROCESS_DELAY_MS); // wait before retrying
@ -1350,14 +1350,13 @@ public abstract class Trade extends XmrWalletBase implements Tradable, Model {
try { try {
MoneroMultisigSignResult result = wallet.signMultisigTxHex(payoutTxHex); MoneroMultisigSignResult result = wallet.signMultisigTxHex(payoutTxHex);
if (result.getSignedMultisigTxHex() == null) throw new IllegalArgumentException("Error signing payout tx, signed multisig hex is null"); if (result.getSignedMultisigTxHex() == null) throw new IllegalArgumentException("Error signing payout tx, signed multisig hex is null");
payoutTxHex = result.getSignedMultisigTxHex(); setPayoutTxHex(result.getSignedMultisigTxHex());
setPayoutTxHex(payoutTxHex);
} catch (Exception e) { } catch (Exception e) {
throw new IllegalStateException(e); throw new IllegalStateException(e);
} }
// describe result // describe result
describedTxSet = wallet.describeMultisigTxSet(payoutTxHex); describedTxSet = wallet.describeMultisigTxSet(getPayoutTxHex());
payoutTx = describedTxSet.getTxs().get(0); payoutTx = describedTxSet.getTxs().get(0);
updatePayout(payoutTx); updatePayout(payoutTx);
@ -1377,14 +1376,16 @@ public abstract class Trade extends XmrWalletBase implements Tradable, Model {
requestPersistence(); requestPersistence();
// submit payout tx // submit payout tx
if (publish) { boolean doPublish = publish && !isPayoutPublished();
if (doPublish) {
try { try {
wallet.submitMultisigTxHex(payoutTxHex); wallet.submitMultisigTxHex(getPayoutTxHex());
setPayoutStatePublished(); setPayoutStatePublished();
} catch (Exception e) { } catch (Exception e) {
if (isPayoutPublished()) throw new IllegalStateException("Payout tx already published for " + getClass().getSimpleName() + " " + getShortId()); if (!isPayoutPublished()) {
if (HavenoUtils.isNotEnoughSigners(e)) throw new IllegalArgumentException(e); if (HavenoUtils.isTransactionRejected(e) || HavenoUtils.isNotEnoughSigners(e)) throw new IllegalArgumentException(e);
throw new RuntimeException("Failed to submit payout tx for " + getClass().getSimpleName() + " " + getId(), e); throw new RuntimeException("Failed to submit payout tx for " + getClass().getSimpleName() + " " + getId() + ", error=" + e.getMessage(), e);
}
} }
} }
} }

View file

@ -120,7 +120,7 @@ public class ProcessPaymentReceivedMessage extends TradeTask {
} catch (Throwable t) { } catch (Throwable t) {
// do not reprocess illegal argument // do not reprocess illegal argument
if (t instanceof IllegalArgumentException) { if (HavenoUtils.isIllegal(t)) {
trade.getSeller().setPaymentReceivedMessage(null); // do not reprocess trade.getSeller().setPaymentReceivedMessage(null); // do not reprocess
trade.requestPersistence(); trade.requestPersistence();
} }
@ -151,6 +151,7 @@ public class ProcessPaymentReceivedMessage extends TradeTask {
boolean deferSignAndPublish = trade instanceof ArbitratorTrade && !isSigned && message.isDeferPublishPayout(); boolean deferSignAndPublish = trade instanceof ArbitratorTrade && !isSigned && message.isDeferPublishPayout();
if (deferSignAndPublish) { if (deferSignAndPublish) {
log.info("Deferring signing and publishing payout tx for {} {}", trade.getClass().getSimpleName(), trade.getId()); log.info("Deferring signing and publishing payout tx for {} {}", trade.getClass().getSimpleName(), trade.getId());
trade.pollWalletNormallyForMs(60000);
for (int i = 0; i < 5; i++) { for (int i = 0; i < 5; i++) {
if (trade.isPayoutPublished()) break; if (trade.isPayoutPublished()) break;
HavenoUtils.waitFor(Trade.DEFER_PUBLISH_MS / 5); HavenoUtils.waitFor(Trade.DEFER_PUBLISH_MS / 5);

View file

@ -65,10 +65,10 @@ public class SellerPreparePaymentReceivedMessage extends TradeTask {
trade.processPayoutTx(trade.getPayoutTxHex(), false, true); trade.processPayoutTx(trade.getPayoutTxHex(), false, true);
} }
} catch (IllegalArgumentException | IllegalStateException e) { } catch (IllegalArgumentException | IllegalStateException e) {
log.warn("Illegal state or argument verifying, signing, and publishing payout tx for {} {}: {}. Creating new unsigned payout tx", trade.getClass().getSimpleName(), trade.getId(), e.getMessage()); log.warn("Illegal state or argument verifying, signing, and publishing payout tx for {} {}: {}. Creating new unsigned payout tx", trade.getClass().getSimpleName(), trade.getId(), e.getMessage(), e);
createUnsignedPayoutTx(); createUnsignedPayoutTx();
} catch (Exception e) { } catch (Exception e) {
log.warn("Error verifying, signing, and publishing payout tx for trade {}: {}", trade.getId(), e.getMessage()); log.warn("Error verifying, signing, and publishing payout tx for trade {}: {}", trade.getId(), e.getMessage(), e);
throw e; throw e;
} }
} }