add testnet4 network support

This commit is contained in:
Craig Raw 2024-05-08 15:50:15 +02:00
parent 07101b3ca0
commit d420c71673
10 changed files with 53 additions and 13 deletions

View file

@ -64,10 +64,12 @@ Usage: sparrow [options]
Possible Values: [ERROR, WARN, INFO, DEBUG, TRACE] Possible Values: [ERROR, WARN, INFO, DEBUG, TRACE]
--network, -n --network, -n
Network to use 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` `export SPARROW_NETWORK=testnet`
@ -83,7 +85,7 @@ When not explicitly configured using the command line argument above, Sparrow st
| Linux | ~/.sparrow | | Linux | ~/.sparrow |
| Windows | %APPDATA%/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 ## Reporting Issues

2
drongo

@ -1 +1 @@
Subproject commit a7dd28dde75a8086a4d23caa138cd0ad48c0db1d Subproject commit 60ac42800222a487651b93529796d31e5a954b99

View file

@ -391,7 +391,7 @@ public class AppController implements Initializable {
MenuItem homeItem = new MenuItem("Home Folder..."); MenuItem homeItem = new MenuItem("Home Folder...");
homeItem.setOnAction(this::restartInHome); homeItem.setOnAction(this::restartInHome);
restart.getItems().add(homeItem); restart.getItems().add(homeItem);
List<Network> networks = new ArrayList<>(List.of(Network.MAINNET, Network.TESTNET, Network.SIGNET)); List<Network> networks = new ArrayList<>(List.of(Network.MAINNET, Network.TESTNET, Network.TESTNET4, Network.SIGNET));
networks.remove(Network.get()); networks.remove(Network.get());
for(Network network : networks) { for(Network network : networks) {
MenuItem networkItem = new MenuItem(network.toDisplayString()); MenuItem networkItem = new MenuItem(network.toDisplayString());

View file

@ -66,6 +66,11 @@ public class SparrowWallet {
Network.set(Network.TESTNET); 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()); File signetFlag = new File(Storage.getSparrowHome(), "network-" + Network.SIGNET.getName());
if(signetFlag.exists()) { if(signetFlag.exists()) {
Network.set(Network.SIGNET); Network.set(Network.SIGNET);

View file

@ -107,7 +107,7 @@ public class CaravanMultisig implements WalletImport, WalletExport {
CaravanFile cf = new CaravanFile(); CaravanFile cf = new CaravanFile();
cf.name = wallet.getFullName(); cf.name = wallet.getFullName();
cf.addressType = wallet.getScriptType().toString().replace('-', '_'); cf.addressType = wallet.getScriptType().toString().replace('-', '_');
cf.network = Network.get().getName(); cf.network = Network.getCanonical().getName();
cf.client = new Client(); cf.client = new Client();
Quorum quorum = new Quorum(); Quorum quorum = new Quorum();

View file

@ -36,7 +36,7 @@ public class GordianSeedTool implements KeystoreFileImport {
@Override @Override
public String getKeystoreImportDescription(int account) { 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 @Override

View file

@ -601,7 +601,7 @@ public class Hwi {
private void addChainType(List<String> elements, boolean commandPresent) { private void addChainType(List<String> elements, boolean commandPresent) {
if(Network.get() != Network.MAINNET) { if(Network.get() != Network.MAINNET) {
elements.add(elements.size() - (commandPresent ? 1 : 0), "--chain"); 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()));
} }
} }

View file

@ -19,6 +19,7 @@ import org.slf4j.LoggerFactory;
import java.io.*; import java.io.*;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.attribute.PosixFilePermission; import java.nio.file.attribute.PosixFilePermission;
import java.nio.file.attribute.PosixFilePermissions; import java.nio.file.attribute.PosixFilePermissions;
import java.security.cert.Certificate; import java.security.cert.Certificate;
@ -216,8 +217,8 @@ public class Storage {
} }
private void checkWalletNetwork(Wallet wallet) { private void checkWalletNetwork(Wallet wallet) {
if(wallet.getNetwork() != null && wallet.getNetwork() != Network.get()) { if(wallet.getNetwork() != null && wallet.getNetwork() != Network.getCanonical()) {
throw new IllegalStateException("Provided " + wallet.getNetwork() + " wallet is invalid on a " + Network.get() + " network. Use a " + wallet.getNetwork() + " configuration to load this wallet."); 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() { public static File getSparrowDir() {
File sparrowDir; File sparrowDir;
if(Network.get() != Network.MAINNET) { Network network = Network.get();
sparrowDir = new File(getSparrowHome(), Network.get().getName()); 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 { } else {
sparrowDir = getSparrowHome(); sparrowDir = getSparrowHome();
} }
@ -536,6 +550,23 @@ public class Storage {
createOwnerOnlyDirectory(sparrowDir); 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; return sparrowDir;
} }

View file

@ -119,7 +119,7 @@ public class Bwt {
*/ */
private void start(Collection<String> outputDescriptors, Collection<String> addresses, Integer rescanSince, Boolean forceRescan, Integer gapLimit, CallbackNotifier callback) { private void start(Collection<String> outputDescriptors, Collection<String> addresses, Integer rescanSince, Boolean forceRescan, Integer gapLimit, CallbackNotifier callback) {
BwtConfig bwtConfig = new BwtConfig(); 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()) { if(!outputDescriptors.isEmpty()) {
bwtConfig.descriptors = outputDescriptors; bwtConfig.descriptors = outputDescriptors;

View file

@ -130,6 +130,8 @@ public class BitcoindTransport implements Transport {
private static File getCookieDir(File bitcoindDir) { private static File getCookieDir(File bitcoindDir) {
if(Network.get() == Network.TESTNET && Files.exists(Path.of(bitcoindDir.getAbsolutePath(), "testnet3", COOKIE_FILENAME))) { if(Network.get() == Network.TESTNET && Files.exists(Path.of(bitcoindDir.getAbsolutePath(), "testnet3", COOKIE_FILENAME))) {
return new File(bitcoindDir, "testnet3"); 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))) { } else if(Network.get() == Network.REGTEST && Files.exists(Path.of(bitcoindDir.getAbsolutePath(), "regtest", COOKIE_FILENAME))) {
return new File(bitcoindDir, "regtest"); return new File(bitcoindDir, "regtest");
} else if(Network.get() == Network.SIGNET && Files.exists(Path.of(bitcoindDir.getAbsolutePath(), "signet", COOKIE_FILENAME))) { } else if(Network.get() == Network.SIGNET && Files.exists(Path.of(bitcoindDir.getAbsolutePath(), "signet", COOKIE_FILENAME))) {