view extracted transaction from psbt

This commit is contained in:
Craig Raw 2020-07-28 13:14:11 +02:00
parent 658ab2f81c
commit 29cfda7908
10 changed files with 125 additions and 25 deletions

View file

@ -0,0 +1,20 @@
package com.sparrowwallet.sparrow.event;
import com.sparrowwallet.drongo.protocol.Transaction;
import com.sparrowwallet.drongo.psbt.PSBT;
/**
* This event is fired when a final transaction has been extracted from a PSBT
*/
public class TransactionExtractedEvent extends PSBTEvent {
private final Transaction finalTransaction;
public TransactionExtractedEvent(PSBT psbt, Transaction finalTransaction) {
super(psbt);
this.finalTransaction = finalTransaction;
}
public Transaction getFinalTransaction() {
return finalTransaction;
}
}

View file

@ -31,6 +31,7 @@ public class FontAwesome5 extends GlyphFont {
PEN_FANCY('\uf5ac'), PEN_FANCY('\uf5ac'),
QRCODE('\uf029'), QRCODE('\uf029'),
QUESTION_CIRCLE('\uf059'), QUESTION_CIRCLE('\uf059'),
SATELLITE_DISH('\uf7c0'),
SD_CARD('\uf7c2'), SD_CARD('\uf7c2'),
SEARCH('\uf002'), SEARCH('\uf002'),
TOOLS('\uf7d9'), TOOLS('\uf7d9'),

View file

@ -669,7 +669,7 @@ public class ElectrumServer {
} }
public BlockTransaction getBlockTransaction() { public BlockTransaction getBlockTransaction() {
return new BlockTransaction(Sha256Hash.wrap(txid), getHeight(), getDate(), 0L, new Transaction(Utils.hexToBytes(hex)), Sha256Hash.wrap(blockhash)); return new BlockTransaction(Sha256Hash.wrap(txid), getHeight(), getDate(), 0L, new Transaction(Utils.hexToBytes(hex)), blockhash == null ? null : Sha256Hash.wrap(blockhash));
} }
} }

View file

