Search in sources :

Example 1 with TxBroadcastException

use of bisq.core.btc.wallet.TxBroadcastException in project bisq-core by bisq-network.

the class DisputeManager method onDisputeResultMessage.

// We get that message at both peers. The dispute object is in context of the trader
private void onDisputeResultMessage(DisputeResultMessage disputeResultMessage) {
    String errorMessage = null;
    boolean success = false;
    PubKeyRing arbitratorsPubKeyRing = null;
    DisputeResult disputeResult = disputeResultMessage.getDisputeResult();
    if (isArbitrator(disputeResult)) {
        log.error("Arbitrator received disputeResultMessage. That must never happen.");
        return;
    }
    final String tradeId = disputeResult.getTradeId();
    Optional<Dispute> disputeOptional = findDispute(tradeId, disputeResult.getTraderId());
    final String uid = disputeResultMessage.getUid();
    if (!disputeOptional.isPresent()) {
        log.debug("We got a dispute result msg but we don't have a matching dispute. " + "That might happen when we get the disputeResultMessage before the dispute was created. " + "We try again after 2 sec. to apply the disputeResultMessage. TradeId = " + tradeId);
        if (!delayMsgMap.containsKey(uid)) {
            // We delay2 sec. to be sure the comm. msg gets added first
            Timer timer = UserThread.runAfter(() -> onDisputeResultMessage(disputeResultMessage), 2);
            delayMsgMap.put(uid, timer);
        } else {
            log.warn("We got a dispute result msg after we already repeated to apply the message after a delay. " + "That should never happen. TradeId = " + tradeId);
        }
        return;
    }
    try {
        cleanupRetryMap(uid);
        Dispute dispute = disputeOptional.get();
        arbitratorsPubKeyRing = dispute.getArbitratorPubKeyRing();
        DisputeCommunicationMessage disputeCommunicationMessage = disputeResult.getDisputeCommunicationMessage();
        if (!dispute.getDisputeCommunicationMessages().contains(disputeCommunicationMessage))
            dispute.addDisputeCommunicationMessage(disputeCommunicationMessage);
        else if (disputeCommunicationMessage != null)
            log.warn("We got a dispute mail msg what we have already stored. TradeId = " + disputeCommunicationMessage.getTradeId());
        dispute.setIsClosed(true);
        if (dispute.disputeResultProperty().get() != null)
            log.warn("We got already a dispute result. That should only happen if a dispute needs to be closed " + "again because the first close did not succeed. TradeId = " + tradeId);
        dispute.setDisputeResult(disputeResult);
        // We need to avoid publishing the tx from both traders as it would create problems with zero confirmation withdrawals
        // There would be different transactions if both sign and publish (signers: once buyer+arb, once seller+arb)
        // The tx publisher is the winner or in case both get 50% the buyer, as the buyer has more inventive to publish the tx as he receives
        // more BTC as he has deposited
        final Contract contract = dispute.getContract();
        boolean isBuyer = keyRing.getPubKeyRing().equals(contract.getBuyerPubKeyRing());
        DisputeResult.Winner publisher = disputeResult.getWinner();
        // Default isLoserPublisher is set to false
        if (disputeResult.isLoserPublisher()) {
            // we invert the logic
            if (publisher == DisputeResult.Winner.BUYER)
                publisher = DisputeResult.Winner.SELLER;
            else if (publisher == DisputeResult.Winner.SELLER)
                publisher = DisputeResult.Winner.BUYER;
        }
        if ((isBuyer && publisher == DisputeResult.Winner.BUYER) || (!isBuyer && publisher == DisputeResult.Winner.SELLER)) {
            final Optional<Trade> tradeOptional = tradeManager.getTradeById(tradeId);
            Transaction payoutTx = null;
            if (tradeOptional.isPresent()) {
                payoutTx = tradeOptional.get().getPayoutTx();
            } else {
                final Optional<Tradable> tradableOptional = closedTradableManager.getTradableById(tradeId);
                if (tradableOptional.isPresent() && tradableOptional.get() instanceof Trade) {
                    payoutTx = ((Trade) tradableOptional.get()).getPayoutTx();
                }
            }
            if (payoutTx == null) {
                if (dispute.getDepositTxSerialized() != null) {
                    byte[] multiSigPubKey = isBuyer ? contract.getBuyerMultiSigPubKey() : contract.getSellerMultiSigPubKey();
                    DeterministicKey multiSigKeyPair = walletService.getMultiSigKeyPair(dispute.getTradeId(), multiSigPubKey);
                    Transaction signedDisputedPayoutTx = tradeWalletService.traderSignAndFinalizeDisputedPayoutTx(dispute.getDepositTxSerialized(), disputeResult.getArbitratorSignature(), disputeResult.getBuyerPayoutAmount(), disputeResult.getSellerPayoutAmount(), contract.getBuyerPayoutAddressString(), contract.getSellerPayoutAddressString(), multiSigKeyPair, contract.getBuyerMultiSigPubKey(), contract.getSellerMultiSigPubKey(), disputeResult.getArbitratorPubKey());
                    Transaction committedDisputedPayoutTx = tradeWalletService.addTxToWallet(signedDisputedPayoutTx);
                    tradeWalletService.broadcastTx(committedDisputedPayoutTx, new TxBroadcaster.Callback() {

                        @Override
                        public void onSuccess(Transaction transaction) {
                            // after successful publish we send peer the tx
                            dispute.setDisputePayoutTxId(transaction.getHashAsString());
                            sendPeerPublishedPayoutTxMessage(transaction, dispute, contract);
                            // set state after payout as we call swapTradeEntryToAvailableEntry
                            if (tradeManager.getTradeById(dispute.getTradeId()).isPresent())
                                tradeManager.closeDisputedTrade(dispute.getTradeId());
                            else {
                                Optional<OpenOffer> openOfferOptional = openOfferManager.getOpenOfferById(dispute.getTradeId());
                                openOfferOptional.ifPresent(openOffer -> openOfferManager.closeOpenOffer(openOffer.getOffer()));
                            }
                        }

                        @Override
                        public void onFailure(TxBroadcastException exception) {
                            log.error(exception.getMessage());
                        }
                    }, 15);
                    success = true;
                } else {
                    errorMessage = "DepositTx is null. TradeId = " + tradeId;
                    log.warn(errorMessage);
                    success = false;
                }
            } else {
                log.warn("We got already a payout tx. That might be the case if the other peer did not get the " + "payout tx and opened a dispute. TradeId = " + tradeId);
                dispute.setDisputePayoutTxId(payoutTx.getHashAsString());
                sendPeerPublishedPayoutTxMessage(payoutTx, dispute, contract);
                success = true;
            }
        } else {
            log.trace("We don't publish the tx as we are not the winning party.");
            // Clean up tangling trades
            if (dispute.disputeResultProperty().get() != null && dispute.isClosed() && tradeManager.getTradeById(dispute.getTradeId()).isPresent()) {
                tradeManager.closeDisputedTrade(dispute.getTradeId());
            }
            success = true;
        }
    } catch (AddressFormatException | WalletException | TransactionVerificationException e) {
        e.printStackTrace();
        errorMessage = "Error at traderSignAndFinalizeDisputedPayoutTx " + e.toString();
        log.error(errorMessage);
        success = false;
        throw new RuntimeException(errorMessage);
    } finally {
        if (arbitratorsPubKeyRing != null) {
            // We use the disputeCommunicationMessage as we only persist those not the disputeResultMessage.
            // If we would use the disputeResultMessage we could not lookup for the msg when we receive the AckMessage.
            DisputeCommunicationMessage disputeCommunicationMessage = disputeResultMessage.getDisputeResult().getDisputeCommunicationMessage();
            sendAckMessage(disputeCommunicationMessage, arbitratorsPubKeyRing, success, errorMessage);
        }
    }
}
Also used : DisputeMessage(bisq.core.arbitration.messages.DisputeMessage) PubKeyRing(bisq.common.crypto.PubKeyRing) Arrays(java.util.Arrays) Transaction(org.bitcoinj.core.Transaction) OpenOffer(bisq.core.offer.OpenOffer) AckMessageSourceType(bisq.network.p2p.AckMessageSourceType) Inject(com.google.inject.Inject) LoggerFactory(org.slf4j.LoggerFactory) Contract(bisq.core.trade.Contract) ListChangeListener(javafx.collections.ListChangeListener) Res(bisq.core.locale.Res) BootstrapListener(bisq.network.p2p.BootstrapListener) SimpleIntegerProperty(javafx.beans.property.SimpleIntegerProperty) Map(java.util.Map) DeterministicKey(org.bitcoinj.crypto.DeterministicKey) AddressFormatException(org.bitcoinj.core.AddressFormatException) WalletException(bisq.core.btc.exceptions.WalletException) TxBroadcastException(bisq.core.btc.wallet.TxBroadcastException) ClosedTradableManager(bisq.core.trade.closed.ClosedTradableManager) NetworkEnvelope(bisq.common.proto.network.NetworkEnvelope) P2PService(bisq.network.p2p.P2PService) PersistedDataHost(bisq.common.proto.persistable.PersistedDataHost) Subscription(org.fxmisc.easybind.Subscription) UUID(java.util.UUID) CopyOnWriteArraySet(java.util.concurrent.CopyOnWriteArraySet) Collectors(java.util.stream.Collectors) AckMessage(bisq.network.p2p.AckMessage) OpenNewDisputeMessage(bisq.core.arbitration.messages.OpenNewDisputeMessage) List(java.util.List) DisputeResultMessage(bisq.core.arbitration.messages.DisputeResultMessage) Stream(java.util.stream.Stream) TradeWalletService(bisq.core.btc.wallet.TradeWalletService) WalletsSetup(bisq.core.btc.wallet.WalletsSetup) TradeManager(bisq.core.trade.TradeManager) NodeAddress(bisq.network.p2p.NodeAddress) UserThread(bisq.common.UserThread) Optional(java.util.Optional) ObservableList(javafx.collections.ObservableList) BtcWalletService(bisq.core.btc.wallet.BtcWalletService) Getter(lombok.Getter) Timer(bisq.common.Timer) HashMap(java.util.HashMap) Tradable(bisq.core.trade.Tradable) TxBroadcaster(bisq.core.btc.wallet.TxBroadcaster) IntegerProperty(javafx.beans.property.IntegerProperty) PersistenceProtoResolver(bisq.common.proto.persistable.PersistenceProtoResolver) ArrayList(java.util.ArrayList) Tuple2(bisq.common.util.Tuple2) TransactionVerificationException(bisq.core.btc.exceptions.TransactionVerificationException) Named(javax.inject.Named) Nullable(javax.annotation.Nullable) PeerOpenedDisputeMessage(bisq.core.arbitration.messages.PeerOpenedDisputeMessage) PeerPublishedDisputePayoutTxMessage(bisq.core.arbitration.messages.PeerPublishedDisputePayoutTxMessage) Logger(org.slf4j.Logger) Trade(bisq.core.trade.Trade) FaultHandler(bisq.common.handlers.FaultHandler) ResultHandler(bisq.common.handlers.ResultHandler) OpenOfferManager(bisq.core.offer.OpenOfferManager) SendMailboxMessageListener(bisq.network.p2p.SendMailboxMessageListener) File(java.io.File) DisputeCommunicationMessage(bisq.core.arbitration.messages.DisputeCommunicationMessage) EasyBind(org.fxmisc.easybind.EasyBind) Storage(bisq.common.storage.Storage) KeyRing(bisq.common.crypto.KeyRing) DecryptedMessageWithPubKey(bisq.network.p2p.DecryptedMessageWithPubKey) Tradable(bisq.core.trade.Tradable) Trade(bisq.core.trade.Trade) PubKeyRing(bisq.common.crypto.PubKeyRing) DisputeCommunicationMessage(bisq.core.arbitration.messages.DisputeCommunicationMessage) WalletException(bisq.core.btc.exceptions.WalletException) AddressFormatException(org.bitcoinj.core.AddressFormatException) Optional(java.util.Optional) TransactionVerificationException(bisq.core.btc.exceptions.TransactionVerificationException) TxBroadcastException(bisq.core.btc.wallet.TxBroadcastException) TxBroadcaster(bisq.core.btc.wallet.TxBroadcaster) Timer(bisq.common.Timer) Transaction(org.bitcoinj.core.Transaction) Contract(bisq.core.trade.Contract) DeterministicKey(org.bitcoinj.crypto.DeterministicKey)

