select alternative network, support testnet on hwi, other fixes

This commit is contained in:
Craig Raw 2020-09-29 15:45:22 +02:00
parent c68cda5b2f
commit ff7a35e68b
12 changed files with 133 additions and 15 deletions

2
drongo

@ -1 +1 @@
Subproject commit 747bfa915f1ecf743b5e8876b9a4c54062e57c94
Subproject commit b877e94cd09adb3fbc17ecba95897ae5c428ffe9

7
sparrow.bat Normal file
View file

@ -0,0 +1,7 @@
set ARGS=%*
if "%ARGS%" != "" (
gradlew.bat run --args="%ARGS%"
) else (
gradlew.bat run
)

11
sparrow.sh Executable file
View file

@ -0,0 +1,11 @@
#!/usr/bin/env sh
args="$*"
args="${args%"${args##*[![:space:]]}"}"
if [ -n "$args" ]
then
./gradlew run --args="$args"
else
./gradlew run
fi

View file

@ -4,6 +4,7 @@ import com.google.common.base.Charsets;
import com.google.common.eventbus.Subscribe;
import com.google.common.io.ByteSource;
import com.sparrowwallet.drongo.BitcoinUnit;
import com.sparrowwallet.drongo.Network;
import com.sparrowwallet.drongo.SecureString;
import com.sparrowwallet.drongo.Utils;
import com.sparrowwallet.drongo.crypto.InvalidPasswordException;
@ -770,6 +771,7 @@ public class AppController implements Initializable {
FileType fileType = IOUtils.getFileType(file);
if(FileType.JSON.equals(fileType)) {
Wallet wallet = storage.loadWallet();
checkWalletNetwork(wallet);
restorePublicKeysFromSeed(wallet, null);
Tab tab = addWalletTab(storage, wallet);
tabs.getSelectionModel().select(tab);
@ -786,10 +788,11 @@ public class AppController implements Initializable {
EventManager.get().post(new StorageEvent(storage.getWalletFile(), TimedEvent.Action.END, "Done"));
Storage.WalletAndKey walletAndKey = loadWalletService.getValue();
try {
checkWalletNetwork(walletAndKey.wallet);
restorePublicKeysFromSeed(walletAndKey.wallet, walletAndKey.key);
Tab tab = addWalletTab(storage, walletAndKey.wallet);
tabs.getSelectionModel().select(tab);
} catch(MnemonicException e) {
} catch(Exception e) {
showErrorDialog("Error Opening Wallet", e.getMessage());
} finally {
walletAndKey.key.clear();
@ -816,6 +819,12 @@ public class AppController implements Initializable {
}
}
private void checkWalletNetwork(Wallet wallet) {
if(wallet.getNetwork() != null && wallet.getNetwork() != Network.get()) {
throw new IllegalStateException("Provided " + wallet.getNetwork() + " wallet is invalid on a " + Network.get() + " network. Use a " + wallet.getNetwork() + " configuration to load this wallet.");
}
}
private void restorePublicKeysFromSeed(Wallet wallet, Key key) throws MnemonicException {
if(wallet.containsSeeds()) {
//Derive xpub and master fingerprint from seed, potentially with passphrase
@ -1382,7 +1391,7 @@ public class AppController implements Initializable {
@Subscribe
public void openWallets(OpenWalletsEvent event) {
List<File> walletFiles = event.getWalletsMap().values().stream().map(storage -> storage.getWalletFile()).collect(Collectors.toList());
List<File> walletFiles = event.getWalletsMap().values().stream().map(Storage::getWalletFile).collect(Collectors.toList());
Config.get().setRecentWalletFiles(walletFiles);
boolean usbWallet = false;

View file

@ -0,0 +1,15 @@
package com.sparrowwallet.sparrow;
import com.beust.jcommander.Parameter;
import com.sparrowwallet.drongo.Network;
public class Args {
@Parameter(names = { "--dir", "-d" }, description = "Path to Sparrow home folder")
public String dir;
@Parameter(names = { "--network", "-n" }, description = "Network to use (mainnet, testnet or regtest)")
public Network network;
@Parameter(names = { "--help", "-h" }, description = "Show usage", help = true)
public boolean help;
}

View file

@ -1,5 +1,7 @@
package com.sparrowwallet.sparrow;
import com.beust.jcommander.JCommander;
import com.sparrowwallet.drongo.Network;
import com.sparrowwallet.sparrow.control.WelcomeDialog;
import com.sparrowwallet.sparrow.glyphfont.FontAwesome5;
import com.sparrowwallet.sparrow.glyphfont.FontAwesome5Brands;
@ -17,18 +19,20 @@ import javafx.scene.image.Image;
import javafx.scene.text.Font;
import javafx.stage.Stage;
import org.controlsfx.glyphfont.GlyphFontRegistry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.*;
import java.util.stream.Collectors;
public class MainApp extends Application {
private static final Logger log = LoggerFactory.getLogger(MainApp.class);
public static final String APP_NAME = "Sparrow";
public static final String APP_VERSION = "0.9.4";
public static final String APP_HOME_PROPERTY = "sparrow.home";
public static final String NETWORK_ENV_PROPERTY = "SPARROW_NETWORK";
private Stage mainStage;
@ -107,7 +111,37 @@ public class MainApp extends Application {
mainStage.close();
}
public static void main(String[] args) {
com.sun.javafx.application.LauncherImpl.launchApplication(MainApp.class, MainAppPreloader.class, args);
public static void main(String[] argv) {
Args args = new Args();
JCommander jCommander = JCommander.newBuilder().addObject(args).programName(APP_NAME.toLowerCase()).acceptUnknownOptions(true).build();
jCommander.parse(argv);
if(args.help) {
jCommander.usage();
System.exit(0);
}
if(args.dir != null) {
log.info("Using configured Sparrow home folder of " + args.dir);
System.setProperty(APP_HOME_PROPERTY, args.dir);
}
if(args.network != null) {
Network.set(args.network);
} else {
String envNetwork = System.getenv(NETWORK_ENV_PROPERTY);
if(envNetwork != null) {
try {
Network.set(Network.valueOf(envNetwork.toUpperCase()));
} catch(Exception e) {
log.warn("Invalid " + NETWORK_ENV_PROPERTY + " property: " + envNetwork);
}
}
}
if(Network.get() != Network.MAINNET) {
log.info("Using " + Network.get() + " configuration");
}
com.sun.javafx.application.LauncherImpl.launchApplication(MainApp.class, MainAppPreloader.class, argv);
}
}

View file

@ -44,7 +44,12 @@ public class Config {
}
private static File getConfigFile() {
return new File(Storage.getSparrowDir(), CONFIG_FILENAME);
File sparrowDir = Storage.getSparrowDir();
if(!sparrowDir.exists()) {
sparrowDir.mkdirs();
}
return new File(sparrowDir, CONFIG_FILENAME);
}
private static Config load() {

View file

@ -3,6 +3,7 @@ package com.sparrowwallet.sparrow.io;
import com.google.common.io.ByteStreams;
import com.google.common.io.CharStreams;
import com.google.gson.*;
import com.sparrowwallet.drongo.Network;
import com.sparrowwallet.drongo.protocol.ScriptType;
import com.sparrowwallet.drongo.psbt.PSBT;
import com.sparrowwallet.drongo.psbt.PSBTParseException;
@ -322,17 +323,27 @@ public class Hwi {
}
private List<String> getDeviceCommand(Device device, Command command) throws IOException {
return List.of(getHwiExecutable(command).getAbsolutePath(), "--device-path", device.getPath(), "--device-type", device.getType(), command.toString());
List<String> elements = new ArrayList<>(List.of(getHwiExecutable(command).getAbsolutePath(), "--device-path", device.getPath(), "--device-type", device.getType(), command.toString()));
if(Network.get() != Network.MAINNET) {
elements.add(elements.size() - 1, "--testnet");
}
return elements;
}
private List<String> getDeviceCommand(Device device, Command command, String... commandData) throws IOException {
List<String> elements = new ArrayList<>(List.of(getHwiExecutable(command).getAbsolutePath(), "--device-path", device.getPath(), "--device-type", device.getType(), command.toString()));
if(Network.get() != Network.MAINNET) {
elements.add(elements.size() - 1, "--testnet");
}
elements.addAll(Arrays.stream(commandData).filter(Objects::nonNull).collect(Collectors.toList()));
return elements;
}
private List<String> getDeviceCommand(Device device, String passphrase, Command command, String... commandData) throws IOException {
List<String> elements = new ArrayList<>(List.of(getHwiExecutable(command).getAbsolutePath(), "--device-path", device.getPath(), "--device-type", device.getType(), "--password", passphrase, command.toString()));
if(Network.get() != Network.MAINNET) {
elements.add(elements.size() - 1, "--testnet");
}
elements.addAll(Arrays.stream(commandData).filter(Objects::nonNull).collect(Collectors.toList()));
return elements;
}

View file

@ -3,6 +3,7 @@ package com.sparrowwallet.sparrow.io;
import com.google.common.io.Files;
import com.google.gson.*;
import com.sparrowwallet.drongo.ExtendedKey;
import com.sparrowwallet.drongo.Network;
import com.sparrowwallet.drongo.SecureString;
import com.sparrowwallet.drongo.Utils;
import com.sparrowwallet.drongo.crypto.*;
@ -12,6 +13,7 @@ import com.sparrowwallet.drongo.wallet.Keystore;
import com.sparrowwallet.drongo.wallet.MnemonicException;
import com.sparrowwallet.drongo.wallet.Wallet;
import com.sparrowwallet.drongo.wallet.WalletNode;
import com.sparrowwallet.sparrow.MainApp;
import javafx.concurrent.Service;
import javafx.concurrent.Task;
import org.controlsfx.tools.Platform;
@ -272,6 +274,18 @@ public class Storage {
}
static File getSparrowDir() {
if(Network.get() != Network.MAINNET) {
return new File(getSparrowHome(), Network.get().getName());
}
return getSparrowHome();
}
static File getSparrowHome() {
if(System.getProperty(MainApp.APP_HOME_PROPERTY) != null) {
return new File(System.getProperty(MainApp.APP_HOME_PROPERTY));
}
if(Platform.getCurrent() == Platform.WINDOWS) {
return new File(getHomeDir(), WINDOWS_SPARROW_DIR);
}

View file

@ -97,6 +97,8 @@ public class SendController extends WalletFormController implements Initializabl
private final ObjectProperty<WalletTransaction> walletTransactionProperty = new SimpleObjectProperty<>(null);
private final ObjectProperty<WalletTransaction> createdWalletTransactionProperty = new SimpleObjectProperty<>(null);
private final BooleanProperty insufficientInputsProperty = new SimpleBooleanProperty(false);
private final ChangeListener<String> amountListener = new ChangeListener<>() {
@ -570,6 +572,7 @@ public class SendController extends WalletFormController implements Initializabl
utxoSelectorProperty.setValue(null);
utxoFilterProperty.setValue(null);
walletTransactionProperty.setValue(null);
createdWalletTransactionProperty.set(null);
validationSupport.setErrorDecorationEnabled(false);
}
@ -583,6 +586,7 @@ public class SendController extends WalletFormController implements Initializabl
}
public void createTransaction(ActionEvent event) {
createdWalletTransactionProperty.set(walletTransactionProperty.get());
PSBT psbt = walletTransactionProperty.get().createPSBT();
EventManager.get().post(new ViewPSBTEvent(label.getText(), psbt));
}
@ -596,8 +600,8 @@ public class SendController extends WalletFormController implements Initializabl
@Subscribe
public void walletHistoryChanged(WalletHistoryChangedEvent event) {
if(event.getWallet().equals(walletForm.getWallet())) {
if(walletTransactionProperty.get() != null && walletTransactionProperty.get().getSelectedUtxos() != null && allSelectedUtxosSpent(event.getHistoryChangedNodes())) {
if(event.getWallet().equals(walletForm.getWallet()) && createdWalletTransactionProperty.get() != null) {
if(createdWalletTransactionProperty.get().getSelectedUtxos() != null && allSelectedUtxosSpent(event.getHistoryChangedNodes())) {
clear(null);
} else {
updateTransaction();
@ -606,9 +610,9 @@ public class SendController extends WalletFormController implements Initializabl
}
private boolean allSelectedUtxosSpent(List<WalletNode> historyChangedNodes) {
Set<BlockTransactionHashIndex> unspentUtxos = new HashSet<>(walletTransactionProperty.get().getSelectedUtxos().keySet());
Set<BlockTransactionHashIndex> unspentUtxos = new HashSet<>(createdWalletTransactionProperty.get().getSelectedUtxos().keySet());
for(Map.Entry<BlockTransactionHashIndex, WalletNode> selectedUtxoEntry : walletTransactionProperty.get().getSelectedUtxos().entrySet()) {
for(Map.Entry<BlockTransactionHashIndex, WalletNode> selectedUtxoEntry : createdWalletTransactionProperty.get().getSelectedUtxos().entrySet()) {
BlockTransactionHashIndex utxo = selectedUtxoEntry.getKey();
WalletNode utxoWalletNode = selectedUtxoEntry.getValue();

View file

@ -17,6 +17,7 @@ import com.sparrowwallet.sparrow.control.CopyableLabel;
import com.sparrowwallet.sparrow.control.DescriptorArea;
import com.sparrowwallet.sparrow.control.TextAreaDialog;
import com.sparrowwallet.sparrow.control.WalletPasswordDialog;
import com.sparrowwallet.sparrow.event.RequestOpenWalletsEvent;
import com.sparrowwallet.sparrow.event.SettingsChangedEvent;
import com.sparrowwallet.sparrow.event.StorageEvent;
import com.sparrowwallet.sparrow.event.TimedEvent;
@ -347,6 +348,9 @@ public class SettingsController extends WalletFormController implements Initiali
try {
walletForm.getStorage().setEncryptionPubKey(Storage.NO_PASSWORD_KEY);
walletForm.saveAndRefresh();
if(requirement == WalletPasswordDialog.PasswordRequirement.UPDATE_NEW) {
EventManager.get().post(new RequestOpenWalletsEvent());
}
} catch (IOException e) {
log.error("Error saving wallet", e);
AppController.showErrorDialog("Error saving wallet", e.getMessage());
@ -381,6 +385,9 @@ public class SettingsController extends WalletFormController implements Initiali
walletForm.getStorage().setEncryptionPubKey(encryptionPubKey);
walletForm.saveAndRefresh();
if(requirement == WalletPasswordDialog.PasswordRequirement.UPDATE_NEW) {
EventManager.get().post(new RequestOpenWalletsEvent());
}
} catch (Exception e) {
log.error("Error saving wallet", e);
AppController.showErrorDialog("Error saving wallet", e.getMessage());

View file

@ -22,5 +22,6 @@ open module com.sparrowwallet.sparrow {
requires webcam.capture;
requires netlayer.jpms;
requires centerdevice.nsmenufx;
requires jcommander;
requires slf4j.api;
}