@ -21,6 +21,7 @@ import javafx.fxml.Initializable;
import javafx.scene.control.*; import javafx.scene.control.*;
import javafx.scene.input.Clipboard; import javafx.scene.input.Clipboard;
import javafx.scene.input.ClipboardContent; import javafx.scene.input.ClipboardContent;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox; import javafx.scene.layout.VBox;
import javafx.stage.FileChooser; import javafx.stage.FileChooser;
import javafx.stage.Stage; import javafx.stage.Stage;
@ -107,12 +108,21 @@ public class HeadersController extends TransactionFormController implements Init
@FXML @FXML
private CopyableLabel blockStatus; private CopyableLabel blockStatus;
@FXML
private Field blockHeightField;
@FXML @FXML
private CopyableLabel blockHeight; private CopyableLabel blockHeight;
@FXML
private Field blockTimestampField;
@FXML @FXML
private CopyableLabel blockTimestamp; private CopyableLabel blockTimestamp;
@FXML
private Field blockHashField;
@FXML @FXML
private IdLabel blockHash; private IdLabel blockHash;
@ -146,11 +156,14 @@ public class HeadersController extends TransactionFormController implements Init
@FXML @FXML
private SignaturesProgressBar signaturesProgressBar; private SignaturesProgressBar signaturesProgressBar;
@FXML
private HBox signButtonBox;
@FXML @FXML
private Button signButton; private Button signButton;
@FXML @FXML
private Form broadcastForm; private HBox broadcastButtonBox;
@Override @Override
public void initialize(URL location, ResourceBundle resources) { public void initialize(URL location, ResourceBundle resources) {
@ -290,12 +303,14 @@ public class HeadersController extends TransactionFormController implements Init
finalizeButtonBox.visibleProperty().bind(signingWalletForm.visibleProperty()); finalizeButtonBox.visibleProperty().bind(signingWalletForm.visibleProperty());
signaturesForm.managedProperty().bind(signaturesForm.visibleProperty()); signaturesForm.managedProperty().bind(signaturesForm.visibleProperty());
broadcastForm.managedProperty().bind(broadcastForm.visibleProperty()); signButtonBox.managedProperty().bind(signButtonBox.visibleProperty());
broadcastButtonBox.managedProperty().bind(broadcastButtonBox.visibleProperty());
blockchainForm.setVisible(false); blockchainForm.setVisible(false);
signingWalletForm.setVisible(false); signingWalletForm.setVisible(false);
signaturesForm.setVisible(false); signaturesForm.setVisible(false);
broadcastForm.setVisible(false); signButtonBox.setVisible(false);
broadcastButtonBox.setVisible(false);
if(headersForm.getBlockTransaction() != null) { if(headersForm.getBlockTransaction() != null) {
blockchainForm.setVisible(true); blockchainForm.setVisible(true);
@ -306,9 +321,11 @@ public class HeadersController extends TransactionFormController implements Init
if(headersForm.isEditable()) { if(headersForm.isEditable()) {
signingWalletForm.setVisible(true); signingWalletForm.setVisible(true);
} else if(headersForm.getPsbt().isSigned()) { } else if(headersForm.getPsbt().isSigned()) {
broadcastForm.setVisible(true); signaturesForm.setVisible(true);
broadcastButtonBox.setVisible(true);
} else { } else {
signaturesForm.setVisible(true); signaturesForm.setVisible(true);
signButtonBox.setVisible(true);
} }
EventManager.get().post(new RequestOpenWalletsEvent()); EventManager.get().post(new RequestOpenWalletsEvent());
@ -387,21 +404,32 @@ public class HeadersController extends TransactionFormController implements Init
blockStatus.setText("Unknown"); blockStatus.setText("Unknown");
} else { } else {
int confirmations = currentHeight - blockTransaction.getHeight() + 1; int confirmations = currentHeight - blockTransaction.getHeight() + 1;
blockStatus.setText(confirmations + " Confirmations"); if(confirmations == 0) {
blockStatus.setText("Unconfirmed");
} else if(confirmations == 1) {
blockStatus.setText(confirmations + " Confirmation");
} else {
blockStatus.setText(confirmations + " Confirmations");
}
} }
blockHeight.setText(Integer.toString(blockTransaction.getHeight())); blockHeightField.managedProperty().bind(blockHeightField.visibleProperty());
blockTimestampField.managedProperty().bind(blockTimestampField.visibleProperty());
blockHashField.managedProperty().bind(blockHashField.visibleProperty());
blockTimestampField.visibleProperty().bind(blockHeightField.visibleProperty());
blockHashField.visibleProperty().bind(blockHeightField.visibleProperty());
SimpleDateFormat dateFormat = new SimpleDateFormat(BLOCK_TIMESTAMP_DATE_FORMAT);
blockTimestamp.setText(dateFormat.format(blockTransaction.getDate()));
blockHash.managedProperty().bind(blockHash.visibleProperty());
if(blockTransaction.getBlockHash() != null) { if(blockTransaction.getBlockHash() != null) {
blockHash.setVisible(true); blockHeightField.setVisible(true);
blockHeight.setText(Integer.toString(blockTransaction.getHeight()));
SimpleDateFormat dateFormat = new SimpleDateFormat(BLOCK_TIMESTAMP_DATE_FORMAT);
blockTimestamp.setText(dateFormat.format(blockTransaction.getDate()));
blockHash.setText(blockTransaction.getBlockHash().toString()); blockHash.setText(blockTransaction.getBlockHash().toString());
blockHash.setContextMenu(new BlockHeightContextMenu(blockTransaction.getBlockHash())); blockHash.setContextMenu(new BlockHeightContextMenu(blockTransaction.getBlockHash()));
} else { } else {
blockHash.setVisible(false); blockHeightField.setVisible(false);
} }
} }
@ -563,6 +591,18 @@ public class HeadersController extends TransactionFormController implements Init
}); });
} }
public void extractTransaction(ActionEvent event) {
Transaction finalTx = headersForm.getPsbt().extractTransaction();
headersForm.setFinalTransaction(finalTx);
EventManager.get().post(new TransactionExtractedEvent(headersForm.getPsbt(), finalTx));
}
public void broadcastTransaction(ActionEvent event) {
extractTransaction(event);
}
@Subscribe @Subscribe
public void transactionChanged(TransactionChangedEvent event) { public void transactionChanged(TransactionChangedEvent event) {
if(headersForm.getTransaction().equals(event.getTransaction())) { if(headersForm.getTransaction().equals(event.getTransaction())) {
@ -637,6 +677,7 @@ public class HeadersController extends TransactionFormController implements Init
signingWalletForm.setVisible(false); signingWalletForm.setVisible(false);
signaturesForm.setVisible(true); signaturesForm.setVisible(true);
signButtonBox.setVisible(true);
} }
} }
@ -647,6 +688,14 @@ public class HeadersController extends TransactionFormController implements Init
} }
} }
@Subscribe
public void psbtFinalized(PSBTFinalizedEvent event) {
if(event.getPsbt().equals(headersForm.getPsbt())) {
signButtonBox.setVisible(false);
broadcastButtonBox.setVisible(true);
}
}
@Subscribe @Subscribe
public void keystoreSigned(KeystoreSignedEvent event) { public void keystoreSigned(KeystoreSignedEvent event) {
if(headersForm.getSignedKeystores().contains(event.getKeystore()) && headersForm.getPsbt() != null) { if(headersForm.getSignedKeystores().contains(event.getKeystore()) && headersForm.getPsbt() != null) {

View file

@ -1,5 +1,6 @@
package com.sparrowwallet.sparrow.transaction; package com.sparrowwallet.sparrow.transaction;
import com.sparrowwallet.drongo.protocol.Transaction;
import javafx.fxml.FXMLLoader; import javafx.fxml.FXMLLoader;
import javafx.scene.Node; import javafx.scene.Node;
@ -10,6 +11,10 @@ public class HeadersForm extends TransactionForm {
super(txdata); super(txdata);
} }
void setFinalTransaction(Transaction finalTransaction) {
txdata.setTransaction(finalTransaction);
}
@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"));

View file

@ -535,4 +535,11 @@ public class InputController extends TransactionFormController implements Initia
updateSignatures(inputForm.getPsbtInput()); updateSignatures(inputForm.getPsbtInput());
} }
} }
@Subscribe
public void transactionExtracted(TransactionExtractedEvent event) {
if(event.getPsbt().equals(inputForm.getPsbt())) {
updateScriptFields(event.getFinalTransaction().getInputs().get(inputForm.getIndex()), null);
}
}
} }