Example 2 with TxBroadcastException

use of bisq.core.btc.wallet.TxBroadcastException in project bisq-core by bisq-network.

the class SellerBroadcastPayoutTx method run.

@Override
protected void run() {
    try {
        runInterceptHook();
        Transaction payoutTx = trade.getPayoutTx();
        checkNotNull(payoutTx, "payoutTx must not be null");
        TransactionConfidence.ConfidenceType confidenceType = payoutTx.getConfidence().getConfidenceType();
        log.debug("payoutTx confidenceType:" + confidenceType);
        if (confidenceType.equals(TransactionConfidence.ConfidenceType.BUILDING) || confidenceType.equals(TransactionConfidence.ConfidenceType.PENDING)) {
            log.debug("payoutTx was already published. confidenceType:" + confidenceType);
            trade.setState(Trade.State.SELLER_PUBLISHED_PAYOUT_TX);
            complete();
        } else {
            processModel.getTradeWalletService().broadcastTx(payoutTx, new TxBroadcaster.Callback() {

                @Override
                public void onSuccess(Transaction transaction) {
                    if (!completed) {
                        log.debug("BroadcastTx succeeded. Transaction:" + transaction);
                        trade.setState(Trade.State.SELLER_PUBLISHED_PAYOUT_TX);
                        complete();
                    } else {
                        log.warn("We got the onSuccess callback called after the timeout has been triggered a complete().");
                    }
                }

                @Override
                public void onFailure(TxBroadcastException exception) {
                    if (!completed) {
                        log.error("BroadcastTx failed. Error:" + exception.getMessage());
                        failed(exception);
                    } else {
                        log.warn("We got the onFailure callback called after the timeout has been triggered a complete().");
                    }
                }
            });
        }
    } catch (Throwable t) {
        failed(t);
    }
}
Also used : TxBroadcaster(bisq.core.btc.wallet.TxBroadcaster) Transaction(org.bitcoinj.core.Transaction) TransactionConfidence(org.bitcoinj.core.TransactionConfidence) TxBroadcastException(bisq.core.btc.wallet.TxBroadcastException)

