add support for lost deposit tx

This commit is contained in:
Manfred Karrer 2016-01-15 11:52:27 +01:00
parent 7ab6cfed60
commit 582999844f
4 changed files with 193 additions and 47 deletions

View File

@ -19,10 +19,7 @@ package io.bitsquare.gui.main.disputes.arbitrator;
import io.bitsquare.arbitration.Dispute;
import io.bitsquare.arbitration.DisputeManager;
import io.bitsquare.btc.TradeWalletService;
import io.bitsquare.btc.WalletService;
import io.bitsquare.common.crypto.KeyRing;
import io.bitsquare.gui.Navigation;
import io.bitsquare.gui.common.view.FxmlView;
import io.bitsquare.gui.main.disputes.trader.DisputeSummaryPopup;
import io.bitsquare.gui.main.disputes.trader.TraderDisputeView;
@ -40,10 +37,10 @@ import javax.inject.Inject;
public class ArbitratorDisputeView extends TraderDisputeView {
@Inject
public ArbitratorDisputeView(DisputeManager disputeManager, KeyRing keyRing, TradeWalletService tradeWalletService, WalletService walletService,
TradeManager tradeManager, Stage stage, BSFormatter formatter, Navigation navigation,
DisputeSummaryPopup disputeSummaryPopup, ContractPopup contractPopup, TradeDetailsPopup tradeDetailsPopup) {
super(disputeManager, keyRing, tradeWalletService, walletService, tradeManager, stage, formatter, navigation,
public ArbitratorDisputeView(DisputeManager disputeManager, KeyRing keyRing, TradeManager tradeManager, Stage stage,
BSFormatter formatter, DisputeSummaryPopup disputeSummaryPopup,
ContractPopup contractPopup, TradeDetailsPopup tradeDetailsPopup) {
super(disputeManager, keyRing, tradeManager, stage, formatter,
disputeSummaryPopup, contractPopup, tradeDetailsPopup);
}

View File

@ -381,7 +381,7 @@ public class DisputeSummaryPopup extends Popup {
e2.printStackTrace();
}
} else {
log.warn("dispute.getDepositTxOptional is empty");
log.warn("dispute.getDepositTxSerialized is null");
}
});

View File

@ -18,6 +18,7 @@
package io.bitsquare.gui.main.portfolio.pendingtrades;
import com.google.inject.Inject;
import io.bitsquare.app.Log;
import io.bitsquare.arbitration.Dispute;
import io.bitsquare.arbitration.DisputeManager;
import io.bitsquare.btc.FeePolicy;
@ -32,6 +33,7 @@ import io.bitsquare.gui.main.disputes.DisputesView;
import io.bitsquare.gui.main.portfolio.PortfolioView;
import io.bitsquare.gui.main.portfolio.closedtrades.ClosedTradesView;
import io.bitsquare.gui.popups.Popup;
import io.bitsquare.gui.popups.SelectDepositTxPopup;
import io.bitsquare.gui.popups.WalletPasswordPopup;
import io.bitsquare.payment.PaymentAccountContractData;
import io.bitsquare.trade.*;
@ -45,8 +47,11 @@ import javafx.collections.ObservableList;
import org.bitcoinj.core.BlockChainListener;
import org.bitcoinj.core.Coin;
import org.bitcoinj.core.Transaction;
import org.bitcoinj.core.TransactionOutput;
import org.spongycastle.crypto.params.KeyParameter;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import static com.google.common.base.Preconditions.checkNotNull;
@ -182,57 +187,94 @@ public class PendingTradesDataModel extends ActivatableDataModel {
}
public void onOpenDispute() {
doOpenDispute(false);
tryOpenDispute(false);
}
public void onOpenSupportTicket() {
doOpenDispute(true);
tryOpenDispute(true);
}
private void doOpenDispute(boolean isSupportTicket) {
private void tryOpenDispute(boolean isSupportTicket) {
if (trade != null) {
Transaction depositTx = trade.getDepositTx();
log.debug("trade.getDepositTx() " + depositTx);
byte[] depositTxSerialized = null;
byte[] payoutTxSerialized = null;
String depositTxHashAsString = null;
String payoutTxHashAsString = null;
if (depositTx != null) {
depositTxSerialized = depositTx.bitcoinSerialize();
depositTxHashAsString = depositTx.getHashAsString();
}
Transaction payoutTx = trade.getPayoutTx();
if (payoutTx != null) {
payoutTxSerialized = payoutTx.bitcoinSerialize();
payoutTxHashAsString = payoutTx.getHashAsString();
}
doOpenDispute(isSupportTicket, trade.getDepositTx());
} else {
log.warn("Trade.depositTx is null. We try to find the tx in our wallet.");
List<Transaction> candidates = new ArrayList<>();
List<Transaction> transactions = walletService.getWallet().getRecentTransactions(100, true);
transactions.stream().forEach(transaction -> {
Coin valueSentFromMe = transaction.getValueSentFromMe(walletService.getWallet());
if (!valueSentFromMe.isZero()) {
// spending tx
for (TransactionOutput transactionOutput : transaction.getOutputs()) {
if (!transactionOutput.isMine(walletService.getWallet())) {
if (transactionOutput.getScriptPubKey().isPayToScriptHash()) {
// MS tx
candidates.add(transaction);
}
}
}
}
});
Dispute dispute = new Dispute(disputeManager.getDisputeStorage(),
trade.getId(),
keyRing.getPubKeyRing().hashCode(), // traderId
trade.getOffer().getDirection() == Offer.Direction.BUY ? isOfferer : !isOfferer,
isOfferer,
keyRing.getPubKeyRing(),
trade.getDate(),
trade.getContract(),
trade.getContractHash(),
depositTxSerialized,
payoutTxSerialized,
depositTxHashAsString,
payoutTxHashAsString,
trade.getContractAsJson(),
trade.getOffererContractSignature(),
trade.getTakerContractSignature(),
user.getAcceptedArbitratorByAddress(trade.getArbitratorAddress()).getPubKeyRing(),
isSupportTicket
);
trade.setDisputeState(Trade.DisputeState.DISPUTE_REQUESTED);
disputeManager.sendOpenNewDisputeMessage(dispute);
navigation.navigateTo(MainView.class, DisputesView.class);
if (candidates.size() == 1)
doOpenDispute(isSupportTicket, candidates.get(0));
else if (candidates.size() > 1)
new SelectDepositTxPopup().transactions(candidates).onSelect(transaction -> {
doOpenDispute(isSupportTicket, transaction);
}).show();
else
log.error("Trade.depositTx is null and we did not find any MultiSig transaction.");
}
} else {
log.error("Trade is null");
}
}
private void doOpenDispute(boolean isSupportTicket, Transaction depositTx) {
Log.traceCall("depositTx=" + depositTx);
byte[] depositTxSerialized = null;
byte[] payoutTxSerialized = null;
String depositTxHashAsString = null;
String payoutTxHashAsString = null;
if (depositTx != null) {
depositTxSerialized = depositTx.bitcoinSerialize();
depositTxHashAsString = depositTx.getHashAsString();
} else {
log.warn("depositTx is null");
}
Transaction payoutTx = trade.getPayoutTx();
if (payoutTx != null) {
payoutTxSerialized = payoutTx.bitcoinSerialize();
payoutTxHashAsString = payoutTx.getHashAsString();
}
Dispute dispute = new Dispute(disputeManager.getDisputeStorage(),
trade.getId(),
keyRing.getPubKeyRing().hashCode(), // traderId
trade.getOffer().getDirection() == Offer.Direction.BUY ? isOfferer : !isOfferer,
isOfferer,
keyRing.getPubKeyRing(),
trade.getDate(),
trade.getContract(),
trade.getContractHash(),
depositTxSerialized,
payoutTxSerialized,
depositTxHashAsString,
payoutTxHashAsString,
trade.getContractAsJson(),
trade.getOffererContractSignature(),
trade.getTakerContractSignature(),
user.getAcceptedArbitratorByAddress(trade.getArbitratorAddress()).getPubKeyRing(),
isSupportTicket
);
trade.setDisputeState(Trade.DisputeState.DISPUTE_REQUESTED);
disputeManager.sendOpenNewDisputeMessage(dispute);
navigation.navigateTo(MainView.class, DisputesView.class);
}
///////////////////////////////////////////////////////////////////////////////////////////
// Getters
///////////////////////////////////////////////////////////////////////////////////////////