View file

@ -490,4 +490,12 @@ public class TransactionController implements Initializable {
txdata.updateOutputsFetchedRange(event.getPageStart(), event.getPageEnd()); txdata.updateOutputsFetchedRange(event.getPageStart(), event.getPageEnd());
} }
} }
@Subscribe
public void transactionExtracted(TransactionExtractedEvent event) {
if(event.getPsbt().equals(getPSBT())) {
txhex.setTransaction(getTransaction());
highlightTxHex();
}
}
} }

View file

@ -16,7 +16,7 @@ import java.util.List;
import java.util.Map; import java.util.Map;
public class TransactionData { public class TransactionData {
private final Transaction transaction; private Transaction transaction;
private String name; private String name;
private PSBT psbt; private PSBT psbt;
private BlockTransaction blockTransaction; private BlockTransaction blockTransaction;
@ -50,6 +50,10 @@ public class TransactionData {
return transaction; return transaction;
} }
public void setTransaction(Transaction transaction) {
this.transaction = transaction;
}
public String getName() { public String getName() {
return name; return name;
} }

View file

@ -17,7 +17,7 @@ import java.util.List;
import java.util.Map; import java.util.Map;
public abstract class TransactionForm { public abstract class TransactionForm {
private final TransactionData txdata; protected final TransactionData txdata;
public TransactionForm(TransactionData txdata) { public TransactionForm(TransactionData txdata) {
this.txdata = txdata; this.txdata = txdata;

View file

@ -117,13 +117,13 @@
<Field text="Status:"> <Field text="Status:">
<CopyableLabel fx:id="blockStatus" /> <CopyableLabel fx:id="blockStatus" />
</Field> </Field>
<Field text="Block Height:"> <Field fx:id="blockHeightField" text="Block Height:">
<CopyableLabel fx:id="blockHeight" /> <CopyableLabel fx:id="blockHeight" />
</Field> </Field>
<Field text="Timestamp:"> <Field fx:id="blockTimestampField" text="Timestamp:">
<CopyableLabel fx:id="blockTimestamp" /> <CopyableLabel fx:id="blockTimestamp" />
</Field> </Field>
<Field text="Block Hash:"> <Field fx:id="blockHashField" text="Block Hash:">
<IdLabel fx:id="blockHash" /> <IdLabel fx:id="blockHash" />
</Field> </Field>
</Fieldset> </Fieldset>
@ -176,7 +176,7 @@
<SignaturesProgressBar fx:id="signaturesProgressBar" /> <SignaturesProgressBar fx:id="signaturesProgressBar" />
</VBox> </VBox>
<VBox> <VBox>
<HBox styleClass="signatures-buttons" spacing="20"> <HBox fx:id="signButtonBox" styleClass="signatures-buttons" spacing="20">
<SegmentedButton HBox.hgrow="ALWAYS"> <SegmentedButton HBox.hgrow="ALWAYS">
<buttons> <buttons>
<ToggleButton HBox.hgrow="ALWAYS" text="Show QR" contentDisplay="TOP" wrapText="true" textAlignment="CENTER" onAction="#showPSBT"> <ToggleButton HBox.hgrow="ALWAYS" text="Show QR" contentDisplay="TOP" wrapText="true" textAlignment="CENTER" onAction="#showPSBT">
@ -211,13 +211,19 @@
</graphic> </graphic>
</Button> </Button>
</HBox> </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">
<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">
<graphic>
<Glyph fontFamily="Font Awesome 5 Free Solid" fontSize="20" icon="SATELLITE_DISH" />
</graphic>
</Button>
</HBox>
</VBox> </VBox>
</Fieldset> </Fieldset>
</Form> </Form>
<Form fx:id="broadcastForm" GridPane.columnIndex="0" GridPane.columnSpan="2" GridPane.rowIndex="6">
<Fieldset text="Send" inputGrow="SOMETIMES">
</Fieldset>
</Form>
</GridPane> </GridPane>