Example 3 with TxBroadcastException

use of bisq.core.btc.wallet.TxBroadcastException in project bisq-core by bisq-network.

the class SellerAsTakerSignAndPublishDepositTx method run.

@Override
protected void run() {
    try {
        runInterceptHook();
        log.debug("\n\n------------------------------------------------------------\n" + "Contract as json\n" + trade.getContractAsJson() + "\n------------------------------------------------------------\n");
        byte[] contractHash = Hash.getSha256Hash(trade.getContractAsJson());
        trade.setContractHash(contractHash);
        List<RawTransactionInput> sellerInputs = checkNotNull(processModel.getRawTransactionInputs(), "sellerInputs must not be null");
        BtcWalletService walletService = processModel.getBtcWalletService();
        String id = processModel.getOffer().getId();
        Optional<AddressEntry> addressEntryOptional = walletService.getAddressEntry(id, AddressEntry.Context.MULTI_SIG);
        checkArgument(addressEntryOptional.isPresent(), "addressEntryOptional must be present");
        AddressEntry sellerMultiSigAddressEntry = addressEntryOptional.get();
        byte[] sellerMultiSigPubKey = processModel.getMyMultiSigPubKey();
        checkArgument(Arrays.equals(sellerMultiSigPubKey, sellerMultiSigAddressEntry.getPubKey()), "sellerMultiSigPubKey from AddressEntry must match the one from the trade data. trade id =" + id);
        Coin sellerInput = Coin.valueOf(sellerInputs.stream().mapToLong(input -> input.value).sum());
        sellerMultiSigAddressEntry.setCoinLockedInMultiSig(sellerInput.subtract(trade.getTxFee().multiply(2)));
        walletService.saveAddressEntryList();
        TradingPeer tradingPeer = processModel.getTradingPeer();
        Transaction depositTx = processModel.getTradeWalletService().takerSignsAndPublishesDepositTx(true, contractHash, processModel.getPreparedDepositTx(), tradingPeer.getRawTransactionInputs(), sellerInputs, tradingPeer.getMultiSigPubKey(), sellerMultiSigPubKey, trade.getArbitratorBtcPubKey(), new TxBroadcaster.Callback() {

            @Override
            public void onSuccess(Transaction transaction) {
                if (!completed) {
                    // We set the depositTx before we change the state as the state change triggers code
                    // which expected the tx to be available. That case will usually never happen as the
                    // callback is called after the method call has returned but in some test scenarios
                    // with regtest we run into such issues, thus fixing it to make it more stict seems
                    // reasonable.
                    trade.setDepositTx(transaction);
                    log.trace("takerSignsAndPublishesDepositTx succeeded " + transaction);
                    trade.setState(Trade.State.TAKER_PUBLISHED_DEPOSIT_TX);
                    walletService.swapTradeEntryToAvailableEntry(id, AddressEntry.Context.RESERVED_FOR_TRADE);
                    complete();
                } else {
                    log.warn("We got the onSuccess callback called after the timeout has been triggered a complete().");
                }
            }

            @Override
            public void onFailure(TxBroadcastException exception) {
                if (!completed) {
                    failed(exception);
                } else {
                    log.warn("We got the onFailure callback called after the timeout has been triggered a complete().");
                }
            }
        });
        if (trade.getDepositTx() == null) {
            // We set the deposit tx in case we get the onFailure called. We cannot set it in the onFailure
            // callback as the tx is returned by the method call where the callback is  used as an argument.
            trade.setDepositTx(depositTx);
        }
    } catch (Throwable t) {
        final Contract contract = trade.getContract();
        if (contract != null)
            contract.printDiff(processModel.getTradingPeer().getContractAsJson());
        failed(t);
    }
}
Also used : AddressEntry(bisq.core.btc.AddressEntry) RawTransactionInput(bisq.core.btc.data.RawTransactionInput) TxBroadcastException(bisq.core.btc.wallet.TxBroadcastException) Coin(org.bitcoinj.core.Coin) TxBroadcaster(bisq.core.btc.wallet.TxBroadcaster) TradingPeer(bisq.core.trade.protocol.TradingPeer) Transaction(org.bitcoinj.core.Transaction) BtcWalletService(bisq.core.btc.wallet.BtcWalletService) Contract(bisq.core.trade.Contract)

