From d420c71673de5823ba1f6c4a0d4411ebd747c7ba Mon Sep 17 00:00:00 2001 From: Craig Raw Date: Wed, 8 May 2024 15:50:15 +0200 Subject: [PATCH] add testnet4 network support --- README.md | 8 ++-- drongo | 2 +- .../sparrowwallet/sparrow/AppController.java | 2 +- .../sparrowwallet/sparrow/SparrowWallet.java | 5 +++ .../sparrow/io/CaravanMultisig.java | 2 +- .../sparrow/io/GordianSeedTool.java | 2 +- .../com/sparrowwallet/sparrow/io/Hwi.java | 2 +- .../com/sparrowwallet/sparrow/io/Storage.java | 39 +++++++++++++++++-- .../com/sparrowwallet/sparrow/net/Bwt.java | 2 +- .../cormorant/bitcoind/BitcoindTransport.java | 2 + 10 files changed, 53 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index b1f79bc7..e9922079 100644 --- a/README.md +++ b/README.md @@ -64,10 +64,12 @@ Usage: sparrow [options] Possible Values: [ERROR, WARN, INFO, DEBUG, TRACE] --network, -n Network to use - Possible Values: [mainnet, testnet, regtest, signet] + Possible Values: [mainnet, testnet, regtest, signet, testnet4] ``` -As a fallback, the network (mainnet, testnet, regtest or signet) can also be set using an environment variable `SPARROW_NETWORK`. For example: +Note that testnet currently refers to testnet3. + +As a fallback, the network (mainnet, testnet, testnet4, regtest or signet) can also be set using an environment variable `SPARROW_NETWORK`. For example: `export SPARROW_NETWORK=testnet` @@ -83,7 +85,7 @@ When not explicitly configured using the command line argument above, Sparrow st | Linux | ~/.sparrow | | Windows | %APPDATA%/Sparrow | -Testnet, regtest and signet configurations (along with their wallets) are stored in subfolders to allow easy switching between networks. +Testnet3, testnet4, regtest and signet configurations (along with their wallets) are stored in subfolders to allow easy switching between networks. ## Reporting Issues diff --git a/drongo b/drongo index a7dd28dd..60ac4280 160000 --- a/drongo +++ b/drongo @@ -1 +1 @@ -Subproject commit a7dd28dde75a8086a4d23caa138cd0ad48c0db1d +Subproject commit 60ac42800222a487651b93529796d31e5a954b99 diff --git a/src/main/java/com/sparrowwallet/sparrow/AppController.java b/src/main/java/com/sparrowwallet/sparrow/AppController.java index 83e86d64..e084a3a0 100644 --- a/src/main/java/com/sparrowwallet/sparrow/AppController.java +++ b/src/main/java/com/sparrowwallet/sparrow/AppController.java @@ -391,7 +391,7 @@ public class AppController implements Initializable { MenuItem homeItem = new MenuItem("Home Folder..."); homeItem.setOnAction(this::restartInHome); restart.getItems().add(homeItem); - List networks = new ArrayList<>(List.of(Network.MAINNET, Network.TESTNET, Network.SIGNET)); + List networks = new ArrayList<>(List.of(Network.MAINNET, Network.TESTNET, Network.TESTNET4, Network.SIGNET)); networks.remove(Network.get()); for(Network network : networks) { MenuItem networkItem = new MenuItem(network.toDisplayString()); diff --git a/src/main/java/com/sparrowwallet/sparrow/SparrowWallet.java b/src/main/java/com/sparrowwallet/sparrow/SparrowWallet.java index ae26ca91..367eb4d8 100644 --- a/src/main/java/com/sparrowwallet/sparrow/SparrowWallet.java +++ b/src/main/java/com/sparrowwallet/sparrow/SparrowWallet.java @@ -66,6 +66,11 @@ public class SparrowWallet { Network.set(Network.TESTNET); } + File testnet4Flag = new File(Storage.getSparrowHome(), "network-" + Network.TESTNET4.getName()); + if(testnet4Flag.exists()) { + Network.set(Network.TESTNET4); + } + File signetFlag = new File(Storage.getSparrowHome(), "network-" + Network.SIGNET.getName()); if(signetFlag.exists()) { Network.set(Network.SIGNET); diff --git a/src/main/java/com/sparrowwallet/sparrow/io/CaravanMultisig.java b/src/main/java/com/sparrowwallet/sparrow/io/CaravanMultisig.java index ce82ff92..42b37c3c 100644 --- a/src/main/java/com/sparrowwallet/sparrow/io/CaravanMultisig.java +++ b/src/main/java/com/sparrowwallet/sparrow/io/CaravanMultisig.java @@ -107,7 +107,7 @@ public class CaravanMultisig implements WalletImport, WalletExport { CaravanFile cf = new CaravanFile(); cf.name = wallet.getFullName(); cf.addressType = wallet.getScriptType().toString().replace('-', '_'); - cf.network = Network.get().getName(); + cf.network = Network.getCanonical().getName(); cf.client = new Client(); Quorum quorum = new Quorum(); diff --git a/src/main/java/com/sparrowwallet/sparrow/io/GordianSeedTool.java b/src/main/java/com/sparrowwallet/sparrow/io/GordianSeedTool.java index 0de1764a..9f03bd56 100644 --- a/src/main/java/com/sparrowwallet/sparrow/io/GordianSeedTool.java +++ b/src/main/java/com/sparrowwallet/sparrow/io/GordianSeedTool.java @@ -36,7 +36,7 @@ public class GordianSeedTool implements KeystoreFileImport { @Override public String getKeystoreImportDescription(int account) { - return "Select your seed and scan the QR code created by Authenticate > Derive Key > Other Key Derivations > " + Network.get().toDisplayString() + " > Master Key > Account Descriptor. Click the share icon at the bottom."; + return "Select your seed and scan the QR code created by Authenticate > Derive Key > Other Key Derivations > " + Network.getCanonical().getCapitalizedName() + " > Master Key > Account Descriptor. Click the share icon at the bottom."; } @Override diff --git a/src/main/java/com/sparrowwallet/sparrow/io/Hwi.java b/src/main/java/com/sparrowwallet/sparrow/io/Hwi.java index 2416e21d..4e4d23d3 100644 --- a/src/main/java/com/sparrowwallet/sparrow/io/Hwi.java +++ b/src/main/java/com/sparrowwallet/sparrow/io/Hwi.java @@ -601,7 +601,7 @@ public class Hwi { private void addChainType(List elements, boolean commandPresent) { if(Network.get() != Network.MAINNET) { elements.add(elements.size() - (commandPresent ? 1 : 0), "--chain"); - elements.add(elements.size() - (commandPresent ? 1 : 0), getChainName(Network.get())); + elements.add(elements.size() - (commandPresent ? 1 : 0), getChainName(Network.getCanonical())); } } diff --git a/src/main/java/com/sparrowwallet/sparrow/io/Storage.java b/src/main/java/com/sparrowwallet/sparrow/io/Storage.java index 57a57b39..6db59335 100644 --- a/src/main/java/com/sparrowwallet/sparrow/io/Storage.java +++ b/src/main/java/com/sparrowwallet/sparrow/io/Storage.java @@ -19,6 +19,7 @@ import org.slf4j.LoggerFactory; import java.io.*; import java.nio.charset.StandardCharsets; import java.nio.file.Files; +import java.nio.file.Path; import java.nio.file.attribute.PosixFilePermission; import java.nio.file.attribute.PosixFilePermissions; import java.security.cert.Certificate; @@ -216,8 +217,8 @@ public class Storage { } 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."); + if(wallet.getNetwork() != null && wallet.getNetwork() != Network.getCanonical()) { + throw new IllegalStateException("Provided " + wallet.getNetwork() + " wallet is invalid on a " + Network.getCanonical() + " network. Use a " + wallet.getNetwork() + " configuration to load this wallet."); } } @@ -526,8 +527,21 @@ public class Storage { public static File getSparrowDir() { File sparrowDir; - if(Network.get() != Network.MAINNET) { - sparrowDir = new File(getSparrowHome(), Network.get().getName()); + Network network = Network.get(); + if(network != Network.MAINNET) { + sparrowDir = new File(getSparrowHome(), network.getHome()); + if(!network.getName().equals(network.getHome()) && !sparrowDir.exists()) { + File networkNameDir = new File(getSparrowHome(), network.getName()); + if(networkNameDir.exists() && networkNameDir.isDirectory() && !Files.isSymbolicLink(networkNameDir.toPath())) { + try { + if(networkNameDir.renameTo(sparrowDir)) { + Files.createSymbolicLink(networkNameDir.toPath(), Path.of(sparrowDir.getName())); + } + } catch(Exception e) { + log.debug("Error creating symlink from " + networkNameDir.getAbsolutePath() + " to " + sparrowDir.getName(), e); + } + } + } } else { sparrowDir = getSparrowHome(); } @@ -536,6 +550,23 @@ public class Storage { createOwnerOnlyDirectory(sparrowDir); } + if(!network.getName().equals(network.getHome())) { + try { + Path networkNamePath = getSparrowHome().toPath().resolve(network.getName()); + if(Files.isSymbolicLink(networkNamePath)) { + Path symlinkTarget = getSparrowHome().toPath().resolve(Files.readSymbolicLink(networkNamePath)); + if(!Files.isSameFile(sparrowDir.toPath(), symlinkTarget)) { + Files.delete(networkNamePath); + Files.createSymbolicLink(networkNamePath, Path.of(sparrowDir.getName())); + } + } else if(!Files.exists(networkNamePath)) { + Files.createSymbolicLink(networkNamePath, Path.of(sparrowDir.getName())); + } + } catch(Exception e) { + log.debug("Error updating symlink from " + network.getName() + " to " + sparrowDir.getName(), e); + } + } + return sparrowDir; } diff --git a/src/main/java/com/sparrowwallet/sparrow/net/Bwt.java b/src/main/java/com/sparrowwallet/sparrow/net/Bwt.java index 2c5a5424..1c1cfa10 100644 --- a/src/main/java/com/sparrowwallet/sparrow/net/Bwt.java +++ b/src/main/java/com/sparrowwallet/sparrow/net/Bwt.java @@ -119,7 +119,7 @@ public class Bwt { */ private void start(Collection outputDescriptors, Collection addresses, Integer rescanSince, Boolean forceRescan, Integer gapLimit, CallbackNotifier callback) { BwtConfig bwtConfig = new BwtConfig(); - bwtConfig.network = Network.get() == Network.MAINNET ? "bitcoin" : Network.get().getName(); + bwtConfig.network = Network.get() == Network.MAINNET ? "bitcoin" : Network.getCanonical().getName(); if(!outputDescriptors.isEmpty()) { bwtConfig.descriptors = outputDescriptors; diff --git a/src/main/java/com/sparrowwallet/sparrow/net/cormorant/bitcoind/BitcoindTransport.java b/src/main/java/com/sparrowwallet/sparrow/net/cormorant/bitcoind/BitcoindTransport.java index e5b844ed..846616b1 100644 --- a/src/main/java/com/sparrowwallet/sparrow/net/cormorant/bitcoind/BitcoindTransport.java +++ b/src/main/java/com/sparrowwallet/sparrow/net/cormorant/bitcoind/BitcoindTransport.java @@ -130,6 +130,8 @@ public class BitcoindTransport implements Transport { private static File getCookieDir(File bitcoindDir) { if(Network.get() == Network.TESTNET && Files.exists(Path.of(bitcoindDir.getAbsolutePath(), "testnet3", COOKIE_FILENAME))) { return new File(bitcoindDir, "testnet3"); + } else if(Network.get() == Network.TESTNET4 && Files.exists(Path.of(bitcoindDir.getAbsolutePath(), "testnet4", COOKIE_FILENAME))) { + return new File(bitcoindDir, "testnet4"); } else if(Network.get() == Network.REGTEST && Files.exists(Path.of(bitcoindDir.getAbsolutePath(), "regtest", COOKIE_FILENAME))) { return new File(bitcoindDir, "regtest"); } else if(Network.get() == Network.SIGNET && Files.exists(Path.of(bitcoindDir.getAbsolutePath(), "signet", COOKIE_FILENAME))) {