mirror of
https://github.com/sparrowwallet/sparrow.git
synced 2024-11-04 21:36:45 +00:00
broadcast tx
This commit is contained in:
parent
75f5fd2e12
commit
c9d7b03afc
6 changed files with 109 additions and 8 deletions
|
@ -24,6 +24,7 @@ public class BalanceChart extends LineChart<Number, Number> {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void initialize(WalletTransactionsEntry walletTransactionsEntry) {
|
public void initialize(WalletTransactionsEntry walletTransactionsEntry) {
|
||||||
|
managedProperty().bind(visibleProperty());
|
||||||
balanceSeries = new XYChart.Series<>();
|
balanceSeries = new XYChart.Series<>();
|
||||||
getData().add(balanceSeries);
|
getData().add(balanceSeries);
|
||||||
update(walletTransactionsEntry);
|
update(walletTransactionsEntry);
|
||||||
|
@ -33,6 +34,10 @@ public class BalanceChart extends LineChart<Number, Number> {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void update(WalletTransactionsEntry walletTransactionsEntry) {
|
public void update(WalletTransactionsEntry walletTransactionsEntry) {
|
||||||
|
if(walletTransactionsEntry.getChildren().isEmpty()) {
|
||||||
|
setVisible(false);
|
||||||
|
}
|
||||||
|
|
||||||
balanceSeries.getData().clear();
|
balanceSeries.getData().clear();
|
||||||
|
|
||||||
List<Data<Number, Number>> balanceDataList = walletTransactionsEntry.getChildren().stream()
|
List<Data<Number, Number>> balanceDataList = walletTransactionsEntry.getChildren().stream()
|
||||||
|
|
|
@ -4,6 +4,7 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||||
import com.github.arteam.simplejsonrpc.client.*;
|
import com.github.arteam.simplejsonrpc.client.*;
|
||||||
import com.github.arteam.simplejsonrpc.client.builder.BatchRequestBuilder;
|
import com.github.arteam.simplejsonrpc.client.builder.BatchRequestBuilder;
|
||||||
import com.github.arteam.simplejsonrpc.client.exception.JsonRpcBatchException;
|
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.JsonRpcMethod;
|
||||||
import com.github.arteam.simplejsonrpc.core.annotation.JsonRpcParam;
|
import com.github.arteam.simplejsonrpc.core.annotation.JsonRpcParam;
|
||||||
import com.github.arteam.simplejsonrpc.core.annotation.JsonRpcService;
|
import com.github.arteam.simplejsonrpc.core.annotation.JsonRpcService;
|
||||||
|
@ -594,6 +595,26 @@ public class ElectrumServer {
|
||||||
return targetBlocksFeeRatesSats;
|
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) {
|
public static String getScriptHash(Wallet wallet, WalletNode node) {
|
||||||
byte[] hash = Sha256Hash.hash(wallet.getOutputScript(node).getProgram());
|
byte[] hash = Sha256Hash.hash(wallet.getOutputScript(node).getProgram());
|
||||||
byte[] reversed = Utils.reverseBytes(hash);
|
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 {
|
public enum Protocol {
|
||||||
TCP {
|
TCP {
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -10,6 +10,7 @@ import com.sparrowwallet.sparrow.EventManager;
|
||||||
import com.sparrowwallet.sparrow.control.*;
|
import com.sparrowwallet.sparrow.control.*;
|
||||||
import com.sparrowwallet.sparrow.event.*;
|
import com.sparrowwallet.sparrow.event.*;
|
||||||
import com.sparrowwallet.sparrow.glyphfont.FontAwesome5Brands;
|
import com.sparrowwallet.sparrow.glyphfont.FontAwesome5Brands;
|
||||||
|
import com.sparrowwallet.sparrow.io.ElectrumServer;
|
||||||
import com.sparrowwallet.sparrow.io.Storage;
|
import com.sparrowwallet.sparrow.io.Storage;
|
||||||
import javafx.collections.FXCollections;
|
import javafx.collections.FXCollections;
|
||||||
import javafx.event.ActionEvent;
|
import javafx.event.ActionEvent;
|
||||||
|
@ -154,6 +155,9 @@ public class HeadersController extends TransactionFormController implements Init
|
||||||
@FXML
|
@FXML
|
||||||
private SignaturesProgressBar signaturesProgressBar;
|
private SignaturesProgressBar signaturesProgressBar;
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private ProgressBar broadcastProgressBar;
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private HBox signButtonBox;
|
private HBox signButtonBox;
|
||||||
|
|
||||||
|
@ -163,6 +167,12 @@ public class HeadersController extends TransactionFormController implements Init
|
||||||
@FXML
|
@FXML
|
||||||
private HBox broadcastButtonBox;
|
private HBox broadcastButtonBox;
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private Button viewFinalButton;
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private Button broadcastButton;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void initialize(URL location, ResourceBundle resources) {
|
public void initialize(URL location, ResourceBundle resources) {
|
||||||
EventManager.get().register(this);
|
EventManager.get().register(this);
|
||||||
|
@ -302,6 +312,10 @@ public class HeadersController extends TransactionFormController implements Init
|
||||||
signButtonBox.managedProperty().bind(signButtonBox.visibleProperty());
|
signButtonBox.managedProperty().bind(signButtonBox.visibleProperty());
|
||||||
broadcastButtonBox.managedProperty().bind(broadcastButtonBox.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);
|
blockchainForm.setVisible(false);
|
||||||
signingWalletForm.setVisible(false);
|
signingWalletForm.setVisible(false);
|
||||||
sigHashForm.setVisible(false);
|
sigHashForm.setVisible(false);
|
||||||
|
@ -312,7 +326,7 @@ public class HeadersController extends TransactionFormController implements Init
|
||||||
|
|
||||||
if(headersForm.getBlockTransaction() != null) {
|
if(headersForm.getBlockTransaction() != null) {
|
||||||
blockchainForm.setVisible(true);
|
blockchainForm.setVisible(true);
|
||||||
updateBlockchainForm(headersForm.getBlockTransaction());
|
updateBlockchainForm(headersForm.getBlockTransaction(), AppController.getCurrentBlockHeight());
|
||||||
} else if(headersForm.getPsbt() != null) {
|
} else if(headersForm.getPsbt() != null) {
|
||||||
PSBT psbt = headersForm.getPsbt();
|
PSBT psbt = headersForm.getPsbt();
|
||||||
|
|
||||||
|
@ -397,10 +411,9 @@ public class HeadersController extends TransactionFormController implements Init
|
||||||
feeRate.setText(String.format("%.2f", feeRateAmt) + " sats/vByte");
|
feeRate.setText(String.format("%.2f", feeRateAmt) + " sats/vByte");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateBlockchainForm(BlockTransaction blockTransaction) {
|
private void updateBlockchainForm(BlockTransaction blockTransaction, Integer currentHeight) {
|
||||||
blockchainForm.setVisible(true);
|
blockchainForm.setVisible(true);
|
||||||
|
|
||||||
Integer currentHeight = AppController.getCurrentBlockHeight();
|
|
||||||
if(currentHeight == null) {
|
if(currentHeight == null) {
|
||||||
blockStatus.setText("Unknown");
|
blockStatus.setText("Unknown");
|
||||||
} else {
|
} else {
|
||||||
|
@ -604,7 +617,6 @@ public class HeadersController extends TransactionFormController implements Init
|
||||||
}
|
}
|
||||||
|
|
||||||
public void extractTransaction(ActionEvent event) {
|
public void extractTransaction(ActionEvent event) {
|
||||||
Button viewFinalButton = (Button)event.getSource();
|
|
||||||
viewFinalButton.setDisable(true);
|
viewFinalButton.setDisable(true);
|
||||||
|
|
||||||
Transaction finalTx = headersForm.getPsbt().extractTransaction();
|
Transaction finalTx = headersForm.getPsbt().extractTransaction();
|
||||||
|
@ -613,9 +625,22 @@ public class HeadersController extends TransactionFormController implements Init
|
||||||
}
|
}
|
||||||
|
|
||||||
public void broadcastTransaction(ActionEvent event) {
|
public void broadcastTransaction(ActionEvent event) {
|
||||||
|
broadcastButton.setDisable(true);
|
||||||
extractTransaction(event);
|
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
|
@Subscribe
|
||||||
|
@ -635,7 +660,7 @@ public class HeadersController extends TransactionFormController implements Init
|
||||||
public void blockTransactionFetched(BlockTransactionFetchedEvent event) {
|
public void blockTransactionFetched(BlockTransactionFetchedEvent event) {
|
||||||
if(event.getTxId().equals(headersForm.getTransaction().getTxId())) {
|
if(event.getTxId().equals(headersForm.getTransaction().getTxId())) {
|
||||||
if(event.getBlockTransaction() != null) {
|
if(event.getBlockTransaction() != null) {
|
||||||
updateBlockchainForm(event.getBlockTransaction());
|
updateBlockchainForm(event.getBlockTransaction(), AppController.getCurrentBlockHeight());
|
||||||
}
|
}
|
||||||
|
|
||||||
Long feeAmt = calculateFee(event.getInputTransactions());
|
Long feeAmt = calculateFee(event.getInputTransactions());
|
||||||
|
@ -766,4 +791,29 @@ public class HeadersController extends TransactionFormController implements Init
|
||||||
updateTxId();
|
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());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
package com.sparrowwallet.sparrow.transaction;
|
package com.sparrowwallet.sparrow.transaction;
|
||||||
|
|
||||||
import com.sparrowwallet.drongo.protocol.Transaction;
|
import com.sparrowwallet.drongo.protocol.Transaction;
|
||||||
|
import com.sparrowwallet.drongo.wallet.BlockTransaction;
|
||||||
import javafx.fxml.FXMLLoader;
|
import javafx.fxml.FXMLLoader;
|
||||||
import javafx.scene.Node;
|
import javafx.scene.Node;
|
||||||
|
|
||||||
|
@ -15,6 +16,10 @@ public class HeadersForm extends TransactionForm {
|
||||||
txdata.setTransaction(finalTransaction);
|
txdata.setTransaction(finalTransaction);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setBlockTransaction(BlockTransaction blockTransaction) {
|
||||||
|
txdata.setBlockTransaction(blockTransaction);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Node getContents() throws IOException {
|
public Node getContents() throws IOException {
|
||||||
FXMLLoader loader = new FXMLLoader(getClass().getResource("headers.fxml"));
|
FXMLLoader loader = new FXMLLoader(getClass().getResource("headers.fxml"));
|
||||||
|
|
|
@ -46,7 +46,7 @@
|
||||||
-fx-max-width: Infinity;
|
-fx-max-width: Infinity;
|
||||||
}
|
}
|
||||||
|
|
||||||
.signatures-progress-bar {
|
.signatures-progress-bar, #broadcastProgressBar {
|
||||||
-fx-padding: 10 0 10 0;
|
-fx-padding: 10 0 10 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
<?import javafx.scene.control.Label?>
|
<?import javafx.scene.control.Label?>
|
||||||
<?import javafx.scene.control.Hyperlink?>
|
<?import javafx.scene.control.Hyperlink?>
|
||||||
<?import com.sparrowwallet.sparrow.control.SignaturesProgressBar?>
|
<?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">
|
<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>
|
<padding>
|
||||||
|
@ -174,6 +175,7 @@
|
||||||
<Fieldset text="Signatures" inputGrow="SOMETIMES">
|
<Fieldset text="Signatures" inputGrow="SOMETIMES">
|
||||||
<VBox>
|
<VBox>
|
||||||
<SignaturesProgressBar fx:id="signaturesProgressBar" />
|
<SignaturesProgressBar fx:id="signaturesProgressBar" />
|
||||||
|
<ProgressBar fx:id="broadcastProgressBar" maxWidth="Infinity" prefHeight="50" />
|
||||||
</VBox>
|
</VBox>
|
||||||
<VBox>
|
<VBox>
|
||||||
<HBox fx:id="signButtonBox" styleClass="signatures-buttons" spacing="20">
|
<HBox fx:id="signButtonBox" styleClass="signatures-buttons" spacing="20">
|
||||||
|
@ -212,12 +214,12 @@
|
||||||
</Button>
|
</Button>
|
||||||
</HBox>
|
</HBox>
|
||||||
<HBox fx:id="broadcastButtonBox" styleClass="signatures-buttons" spacing="20">
|
<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>
|
<graphic>
|
||||||
<Glyph fontFamily="Font Awesome 5 Free Solid" fontSize="20" icon="SEARCH" />
|
<Glyph fontFamily="Font Awesome 5 Free Solid" fontSize="20" icon="SEARCH" />
|
||||||
</graphic>
|
</graphic>
|
||||||
</Button>
|
</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>
|
<graphic>
|
||||||
<Glyph fontFamily="Font Awesome 5 Free Solid" fontSize="20" icon="SATELLITE_DISH" />
|
<Glyph fontFamily="Font Awesome 5 Free Solid" fontSize="20" icon="SATELLITE_DISH" />
|
||||||
</graphic>
|
</graphic>
|
||||||
|
|
Loading…
Reference in a new issue