mirror of
https://github.com/sparrowwallet/sparrow.git
synced 2024-12-25 05:06:45 +00:00
deduplicate signed keystores on signature
This commit is contained in:
parent
4d7d51f3f8
commit
b808222faa
7 changed files with 43 additions and 26 deletions
2
drongo
2
drongo
|
@ -1 +1 @@
|
||||||
Subproject commit 55717c31bf8046e558ee90a5997c1de769517813
|
Subproject commit 10035278543d9ca90b11ae3d396edc3e6131fee2
|
|
@ -1,5 +1,6 @@
|
||||||
package com.sparrowwallet.sparrow.control;
|
package com.sparrowwallet.sparrow.control;
|
||||||
|
|
||||||
|
import com.sparrowwallet.drongo.protocol.TransactionSignature;
|
||||||
import com.sparrowwallet.drongo.wallet.Keystore;
|
import com.sparrowwallet.drongo.wallet.Keystore;
|
||||||
import com.sparrowwallet.sparrow.EventManager;
|
import com.sparrowwallet.sparrow.EventManager;
|
||||||
import com.sparrowwallet.sparrow.event.KeystoreSignedEvent;
|
import com.sparrowwallet.sparrow.event.KeystoreSignedEvent;
|
||||||
|
@ -7,8 +8,8 @@ import javafx.animation.KeyFrame;
|
||||||
import javafx.animation.KeyValue;
|
import javafx.animation.KeyValue;
|
||||||
import javafx.animation.Timeline;
|
import javafx.animation.Timeline;
|
||||||
import javafx.beans.property.SimpleObjectProperty;
|
import javafx.beans.property.SimpleObjectProperty;
|
||||||
import javafx.collections.ListChangeListener;
|
import javafx.collections.MapChangeListener;
|
||||||
import javafx.collections.ObservableList;
|
import javafx.collections.ObservableMap;
|
||||||
import javafx.geometry.Insets;
|
import javafx.geometry.Insets;
|
||||||
import javafx.geometry.Orientation;
|
import javafx.geometry.Orientation;
|
||||||
import javafx.geometry.Pos;
|
import javafx.geometry.Pos;
|
||||||
|
@ -18,6 +19,9 @@ import javafx.scene.layout.StackPane;
|
||||||
import javafx.util.Duration;
|
import javafx.util.Duration;
|
||||||
import org.controlsfx.control.SegmentedBar;
|
import org.controlsfx.control.SegmentedBar;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public class SignaturesProgressBar extends SegmentedBar<SignaturesProgressBar.SignatureProgressSegment> {
|
public class SignaturesProgressBar extends SegmentedBar<SignaturesProgressBar.SignatureProgressSegment> {
|
||||||
public SignaturesProgressBar() {
|
public SignaturesProgressBar() {
|
||||||
setOrientation(Orientation.HORIZONTAL);
|
setOrientation(Orientation.HORIZONTAL);
|
||||||
|
@ -25,10 +29,11 @@ public class SignaturesProgressBar extends SegmentedBar<SignaturesProgressBar.Si
|
||||||
setInfoNodeFactory(segment -> segment.getKeystore() == null ? null : new SignatureProgressSegmentLabel(segment.getKeystore().getLabel()));
|
setInfoNodeFactory(segment -> segment.getKeystore() == null ? null : new SignatureProgressSegmentLabel(segment.getKeystore().getLabel()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void initialize(ObservableList<Keystore> signedKeystores, int threshold) {
|
public void initialize(ObservableMap<TransactionSignature, Keystore> signatureKeystoreMap, int threshold) {
|
||||||
getStyleClass().add("signatures-progress-bar");
|
getStyleClass().add("signatures-progress-bar");
|
||||||
getSegments().clear();
|
getSegments().clear();
|
||||||
|
|
||||||
|
List<Keystore> signedKeystores = new ArrayList<>(signatureKeystoreMap.values());
|
||||||
int numSegments = Math.max(threshold, signedKeystores.size());
|
int numSegments = Math.max(threshold, signedKeystores.size());
|
||||||
double segmentSize = 100d / numSegments;
|
double segmentSize = 100d / numSegments;
|
||||||
for(int i = 0; i < numSegments; i++) {
|
for(int i = 0; i < numSegments; i++) {
|
||||||
|
@ -39,19 +44,20 @@ public class SignaturesProgressBar extends SegmentedBar<SignaturesProgressBar.Si
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
signedKeystores.addListener((ListChangeListener<Keystore>) c -> {
|
signatureKeystoreMap.addListener((MapChangeListener<TransactionSignature, Keystore>) c -> {
|
||||||
int numSegments1 = Math.max(threshold, c.getList().size());
|
List<Keystore> newSignedKeystores = new ArrayList<>(c.getMap().values());
|
||||||
double newSegmentSize = 100d / numSegments1;
|
int newNumSegments = Math.max(threshold, newSignedKeystores.size());
|
||||||
|
double newSegmentSize = 100d / newNumSegments;
|
||||||
|
|
||||||
for(int i = 0; i < numSegments1; i++) {
|
for(int i = 0; i < newNumSegments; i++) {
|
||||||
SignatureProgressSegment segment = null;
|
SignatureProgressSegment segment = null;
|
||||||
if(i < getSegments().size()) {
|
if(i < getSegments().size()) {
|
||||||
segment = getSegments().get(i);
|
segment = getSegments().get(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
Keystore signedKeystore = null;
|
Keystore signedKeystore = null;
|
||||||
if(i < signedKeystores.size()) {
|
if(i < newSignedKeystores.size()) {
|
||||||
signedKeystore = signedKeystores.get(i);
|
signedKeystore = newSignedKeystores.get(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(segment != null) {
|
if(segment != null) {
|
||||||
|
|
|
@ -405,7 +405,7 @@ public class HeadersController extends TransactionFormController implements Init
|
||||||
updateSignedKeystores(signingWallet);
|
updateSignedKeystores(signingWallet);
|
||||||
|
|
||||||
int threshold = signingWallet.getDefaultPolicy().getNumSignaturesRequired();
|
int threshold = signingWallet.getDefaultPolicy().getNumSignaturesRequired();
|
||||||
signaturesProgressBar.initialize(headersForm.getSignedKeystores(), threshold);
|
signaturesProgressBar.initialize(headersForm.getSignatureKeystoreMap(), threshold);
|
||||||
});
|
});
|
||||||
|
|
||||||
EventManager.get().post(new RequestOpenWalletsEvent());
|
EventManager.get().post(new RequestOpenWalletsEvent());
|
||||||
|
@ -705,12 +705,11 @@ public class HeadersController extends TransactionFormController implements Init
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateSignedKeystores(Wallet signingWallet) {
|
private void updateSignedKeystores(Wallet signingWallet) {
|
||||||
Map<PSBTInput, List<Keystore>> signedKeystoresMap = signingWallet.getSignedKeystores(headersForm.getPsbt());
|
Map<PSBTInput, Map<TransactionSignature, Keystore>> signedKeystoresMap = signingWallet.getSignedKeystores(headersForm.getPsbt());
|
||||||
Optional<List<Keystore>> optSignedKeystores = signedKeystoresMap.values().stream().filter(list -> !list.isEmpty()).min(Comparator.comparingInt(List::size));
|
Optional<Map<TransactionSignature, Keystore>> optSignedKeystores = signedKeystoresMap.values().stream().filter(map -> !map.isEmpty()).min(Comparator.comparingInt(Map::size));
|
||||||
optSignedKeystores.ifPresent(signedKeystores -> {
|
optSignedKeystores.ifPresent(signedKeystores -> {
|
||||||
List<Keystore> newSignedKeystores = new ArrayList<>(signedKeystores);
|
headersForm.getSignatureKeystoreMap().keySet().retainAll(signedKeystores.keySet());
|
||||||
newSignedKeystores.removeAll(headersForm.getSignedKeystores());
|
headersForm.getSignatureKeystoreMap().putAll(signedKeystores);
|
||||||
headersForm.getSignedKeystores().addAll(newSignedKeystores);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -922,6 +921,7 @@ public class HeadersController extends TransactionFormController implements Init
|
||||||
@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) {
|
||||||
|
//Attempt to finalize PSBT - will do nothing if all inputs are not signed
|
||||||
finalizePSBT();
|
finalizePSBT();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ import com.sparrowwallet.drongo.wallet.Keystore;
|
||||||
import com.sparrowwallet.sparrow.EventManager;
|
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 javafx.collections.ListChangeListener;
|
import javafx.collections.MapChangeListener;
|
||||||
import javafx.fxml.FXML;
|
import javafx.fxml.FXML;
|
||||||
import javafx.fxml.Initializable;
|
import javafx.fxml.Initializable;
|
||||||
import javafx.scene.control.*;
|
import javafx.scene.control.*;
|
||||||
|
@ -126,7 +126,7 @@ public class InputController extends TransactionFormController implements Initia
|
||||||
initializeLocktimeFields(txInput);
|
initializeLocktimeFields(txInput);
|
||||||
|
|
||||||
if(psbtInput != null) {
|
if(psbtInput != null) {
|
||||||
inputForm.getSignedKeystores().addListener((ListChangeListener<Keystore>) c -> {
|
inputForm.getSignatureKeystoreMap().addListener((MapChangeListener<TransactionSignature, Keystore>) c -> {
|
||||||
updateSignatures(inputForm.getPsbtInput());
|
updateSignatures(inputForm.getPsbtInput());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@ import com.sparrowwallet.sparrow.event.BitcoinUnitChangedEvent;
|
||||||
import com.sparrowwallet.sparrow.event.BlockTransactionFetchedEvent;
|
import com.sparrowwallet.sparrow.event.BlockTransactionFetchedEvent;
|
||||||
import com.sparrowwallet.sparrow.event.PSBTCombinedEvent;
|
import com.sparrowwallet.sparrow.event.PSBTCombinedEvent;
|
||||||
import com.sparrowwallet.sparrow.event.PSBTFinalizedEvent;
|
import com.sparrowwallet.sparrow.event.PSBTFinalizedEvent;
|
||||||
import javafx.collections.ListChangeListener;
|
import javafx.collections.MapChangeListener;
|
||||||
import javafx.fxml.FXML;
|
import javafx.fxml.FXML;
|
||||||
import javafx.fxml.Initializable;
|
import javafx.fxml.Initializable;
|
||||||
import javafx.scene.chart.PieChart;
|
import javafx.scene.chart.PieChart;
|
||||||
|
@ -62,7 +62,7 @@ public class InputsController extends TransactionFormController implements Initi
|
||||||
|
|
||||||
if(inputsForm.getPsbt() != null) {
|
if(inputsForm.getPsbt() != null) {
|
||||||
updatePSBTInputs(inputsForm.getPsbt());
|
updatePSBTInputs(inputsForm.getPsbt());
|
||||||
inputsForm.getSignedKeystores().addListener((ListChangeListener<Keystore>) c -> {
|
inputsForm.getSignatureKeystoreMap().addListener((MapChangeListener<TransactionSignature, Keystore>) c -> {
|
||||||
updatePSBTInputs(inputsForm.getPsbt());
|
updatePSBTInputs(inputsForm.getPsbt());
|
||||||
});
|
});
|
||||||
} else if(inputsForm.getInputTransactions() != null) {
|
} else if(inputsForm.getInputTransactions() != null) {
|
||||||
|
|
|
@ -2,6 +2,7 @@ package com.sparrowwallet.sparrow.transaction;
|
||||||
|
|
||||||
import com.sparrowwallet.drongo.protocol.Sha256Hash;
|
import com.sparrowwallet.drongo.protocol.Sha256Hash;
|
||||||
import com.sparrowwallet.drongo.protocol.Transaction;
|
import com.sparrowwallet.drongo.protocol.Transaction;
|
||||||
|
import com.sparrowwallet.drongo.protocol.TransactionSignature;
|
||||||
import com.sparrowwallet.drongo.psbt.PSBT;
|
import com.sparrowwallet.drongo.psbt.PSBT;
|
||||||
import com.sparrowwallet.drongo.wallet.BlockTransaction;
|
import com.sparrowwallet.drongo.wallet.BlockTransaction;
|
||||||
import com.sparrowwallet.drongo.wallet.Keystore;
|
import com.sparrowwallet.drongo.wallet.Keystore;
|
||||||
|
@ -9,9 +10,10 @@ import com.sparrowwallet.drongo.wallet.Wallet;
|
||||||
import com.sparrowwallet.sparrow.io.Storage;
|
import com.sparrowwallet.sparrow.io.Storage;
|
||||||
import javafx.beans.property.SimpleObjectProperty;
|
import javafx.beans.property.SimpleObjectProperty;
|
||||||
import javafx.collections.FXCollections;
|
import javafx.collections.FXCollections;
|
||||||
import javafx.collections.ObservableList;
|
|
||||||
import javafx.collections.ObservableMap;
|
import javafx.collections.ObservableMap;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
@ -30,7 +32,7 @@ public class TransactionData {
|
||||||
|
|
||||||
private final ObservableMap<Wallet, Storage> availableWallets = FXCollections.observableHashMap();
|
private final ObservableMap<Wallet, Storage> availableWallets = FXCollections.observableHashMap();
|
||||||
private final SimpleObjectProperty<Wallet> signingWallet = new SimpleObjectProperty<>(this, "signingWallet", null);
|
private final SimpleObjectProperty<Wallet> signingWallet = new SimpleObjectProperty<>(this, "signingWallet", null);
|
||||||
private final ObservableList<Keystore> signedKeystores = FXCollections.observableArrayList();
|
private final ObservableMap<TransactionSignature, Keystore> signatureKeystoreMap = FXCollections.observableMap(new LinkedHashMap<>());
|
||||||
|
|
||||||
public TransactionData(String name, PSBT psbt) {
|
public TransactionData(String name, PSBT psbt) {
|
||||||
this(name, psbt.getTransaction());
|
this(name, psbt.getTransaction());
|
||||||
|
@ -147,7 +149,11 @@ public class TransactionData {
|
||||||
this.signingWallet.set(wallet);
|
this.signingWallet.set(wallet);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ObservableList<Keystore> getSignedKeystores() {
|
public ObservableMap<TransactionSignature, Keystore> getSignatureKeystoreMap() {
|
||||||
return signedKeystores;
|
return signatureKeystoreMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Collection<Keystore> getSignedKeystores() {
|
||||||
|
return signatureKeystoreMap.values();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,17 +2,18 @@ package com.sparrowwallet.sparrow.transaction;
|
||||||
|
|
||||||
import com.sparrowwallet.drongo.protocol.Sha256Hash;
|
import com.sparrowwallet.drongo.protocol.Sha256Hash;
|
||||||
import com.sparrowwallet.drongo.protocol.Transaction;
|
import com.sparrowwallet.drongo.protocol.Transaction;
|
||||||
|
import com.sparrowwallet.drongo.protocol.TransactionSignature;
|
||||||
import com.sparrowwallet.drongo.psbt.PSBT;
|
import com.sparrowwallet.drongo.psbt.PSBT;
|
||||||
import com.sparrowwallet.drongo.wallet.BlockTransaction;
|
import com.sparrowwallet.drongo.wallet.BlockTransaction;
|
||||||
import com.sparrowwallet.drongo.wallet.Keystore;
|
import com.sparrowwallet.drongo.wallet.Keystore;
|
||||||
import com.sparrowwallet.drongo.wallet.Wallet;
|
import com.sparrowwallet.drongo.wallet.Wallet;
|
||||||
import com.sparrowwallet.sparrow.io.Storage;
|
import com.sparrowwallet.sparrow.io.Storage;
|
||||||
import javafx.beans.property.SimpleObjectProperty;
|
import javafx.beans.property.SimpleObjectProperty;
|
||||||
import javafx.collections.ObservableList;
|
|
||||||
import javafx.collections.ObservableMap;
|
import javafx.collections.ObservableMap;
|
||||||
import javafx.scene.Node;
|
import javafx.scene.Node;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
@ -83,7 +84,11 @@ public abstract class TransactionForm {
|
||||||
txdata.setSigningWallet(signingWallet);
|
txdata.setSigningWallet(signingWallet);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ObservableList<Keystore> getSignedKeystores() {
|
public ObservableMap<TransactionSignature, Keystore> getSignatureKeystoreMap() {
|
||||||
|
return txdata.getSignatureKeystoreMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Collection<Keystore> getSignedKeystores() {
|
||||||
return txdata.getSignedKeystores();
|
return txdata.getSignedKeystores();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue