don't delete wallet backup if possibly funded

support new trade state: PUBLISH_DEPOSIT_TX_REQUEST_FAILED
This commit is contained in:
woodser 2023-01-13 10:50:47 -05:00
parent a8114e147d
commit 266d129462
6 changed files with 64 additions and 26 deletions

View file

@ -278,6 +278,15 @@ public class XmrWalletService {
} }
} }
public void deleteMultisigWalletBackups(String tradeId) {
log.info("{}.deleteMultisigWalletBackups({})", getClass().getSimpleName(), tradeId);
initWalletLock(tradeId);
synchronized (walletLocks.get(tradeId)) {
String walletName = MONERO_MULTISIG_WALLET_PREFIX + tradeId;
deleteWalletBackups(walletName);
}
}
public MoneroTxWallet createTx(List<MoneroDestination> destinations) { public MoneroTxWallet createTx(List<MoneroDestination> destinations) {
try { try {
synchronized (wallet) { synchronized (wallet) {
@ -726,7 +735,6 @@ public class XmrWalletService {
if (!new File(path).delete()) throw new RuntimeException("Failed to delete wallet file: " + path); if (!new File(path).delete()) throw new RuntimeException("Failed to delete wallet file: " + path);
if (!new File(path + ".keys").delete()) throw new RuntimeException("Failed to delete wallet file: " + path); if (!new File(path + ".keys").delete()) throw new RuntimeException("Failed to delete wallet file: " + path);
if (!new File(path + ".address.txt").delete()) throw new RuntimeException("Failed to delete wallet file: " + path); if (!new File(path + ".address.txt").delete()) throw new RuntimeException("Failed to delete wallet file: " + path);
deleteBackupWallets(walletName); // TODO: retain backup for some time?
} }
private void closeAllWallets() { private void closeAllWallets() {
@ -761,7 +769,7 @@ public class XmrWalletService {
FileUtil.rollingBackup(walletDir, walletName + ".address.txt", NUM_MAX_BACKUP_WALLETS); FileUtil.rollingBackup(walletDir, walletName + ".address.txt", NUM_MAX_BACKUP_WALLETS);
} }
private void deleteBackupWallets(String walletName) { private void deleteWalletBackups(String walletName) {
FileUtil.deleteRollingBackup(walletDir, walletName); FileUtil.deleteRollingBackup(walletDir, walletName);
FileUtil.deleteRollingBackup(walletDir, walletName + ".keys"); FileUtil.deleteRollingBackup(walletDir, walletName + ".keys");
FileUtil.deleteRollingBackup(walletDir, walletName + ".address.txt"); FileUtil.deleteRollingBackup(walletDir, walletName + ".address.txt");

View file

@ -133,6 +133,7 @@ public abstract class Trade implements Tradable, Model {
SENT_PUBLISH_DEPOSIT_TX_REQUEST(Phase.DEPOSIT_REQUESTED), SENT_PUBLISH_DEPOSIT_TX_REQUEST(Phase.DEPOSIT_REQUESTED),
SEND_FAILED_PUBLISH_DEPOSIT_TX_REQUEST(Phase.DEPOSIT_REQUESTED), SEND_FAILED_PUBLISH_DEPOSIT_TX_REQUEST(Phase.DEPOSIT_REQUESTED),
SAW_ARRIVED_PUBLISH_DEPOSIT_TX_REQUEST(Phase.DEPOSIT_REQUESTED), SAW_ARRIVED_PUBLISH_DEPOSIT_TX_REQUEST(Phase.DEPOSIT_REQUESTED),
PUBLISH_DEPOSIT_TX_REQUEST_FAILED(Phase.DEPOSIT_REQUESTED),
// deposit published // deposit published
ARBITRATOR_PUBLISHED_DEPOSIT_TXS(Phase.DEPOSITS_PUBLISHED), ARBITRATOR_PUBLISHED_DEPOSIT_TXS(Phase.DEPOSITS_PUBLISHED),
@ -935,8 +936,24 @@ public abstract class Trade implements Tradable, Model {
} }
public void deleteWallet() { public void deleteWallet() {
if (xmrWalletService.multisigWalletExists(getId())) xmrWalletService.deleteMultisigWallet(getId()); if (xmrWalletService.multisigWalletExists(getId())) {
else log.warn("Multisig wallet to delete for trade {} does not exist", getId());
// delete trade wallet unless funded
if (isDepositPublished() && !isPayoutUnlocked()) {
log.warn("Refusing to delete wallet for {} {} because it could be funded", getClass().getSimpleName(), getId());
return;
}
xmrWalletService.deleteMultisigWallet(getId());
// delete trade wallet backups unless possibly funded
boolean possiblyFunded = isDepositRequested() && !isPayoutUnlocked();
if (possiblyFunded) {
log.warn("Refusing to delete backup wallet for {} {} in the small chance it becomes funded", getClass().getSimpleName(), getId());
return;
}
} else {
log.warn("Multisig wallet to delete for trade {} does not exist", getId());
}
} }
public void shutDown() { public void shutDown() {
@ -1266,6 +1283,10 @@ public abstract class Trade implements Tradable, Model {
return getState().getPhase().ordinal() >= Phase.DEPOSIT_REQUESTED.ordinal(); return getState().getPhase().ordinal() >= Phase.DEPOSIT_REQUESTED.ordinal();
} }
public boolean isDepositFailed() {
return getState() == Trade.State.PUBLISH_DEPOSIT_TX_REQUEST_FAILED;
}
public boolean isDepositPublished() { public boolean isDepositPublished() {
return getState().getPhase().ordinal() >= Phase.DEPOSITS_PUBLISHED.ordinal(); return getState().getPhase().ordinal() >= Phase.DEPOSITS_PUBLISHED.ordinal();
} }

View file

@ -1078,9 +1078,8 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi
return; return;
} }
// remove trade and wallet unless timeout after deposit requested // remove trade and wallet unless deposit requested without nack
boolean isTimeoutError = TradeProtocol.isTimeoutError(trade.getErrorMessage()); if (!trade.isDepositRequested() || trade.isDepositFailed()) {
if (!trade.isDepositRequested() || !isTimeoutError) {
removeTrade(trade); removeTrade(trade);
if (xmrWalletService.multisigWalletExists(trade.getId())) trade.deleteWallet(); if (xmrWalletService.multisigWalletExists(trade.getId())) trade.deleteWallet();
} else { } else {
@ -1100,13 +1099,13 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi
MoneroTx takerDepositTx = xmrWalletService.getDaemon().getTx(trade.getTaker().getDepositTxHash()); MoneroTx takerDepositTx = xmrWalletService.getDaemon().getTx(trade.getTaker().getDepositTxHash());
// delete multisig trade wallet if neither deposit tx published // delete multisig trade wallet if neither deposit tx published
if ((makerDepositTx != null && makerDepositTx.isRelayed()) || (takerDepositTx != null && takerDepositTx.isRelayed())) { if (makerDepositTx == null && takerDepositTx == null) {
log.warn("Refusing to delete {} {} after protocol timeout because its wallet might be funded", trade.getClass().getSimpleName(), trade.getId());
} else {
log.warn("Deleting {} {} after protocol timeout", trade.getClass().getSimpleName(), trade.getId()); log.warn("Deleting {} {} after protocol timeout", trade.getClass().getSimpleName(), trade.getId());
removeTrade(trade); removeTrade(trade);
failedTradesManager.removeTrade(trade); failedTradesManager.removeTrade(trade);
if (xmrWalletService.multisigWalletExists(trade.getId())) trade.deleteWallet(); if (xmrWalletService.multisigWalletExists(trade.getId())) trade.deleteWallet();
} else {
log.warn("Refusing to delete {} {} after protocol timeout because its wallet might be funded", trade.getClass().getSimpleName(), trade.getId());
} }
}, 60); }, 60);
} }

View file

@ -27,6 +27,7 @@ import bisq.core.trade.HavenoUtils;
import bisq.core.trade.SellerTrade; import bisq.core.trade.SellerTrade;
import bisq.core.trade.handlers.TradeResultHandler; import bisq.core.trade.handlers.TradeResultHandler;
import bisq.core.trade.messages.PaymentSentMessage; import bisq.core.trade.messages.PaymentSentMessage;
import bisq.core.trade.messages.DepositRequest;
import bisq.core.trade.messages.DepositResponse; import bisq.core.trade.messages.DepositResponse;
import bisq.core.trade.messages.DepositsConfirmedMessage; import bisq.core.trade.messages.DepositsConfirmedMessage;
import bisq.core.trade.messages.InitMultisigRequest; import bisq.core.trade.messages.InitMultisigRequest;
@ -549,6 +550,13 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D
String err = "Received AckMessage with error state for " + ackMessage.getSourceMsgClassName() + String err = "Received AckMessage with error state for " + ackMessage.getSourceMsgClassName() +
" from "+ peer + " with tradeId " + trade.getId() + " and errorMessage=" + ackMessage.getErrorMessage(); " from "+ peer + " with tradeId " + trade.getId() + " and errorMessage=" + ackMessage.getErrorMessage();
log.warn(err); log.warn(err);
// set trade state on deposit request nack
if (ackMessage.getSourceMsgClassName().equals(DepositRequest.class.getSimpleName())) {
trade.setStateIfValidTransitionTo(Trade.State.PUBLISH_DEPOSIT_TX_REQUEST_FAILED);
processModel.getTradeManager().requestPersistence();
}
handleError(err); handleError(err);
} }
} }

