sign psbt inputs

This commit is contained in:
Craig Raw 2020-07-22 14:56:59 +02:00
parent a188f70dbe
commit 279b0e0ac1
6 changed files with 93 additions and 18 deletions

2
drongo

@ -1 +1 @@
Subproject commit f6dcdb6d26c3b40ae1c0f7502b3e526aa8959564
Subproject commit af562dad1022c24d5ff851100cc3958a852fbec8

View file

@ -409,14 +409,14 @@ public class AppController implements Initializable {
return fiatCurrencyExchangeRate;
}
public List<Wallet> getOpenWallets() {
List<Wallet> openWallets = new ArrayList<>();
public Map<Wallet, Storage> getOpenWallets() {
Map<Wallet, Storage> openWallets = new LinkedHashMap<>();
for(Tab tab : tabs.getTabs()) {
TabData tabData = (TabData)tab.getUserData();
if(tabData.getType() == TabData.TabType.WALLET) {
WalletTabData walletTabData = (WalletTabData) tabData;
openWallets.add(walletTabData.getWallet());
openWallets.put(walletTabData.getWallet(), walletTabData.getStorage());
}
}

View file

@ -1,17 +1,28 @@
package com.sparrowwallet.sparrow.event;
import com.sparrowwallet.drongo.wallet.Wallet;
import com.sparrowwallet.sparrow.io.Storage;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class OpenWalletsEvent {
private final List<Wallet> wallets;
private final Map<Wallet, Storage> walletsMap;
public OpenWalletsEvent(List<Wallet> wallets) {
this.wallets = wallets;
public OpenWalletsEvent(Map<Wallet, Storage> walletsMap) {
this.walletsMap = walletsMap;
}
public List<Wallet> getWallets() {
return wallets;
return new ArrayList<>(walletsMap.keySet());
}
public Storage getStorage(Wallet wallet) {
return walletsMap.get(wallet);
}
public Map<Wallet, Storage> getWalletsMap() {
return walletsMap;
}
}

View file

@ -1,5 +1,6 @@
package com.sparrowwallet.sparrow.transaction;
import com.sparrowwallet.drongo.SecureString;
import com.sparrowwallet.drongo.protocol.*;
import com.sparrowwallet.drongo.psbt.PSBT;
import com.sparrowwallet.drongo.psbt.PSBTInput;
@ -9,12 +10,10 @@ import com.sparrowwallet.drongo.wallet.KeystoreSource;
import com.sparrowwallet.drongo.wallet.Wallet;
import com.sparrowwallet.sparrow.AppController;
import com.sparrowwallet.sparrow.EventManager;
import com.sparrowwallet.sparrow.control.CoinLabel;
import com.sparrowwallet.sparrow.control.IdLabel;
import com.sparrowwallet.sparrow.control.CopyableLabel;
import com.sparrowwallet.sparrow.control.SignaturesProgressBar;
import com.sparrowwallet.sparrow.control.*;
import com.sparrowwallet.sparrow.event.*;
import com.sparrowwallet.sparrow.glyphfont.FontAwesome5Brands;
import com.sparrowwallet.sparrow.io.Storage;
import javafx.collections.FXCollections;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
@ -29,6 +28,7 @@ import tornadofx.control.Fieldset;
import com.google.common.eventbus.Subscribe;
import tornadofx.control.Form;
import java.io.File;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.time.*;
@ -315,10 +315,7 @@ public class HeadersController extends TransactionFormController implements Init
headersForm.signingWalletProperty().addListener((observable, oldValue, signingWallet) -> {
initializeSignButton(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));
optSignedKeystores.ifPresent(keystores -> headersForm.getSignedKeystores().setAll(keystores));
updateSignedKeystores(signingWallet);
int threshold = signingWallet.getDefaultPolicy().getNumSignaturesRequired();
signaturesProgressBar.initialize(headersForm.getSignedKeystores(), threshold);
@ -437,7 +434,7 @@ public class HeadersController extends TransactionFormController implements Init
}
public void showPSBT(ActionEvent event) {
headersForm.getSignedKeystores().add(headersForm.getSigningWallet().getKeystores().get(0));
}
public void savePSBT(ActionEvent event) {
@ -445,7 +442,56 @@ public class HeadersController extends TransactionFormController implements Init
}
public void signPSBT(ActionEvent event) {
headersForm.getSignedKeystores().add(headersForm.getSigningWallet().getKeystores().get(0));
signSoftwareKeystores();
}
private void signSoftwareKeystores() {
if(headersForm.getSigningWallet().getKeystores().stream().noneMatch(Keystore::hasSeed)) {
return;
}
Wallet copy = headersForm.getSigningWallet().copy();
File file = headersForm.getAvailableWallets().get(headersForm.getSigningWallet()).getWalletFile();
if(copy.isEncrypted()) {
WalletPasswordDialog dlg = new WalletPasswordDialog(WalletPasswordDialog.PasswordRequirement.LOAD);
Optional<SecureString> password = dlg.showAndWait();
if(password.isPresent()) {
Storage.DecryptWalletService decryptWalletService = new Storage.DecryptWalletService(copy, password.get());
decryptWalletService.setOnSucceeded(workerStateEvent -> {
EventManager.get().post(new StorageEvent(file, TimedEvent.Action.END, "Done"));
Wallet decryptedWallet = decryptWalletService.getValue();
signUnencryptedKeystores(decryptedWallet);
});
decryptWalletService.setOnFailed(workerStateEvent -> {
EventManager.get().post(new StorageEvent(file, TimedEvent.Action.END, "Failed"));
AppController.showErrorDialog("Incorrect Password", decryptWalletService.getException().getMessage());
});
EventManager.get().post(new StorageEvent(file, TimedEvent.Action.START, "Decrypting wallet..."));
decryptWalletService.start();
}
} else {
signUnencryptedKeystores(copy);
}
}
private void signUnencryptedKeystores(Wallet unencryptedWallet) {
try {
unencryptedWallet.sign(headersForm.getPsbt());
updateSignedKeystores(headersForm.getSigningWallet());
} catch(Exception e) {
AppController.showErrorDialog("Failed to Sign", e.getMessage());
}
}
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));
optSignedKeystores.ifPresent(signedKeystores -> {
List<Keystore> newSignedKeystores = new ArrayList<>(signedKeystores);
newSignedKeystores.removeAll(headersForm.getSignedKeystores());
headersForm.getSignedKeystores().addAll(newSignedKeystores);
});
}
@Subscribe
@ -484,6 +530,11 @@ public class HeadersController extends TransactionFormController implements Init
public void openWallets(OpenWalletsEvent event) {
if(headersForm.getPsbt() != null && headersForm.isEditable()) {
List<Wallet> availableWallets = event.getWallets().stream().filter(wallet -> wallet.canSign(headersForm.getPsbt())).collect(Collectors.toList());
Map<Wallet, Storage> availableWalletsMap = new LinkedHashMap<>(event.getWalletsMap());
availableWalletsMap.keySet().retainAll(availableWallets);
headersForm.getAvailableWallets().keySet().retainAll(availableWallets);
headersForm.getAvailableWallets().putAll(availableWalletsMap);
signingWallet.setItems(FXCollections.observableList(availableWallets));
if(!availableWallets.isEmpty()) {
if(availableWallets.contains(headersForm.getSigningWallet())) {

View file

@ -6,9 +6,11 @@ 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.FXCollections;
import javafx.collections.ObservableList;
import javafx.collections.ObservableMap;
import java.util.List;
import java.util.Map;
@ -25,6 +27,7 @@ public class TransactionData {
private int minOutputFetched;
private int maxOutputFetched;
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();
@ -118,6 +121,10 @@ public class TransactionData {
return minOutputFetched == 0 && maxOutputFetched == transaction.getOutputs().size();
}
public ObservableMap<Wallet, Storage> getAvailableWallets() {
return availableWallets;
}
public Wallet getSigningWallet() {
return signingWallet.get();
}

View file

@ -6,8 +6,10 @@ 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;
@ -57,6 +59,10 @@ public abstract class TransactionForm {
return txdata.allOutputsFetched();
}
public ObservableMap<Wallet, Storage> getAvailableWallets() {
return txdata.getAvailableWallets();
}
public Wallet getSigningWallet() {
return txdata.getSigningWallet();
}