Add tool for manually creating the payout tx. Change shortcuts

This commit is contained in:
Manfred Karrer 2016-11-26 18:16:12 +01:00
parent a87b855164
commit 7acfdb23de
11 changed files with 365 additions and 26 deletions

View file

@ -827,6 +827,137 @@ public class TradeWalletService {
}
// Emergency payout tool. Used only in cased when the payput from the arbitrator does not work because some data
// in the trade/dispute are messed up.
public Transaction emergencySignAndPublishPayoutTx(String depositTxHex,
Coin buyerPayoutAmount,
Coin sellerPayoutAmount,
Coin arbitratorPayoutAmount,
String buyerAddressString,
String sellerAddressString,
String arbitratorAddressString,
@Nullable String buyerPrivateKeyAsHex,
@Nullable String sellerPrivateKeyAsHex,
String arbitratorPrivateKeyAsHex,
String buyerPubKeyAsHex,
String sellerPubKeyAsHex,
String arbitratorPubKeyAsHex,
String P2SHMultiSigOutputScript,
List<String> buyerPubKeys,
List<String> sellerPubKeys,
FutureCallback<Transaction> callback)
throws AddressFormatException, TransactionVerificationException, WalletException {
log.trace("signAndPublishPayoutTx called");
log.trace("depositTxHex " + depositTxHex);
log.trace("buyerPayoutAmount " + buyerPayoutAmount.toFriendlyString());
log.trace("sellerPayoutAmount " + sellerPayoutAmount.toFriendlyString());
log.trace("arbitratorPayoutAmount " + arbitratorPayoutAmount.toFriendlyString());
log.trace("buyerAddressString " + buyerAddressString);
log.trace("sellerAddressString " + sellerAddressString);
log.trace("arbitratorAddressString " + arbitratorAddressString);
log.trace("buyerPrivateKeyAsHex " + buyerPrivateKeyAsHex);
log.trace("sellerPrivateKeyAsHex " + sellerPrivateKeyAsHex);
log.trace("arbitratorPrivateKeyAsHex " + arbitratorPrivateKeyAsHex);
log.trace("buyerPubKeyAsHex " + buyerPubKeyAsHex);
log.trace("sellerPubKeyAsHex " + sellerPubKeyAsHex);
log.trace("arbitratorPubKeyAsHex " + arbitratorPubKeyAsHex);
log.trace("P2SHMultiSigOutputScript " + P2SHMultiSigOutputScript);
log.trace("buyerPubKeys " + buyerPubKeys);
log.trace("sellerPubKeys " + sellerPubKeys);
checkNotNull((buyerPrivateKeyAsHex != null || sellerPrivateKeyAsHex != null), "either buyerPrivateKeyAsHex or sellerPrivateKeyAsHex must not be null");
byte[] buyerPubKey = ECKey.fromPublicOnly(Utils.HEX.decode(buyerPubKeyAsHex)).getPubKey();
byte[] sellerPubKey = ECKey.fromPublicOnly(Utils.HEX.decode(sellerPubKeyAsHex)).getPubKey();
final byte[] arbitratorPubKey = ECKey.fromPublicOnly(Utils.HEX.decode(arbitratorPubKeyAsHex)).getPubKey();
Script p2SHMultiSigOutputScript = getP2SHMultiSigOutputScript(buyerPubKey, sellerPubKey, arbitratorPubKey);
if (!p2SHMultiSigOutputScript.toString().contains(P2SHMultiSigOutputScript)) {
if (buyerPubKeys.isEmpty())
buyerPubKeys.add(buyerPubKeyAsHex);
if (sellerPubKeys.isEmpty())
sellerPubKeys.add(sellerPubKeyAsHex);
boolean found = false;
for (String b : buyerPubKeys) {
if (found)
break;
byte[] bk = ECKey.fromPublicOnly(Utils.HEX.decode(b)).getPubKey();
for (String s : sellerPubKeys) {
byte[] sk = ECKey.fromPublicOnly(Utils.HEX.decode(s)).getPubKey();
p2SHMultiSigOutputScript = getP2SHMultiSigOutputScript(bk, sk, arbitratorPubKey);
if (p2SHMultiSigOutputScript.toString().contains(P2SHMultiSigOutputScript)) {
log.trace("Found buyers pub key " + b);
log.trace("Found sellers pub key " + s);
buyerPubKey = ECKey.fromPublicOnly(Utils.HEX.decode(b)).getPubKey();
sellerPubKey = ECKey.fromPublicOnly(Utils.HEX.decode(s)).getPubKey();
found = true;
break;
}
}
}
if (!found)
log.warn("We did not find any matching pub keys for generating the required p2SHMultiSigOutputScript");
}
Coin msOutput = buyerPayoutAmount.add(sellerPayoutAmount).add(arbitratorPayoutAmount).add(FeePolicy.getFixedTxFeeForTrades());
TransactionOutput p2SHMultiSigOutput = new TransactionOutput(params, null, msOutput, p2SHMultiSigOutputScript.getProgram());
Transaction depositTx = new Transaction(params);
depositTx.addOutput(p2SHMultiSigOutput);
Transaction payoutTx = new Transaction(params);
Sha256Hash spendTxHash = Sha256Hash.wrap(depositTxHex);
payoutTx.addInput(new TransactionInput(params, depositTx, p2SHMultiSigOutputScript.getProgram(), new TransactionOutPoint(params, 0, spendTxHash), msOutput));
if (buyerPayoutAmount.isGreaterThan(Coin.ZERO))
payoutTx.addOutput(buyerPayoutAmount, new Address(params, buyerAddressString));
if (sellerPayoutAmount.isGreaterThan(Coin.ZERO))
payoutTx.addOutput(sellerPayoutAmount, new Address(params, sellerAddressString));
if (arbitratorPayoutAmount.isGreaterThan(Coin.ZERO))
payoutTx.addOutput(arbitratorPayoutAmount, new Address(params, arbitratorAddressString));
// take care of sorting!
Script redeemScript = getMultiSigRedeemScript(buyerPubKey, sellerPubKey, arbitratorPubKey);
Sha256Hash sigHash = payoutTx.hashForSignature(0, redeemScript, Transaction.SigHash.ALL, false);
ECKey.ECDSASignature tradersSignature;
if (buyerPrivateKeyAsHex != null && !buyerPrivateKeyAsHex.isEmpty()) {
final ECKey buyerPrivateKey = ECKey.fromPrivate(Utils.HEX.decode(buyerPrivateKeyAsHex));
checkNotNull(buyerPrivateKey, "buyerPrivateKey must not be null");
tradersSignature = buyerPrivateKey.sign(sigHash, aesKey).toCanonicalised();
} else {
checkNotNull(sellerPrivateKeyAsHex, "sellerPrivateKeyAsHex must not be null");
final ECKey sellerPrivateKey = ECKey.fromPrivate(Utils.HEX.decode(sellerPrivateKeyAsHex));
checkNotNull(sellerPrivateKey, "sellerPrivateKey must not be null");
tradersSignature = sellerPrivateKey.sign(sigHash, aesKey).toCanonicalised();
}
final ECKey key = ECKey.fromPrivate(Utils.HEX.decode(arbitratorPrivateKeyAsHex));
checkNotNull(key, "key must not be null");
ECKey.ECDSASignature arbitratorSignature = key.sign(sigHash, aesKey).toCanonicalised();
TransactionSignature tradersTxSig = new TransactionSignature(tradersSignature, Transaction.SigHash.ALL, false);
TransactionSignature arbitratorTxSig = new TransactionSignature(arbitratorSignature, Transaction.SigHash.ALL, false);
// Take care of order of signatures. See comment below at getMultiSigRedeemScript (sort order needed here: arbitrator, seller, buyer)
Script inputScript = ScriptBuilder.createP2SHMultiSigInputScript(ImmutableList.of(arbitratorTxSig, tradersTxSig), redeemScript);
TransactionInput input = payoutTx.getInput(0);
input.setScriptSig(inputScript);
printTxWithInputs("payoutTx", payoutTx);
verifyTransaction(payoutTx);
checkWalletConsistency();
if (walletAppKit != null) {
ListenableFuture<Transaction> future = walletAppKit.peerGroup().broadcastTransaction(payoutTx).future();
Futures.addCallback(future, callback);
}
return payoutTx;
}
///////////////////////////////////////////////////////////////////////////////////////////
// Misc
///////////////////////////////////////////////////////////////////////////////////////////