View file

@ -47,6 +47,7 @@ public class ProcessDepositResponse extends TradeTask {
processModel.getTradeManager().requestPersistence(); processModel.getTradeManager().requestPersistence();
complete(); complete();
} catch (Throwable t) { } catch (Throwable t) {
trade.setStateIfValidTransitionTo(Trade.State.PUBLISH_DEPOSIT_TX_REQUEST_FAILED);
failed(t); failed(t);
} }
} }

View file

@ -1573,22 +1573,23 @@ message Trade {
SENT_PUBLISH_DEPOSIT_TX_REQUEST = 8; SENT_PUBLISH_DEPOSIT_TX_REQUEST = 8;
SEND_FAILED_PUBLISH_DEPOSIT_TX_REQUEST = 9; SEND_FAILED_PUBLISH_DEPOSIT_TX_REQUEST = 9;
SAW_ARRIVED_PUBLISH_DEPOSIT_TX_REQUEST = 10; SAW_ARRIVED_PUBLISH_DEPOSIT_TX_REQUEST = 10;
ARBITRATOR_PUBLISHED_DEPOSIT_TXS = 11; PUBLISH_DEPOSIT_TX_REQUEST_FAILED = 11;
DEPOSIT_TXS_SEEN_IN_NETWORK = 12; ARBITRATOR_PUBLISHED_DEPOSIT_TXS = 12;
DEPOSIT_TXS_CONFIRMED_IN_BLOCKCHAIN = 13; DEPOSIT_TXS_SEEN_IN_NETWORK = 13;
DEPOSIT_TXS_UNLOCKED_IN_BLOCKCHAIN = 14; DEPOSIT_TXS_CONFIRMED_IN_BLOCKCHAIN = 14;
BUYER_CONFIRMED_IN_UI_PAYMENT_SENT = 15; DEPOSIT_TXS_UNLOCKED_IN_BLOCKCHAIN = 15;
BUYER_SENT_PAYMENT_SENT_MSG = 16; BUYER_CONFIRMED_IN_UI_PAYMENT_SENT = 16;
BUYER_SEND_FAILED_PAYMENT_SENT_MSG = 17; BUYER_SENT_PAYMENT_SENT_MSG = 17;
BUYER_STORED_IN_MAILBOX_PAYMENT_SENT_MSG = 18; BUYER_SEND_FAILED_PAYMENT_SENT_MSG = 18;
BUYER_SAW_ARRIVED_PAYMENT_SENT_MSG = 19; BUYER_STORED_IN_MAILBOX_PAYMENT_SENT_MSG = 19;
SELLER_RECEIVED_PAYMENT_SENT_MSG = 20; BUYER_SAW_ARRIVED_PAYMENT_SENT_MSG = 20;
SELLER_CONFIRMED_IN_UI_PAYMENT_RECEIPT = 21; SELLER_RECEIVED_PAYMENT_SENT_MSG = 21;
SELLER_SENT_PAYMENT_RECEIVED_MSG = 22; SELLER_CONFIRMED_IN_UI_PAYMENT_RECEIPT = 22;
SELLER_SEND_FAILED_PAYMENT_RECEIVED_MSG = 23; SELLER_SENT_PAYMENT_RECEIVED_MSG = 23;
SELLER_STORED_IN_MAILBOX_PAYMENT_RECEIVED_MSG = 24; SELLER_SEND_FAILED_PAYMENT_RECEIVED_MSG = 24;
SELLER_SAW_ARRIVED_PAYMENT_RECEIVED_MSG = 25; SELLER_STORED_IN_MAILBOX_PAYMENT_RECEIVED_MSG = 25;
TRADE_COMPLETED = 26; SELLER_SAW_ARRIVED_PAYMENT_RECEIVED_MSG = 26;
TRADE_COMPLETED = 27;
} }
enum Phase { enum Phase {