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();
trade.advanceDisputeState(Trade.DisputeState.DISPUTE_OPENED);
} 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
disputeResult.getChatMessage().setArrived(true);
trade.advanceDisputeState(Trade.DisputeState.ARBITRATOR_SAW_ARRIVED_DISPUTE_CLOSED_MSG);
trade.pollWalletNormallyForMs(30000);
trade.pollWalletNormallyForMs(60000);
requestPersistence(trade);
resultHandler.handleResult();
}

View file

@ -361,7 +361,7 @@ public final class ArbitrationManager extends DisputeManager<ArbitrationDisputeL
requestPersistence(trade);
// 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.setDisputeState(Trade.DisputeState.DISPUTE_CLOSED);
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);
}
public static boolean isConnectionRefused(Exception e) {
public static boolean isConnectionRefused(Throwable e) {
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");
}
public static boolean isUnresponsive(Exception e) {
public static boolean isUnresponsive(Throwable 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");
}
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) {
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
}
@ -1278,7 +1278,7 @@ public abstract class Trade extends XmrWalletBase implements Tradable, Model {
} catch (IllegalArgumentException | IllegalStateException e) {
throw 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);
if (i == TradeProtocol.MAX_ATTEMPTS - 1) throw e;
HavenoUtils.waitFor(TradeProtocol.REPROCESS_DELAY_MS); // wait before retrying
@ -1350,14 +1350,13 @@ public abstract class Trade extends XmrWalletBase implements Tradable, Model {
try {
MoneroMultisigSignResult result = wallet.signMultisigTxHex(payoutTxHex);
if (result.getSignedMultisigTxHex() == null) throw new IllegalArgumentException("Error signing payout tx, signed multisig hex is null");
payoutTxHex = result.getSignedMultisigTxHex();
setPayoutTxHex(payoutTxHex);
setPayoutTxHex(result.getSignedMultisigTxHex());
} catch (Exception e) {
throw new IllegalStateException(e);
}
// describe result
describedTxSet = wallet.describeMultisigTxSet(payoutTxHex);
describedTxSet = wallet.describeMultisigTxSet(getPayoutTxHex());
payoutTx = describedTxSet.getTxs().get(0);
updatePayout(payoutTx);
@ -1377,14 +1376,16 @@ public abstract class Trade extends XmrWalletBase implements Tradable, Model {
requestPersistence();
// submit payout tx
if (publish) {
boolean doPublish = publish && !isPayoutPublished();
if (doPublish) {
try {
wallet.submitMultisigTxHex(payoutTxHex);
wallet.submitMultisigTxHex(getPayoutTxHex());
setPayoutStatePublished();
} catch (Exception e) {
if (isPayoutPublished()) throw new IllegalStateException("Payout tx already published for " + getClass().getSimpleName() + " " + getShortId());
if (HavenoUtils.isNotEnoughSigners(e)) throw new IllegalArgumentException(e);
throw new RuntimeException("Failed to submit payout tx for " + getClass().getSimpleName() + " " + getId(), e);
if (!isPayoutPublished()) {
if (HavenoUtils.isTransactionRejected(e) || HavenoUtils.isNotEnoughSigners(e)) throw new IllegalArgumentException(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) {
// do not reprocess illegal argument
if (t instanceof IllegalArgumentException) {
if (HavenoUtils.isIllegal(t)) {
trade.getSeller().setPaymentReceivedMessage(null); // do not reprocess
trade.requestPersistence();
}
@ -151,6 +151,7 @@ public class ProcessPaymentReceivedMessage extends TradeTask {
boolean deferSignAndPublish = trade instanceof ArbitratorTrade && !isSigned && message.isDeferPublishPayout();
if (deferSignAndPublish) {
log.info("Deferring signing and publishing payout tx for {} {}", trade.getClass().getSimpleName(), trade.getId());
trade.pollWalletNormallyForMs(60000);
for (int i = 0; i < 5; i++) {
if (trade.isPayoutPublished()) break;
HavenoUtils.waitFor(Trade.DEFER_PUBLISH_MS / 5);

View file

@ -65,10 +65,10 @@ public class SellerPreparePaymentReceivedMessage extends TradeTask {
trade.processPayoutTx(trade.getPayoutTxHex(), false, true);
}
} 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();
} 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;
}
}