Example 4 with TxBroadcastException

use of bisq.core.btc.wallet.TxBroadcastException in project bisq-core by bisq-network.

the class CreateMakerFeeTx method run.

@Override
protected void run() {
    Offer offer = model.getOffer();
    try {
        runInterceptHook();
        String id = offer.getId();
        BtcWalletService walletService = model.getWalletService();
        NodeAddress selectedArbitratorNodeAddress = ArbitratorSelectionRule.select(model.getUser().getAcceptedArbitratorAddresses(), model.getOffer());
        log.debug("selectedArbitratorAddress " + selectedArbitratorNodeAddress);
        Arbitrator selectedArbitrator = model.getUser().getAcceptedArbitratorByAddress(selectedArbitratorNodeAddress);
        checkNotNull(selectedArbitrator, "selectedArbitrator must not be null at CreateOfferFeeTx");
        Address fundingAddress = walletService.getOrCreateAddressEntry(id, AddressEntry.Context.OFFER_FUNDING).getAddress();
        Address reservedForTradeAddress = walletService.getOrCreateAddressEntry(id, AddressEntry.Context.RESERVED_FOR_TRADE).getAddress();
        Address changeAddress = walletService.getFreshAddressEntry().getAddress();
        final TradeWalletService tradeWalletService = model.getTradeWalletService();
        if (offer.isCurrencyForMakerFeeBtc()) {
            tradeFeeTx = tradeWalletService.createBtcTradingFeeTx(fundingAddress, reservedForTradeAddress, changeAddress, model.getReservedFundsForOffer(), model.isUseSavingsWallet(), offer.getMakerFee(), offer.getTxFee(), selectedArbitrator.getBtcAddress(), new TxBroadcaster.Callback() {

                @Override
                public void onSuccess(Transaction transaction) {
                    // we delay one render frame to be sure we don't get called before the method call has
                    // returned (tradeFeeTx would be null in that case)
                    UserThread.execute(() -> {
                        if (!completed) {
                            offer.setOfferFeePaymentTxId(tradeFeeTx.getHashAsString());
                            model.setTransaction(tradeFeeTx);
                            walletService.swapTradeEntryToAvailableEntry(id, AddressEntry.Context.OFFER_FUNDING);
                            model.getOffer().setState(Offer.State.OFFER_FEE_PAID);
                            complete();
                        } else {
                            log.warn("We got the onSuccess callback called after the timeout has been triggered a complete().");
                        }
                    });
                }

                @Override
                public void onFailure(TxBroadcastException exception) {
                    if (!completed) {
                        failed(exception);
                    } else {
                        log.warn("We got the onFailure callback called after the timeout has been triggered a complete().");
                    }
                }
            });
        } else {
            final BsqWalletService bsqWalletService = model.getBsqWalletService();
            Transaction preparedBurnFeeTx = model.getBsqWalletService().getPreparedBurnFeeTx(offer.getMakerFee());
            Transaction txWithBsqFee = tradeWalletService.completeBsqTradingFeeTx(preparedBurnFeeTx, fundingAddress, reservedForTradeAddress, changeAddress, model.getReservedFundsForOffer(), model.isUseSavingsWallet(), offer.getTxFee());
            Transaction signedTx = model.getBsqWalletService().signTx(txWithBsqFee);
            WalletService.checkAllScriptSignaturesForTx(signedTx);
            bsqWalletService.commitTx(signedTx);
            // We need to create another instance, otherwise the tx would trigger an invalid state exception
            // if it gets committed 2 times
            tradeWalletService.commitTx(tradeWalletService.getClonedTransaction(signedTx));
            bsqWalletService.broadcastTx(signedTx, new TxBroadcaster.Callback() {

                @Override
                public void onSuccess(@Nullable Transaction transaction) {
                    if (transaction != null) {
                        offer.setOfferFeePaymentTxId(transaction.getHashAsString());
                        model.setTransaction(transaction);
                        log.debug("onSuccess, offerId={}, OFFER_FUNDING", id);
                        walletService.swapTradeEntryToAvailableEntry(id, AddressEntry.Context.OFFER_FUNDING);
                        log.debug("Successfully sent tx with id " + transaction.getHashAsString());
                        model.getOffer().setState(Offer.State.OFFER_FEE_PAID);
                        complete();
                    }
                }

                @Override
                public void onFailure(TxBroadcastException exception) {
                    log.error(exception.toString());
                    exception.printStackTrace();
                    offer.setErrorMessage("An error occurred.\n" + "Error message:\n" + exception.getMessage());
                    failed(exception);
                }
            });
        }
    } catch (Throwable t) {
        offer.setErrorMessage("An error occurred.\n" + "Error message:\n" + t.getMessage());
        failed(t);
    }
}
Also used : NodeAddress(bisq.network.p2p.NodeAddress) Address(org.bitcoinj.core.Address) TradeWalletService(bisq.core.btc.wallet.TradeWalletService) Arbitrator(bisq.core.arbitration.Arbitrator) TxBroadcastException(bisq.core.btc.wallet.TxBroadcastException) TxBroadcaster(bisq.core.btc.wallet.TxBroadcaster) Transaction(org.bitcoinj.core.Transaction) Offer(bisq.core.offer.Offer) BtcWalletService(bisq.core.btc.wallet.BtcWalletService) BsqWalletService(bisq.core.btc.wallet.BsqWalletService) NodeAddress(bisq.network.p2p.NodeAddress)

