From 60ac42800222a487651b93529796d31e5a954b99 Mon Sep 17 00:00:00 2001 From: Craig Raw Date: Wed, 8 May 2024 15:49:59 +0200 Subject: [PATCH] add testnet4 network support --- .../com/sparrowwallet/drongo/ExtendedKey.java | 14 ++++---- .../com/sparrowwallet/drongo/Network.java | 34 +++++++++++++++---- .../sparrowwallet/drongo/address/Address.java | 6 ++-- .../drongo/crypto/DumpedPrivateKey.java | 2 +- .../sparrowwallet/drongo/wallet/Wallet.java | 2 +- 5 files changed, 41 insertions(+), 17 deletions(-) diff --git a/src/main/java/com/sparrowwallet/drongo/ExtendedKey.java b/src/main/java/com/sparrowwallet/drongo/ExtendedKey.java index 67b1d50..2d3e80e 100644 --- a/src/main/java/com/sparrowwallet/drongo/ExtendedKey.java +++ b/src/main/java/com/sparrowwallet/drongo/ExtendedKey.java @@ -80,7 +80,7 @@ public class ExtendedKey { int headerInt = buffer.getInt(); Header header = Header.getHeader(headerInt); if(header == null) { - throw new IllegalArgumentException("Unknown header bytes for extended key on " + Network.get().getName() + ": " + DeterministicKey.toBase58(serializedKey).substring(0, 4)); + throw new IllegalArgumentException("Unknown header bytes for extended key on " + Network.getCanonical().getName() + ": " + DeterministicKey.toBase58(serializedKey).substring(0, 4)); } int depth = buffer.get() & 0xFF; // convert signed byte to positive int since depth cannot be negative @@ -206,7 +206,9 @@ public class ExtendedKey { } public static List
getHeaders(Network network) { - return Arrays.stream(Header.values()).filter(header -> header.getNetwork() == network || (header.getNetwork() == Network.TESTNET && network == Network.REGTEST) || (header.getNetwork() == Network.TESTNET && network == Network.SIGNET)).collect(Collectors.toList()); + return Arrays.stream(Header.values()) + .filter(header -> header.getNetwork() == network || (header.getNetwork() == Network.TESTNET && network == Network.REGTEST) || (header.getNetwork() == Network.TESTNET && network == Network.SIGNET) || (header.getNetwork() == Network.TESTNET && network == Network.TESTNET4)) + .collect(Collectors.toList()); } public static Header fromExtendedKey(String xkey) { @@ -219,12 +221,12 @@ public class ExtendedKey { for(Network network : getOtherNetworks(Network.get())) { for(Header otherNetworkKeyHeader : getHeaders(network)) { if(xkey.startsWith(otherNetworkKeyHeader.name)) { - throw new IllegalArgumentException("Provided " + otherNetworkKeyHeader.name + " extended key invalid on configured " + Network.get().getName() + " network. Use a " + network.getName() + " configuration to use this extended key."); + throw new IllegalArgumentException("Provided " + otherNetworkKeyHeader.name + " extended key invalid on configured " + Network.getCanonical().getName() + " network. Use a " + network.getName() + " configuration to use this extended key."); } } } - throw new IllegalArgumentException("Unrecognised extended key header for " + Network.get().getName() + ": " + xkey); + throw new IllegalArgumentException("Unrecognised extended key header for " + Network.getCanonical().getName() + ": " + xkey); } public static Header fromScriptType(ScriptType scriptType, boolean privateKey) { @@ -247,7 +249,7 @@ public class ExtendedKey { for(Network otherNetwork : getOtherNetworks(Network.get())) { for(Header otherNetworkKeyHeader : getHeaders(otherNetwork)) { if(header == otherNetworkKeyHeader.header) { - throw new IllegalArgumentException("Provided " + otherNetworkKeyHeader.name + " extended key invalid on configured " + Network.get().getName() + " network. Use a " + otherNetwork.getName() + " configuration to use this extended key."); + throw new IllegalArgumentException("Provided " + otherNetworkKeyHeader.name + " extended key invalid on configured " + Network.getCanonical().getName() + " network. Use a " + otherNetwork.getName() + " configuration to use this extended key."); } } } @@ -256,7 +258,7 @@ public class ExtendedKey { } private static List getOtherNetworks(Network providedNetwork) { - return Arrays.stream(Network.values()).filter(network -> network != providedNetwork).collect(Collectors.toList()); + return Arrays.stream(Network.canonicalValues()).filter(network -> network != providedNetwork).collect(Collectors.toList()); } } } \ No newline at end of file diff --git a/src/main/java/com/sparrowwallet/drongo/Network.java b/src/main/java/com/sparrowwallet/drongo/Network.java index a20fa34..a413e0e 100644 --- a/src/main/java/com/sparrowwallet/drongo/Network.java +++ b/src/main/java/com/sparrowwallet/drongo/Network.java @@ -3,15 +3,19 @@ package com.sparrowwallet.drongo; import java.util.Locale; public enum Network { - MAINNET("mainnet", 0, "1", 5, "3", "bc", ExtendedKey.Header.xprv, ExtendedKey.Header.xpub, 128, 8332), - TESTNET("testnet", 111, "mn", 196, "2", "tb", ExtendedKey.Header.tprv, ExtendedKey.Header.tpub, 239, 18332), - REGTEST("regtest", 111, "mn", 196, "2", "bcrt", ExtendedKey.Header.tprv, ExtendedKey.Header.tpub, 239, 18443), - SIGNET("signet", 111, "mn", 196, "2", "tb", ExtendedKey.Header.tprv, ExtendedKey.Header.tpub, 239, 38332); + MAINNET("mainnet", "Mainnet", "mainnet", 0, "1", 5, "3", "bc", ExtendedKey.Header.xprv, ExtendedKey.Header.xpub, 128, 8332), + TESTNET("testnet", "Testnet3", "testnet3", 111, "mn", 196, "2", "tb", ExtendedKey.Header.tprv, ExtendedKey.Header.tpub, 239, 18332), + REGTEST("regtest", "Regtest", "regtest", 111, "mn", 196, "2", "bcrt", ExtendedKey.Header.tprv, ExtendedKey.Header.tpub, 239, 18443), + SIGNET("signet", "Signet", "signet", 111, "mn", 196, "2", "tb", ExtendedKey.Header.tprv, ExtendedKey.Header.tpub, 239, 38332), + TESTNET4("testnet4", "Testnet4", "testnet4", 111, "mn", 196, "2", "tb", ExtendedKey.Header.tprv, ExtendedKey.Header.tpub, 239, 48332); public static final String BLOCK_HEIGHT_PROPERTY = "com.sparrowwallet.blockHeight"; + private static final Network[] CANONICAL_VALUES = new Network[]{MAINNET, TESTNET, REGTEST, SIGNET}; - Network(String name, int p2pkhAddressHeader, String p2pkhAddressPrefix, int p2shAddressHeader, String p2shAddressPrefix, String bech32AddressHrp, ExtendedKey.Header xprvHeader, ExtendedKey.Header xpubHeader, int dumpedPrivateKeyHeader, int defaultPort) { + Network(String name, String displayName, String home, int p2pkhAddressHeader, String p2pkhAddressPrefix, int p2shAddressHeader, String p2shAddressPrefix, String bech32AddressHrp, ExtendedKey.Header xprvHeader, ExtendedKey.Header xpubHeader, int dumpedPrivateKeyHeader, int defaultPort) { this.name = name; + this.displayName = displayName; + this.home = home; this.p2pkhAddressHeader = p2pkhAddressHeader; this.p2pkhAddressPrefix = p2pkhAddressPrefix; this.p2shAddressHeader = p2shAddressHeader; @@ -24,6 +28,8 @@ public enum Network { } private final String name; + private final String displayName; + private final String home; private final int p2pkhAddressHeader; private final String p2pkhAddressPrefix; private final int p2shAddressHeader; @@ -40,10 +46,18 @@ public enum Network { return name; } - public String toDisplayString() { + public String getCapitalizedName() { return name.substring(0, 1).toUpperCase(Locale.ROOT) + name.substring(1); } + public String toDisplayString() { + return displayName; + } + + public String getHome() { + return home; + } + public int getP2PKHAddressHeader() { return p2pkhAddressHeader; } @@ -94,6 +108,14 @@ public enum Network { return currentNetwork; } + public static Network getCanonical() { + return get() == TESTNET4 ? TESTNET : get(); + } + + public static Network[] canonicalValues() { + return CANONICAL_VALUES; + } + public static void set(Network network) { if(currentNetwork != null && network != currentNetwork && !isTest()) { throw new IllegalStateException("Network already set to " + currentNetwork.getName()); diff --git a/src/main/java/com/sparrowwallet/drongo/address/Address.java b/src/main/java/com/sparrowwallet/drongo/address/Address.java index fc9bb0d..c44fa86 100644 --- a/src/main/java/com/sparrowwallet/drongo/address/Address.java +++ b/src/main/java/com/sparrowwallet/drongo/address/Address.java @@ -70,11 +70,11 @@ public abstract class Address { try { return fromString(Network.get(), address); } catch(InvalidAddressException e) { - for(Network network : Network.values()) { + for(Network network : Network.canonicalValues()) { try { fromString(network, address); - if(network != Network.get()) { - throw new InvalidAddressException("Provided " + network.getName() + " address invalid on configured " + Network.get().getName() + " network: " + address + ". Use a " + network.getName() + " configuration to use this address."); + if(network != Network.getCanonical()) { + throw new InvalidAddressException("Provided " + network.getName() + " address invalid on configured " + Network.getCanonical().getName() + " network: " + address + ". Use a " + network.getName() + " configuration to use this address."); } } catch(InvalidAddressException i) { //ignore diff --git a/src/main/java/com/sparrowwallet/drongo/crypto/DumpedPrivateKey.java b/src/main/java/com/sparrowwallet/drongo/crypto/DumpedPrivateKey.java index 8fac3ce..8a45d2d 100644 --- a/src/main/java/com/sparrowwallet/drongo/crypto/DumpedPrivateKey.java +++ b/src/main/java/com/sparrowwallet/drongo/crypto/DumpedPrivateKey.java @@ -48,7 +48,7 @@ public class DumpedPrivateKey extends VersionedChecksummedBytes { private DumpedPrivateKey(String encoded) { super(encoded); if(version != Network.get().getDumpedPrivateKeyHeader()) - throw new IllegalArgumentException("Invalid version " + version + " for network " + Network.get()); + throw new IllegalArgumentException("Invalid version " + version + " for network " + Network.getCanonical()); if(bytes.length == 33 && bytes[32] == 1) { compressed = true; bytes = Arrays.copyOf(bytes, 32); // Chop off the additional marker byte. diff --git a/src/main/java/com/sparrowwallet/drongo/wallet/Wallet.java b/src/main/java/com/sparrowwallet/drongo/wallet/Wallet.java index 65f31fe..d662f63 100644 --- a/src/main/java/com/sparrowwallet/drongo/wallet/Wallet.java +++ b/src/main/java/com/sparrowwallet/drongo/wallet/Wallet.java @@ -32,7 +32,7 @@ public class Wallet extends Persistable implements Comparable { private String label; private Wallet masterWallet; private List childWallets = new ArrayList<>(); - private Network network = Network.get(); + private Network network = Network.getCanonical(); private PolicyType policyType; private ScriptType scriptType; private Policy defaultPolicy;