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) {
try {
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 + ".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);
deleteBackupWallets(walletName); // TODO: retain backup for some time?
}
private void closeAllWallets() {
@ -761,7 +769,7 @@ public class XmrWalletService {
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 + ".keys");
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),
SEND_FAILED_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
ARBITRATOR_PUBLISHED_DEPOSIT_TXS(Phase.DEPOSITS_PUBLISHED),
@ -935,8 +936,24 @@ public abstract class Trade implements Tradable, Model {
}
public void deleteWallet() {
if (xmrWalletService.multisigWalletExists(getId())) xmrWalletService.deleteMultisigWallet(getId());
else log.warn("Multisig wallet to delete for trade {} does not exist", getId());
if (xmrWalletService.multisigWalletExists(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() {
@ -1266,6 +1283,10 @@ public abstract class Trade implements Tradable, Model {
return getState().getPhase().ordinal() >= Phase.DEPOSIT_REQUESTED.ordinal();
}
public boolean isDepositFailed() {
return getState() == Trade.State.PUBLISH_DEPOSIT_TX_REQUEST_FAILED;
}
public boolean isDepositPublished() {
return getState().getPhase().ordinal() >= Phase.DEPOSITS_PUBLISHED.ordinal();
}

View file

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

View file

@ -27,6 +27,7 @@ import bisq.core.trade.HavenoUtils;
import bisq.core.trade.SellerTrade;
import bisq.core.trade.handlers.TradeResultHandler;
import bisq.core.trade.messages.PaymentSentMessage;
import bisq.core.trade.messages.DepositRequest;
import bisq.core.trade.messages.DepositResponse;
import bisq.core.trade.messages.DepositsConfirmedMessage;
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() +
" from "+ peer + " with tradeId " + trade.getId() + " and errorMessage=" + ackMessage.getErrorMessage();
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);
}
}

View file

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

View file

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