mirror of
https://github.com/haveno-dex/haveno.git
synced 2024-10-01 01:35:48 -04:00
synchronize reserving funds for open offer to fix race condition
This commit is contained in:
parent
9d9635ff50
commit
f0862b7aeb
@ -20,18 +20,11 @@ package haveno.core.offer.placeoffer.tasks;
|
||||
import haveno.common.taskrunner.Task;
|
||||
import haveno.common.taskrunner.TaskRunner;
|
||||
import haveno.core.offer.Offer;
|
||||
import haveno.core.offer.OfferDirection;
|
||||
import haveno.core.offer.placeoffer.PlaceOfferModel;
|
||||
import haveno.core.trade.HavenoUtils;
|
||||
import haveno.core.xmr.model.XmrAddressEntry;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import monero.daemon.model.MoneroOutput;
|
||||
import monero.wallet.model.MoneroTxWallet;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Slf4j
|
||||
public class MakerReserveOfferFunds extends Task<PlaceOfferModel> {
|
||||
|
||||
@ -51,14 +44,8 @@ public class MakerReserveOfferFunds extends Task<PlaceOfferModel> {
|
||||
model.getXmrWalletService().getConnectionService().verifyConnection();
|
||||
|
||||
// create reserve tx
|
||||
BigInteger penaltyFee = HavenoUtils.multiply(offer.getAmount(), offer.getPenaltyFeePct());
|
||||
BigInteger makerFee = offer.getMaxMakerFee();
|
||||
BigInteger sendAmount = offer.getDirection() == OfferDirection.BUY ? BigInteger.ZERO : offer.getAmount();
|
||||
BigInteger securityDeposit = offer.getDirection() == OfferDirection.BUY ? offer.getMaxBuyerSecurityDeposit() : offer.getMaxSellerSecurityDeposit();
|
||||
String returnAddress = model.getXmrWalletService().getOrCreateAddressEntry(offer.getId(), XmrAddressEntry.Context.TRADE_PAYOUT).getAddressString();
|
||||
XmrAddressEntry fundingEntry = model.getXmrWalletService().getAddressEntry(offer.getId(), XmrAddressEntry.Context.OFFER_FUNDING).orElse(null);
|
||||
Integer preferredSubaddressIndex = fundingEntry == null ? null : fundingEntry.getSubaddressIndex();
|
||||
MoneroTxWallet reserveTx = model.getXmrWalletService().createReserveTx(penaltyFee, makerFee, sendAmount, securityDeposit, returnAddress, model.getOpenOffer().isReserveExactAmount(), preferredSubaddressIndex);
|
||||
MoneroTxWallet reserveTx = model.getXmrWalletService().createReserveTx(model.getOpenOffer());
|
||||
model.setReserveTx(reserveTx);
|
||||
|
||||
// check for error in case creating reserve tx exceeded timeout // TODO: better way?
|
||||
if (!model.getXmrWalletService().getAddressEntry(offer.getId(), XmrAddressEntry.Context.TRADE_PAYOUT).isPresent()) {
|
||||
@ -67,17 +54,6 @@ public class MakerReserveOfferFunds extends Task<PlaceOfferModel> {
|
||||
|
||||
// reset protocol timeout
|
||||
model.getProtocol().startTimeoutTimer();
|
||||
|
||||
// collect reserved key images
|
||||
List<String> reservedKeyImages = new ArrayList<String>();
|
||||
for (MoneroOutput input : reserveTx.getInputs()) reservedKeyImages.add(input.getKeyImage().getHex());
|
||||
|
||||
// save offer state
|
||||
model.setReserveTx(reserveTx);
|
||||
model.getOpenOffer().setReserveTxHash(reserveTx.getHash());
|
||||
model.getOpenOffer().setReserveTxHex(reserveTx.getFullHex());
|
||||
model.getOpenOffer().setReserveTxKey(reserveTx.getKey());
|
||||
offer.getOfferPayload().setReserveTxKeyImages(reservedKeyImages);
|
||||
complete();
|
||||
} catch (Throwable t) {
|
||||
offer.setErrorMessage("An error occurred.\n" +
|
||||
|
@ -33,6 +33,8 @@ import haveno.common.util.Utilities;
|
||||
import haveno.core.api.AccountServiceListener;
|
||||
import haveno.core.api.CoreAccountService;
|
||||
import haveno.core.api.XmrConnectionService;
|
||||
import haveno.core.offer.Offer;
|
||||
import haveno.core.offer.OfferDirection;
|
||||
import haveno.core.offer.OpenOffer;
|
||||
import haveno.core.trade.BuyerTrade;
|
||||
import haveno.core.trade.HavenoUtils;
|
||||
@ -546,6 +548,40 @@ public class XmrWalletService {
|
||||
return new ArrayList<Integer>(subaddressIndices);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a reserve tx for an open offer and freeze its inputs.
|
||||
*
|
||||
* @param openOffer is the open offer to create a reserve tx for
|
||||
*/
|
||||
public MoneroTxWallet createReserveTx(OpenOffer openOffer) {
|
||||
synchronized (walletLock) {
|
||||
|
||||
// collect offer data
|
||||
Offer offer = openOffer.getOffer();
|
||||
BigInteger penaltyFee = HavenoUtils.multiply(offer.getAmount(), offer.getPenaltyFeePct());
|
||||
BigInteger makerFee = offer.getMaxMakerFee();
|
||||
BigInteger sendAmount = offer.getDirection() == OfferDirection.BUY ? BigInteger.ZERO : offer.getAmount();
|
||||
BigInteger securityDeposit = offer.getDirection() == OfferDirection.BUY ? offer.getMaxBuyerSecurityDeposit() : offer.getMaxSellerSecurityDeposit();
|
||||
String returnAddress = getOrCreateAddressEntry(offer.getId(), XmrAddressEntry.Context.TRADE_PAYOUT).getAddressString();
|
||||
XmrAddressEntry fundingEntry = getAddressEntry(offer.getId(), XmrAddressEntry.Context.OFFER_FUNDING).orElse(null);
|
||||
Integer preferredSubaddressIndex = fundingEntry == null ? null : fundingEntry.getSubaddressIndex();
|
||||
|
||||
// create reserve tx
|
||||
MoneroTxWallet reserveTx = createReserveTx(penaltyFee, makerFee, sendAmount, securityDeposit, returnAddress, openOffer.isReserveExactAmount(), preferredSubaddressIndex);
|
||||
|
||||
// collect reserved key images
|
||||
List<String> reservedKeyImages = new ArrayList<String>();
|
||||
for (MoneroOutput input : reserveTx.getInputs()) reservedKeyImages.add(input.getKeyImage().getHex());
|
||||
|
||||
// save offer state
|
||||
openOffer.setReserveTxHash(reserveTx.getHash());
|
||||
openOffer.setReserveTxHex(reserveTx.getFullHex());
|
||||
openOffer.setReserveTxKey(reserveTx.getKey());
|
||||
offer.getOfferPayload().setReserveTxKeyImages(reservedKeyImages);
|
||||
return reserveTx;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the reserve tx and freeze its inputs. The full amount is returned
|
||||
* to the sender's payout address less the penalty and mining fees.
|
||||
|
Loading…
Reference in New Issue
Block a user