Example 5 with TxBroadcastException

use of bisq.core.btc.wallet.TxBroadcastException in project bisq-core by bisq-network.

the class BuyerAsTakerSignAndPublishDepositTx method run.

@Override
protected void run() {
    try {
        runInterceptHook();
        log.debug("\n\n------------------------------------------------------------\n" + "Contract as json\n" + trade.getContractAsJson() + "\n------------------------------------------------------------\n");
        byte[] contractHash = Hash.getSha256Hash(trade.getContractAsJson());
        trade.setContractHash(contractHash);
        List<RawTransactionInput> buyerInputs = checkNotNull(processModel.getRawTransactionInputs(), "buyerInputs must not be null");
        BtcWalletService walletService = processModel.getBtcWalletService();
        String id = processModel.getOffer().getId();
        Optional<AddressEntry> addressEntryOptional = walletService.getAddressEntry(id, AddressEntry.Context.MULTI_SIG);
        checkArgument(addressEntryOptional.isPresent(), "addressEntryOptional must be present");
        AddressEntry buyerMultiSigAddressEntry = addressEntryOptional.get();
        Coin buyerInput = Coin.valueOf(buyerInputs.stream().mapToLong(input -> input.value).sum());
        buyerMultiSigAddressEntry.setCoinLockedInMultiSig(buyerInput.subtract(trade.getTxFee().multiply(2)));
        walletService.saveAddressEntryList();
        TradingPeer tradingPeer = processModel.getTradingPeer();
        byte[] buyerMultiSigPubKey = processModel.getMyMultiSigPubKey();
        checkArgument(Arrays.equals(buyerMultiSigPubKey, buyerMultiSigAddressEntry.getPubKey()), "buyerMultiSigPubKey from AddressEntry must match the one from the trade data. trade id =" + id);
        Transaction depositTx = processModel.getTradeWalletService().takerSignsAndPublishesDepositTx(false, contractHash, processModel.getPreparedDepositTx(), buyerInputs, tradingPeer.getRawTransactionInputs(), buyerMultiSigPubKey, tradingPeer.getMultiSigPubKey(), trade.getArbitratorBtcPubKey(), new TxBroadcaster.Callback() {

            @Override
            public void onSuccess(Transaction transaction) {
                if (!completed) {
                    // We set the depositTx before we change the state as the state change triggers code
                    // which expected the tx to be available. That case will usually never happen as the
                    // callback is called after the method call has returned but in some test scenarios
                    // with regtest we run into such issues, thus fixing it to make it more stict seems
                    // reasonable.
                    trade.setDepositTx(transaction);
                    log.trace("takerSignsAndPublishesDepositTx succeeded " + transaction);
                    trade.setState(Trade.State.TAKER_PUBLISHED_DEPOSIT_TX);
                    walletService.swapTradeEntryToAvailableEntry(id, AddressEntry.Context.RESERVED_FOR_TRADE);
                    complete();
                } else {
                    log.warn("We got the onSuccess callback called after the timeout has been triggered a complete().");
                }
            }

            @Override
            public void onFailure(TxBroadcastException exception) {
                if (!completed) {
                    failed(exception);
                } else {
                    log.warn("We got the onFailure callback called after the timeout has been triggered a complete().");
                }
            }
        });
        if (trade.getDepositTx() == null) {
            // We set the deposit tx in case we get the onFailure called. We cannot set it in the onFailure
            // callback as the tx is returned by the method call where the callback is  used as an argument.
            trade.setDepositTx(depositTx);
        }
    } catch (Throwable t) {
        failed(t);
    }
}
Also used : AddressEntry(bisq.core.btc.AddressEntry) RawTransactionInput(bisq.core.btc.data.RawTransactionInput) TxBroadcastException(bisq.core.btc.wallet.TxBroadcastException) Coin(org.bitcoinj.core.Coin) TxBroadcaster(bisq.core.btc.wallet.TxBroadcaster) TradingPeer(bisq.core.trade.protocol.TradingPeer) Transaction(org.bitcoinj.core.Transaction) BtcWalletService(bisq.core.btc.wallet.BtcWalletService)

