Set takerFeeTxId and depositTx in trade only once they are published. Before that we keep it temporary in the processModel.

The buyer receives the takerFeeTxId with the frist message, but at the moment it is not published. To reflect that he also keeps it in the process model and
at the next message when the fee tx is published he sets it in the Trade.

Remove
`checkArgument(!walletService.getAddressEntry(id, AddressEntry.Context.MULTI_SIG).isPresent(),
                     "addressEntry must not be set here.");
`
as it causes failure if a taker takes same offer after certain error conditions again.
This commit is contained in:
chimp1984 2020-09-25 00:19:43 -05:00
parent 7167e2a8bd
commit 6f614f4f4c
No known key found for this signature in database
GPG key ID: 9801B4EC591F90E3
13 changed files with 34 additions and 18 deletions

View file

@ -1164,7 +1164,7 @@ public abstract class Trade implements Tradable, Model {
}
public boolean isTxChainInvalid() {
return offer.getOfferFeePaymentTxId() == null ||
return checkNotNull(offer).getOfferFeePaymentTxId() == null ||
getTakerFeeTxId() == null ||
getDepositTxId() == null ||
getDelayedPayoutTxBytes() == null;

View file

@ -169,6 +169,11 @@ public class ProcessModel implements Model, PersistablePayload {
@Setter
private long sellerPayoutAmountFromMediation;
// Added in v 1.4.0
@Setter
@Getter
transient private Transaction depositTx;
// We want to indicate the user the state of the message delivery of the
// CounterCurrencyTransferStartedMessage. As well we do an automatic re-send in case it was not ACKed yet.
// To enable that even after restart we persist the state.

View file

@ -47,6 +47,11 @@ public class BuyerProcessDelayedPayoutTxSignatureRequest extends TradeTask {
Transaction preparedDelayedPayoutTx = processModel.getBtcWalletService().getTxFromSerializedTx(delayedPayoutTxAsBytes);
processModel.setPreparedDelayedPayoutTx(preparedDelayedPayoutTx);
// When we receive that message the taker has published the taker fee, so we apply it to the trade.
// The takerFeeTx was sent in the first message. It should be part of DelayedPayoutTxSignatureRequest
// but that cannot be changed due backward compatibility issues. It is a left over from the old trade protocol.
trade.setTakerFeeTxId(processModel.getTakeOfferFeeTxId());
trade.setTradingPeerNodeAddress(processModel.getTempTradingPeerNodeAddress());
complete();

View file

@ -32,11 +32,8 @@ import bisq.common.crypto.Sig;
import bisq.common.taskrunner.TaskRunner;
import bisq.common.util.Utilities;
import com.google.common.base.Preconditions;
import lombok.extern.slf4j.Slf4j;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
@Slf4j
@ -49,7 +46,7 @@ public class MakerCreateAndSignContract extends TradeTask {
protected void run() {
try {
runInterceptHook();
Preconditions.checkNotNull(trade.getTakerFeeTxId(), "trade.getTakeOfferFeeTxId() must not be null");
String takerFeeTxId = checkNotNull(processModel.getTakeOfferFeeTxId());
TradingPeer taker = processModel.getTradingPeer();
boolean isBuyerMakerAndSellerTaker = trade instanceof BuyerAsMakerTrade;
@ -60,8 +57,6 @@ public class MakerCreateAndSignContract extends TradeTask {
BtcWalletService walletService = processModel.getBtcWalletService();
String id = processModel.getOffer().getId();
checkArgument(!walletService.getAddressEntry(id, AddressEntry.Context.MULTI_SIG).isPresent(),
"addressEntry must not be set here.");
AddressEntry makerAddressEntry = walletService.getOrCreateAddressEntry(id, AddressEntry.Context.MULTI_SIG);
byte[] makerMultiSigPubKey = makerAddressEntry.getPubKey();
@ -70,7 +65,7 @@ public class MakerCreateAndSignContract extends TradeTask {
processModel.getOffer().getOfferPayload(),
checkNotNull(trade.getTradeAmount()).value,
trade.getTradePrice().getValue(),
trade.getTakerFeeTxId(),
takerFeeTxId,
buyerNodeAddress,
sellerNodeAddress,
trade.getMediatorNodeAddress(),

View file

@ -68,7 +68,12 @@ public class MakerProcessesInputsForDepositTxRequest extends TradeTask {
tradingPeer.setPubKeyRing(checkNotNull(request.getTakerPubKeyRing()));
tradingPeer.setAccountId(nonEmptyStringOf(request.getTakerAccountId()));
trade.setTakerFeeTxId(nonEmptyStringOf(request.getTakerFeeTxId()));
// We set the taker fee only in the processModel yet not in the trade as the tx was only created but not
// published yet. Once it was published we move it to trade. The takerFeeTx should be sent in a later
// message bu that cannot be changed due backward compatibility issues. It is a left over from the
// old trade protocol.
processModel.setTakeOfferFeeTxId(nonEmptyStringOf(request.getTakerFeeTxId()));
// Taker has to sign offerId (he cannot manipulate that - so we avoid to have a challenge protocol for
// passing the nonce we want to get signed)

View file

@ -46,7 +46,7 @@ public class SellerCreatesDelayedPayoutTx extends TradeTask {
String donationAddressString = processModel.getDaoFacade().getParamValue(Param.RECIPIENT_BTC_ADDRESS);
Coin minerFee = trade.getTxFee();
TradeWalletService tradeWalletService = processModel.getTradeWalletService();
Transaction depositTx = checkNotNull(trade.getDepositTx());
Transaction depositTx = checkNotNull(processModel.getDepositTx());
long lockTime = trade.getLockTime();
Transaction preparedDelayedPayoutTx = tradeWalletService.createDelayedUnsignedPayoutTx(depositTx,

View file

@ -40,11 +40,15 @@ public class SellerPublishesDepositTx extends TradeTask {
try {
runInterceptHook();
processModel.getTradeWalletService().broadcastTx(trade.getDepositTx(),
final Transaction depositTx = processModel.getDepositTx();
processModel.getTradeWalletService().broadcastTx(depositTx,
new TxBroadcaster.Callback() {
@Override
public void onSuccess(Transaction transaction) {
if (!completed) {
// Now as we have published the deposit tx we set it in trade
trade.applyDepositTx(depositTx);
trade.setState(Trade.State.SELLER_PUBLISHED_DEPOSIT_TX);
processModel.getBtcWalletService().swapTradeEntryToAvailableEntry(processModel.getOffer().getId(),

View file

@ -67,7 +67,7 @@ public class SellerSendsDepositTxAndDelayedPayoutTxMessage extends SendMailboxMe
deterministicId,
processModel.getOfferId(),
processModel.getMyNodeAddress(),
checkNotNull(trade.getDepositTx()).bitcoinSerialize(),
checkNotNull(processModel.getDepositTx()).bitcoinSerialize(),
checkNotNull(trade.getDelayedPayoutTx()).bitcoinSerialize());
}
return message;

View file

@ -80,7 +80,8 @@ public class SellerAsTakerSignsDepositTx extends TradeTask {
tradingPeer.getMultiSigPubKey(),
sellerMultiSigPubKey);
trade.applyDepositTx(depositTx);
// We set the deposit tx to trade once we have it published
processModel.setDepositTx(depositTx);
complete();
} catch (Throwable t) {

View file

@ -95,7 +95,9 @@ public class CreateTakerFeeTx extends TradeTask {
// We did not broadcast and commit the tx yet to avoid issues with lost trade fee in case the
// take offer attempt failed.
trade.setTakerFeeTxId(transaction.getTxId().toString());
// We do not set the takerFeeTxId yet to trade as it is not published.
processModel.setTakeOfferFeeTxId(transaction.getTxId().toString());
processModel.setTakeOfferFeeTx(transaction);
walletService.swapTradeEntryToAvailableEntry(id, AddressEntry.Context.OFFER_FUNDING);
complete();

View file

@ -57,6 +57,7 @@ public class TakerPublishFeeTx extends TradeTask {
new TxBroadcaster.Callback() {
@Override
public void onSuccess(Transaction transaction) {
trade.setTakerFeeTxId(transaction.getTxId().toString());
trade.setState(Trade.State.TAKER_PUBLISHED_TAKER_FEE_TX);
complete();
}
@ -81,9 +82,7 @@ public class TakerPublishFeeTx extends TradeTask {
if (!completed) {
if (transaction != null) {
trade.setTakerFeeTxId(transaction.getTxId().toString());
processModel.setTakeOfferFeeTx(transaction);
trade.setState(Trade.State.TAKER_PUBLISHED_TAKER_FEE_TX);
complete();
}
} else {

View file

@ -58,7 +58,7 @@ public class TakerSendInputsForDepositTxRequest extends TradeTask {
try {
runInterceptHook();
Coin tradeAmount = checkNotNull(trade.getTradeAmount(), "TradeAmount must not be null");
String takerFeeTxId = checkNotNull(trade.getTakerFeeTxId(), "TakeOfferFeeTxId must not be null");
String takerFeeTxId = checkNotNull(processModel.getTakeOfferFeeTxId(), "TakeOfferFeeTxId must not be null");
User user = checkNotNull(processModel.getUser(), "User must not be null");
List<NodeAddress> acceptedArbitratorAddresses = user.getAcceptedArbitratorAddresses() == null ?
new ArrayList<>() :

View file

@ -53,7 +53,7 @@ public class TakerVerifyAndSignContract extends TradeTask {
try {
runInterceptHook();
String takerFeeTxId = checkNotNull(trade.getTakerFeeTxId());
String takerFeeTxId = checkNotNull(processModel.getTakeOfferFeeTxId());
TradingPeer maker = processModel.getTradingPeer();
PaymentAccountPayload makerPaymentAccountPayload = checkNotNull(maker.getPaymentAccountPayload());
PaymentAccountPayload takerPaymentAccountPayload = checkNotNull(processModel.getPaymentAccountPayload(trade));