View File

@ -0,0 +1,107 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.gui.popups;
import io.bitsquare.common.util.Tuple2;
import javafx.collections.FXCollections;
import javafx.scene.control.Button;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Label;
import javafx.util.StringConverter;
import org.bitcoinj.core.Transaction;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.inject.Inject;
import java.util.List;
import java.util.Optional;
import java.util.function.Consumer;
import static io.bitsquare.gui.util.FormBuilder.addLabelComboBox;
import static io.bitsquare.gui.util.FormBuilder.addMultilineLabel;
public class SelectDepositTxPopup extends Popup {
private static final Logger log = LoggerFactory.getLogger(SelectDepositTxPopup.class);
private Button emptyWalletButton;
private ComboBox<Transaction> transactionsComboBox;
private List<Transaction> transaction;
private Optional<Consumer<Transaction>> selectHandlerOptional;
///////////////////////////////////////////////////////////////////////////////////////////
// Public API
///////////////////////////////////////////////////////////////////////////////////////////
@Inject
public SelectDepositTxPopup() {
}
public SelectDepositTxPopup show() {
if (headLine == null)
headLine = "Select deposit transaction for dispute";
width = 700;
createGridPane();
addHeadLine();
addContent();
createPopup();
return this;
}
public SelectDepositTxPopup onSelect(Consumer<Transaction> selectHandler) {
this.selectHandlerOptional = Optional.of(selectHandler);
return this;
}
public SelectDepositTxPopup transactions(List<Transaction> transaction) {
this.transaction = transaction;
return this;
}
///////////////////////////////////////////////////////////////////////////////////////////
// Protected
///////////////////////////////////////////////////////////////////////////////////////////
private void addContent() {
addMultilineLabel(gridPane, ++rowIndex,
"The deposit transaction was not stored in the trade.\n" +
"Please select one of the existing MultiSig transactions from your wallet which was the " +
"deposit transaction used in the failed trade.",
10);
Tuple2<Label, ComboBox> tuple = addLabelComboBox(gridPane, ++rowIndex);
transactionsComboBox = tuple.second;
transactionsComboBox.setConverter(new StringConverter<Transaction>() {
@Override
public String toString(Transaction transaction) {
return transaction.getHashAsString();
}
@Override
public Transaction fromString(String string) {
return null;
}
});
transactionsComboBox.setItems(FXCollections.observableArrayList(transaction));
transactionsComboBox.setOnAction(event -> {
selectHandlerOptional.get().accept(transactionsComboBox.getSelectionModel().getSelectedItem());
});
}
}