Aggregations

TxBroadcastException (bisq.core.btc.wallet.TxBroadcastException)8 TxBroadcaster (bisq.core.btc.wallet.TxBroadcaster)8 Transaction (org.bitcoinj.core.Transaction)8 BtcWalletService (bisq.core.btc.wallet.BtcWalletService)5 AddressEntry (bisq.core.btc.AddressEntry)3 TransactionVerificationException (bisq.core.btc.exceptions.TransactionVerificationException)3 WalletException (bisq.core.btc.exceptions.WalletException)3 TradeWalletService (bisq.core.btc.wallet.TradeWalletService)3 Arbitrator (bisq.core.arbitration.Arbitrator)2 RawTransactionInput (bisq.core.btc.data.RawTransactionInput)2 BsqWalletService (bisq.core.btc.wallet.BsqWalletService)2 TxMalleabilityException (bisq.core.btc.wallet.TxMalleabilityException)2 Contract (bisq.core.trade.Contract)2 TradingPeer (bisq.core.trade.protocol.TradingPeer)2 NodeAddress (bisq.network.p2p.NodeAddress)2 Address (org.bitcoinj.core.Address)2 InsufficientMoneyException (org.bitcoinj.core.InsufficientMoneyException)2 Timer (bisq.common.Timer)1 UserThread (bisq.common.UserThread)1 KeyRing (bisq.common.crypto.KeyRing)1