deduplicate signed keystores on signature

This commit is contained in:
Craig Raw 2020-08-31 10:14:48 +02:00
parent 4d7d51f3f8
commit b808222faa
7 changed files with 43 additions and 26 deletions

2
drongo

@ -1 +1 @@
Subproject commit 55717c31bf8046e558ee90a5997c1de769517813
Subproject commit 10035278543d9ca90b11ae3d396edc3e6131fee2

View file

@ -1,5 +1,6 @@
package com.sparrowwallet.sparrow.control;
import com.sparrowwallet.drongo.protocol.TransactionSignature;
import com.sparrowwallet.drongo.wallet.Keystore;
import com.sparrowwallet.sparrow.EventManager;
import com.sparrowwallet.sparrow.event.KeystoreSignedEvent;
@ -7,8 +8,8 @@ import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.beans.property.SimpleObjectProperty;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.collections.MapChangeListener;
import javafx.collections.ObservableMap;
import javafx.geometry.Insets;
import javafx.geometry.Orientation;
import javafx.geometry.Pos;
@ -18,6 +19,9 @@ import javafx.scene.layout.StackPane;
import javafx.util.Duration;
import org.controlsfx.control.SegmentedBar;
import java.util.ArrayList;
import java.util.List;
public class SignaturesProgressBar extends SegmentedBar<SignaturesProgressBar.SignatureProgressSegment> {
public SignaturesProgressBar() {
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()));
}
public void initialize(ObservableList<Keystore> signedKeystores, int threshold) {
public void initialize(ObservableMap<TransactionSignature, Keystore> signatureKeystoreMap, int threshold) {
getStyleClass().add("signatures-progress-bar");
getSegments().clear();
List<Keystore> signedKeystores = new ArrayList<>(signatureKeystoreMap.values());
int numSegments = Math.max(threshold, signedKeystores.size());
double segmentSize = 100d / numSegments;
for(int i = 0; i < numSegments; i++) {
@ -39,19 +44,20 @@ public class SignaturesProgressBar extends SegmentedBar<SignaturesProgressBar.Si
}
}
signedKeystores.addListener((ListChangeListener<Keystore>) c -> {
int numSegments1 = Math.max(threshold, c.getList().size());
double newSegmentSize = 100d / numSegments1;
signatureKeystoreMap.addListener((MapChangeListener<TransactionSignature, Keystore>) c -> {
List<Keystore> newSignedKeystores = new ArrayList<>(c.getMap().values());
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;
if(i < getSegments().size()) {
segment = getSegments().get(i);
}
Keystore signedKeystore = null;
if(i < signedKeystores.size()) {
signedKeystore = signedKeystores.get(i);
if(i < newSignedKeystores.size()) {
signedKeystore = newSignedKeystores.get(i);
}
if(segment != null) {

View file

@ -405,7 +405,7 @@ public class HeadersController extends TransactionFormController implements Init
updateSignedKeystores(signingWallet);
int threshold = signingWallet.getDefaultPolicy().getNumSignaturesRequired();
signaturesProgressBar.initialize(headersForm.getSignedKeystores(), threshold);
signaturesProgressBar.initialize(headersForm.getSignatureKeystoreMap(), threshold);
});
EventManager.get().post(new RequestOpenWalletsEvent());
@ -705,12 +705,11 @@ public class HeadersController extends TransactionFormController implements Init
}
private void updateSignedKeystores(Wallet signingWallet) {
Map<PSBTInput, List<Keystore>> signedKeystoresMap = signingWallet.getSignedKeystores(headersForm.getPsbt());
Optional<List<Keystore>> optSignedKeystores = signedKeystoresMap.values().stream().filter(list -> !list.isEmpty()).min(Comparator.comparingInt(List::size));
Map<PSBTInput, Map<TransactionSignature, Keystore>> signedKeystoresMap = signingWallet.getSignedKeystores(headersForm.getPsbt());
Optional<Map<TransactionSignature, Keystore>> optSignedKeystores = signedKeystoresMap.values().stream().filter(map -> !map.isEmpty()).min(Comparator.comparingInt(Map::size));
optSignedKeystores.ifPresent(signedKeystores -> {
List<Keystore> newSignedKeystores = new ArrayList<>(signedKeystores);
newSignedKeystores.removeAll(headersForm.getSignedKeystores());
headersForm.getSignedKeystores().addAll(newSignedKeystores);
headersForm.getSignatureKeystoreMap().keySet().retainAll(signedKeystores.keySet());
headersForm.getSignatureKeystoreMap().putAll(signedKeystores);
});
}
@ -922,6 +921,7 @@ public class HeadersController extends TransactionFormController implements Init
@Subscribe
public void keystoreSigned(KeystoreSignedEvent event) {
if(headersForm.getSignedKeystores().contains(event.getKeystore()) && headersForm.getPsbt() != null) {
//Attempt to finalize PSBT - will do nothing if all inputs are not signed
finalizePSBT();
}
}

View file

@ -11,7 +11,7 @@ import com.sparrowwallet.drongo.wallet.Keystore;
import com.sparrowwallet.sparrow.EventManager;
import com.sparrowwallet.sparrow.control.*;
import com.sparrowwallet.sparrow.event.*;
import javafx.collections.ListChangeListener;
import javafx.collections.MapChangeListener;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.*;
@ -126,7 +126,7 @@ public class InputController extends TransactionFormController implements Initia
initializeLocktimeFields(txInput);
if(psbtInput != null) {
inputForm.getSignedKeystores().addListener((ListChangeListener<Keystore>) c -> {
inputForm.getSignatureKeystoreMap().addListener((MapChangeListener<TransactionSignature, Keystore>) c -> {
updateSignatures(inputForm.getPsbtInput());
});
}

View file

@ -13,7 +13,7 @@ import com.sparrowwallet.sparrow.event.BitcoinUnitChangedEvent;
import com.sparrowwallet.sparrow.event.BlockTransactionFetchedEvent;
import com.sparrowwallet.sparrow.event.PSBTCombinedEvent;
import com.sparrowwallet.sparrow.event.PSBTFinalizedEvent;
import javafx.collections.ListChangeListener;
import javafx.collections.MapChangeListener;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.chart.PieChart;
@ -62,7 +62,7 @@ public class InputsController extends TransactionFormController implements Initi
if(inputsForm.getPsbt() != null) {
updatePSBTInputs(inputsForm.getPsbt());
inputsForm.getSignedKeystores().addListener((ListChangeListener<Keystore>) c -> {
inputsForm.getSignatureKeystoreMap().addListener((MapChangeListener<TransactionSignature, Keystore>) c -> {
updatePSBTInputs(inputsForm.getPsbt());
});
} else if(inputsForm.getInputTransactions() != null) {

View file

@ -2,6 +2,7 @@ package com.sparrowwallet.sparrow.transaction;
import com.sparrowwallet.drongo.protocol.Sha256Hash;
import com.sparrowwallet.drongo.protocol.Transaction;
import com.sparrowwallet.drongo.protocol.TransactionSignature;
import com.sparrowwallet.drongo.psbt.PSBT;
import com.sparrowwallet.drongo.wallet.BlockTransaction;
import com.sparrowwallet.drongo.wallet.Keystore;
@ -9,9 +10,10 @@ import com.sparrowwallet.drongo.wallet.Wallet;
import com.sparrowwallet.sparrow.io.Storage;
import javafx.beans.property.SimpleObjectProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.collections.ObservableMap;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@ -30,7 +32,7 @@ public class TransactionData {
private final ObservableMap<Wallet, Storage> availableWallets = FXCollections.observableHashMap();
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) {
this(name, psbt.getTransaction());
@ -147,7 +149,11 @@ public class TransactionData {
this.signingWallet.set(wallet);
}
public ObservableList<Keystore> getSignedKeystores() {
return signedKeystores;
public ObservableMap<TransactionSignature, Keystore> getSignatureKeystoreMap() {
return signatureKeystoreMap;
}
public Collection<Keystore> getSignedKeystores() {
return signatureKeystoreMap.values();
}
}

View file

@ -2,17 +2,18 @@ package com.sparrowwallet.sparrow.transaction;
import com.sparrowwallet.drongo.protocol.Sha256Hash;
import com.sparrowwallet.drongo.protocol.Transaction;
import com.sparrowwallet.drongo.protocol.TransactionSignature;
import com.sparrowwallet.drongo.psbt.PSBT;
import com.sparrowwallet.drongo.wallet.BlockTransaction;
import com.sparrowwallet.drongo.wallet.Keystore;
import com.sparrowwallet.drongo.wallet.Wallet;
import com.sparrowwallet.sparrow.io.Storage;
import javafx.beans.property.SimpleObjectProperty;
import javafx.collections.ObservableList;
import javafx.collections.ObservableMap;
import javafx.scene.Node;
import java.io.IOException;
import java.util.Collection;
import java.util.List;
import java.util.Map;
@ -83,7 +84,11 @@ public abstract class TransactionForm {
txdata.setSigningWallet(signingWallet);
}
public ObservableList<Keystore> getSignedKeystores() {
public ObservableMap<TransactionSignature, Keystore> getSignatureKeystoreMap() {
return txdata.getSignatureKeystoreMap();
}
public Collection<Keystore> getSignedKeystores() {
return txdata.getSignedKeystores();
}