broadcast tx

This commit is contained in:
Craig Raw 2020-07-30 12:18:45 +02:00
parent 75f5fd2e12
commit c9d7b03afc
6 changed files with 109 additions and 8 deletions

View file

@ -24,6 +24,7 @@ public class BalanceChart extends LineChart<Number, Number> {
}
public void initialize(WalletTransactionsEntry walletTransactionsEntry) {
managedProperty().bind(visibleProperty());
balanceSeries = new XYChart.Series<>();
getData().add(balanceSeries);
update(walletTransactionsEntry);
@ -33,6 +34,10 @@ public class BalanceChart extends LineChart<Number, Number> {
}
public void update(WalletTransactionsEntry walletTransactionsEntry) {
if(walletTransactionsEntry.getChildren().isEmpty()) {
setVisible(false);
}
balanceSeries.getData().clear();
List<Data<Number, Number>> balanceDataList = walletTransactionsEntry.getChildren().stream()

View file

@ -4,6 +4,7 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.github.arteam.simplejsonrpc.client.*;
import com.github.arteam.simplejsonrpc.client.builder.BatchRequestBuilder;
import com.github.arteam.simplejsonrpc.client.exception.JsonRpcBatchException;
import com.github.arteam.simplejsonrpc.client.exception.JsonRpcException;
import com.github.arteam.simplejsonrpc.core.annotation.JsonRpcMethod;
import com.github.arteam.simplejsonrpc.core.annotation.JsonRpcParam;
import com.github.arteam.simplejsonrpc.core.annotation.JsonRpcService;
@ -594,6 +595,26 @@ public class ElectrumServer {
return targetBlocksFeeRatesSats;
}
public Sha256Hash broadcastTransaction(Transaction transaction) throws ServerException {
byte[] rawtxBytes = transaction.bitcoinSerialize();
String rawtxHex = Utils.bytesToHex(rawtxBytes);
JsonRpcClient client = new JsonRpcClient(getTransport());
try {
String strTxHash = client.createRequest().returnAs(String.class).method("blockchain.transaction.broadcast").id(1).param("raw_tx", rawtxHex).execute();
Sha256Hash receivedTxid = Sha256Hash.wrap(strTxHash);
if(!receivedTxid.equals(transaction.getTxId())) {
throw new ServerException("Received txid was different (" + receivedTxid + ")");
}
return receivedTxid;
} catch(JsonRpcException e) {
throw new ServerException(e.getErrorMessage().getMessage());
} catch(IllegalStateException e) {
throw new ServerException(e.getMessage());
}
}
public static String getScriptHash(Wallet wallet, WalletNode node) {
byte[] hash = Sha256Hash.hash(wallet.getOutputScript(node).getProgram());
byte[] reversed = Utils.reverseBytes(hash);
@ -1139,6 +1160,24 @@ public class ElectrumServer {
}
}
public static class BroadcastTransactionService extends Service<Sha256Hash> {
private final Transaction transaction;
public BroadcastTransactionService(Transaction transaction) {
this.transaction = transaction;
}
@Override
protected Task<Sha256Hash> createTask() {
return new Task<>() {
protected Sha256Hash call() throws ServerException {
ElectrumServer electrumServer = new ElectrumServer();
return electrumServer.broadcastTransaction(transaction);
}
};
}
}
public enum Protocol {
TCP {
@Override

View file

@ -10,6 +10,7 @@ import com.sparrowwallet.sparrow.EventManager;
import com.sparrowwallet.sparrow.control.*;
import com.sparrowwallet.sparrow.event.*;
import com.sparrowwallet.sparrow.glyphfont.FontAwesome5Brands;
import com.sparrowwallet.sparrow.io.ElectrumServer;
import com.sparrowwallet.sparrow.io.Storage;
import javafx.collections.FXCollections;
import javafx.event.ActionEvent;
@ -154,6 +155,9 @@ public class HeadersController extends TransactionFormController implements Init
@FXML
private SignaturesProgressBar signaturesProgressBar;
@FXML
private ProgressBar broadcastProgressBar;
@FXML
private HBox signButtonBox;
@ -163,6 +167,12 @@ public class HeadersController extends TransactionFormController implements Init
@FXML
private HBox broadcastButtonBox;
@FXML
private Button viewFinalButton;
@FXML
private Button broadcastButton;
@Override
public void initialize(URL location, ResourceBundle resources) {
EventManager.get().register(this);
@ -302,6 +312,10 @@ public class HeadersController extends TransactionFormController implements Init
signButtonBox.managedProperty().bind(signButtonBox.visibleProperty());
broadcastButtonBox.managedProperty().bind(broadcastButtonBox.visibleProperty());
signaturesProgressBar.managedProperty().bind(signaturesProgressBar.visibleProperty());
broadcastProgressBar.managedProperty().bind(broadcastProgressBar.visibleProperty());
broadcastProgressBar.visibleProperty().bind(signaturesProgressBar.visibleProperty().not());
blockchainForm.setVisible(false);
signingWalletForm.setVisible(false);
sigHashForm.setVisible(false);
@ -312,7 +326,7 @@ public class HeadersController extends TransactionFormController implements Init
if(headersForm.getBlockTransaction() != null) {
blockchainForm.setVisible(true);
updateBlockchainForm(headersForm.getBlockTransaction());
updateBlockchainForm(headersForm.getBlockTransaction(), AppController.getCurrentBlockHeight());
} else if(headersForm.getPsbt() != null) {
PSBT psbt = headersForm.getPsbt();
@ -397,10 +411,9 @@ public class HeadersController extends TransactionFormController implements Init
feeRate.setText(String.format("%.2f", feeRateAmt) + " sats/vByte");
}
private void updateBlockchainForm(BlockTransaction blockTransaction) {
private void updateBlockchainForm(BlockTransaction blockTransaction, Integer currentHeight) {
blockchainForm.setVisible(true);
Integer currentHeight = AppController.getCurrentBlockHeight();
if(currentHeight == null) {
blockStatus.setText("Unknown");
} else {
@ -604,7 +617,6 @@ public class HeadersController extends TransactionFormController implements Init
}
public void extractTransaction(ActionEvent event) {
Button viewFinalButton = (Button)event.getSource();
viewFinalButton.setDisable(true);
Transaction finalTx = headersForm.getPsbt().extractTransaction();
@ -613,9 +625,22 @@ public class HeadersController extends TransactionFormController implements Init
}
public void broadcastTransaction(ActionEvent event) {
broadcastButton.setDisable(true);
extractTransaction(event);
ElectrumServer.BroadcastTransactionService broadcastTransactionService = new ElectrumServer.BroadcastTransactionService(headersForm.getTransaction());
broadcastTransactionService.setOnSucceeded(workerStateEvent -> {
//Do nothing and wait for WalletNodeHistoryChangedEvent to indicate tx is in mempool
});
broadcastTransactionService.setOnFailed(workerStateEvent -> {
broadcastProgressBar.setProgress(0);
AppController.showErrorDialog("Error broadcasting transaction", workerStateEvent.getSource().getException().getMessage());
broadcastButton.setDisable(false);
});
signaturesProgressBar.setVisible(false);
broadcastProgressBar.setProgress(-1);
broadcastTransactionService.start();
}
@Subscribe
@ -635,7 +660,7 @@ public class HeadersController extends TransactionFormController implements Init
public void blockTransactionFetched(BlockTransactionFetchedEvent event) {
if(event.getTxId().equals(headersForm.getTransaction().getTxId())) {
if(event.getBlockTransaction() != null) {
updateBlockchainForm(event.getBlockTransaction());
updateBlockchainForm(event.getBlockTransaction(), AppController.getCurrentBlockHeight());
}
Long feeAmt = calculateFee(event.getInputTransactions());
@ -766,4 +791,29 @@ public class HeadersController extends TransactionFormController implements Init
updateTxId();
}
}
@Subscribe
public void walletNodeHistoryChanged(WalletNodeHistoryChangedEvent event) {
if(headersForm.getSigningWallet() != null && event.getWalletNode(headersForm.getSigningWallet()) != null) {
Sha256Hash txid = headersForm.getTransaction().getTxId();
ElectrumServer.TransactionReferenceService transactionReferenceService = new ElectrumServer.TransactionReferenceService(Set.of(txid));
transactionReferenceService.setOnSucceeded(successEvent -> {
Map<Sha256Hash, BlockTransaction> transactionMap = transactionReferenceService.getValue();
BlockTransaction blockTransaction = transactionMap.get(txid);
if(blockTransaction != null) {
headersForm.setBlockTransaction(blockTransaction);
signaturesForm.setVisible(false);
updateBlockchainForm(blockTransaction, AppController.getCurrentBlockHeight());
}
});
transactionReferenceService.start();
}
}
@Subscribe
public void walletBlockHeightChanged(WalletBlockHeightChangedEvent event) {
if(headersForm.getSigningWallet() != null && event.getWallet() == headersForm.getSigningWallet() && headersForm.getBlockTransaction() != null) {
updateBlockchainForm(headersForm.getBlockTransaction(), event.getBlockHeight());
}
}
}

View file

@ -1,6 +1,7 @@
package com.sparrowwallet.sparrow.transaction;
import com.sparrowwallet.drongo.protocol.Transaction;
import com.sparrowwallet.drongo.wallet.BlockTransaction;
import javafx.fxml.FXMLLoader;
import javafx.scene.Node;
@ -15,6 +16,10 @@ public class HeadersForm extends TransactionForm {
txdata.setTransaction(finalTransaction);
}
void setBlockTransaction(BlockTransaction blockTransaction) {
txdata.setBlockTransaction(blockTransaction);
}
@Override
public Node getContents() throws IOException {
FXMLLoader loader = new FXMLLoader(getClass().getResource("headers.fxml"));

View file

@ -46,7 +46,7 @@
-fx-max-width: Infinity;
}
.signatures-progress-bar {
.signatures-progress-bar, #broadcastProgressBar {
-fx-padding: 10 0 10 0;
}

View file

@ -22,6 +22,7 @@
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.Hyperlink?>
<?import com.sparrowwallet.sparrow.control.SignaturesProgressBar?>
<?import javafx.scene.control.ProgressBar?>
<GridPane hgap="10.0" vgap="10.0" styleClass="tx-pane" xmlns="http://javafx.com/javafx/10.0.2-internal" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.sparrowwallet.sparrow.transaction.HeadersController" stylesheets="@headers.css, @transaction.css, @../general.css">
<padding>
@ -174,6 +175,7 @@
<Fieldset text="Signatures" inputGrow="SOMETIMES">
<VBox>
<SignaturesProgressBar fx:id="signaturesProgressBar" />
<ProgressBar fx:id="broadcastProgressBar" maxWidth="Infinity" prefHeight="50" />
</VBox>
<VBox>
<HBox fx:id="signButtonBox" styleClass="signatures-buttons" spacing="20">
@ -212,12 +214,12 @@
</Button>
</HBox>
<HBox fx:id="broadcastButtonBox" styleClass="signatures-buttons" spacing="20">
<Button HBox.hgrow="ALWAYS" text="View Final Transaction" contentDisplay="TOP" wrapText="true" textAlignment="CENTER" onAction="#extractTransaction">
<Button fx:id="viewFinalButton" HBox.hgrow="ALWAYS" text="View Final Transaction" contentDisplay="TOP" wrapText="true" textAlignment="CENTER" onAction="#extractTransaction">
<graphic>
<Glyph fontFamily="Font Awesome 5 Free Solid" fontSize="20" icon="SEARCH" />
</graphic>
</Button>
<Button defaultButton="true" HBox.hgrow="ALWAYS" text="Broadcast Transaction" contentDisplay="TOP" wrapText="true" textAlignment="CENTER" onAction="#broadcastTransaction">
<Button fx:id="broadcastButton" defaultButton="true" HBox.hgrow="ALWAYS" text="Broadcast Transaction" contentDisplay="TOP" wrapText="true" textAlignment="CENTER" onAction="#broadcastTransaction">
<graphic>
<Glyph fontFamily="Font Awesome 5 Free Solid" fontSize="20" icon="SATELLITE_DISH" />
</graphic>