View file

@ -172,6 +172,7 @@ public class WalletService {
addressEntryList.onWalletReady(wallet);
walletAppKit.peerGroup().addEventListener(new PeerEventListener() {
@Override
public void onPeersDiscovered(Set<PeerAddress> peerAddresses) {
@ -385,7 +386,9 @@ public class WalletService {
return "BitcoinJ wallet:\n" +
wallet.toString(includePrivKeys, true, true, walletAppKit.chain()) + "\n\n" +
"Bitsquare address entry list:\n" +
addressEntryListData.toString();
addressEntryListData.toString() +
"All pubkeys as hex:\n" +
wallet.printAllPubKeysAsHex();
}
public void restoreSeedWords(DeterministicSeed seed, ResultHandler resultHandler, ExceptionHandler exceptionHandler) {

View file

@ -110,7 +110,7 @@ public abstract class TradeProtocol {
stopTimeout();
timeoutTimer = UserThread.runAfter(() -> {
log.error("Timeout reached");
log.error("Timeout reached. TradeID=" + trade.getId());
trade.setErrorMessage("A timeout occurred.");
cleanupTradable();
cleanup();

View file

@ -23,6 +23,7 @@ import com.google.inject.Guice;
import com.google.inject.Injector;
import io.bitsquare.alert.AlertManager;
import io.bitsquare.arbitration.ArbitratorManager;
import io.bitsquare.btc.TradeWalletService;
import io.bitsquare.btc.WalletService;
import io.bitsquare.common.CommonOptionKeys;
import io.bitsquare.common.UserThread;
@ -41,10 +42,7 @@ import io.bitsquare.gui.main.MainView;
import io.bitsquare.gui.main.MainViewModel;
import io.bitsquare.gui.main.debug.DebugView;
import io.bitsquare.gui.main.overlays.popups.Popup;
import io.bitsquare.gui.main.overlays.windows.EmptyWalletWindow;
import io.bitsquare.gui.main.overlays.windows.FilterWindow;
import io.bitsquare.gui.main.overlays.windows.SendAlertMessageWindow;
import io.bitsquare.gui.main.overlays.windows.ShowWalletDataWindow;
import io.bitsquare.gui.main.overlays.windows.*;
import io.bitsquare.gui.util.ImageUtil;
import io.bitsquare.p2p.P2PService;
import io.bitsquare.storage.Storage;
@ -197,27 +195,33 @@ public class BitsquareApp extends Application {
stop();
});
scene.addEventHandler(KeyEvent.KEY_RELEASED, keyEvent -> {
if (new KeyCodeCombination(KeyCode.W, KeyCombination.SHORTCUT_DOWN).match(keyEvent)) {
if (new KeyCodeCombination(KeyCode.W, KeyCombination.SHORTCUT_DOWN).match(keyEvent) || new KeyCodeCombination(KeyCode.W, KeyCombination.CONTROL_DOWN).match(keyEvent)) {
stop();
} else if (new KeyCodeCombination(KeyCode.Q, KeyCombination.SHORTCUT_DOWN).match(keyEvent)) {
} else if (new KeyCodeCombination(KeyCode.Q, KeyCombination.SHORTCUT_DOWN).match(keyEvent) || new KeyCodeCombination(KeyCode.Q, KeyCombination.CONTROL_DOWN).match(keyEvent)) {
stop();
} else if (new KeyCodeCombination(KeyCode.E, KeyCombination.SHORTCUT_DOWN).match(keyEvent)) {
} else if (new KeyCodeCombination(KeyCode.E, KeyCombination.SHORTCUT_DOWN).match(keyEvent) || new KeyCodeCombination(KeyCode.E, KeyCombination.CONTROL_DOWN).match(keyEvent)) {
showEmptyWalletPopup();
} else if (new KeyCodeCombination(KeyCode.M, KeyCombination.SHORTCUT_DOWN).match(keyEvent)) {
} else if (new KeyCodeCombination(KeyCode.M, KeyCombination.ALT_DOWN).match(keyEvent)) {
showSendAlertMessagePopup();
} else if (new KeyCodeCombination(KeyCode.F, KeyCombination.SHORTCUT_DOWN).match(keyEvent)) {
} else if (new KeyCodeCombination(KeyCode.F, KeyCombination.ALT_DOWN).match(keyEvent)) {
showFilterPopup();
} else if (new KeyCodeCombination(KeyCode.F, KeyCombination.SHORTCUT_DOWN).match(keyEvent)) {
} else if (new KeyCodeCombination(KeyCode.F, KeyCombination.ALT_DOWN).match(keyEvent)) {
showFPSWindow();
} else if (new KeyCodeCombination(KeyCode.J, KeyCombination.SHORTCUT_DOWN).match(keyEvent)) {
} else if (new KeyCodeCombination(KeyCode.J, KeyCombination.ALT_DOWN).match(keyEvent)) {
WalletService walletService = injector.getInstance(WalletService.class);
if (walletService.getWallet() != null)
new ShowWalletDataWindow(walletService).information("Wallet raw data").show();
else
new Popup<>().warning("The wallet is not initialized yet").show();
} else if (DevFlags.DEV_MODE) {
if (new KeyCodeCombination(KeyCode.D, KeyCombination.SHORTCUT_DOWN).match(keyEvent))
showDebugWindow();
} else if (DevFlags.DEV_MODE && new KeyCodeCombination(KeyCode.G, KeyCombination.ALT_DOWN).match(keyEvent)) {
TradeWalletService tradeWalletService = injector.getInstance(TradeWalletService.class);
WalletService walletService = injector.getInstance(WalletService.class);
if (walletService.getWallet() != null)
new SpendFromDepositTxWindow(tradeWalletService).information("Emergency wallet tool").show();
else
new Popup<>().warning("The wallet is not initialized yet").show();
} else if (DevFlags.DEV_MODE && new KeyCodeCombination(KeyCode.D, KeyCombination.SHORTCUT_DOWN).match(keyEvent)) {
showDebugWindow();
}
});
@ -256,9 +260,14 @@ public class BitsquareApp extends Application {
UserThread.runPeriodically(() -> Profiler.printSystemLoad(log), LOG_MEMORY_PERIOD_MIN, TimeUnit.MINUTES);
} catch (Throwable throwable) {
} catch (
Throwable throwable
)
{
showErrorPopup(throwable, false);
}
}
private void showSendAlertMessagePopup() {

View file

@ -79,7 +79,7 @@ public class AccountView extends ActivatableView<TabPane, AccountViewModel> {
};
keyEventEventHandler = event -> {
if (new KeyCodeCombination(KeyCode.R, KeyCombination.SHORTCUT_DOWN).match(event) &&
if (new KeyCodeCombination(KeyCode.R, KeyCombination.ALT_DOWN).match(event) &&
arbitratorRegistrationTab == null) {
arbitratorRegistrationTab = new Tab("Arbitrator registration");
arbitratorRegistrationTab.setClosable(false);

View file

@ -208,7 +208,7 @@ public class TraderDisputeView extends ActivatableView<VBox, Void> {
disputeDirectMessageListListener = c -> scrollToBottom();
keyEventEventHandler = event -> {
if (new KeyCodeCombination(KeyCode.L, KeyCombination.SHORTCUT_DOWN).match(event)) {
if (new KeyCodeCombination(KeyCode.L, KeyCombination.ALT_DOWN).match(event)) {
Map<String, List<Dispute>> map = new HashMap<>();
disputeManager.getDisputesAsObservableList().stream().forEach(dispute -> {
String tradeId = dispute.getTradeId();
@ -269,14 +269,14 @@ public class TraderDisputeView extends ActivatableView<VBox, Void> {
.actionButtonText("Copy")
.onAction(() -> Utilities.copyToClipboard(message))
.show();
} else if (new KeyCodeCombination(KeyCode.U, KeyCombination.SHORTCUT_DOWN).match(event)) {
} else if (new KeyCodeCombination(KeyCode.U, KeyCombination.ALT_DOWN).match(event)) {
// Hidden shortcut to re-open a dispute. Allow it also for traders not only arbitrator.
if (selectedDispute != null) {
if (selectedDisputeClosedPropertyListener != null)
selectedDispute.isClosedProperty().removeListener(selectedDisputeClosedPropertyListener);
selectedDispute.setIsClosed(false);
}
} else if (new KeyCodeCombination(KeyCode.R, KeyCombination.SHORTCUT_DOWN).match(event)) {
} else if (new KeyCodeCombination(KeyCode.R, KeyCombination.ALT_DOWN).match(event)) {
if (selectedDispute != null) {
PubKeyRing pubKeyRing = selectedDispute.getTraderPubKeyRing();
NodeAddress nodeAddress;

View file

@ -184,9 +184,9 @@ public class TransactionsView extends ActivatableView<VBox, Void> {
};
keyEventEventHandler = event -> {
if (new KeyCodeCombination(KeyCode.R, KeyCombination.SHORTCUT_DOWN).match(event))
if (new KeyCodeCombination(KeyCode.R, KeyCombination.ALT_DOWN).match(event))
revertTxColumn.setVisible(!revertTxColumn.isVisible());
else if (new KeyCodeCombination(KeyCode.A, KeyCombination.SHORTCUT_DOWN).match(event))
else if (new KeyCodeCombination(KeyCode.A, KeyCombination.ALT_DOWN).match(event))
showStatisticsPopup();
};

View file

@ -147,7 +147,7 @@ public class PeerInfoWithTagEditor extends Overlay<PeerInfoWithTagEditor> {
inputTextField.setText(tag);
keyEventEventHandler = event -> {
if (new KeyCodeCombination(KeyCode.R, KeyCombination.SHORTCUT_DOWN).match(event)) {
if (new KeyCodeCombination(KeyCode.R, KeyCombination.ALT_DOWN).match(event)) {
new SendPrivateNotificationWindow(offer.getPubKeyRing(), offer.getOffererNodeAddress())
.onAddAlertMessage(privateNotificationManager::sendPrivateNotificationMessageIfKeyIsValid)
.show();

View file

@ -177,7 +177,10 @@ public class ContractWindow extends Overlay<ContractWindow> {
viewContractButton.setDefaultButton(false);
viewContractButton.setOnAction(e -> {
TextArea textArea = new TextArea();
textArea.setText(dispute.getContractAsJson());
String contractAsJson = dispute.getContractAsJson();
contractAsJson += "\n\nBuyerPubKeyHex: " + Utils.HEX.encode(dispute.getContract().getBuyerBtcPubKey());
contractAsJson += "\nSellerPubKeyHex: " + Utils.HEX.encode(dispute.getContract().getSellerBtcPubKey());
textArea.setText(contractAsJson);
textArea.setPrefHeight(50);
textArea.setEditable(false);
textArea.setWrapText(true);

View file

@ -0,0 +1,193 @@
/*
* 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.main.overlays.windows;
import com.google.common.util.concurrent.FutureCallback;
import io.bitsquare.btc.TradeWalletService;
import io.bitsquare.btc.exceptions.TransactionVerificationException;
import io.bitsquare.btc.exceptions.WalletException;
import io.bitsquare.common.UserThread;
import io.bitsquare.gui.components.InputTextField;
import io.bitsquare.gui.main.overlays.Overlay;
import io.bitsquare.gui.main.overlays.popups.Popup;
import javafx.scene.Scene;
import javafx.scene.input.KeyCode;
import org.bitcoinj.core.AddressFormatException;
import org.bitcoinj.core.Coin;
import org.bitcoinj.core.Transaction;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.Nullable;
import java.util.Arrays;
import java.util.List;
import static io.bitsquare.gui.util.FormBuilder.addLabelInputTextField;
public class SpendFromDepositTxWindow extends Overlay<SpendFromDepositTxWindow> {
private static final Logger log = LoggerFactory.getLogger(SpendFromDepositTxWindow.class);
private TradeWalletService tradeWalletService;
///////////////////////////////////////////////////////////////////////////////////////////
// Public API
///////////////////////////////////////////////////////////////////////////////////////////
public SpendFromDepositTxWindow(TradeWalletService tradeWalletService) {
this.tradeWalletService = tradeWalletService;
type = Type.Attention;
}
public void show() {
if (headLine == null)
headLine = "Emergency MS payout tool";
width = 1000;
createGridPane();
addHeadLine();
addSeparator();
addContent();
addCloseButton();
applyStyles();
display();
}
///////////////////////////////////////////////////////////////////////////////////////////
// Protected
///////////////////////////////////////////////////////////////////////////////////////////
@Override
protected void setupKeyHandler(Scene scene) {
if (!hideCloseButton) {
scene.setOnKeyPressed(e -> {
if (e.getCode() == KeyCode.ESCAPE) {
e.consume();
doClose();
}
});
}
}
private void addContent() {
InputTextField depositTxHex = addLabelInputTextField(gridPane, ++rowIndex, "depositTxHex:").second;
InputTextField buyerPayoutAmount = addLabelInputTextField(gridPane, ++rowIndex, "buyerPayoutAmount:").second;
InputTextField sellerPayoutAmount = addLabelInputTextField(gridPane, ++rowIndex, "sellerPayoutAmount:").second;
InputTextField arbitratorPayoutAmount = addLabelInputTextField(gridPane, ++rowIndex, "arbitratorPayoutAmount:").second;
InputTextField buyerAddressString = addLabelInputTextField(gridPane, ++rowIndex, "buyerAddressString:").second;
InputTextField sellerAddressString = addLabelInputTextField(gridPane, ++rowIndex, "sellerAddressString:").second;
InputTextField arbitratorAddressString = addLabelInputTextField(gridPane, ++rowIndex, "arbitratorAddressString:").second;
InputTextField buyerPrivateKeyAsHex = addLabelInputTextField(gridPane, ++rowIndex, "buyerPrivateKeyAsHex:").second;
InputTextField sellerPrivateKeyAsHex = addLabelInputTextField(gridPane, ++rowIndex, "sellerPrivateKeyAsHex:").second;
InputTextField arbitratorPrivateKeyAsHex = addLabelInputTextField(gridPane, ++rowIndex, "arbitratorPrivateKeyAsHex:").second;
InputTextField buyerPubKeyAsHex = addLabelInputTextField(gridPane, ++rowIndex, "buyerPubKeyAsHex:").second;
InputTextField sellerPubKeyAsHex = addLabelInputTextField(gridPane, ++rowIndex, "sellerPubKeyAsHex:").second;
InputTextField arbitratorPubKeyAsHex = addLabelInputTextField(gridPane, ++rowIndex, "arbitratorPubKeyAsHex:").second;
InputTextField P2SHMultiSigOutputScript = addLabelInputTextField(gridPane, ++rowIndex, "P2SHMultiSigOutputScript:").second;
InputTextField buyerPubKeysInputTextField = addLabelInputTextField(gridPane, ++rowIndex, "buyerPubKeys:").second;
InputTextField sellerPubKeysInputTextField = addLabelInputTextField(gridPane, ++rowIndex, "sellerPubKeys:").second;
List<String> buyerPubKeys = Arrays.asList(buyerPubKeysInputTextField.getText().split(","));
List<String> sellerPubKeys = Arrays.asList(sellerPubKeysInputTextField.getText().split(","));
/*
depositTxHex.setText("");
buyerPayoutAmount.setText("1.01");
sellerPayoutAmount.setText("0.01");
arbitratorPayoutAmount.setText("0");
buyerAddressString.setText("");
buyerPubKeyAsHex.setText("");
buyerPrivateKeyAsHex.setText("");
sellerAddressString.setText("");
sellerPubKeyAsHex.setText("");
sellerPrivateKeyAsHex.setText("");
arbitratorAddressString.setText("19xdeiQM2Hn2M2wbpT5imcYWzqhiSDHPy4");
arbitratorPubKeyAsHex.setText("02c62e794fe67f3a2115e2de4757143ff7f27bdf38aa4ae58a3595baa6d676875b");
arbitratorAddressString.setText("1FdFzBazmHQxbUbdCUJwuCtR37DrZrEobu");
arbitratorPubKeyAsHex.setText("030fdc2ebc297df4047442f6079f1ce3b7d1938a41f88bd11497545cc94fcfd315");
P2SHMultiSigOutputScript.setText("");
sellerPubKeys = Arrays.asList();
*/
actionButtonText("Sign and publish transaction");
final List<String> finalSellerPubKeys = sellerPubKeys;
FutureCallback<Transaction> callback = new FutureCallback<Transaction>() {
@Override
public void onSuccess(@Nullable Transaction result) {
log.error("onSuccess");
UserThread.execute(() -> {
String txId = result != null ? result.getHashAsString() : "null";
new Popup<>()
.information("Transaction successful published. Transaction ID: " + txId)
.show();
});
}
@Override
public void onFailure(Throwable t) {
log.error(t.toString());
log.error("onFailure");
UserThread.execute(() -> new Popup<>().warning(t.toString()).show());
}
};
onAction(() -> {
try {
tradeWalletService.emergencySignAndPublishPayoutTx(depositTxHex.getText(),
Coin.parseCoin(buyerPayoutAmount.getText()),
Coin.parseCoin(sellerPayoutAmount.getText()),
Coin.parseCoin(arbitratorPayoutAmount.getText()),
buyerAddressString.getText(),
sellerAddressString.getText(),
arbitratorAddressString.getText(),
buyerPrivateKeyAsHex.getText(),
sellerPrivateKeyAsHex.getText(),
arbitratorPrivateKeyAsHex.getText(),
buyerPubKeyAsHex.getText(),
sellerPubKeyAsHex.getText(),
arbitratorPubKeyAsHex.getText(),
P2SHMultiSigOutputScript.getText(),
buyerPubKeys,
finalSellerPubKeys,
callback);
} catch (AddressFormatException | WalletException | TransactionVerificationException e) {
log.error(e.toString());
e.printStackTrace();
UserThread.execute(() -> new Popup<>().warning(e.toString()).show());
}
});
}
@Override
protected void addCloseButton() {
super.addCloseButton();
actionButton.setOnAction(event -> actionHandlerOptional.ifPresent(Runnable::run));
}
}

View file

@ -126,7 +126,7 @@ public class PendingTradesView extends ActivatableViewAndModel<VBox, PendingTrad
// we use a hidden emergency shortcut to open support ticket
keyEventEventHandler = event -> {
if (new KeyCodeCombination(KeyCode.O, KeyCombination.SHORTCUT_DOWN).match(event)) {
if (new KeyCodeCombination(KeyCode.O, KeyCombination.SHORTCUT_DOWN).match(event) || new KeyCodeCombination(KeyCode.O, KeyCombination.CONTROL_DOWN).match(event)) {
Popup popup = new Popup();
popup.headLine("Open support ticket")
.message("Please use that only in emergency case if you don't get displayed a \"Open support\" or \"Open dispute\" button.\n\n" +