add support for alternative (non-mainnet) networks

This commit is contained in:
Craig Raw 2020-09-28 14:31:25 +02:00
parent e8d8fa6126
commit 747bfa915f
10 changed files with 252 additions and 37 deletions

View file

@ -6,6 +6,7 @@ import com.sparrowwallet.drongo.protocol.ScriptType;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.*; import java.util.*;
import java.util.stream.Collectors;
public class ExtendedKey { public class ExtendedKey {
private final byte[] parentFingerprint; private final byte[] parentFingerprint;
@ -53,7 +54,7 @@ public class ExtendedKey {
} }
public byte[] getExtendedKeyBytes() { public byte[] getExtendedKeyBytes() {
return getExtendedKeyBytes(key.isPubKeyOnly() ? Header.xpub : Header.xprv); return getExtendedKeyBytes(key.isPubKeyOnly() ? Network.get().getXpubHeader() : Network.get().getXprvHeader());
} }
public byte[] getExtendedKeyBytes(Header extendedKeyHeader) { public byte[] getExtendedKeyBytes(Header extendedKeyHeader) {
@ -79,7 +80,7 @@ public class ExtendedKey {
int headerInt = buffer.getInt(); int headerInt = buffer.getInt();
Header header = Header.getHeader(headerInt); Header header = Header.getHeader(headerInt);
if(header == null) { if(header == null) {
throw new IllegalArgumentException("Unknown header bytes: " + DeterministicKey.toBase58(serializedKey).substring(0, 4)); throw new IllegalArgumentException("Unknown header bytes for extended key on " + Network.get().getName() + ": " + DeterministicKey.toBase58(serializedKey).substring(0, 4));
} }
int depth = buffer.get() & 0xFF; // convert signed byte to positive int since depth cannot be negative int depth = buffer.get() & 0xFF; // convert signed byte to positive int since depth cannot be negative
@ -196,38 +197,62 @@ public class ExtendedKey {
return privateKey; return privateKey;
} }
public boolean isMainnet() { public Network getNetwork() {
return mainnet; return mainnet ? Network.MAINNET : Network.TESTNET;
}
public static List<Header> getHeaders(Network network) {
return Arrays.stream(Header.values()).filter(header -> header.getNetwork() == network || (header.getNetwork() == Network.TESTNET && network == Network.REGTEST)).collect(Collectors.toList());
} }
public static Header fromExtendedKey(String xkey) { public static Header fromExtendedKey(String xkey) {
for(Header extendedKeyHeader : Header.values()) { for(Header extendedKeyHeader : getHeaders(Network.get())) {
if(xkey.startsWith(extendedKeyHeader.name)) { if(xkey.startsWith(extendedKeyHeader.name)) {
return extendedKeyHeader; return extendedKeyHeader;
} }
} }
throw new IllegalArgumentException("Unrecognised extended key header for extended key: " + xkey); 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("Unrecognised extended key header for " + Network.get().getName() + ": " + xkey);
} }
public static Header fromScriptType(ScriptType scriptType, boolean privateKey) { public static Header fromScriptType(ScriptType scriptType, boolean privateKey) {
for(Header header : Header.values()) { for(Header header : getHeaders(Network.get())) {
if(header.defaultScriptType != null && header.defaultScriptType.equals(scriptType) && header.isPrivateKey() == privateKey) { if(header.defaultScriptType != null && header.defaultScriptType.equals(scriptType) && header.isPrivateKey() == privateKey) {
return header; return header;
} }
} }
return Header.xpub; return Network.get().getXpubHeader();
} }
public static Header getHeader(int header) { private static Header getHeader(int header) {
for(Header extendedKeyHeader : Header.values()) { for(Header extendedKeyHeader : getHeaders(Network.get())) {
if(header == extendedKeyHeader.header) { if(header == extendedKeyHeader.header) {
return extendedKeyHeader; return extendedKeyHeader;
} }
} }
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.");
}
}
}
return null; return null;
} }
private static List<Network> getOtherNetworks(Network providedNetwork) {
return Arrays.stream(Network.values()).filter(network -> network != providedNetwork).collect(Collectors.toList());
}
} }
} }

View file

@ -0,0 +1,87 @@
package com.sparrowwallet.drongo;
public enum Network {
MAINNET("mainnet", 0, "1", 5, "3", "bc", ExtendedKey.Header.xprv, ExtendedKey.Header.xpub),
TESTNET("testnet", 111, "mn", 196, "2", "tb", ExtendedKey.Header.tprv, ExtendedKey.Header.tpub),
REGTEST("regtest", 111, "mn", 196, "2", "bcrt", ExtendedKey.Header.tprv, ExtendedKey.Header.tpub);
Network(String name, int p2pkhAddressHeader, String p2pkhAddressPrefix, int p2shAddressHeader, String p2shAddressPrefix, String bech32AddressHrp, ExtendedKey.Header xprvHeader, ExtendedKey.Header xpubHeader) {
this.name = name;
this.p2pkhAddressHeader = p2pkhAddressHeader;
this.p2pkhAddressPrefix = p2pkhAddressPrefix;
this.p2shAddressHeader = p2shAddressHeader;
this.p2shAddressPrefix = p2shAddressPrefix;
this.bech32AddressHrp = bech32AddressHrp;
this.xprvHeader = xprvHeader;
this.xpubHeader = xpubHeader;
}
private final String name;
private final int p2pkhAddressHeader;
private final String p2pkhAddressPrefix;
private final int p2shAddressHeader;
private final String p2shAddressPrefix;
private final String bech32AddressHrp;
private final ExtendedKey.Header xprvHeader;
private final ExtendedKey.Header xpubHeader;
private static Network currentNetwork;
public String getName() {
return name;
}
public int getP2PKHAddressHeader() {
return p2pkhAddressHeader;
}
public int getP2SHAddressHeader() {
return p2shAddressHeader;
}
public String getBech32AddressHRP() {
return bech32AddressHrp;
}
public ExtendedKey.Header getXprvHeader() {
return xprvHeader;
}
public ExtendedKey.Header getXpubHeader() {
return xpubHeader;
}
public boolean hasP2PKHAddressPrefix(String address) {
for(String prefix : p2pkhAddressPrefix.split("")) {
if(address.startsWith(prefix)) {
return true;
}
}
return false;
}
public boolean hasP2SHAddressPrefix(String address) {
return address.startsWith(p2shAddressPrefix);
}
public static Network get() {
if(currentNetwork == null) {
currentNetwork = MAINNET;
}
return currentNetwork;
}
public static void set(Network network) {
if(currentNetwork != null && network != currentNetwork && !isTest()) {
throw new IllegalStateException("Network already set to " + currentNetwork.getName());
}
currentNetwork = network;
}
private static boolean isTest() {
return System.getProperty("org.gradle.test.worker") != null;
}
}

View file

@ -1,5 +1,6 @@
package com.sparrowwallet.drongo.address; package com.sparrowwallet.drongo.address;
import com.sparrowwallet.drongo.Network;
import com.sparrowwallet.drongo.protocol.Base58; import com.sparrowwallet.drongo.protocol.Base58;
import com.sparrowwallet.drongo.protocol.Bech32; import com.sparrowwallet.drongo.protocol.Bech32;
import com.sparrowwallet.drongo.protocol.Script; import com.sparrowwallet.drongo.protocol.Script;
@ -7,8 +8,6 @@ import com.sparrowwallet.drongo.protocol.ScriptType;
import java.util.Arrays; import java.util.Arrays;
import static com.sparrowwallet.drongo.address.P2WPKHAddress.HRP;
public abstract class Address { public abstract class Address {
protected final byte[] hash; protected final byte[] hash;
@ -21,14 +20,26 @@ public abstract class Address {
} }
public String getAddress() { public String getAddress() {
return Base58.encodeChecked(getVersion(), hash); return getAddress(Network.get());
}
public String getAddress(Network network) {
return Base58.encodeChecked(getVersion(network), hash);
} }
public String toString() { public String toString() {
return getAddress(); return getAddress(Network.get());
} }
public abstract int getVersion(); public String toString(Network network) {
return getAddress(network);
}
public int getVersion() {
return getVersion(Network.get());
}
public abstract int getVersion(Network network);
public abstract ScriptType getScriptType(); public abstract ScriptType getScriptType();
@ -52,18 +63,37 @@ public abstract class Address {
} }
public static Address fromString(String address) throws InvalidAddressException { public static Address fromString(String address) throws InvalidAddressException {
try {
return fromString(Network.get(), address);
} catch(InvalidAddressException e) {
for(Network network : Network.values()) {
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.");
}
} catch(InvalidAddressException i) {
//ignore
}
}
throw e;
}
}
public static Address fromString(Network network, String address) throws InvalidAddressException {
Exception nested = null; Exception nested = null;
if(address != null && (address.startsWith("1") || address.startsWith("3"))) { if(address != null && (network.hasP2PKHAddressPrefix(address) || network.hasP2SHAddressPrefix(address))) {
try { try {
byte[] decodedBytes = Base58.decodeChecked(address); byte[] decodedBytes = Base58.decodeChecked(address);
if(decodedBytes.length == 21) { if(decodedBytes.length == 21) {
int version = decodedBytes[0]; int version = Byte.toUnsignedInt(decodedBytes[0]);
byte[] hash = Arrays.copyOfRange(decodedBytes, 1, 21); byte[] hash = Arrays.copyOfRange(decodedBytes, 1, 21);
if(version == 0) { if(version == network.getP2PKHAddressHeader()) {
return new P2PKHAddress(hash); return new P2PKHAddress(hash);
} }
if(version == 5) { if(version == network.getP2SHAddressHeader()) {
return new P2SHAddress(hash); return new P2SHAddress(hash);
} }
} }
@ -72,10 +102,10 @@ public abstract class Address {
} }
} }
if(address != null && address.startsWith(HRP)) { if(address != null && address.startsWith(network.getBech32AddressHRP())) {
try { try {
Bech32.Bech32Data data = Bech32.decode(address); Bech32.Bech32Data data = Bech32.decode(address);
if (data.hrp.equals(HRP)) { if(data.hrp.equals(network.getBech32AddressHRP())) {
int witnessVersion = data.data[0]; int witnessVersion = data.data[0];
if (witnessVersion == 0) { if (witnessVersion == 0) {
byte[] convertedProgram = Arrays.copyOfRange(data.data, 1, data.data.length); byte[] convertedProgram = Arrays.copyOfRange(data.data, 1, data.data.length);

View file

@ -1,5 +1,6 @@
package com.sparrowwallet.drongo.address; package com.sparrowwallet.drongo.address;
import com.sparrowwallet.drongo.Network;
import com.sparrowwallet.drongo.Utils; import com.sparrowwallet.drongo.Utils;
import com.sparrowwallet.drongo.protocol.Script; import com.sparrowwallet.drongo.protocol.Script;
import com.sparrowwallet.drongo.protocol.ScriptType; import com.sparrowwallet.drongo.protocol.ScriptType;
@ -12,8 +13,9 @@ public class P2PKAddress extends Address {
this.pubKey = pubKey; this.pubKey = pubKey;
} }
public int getVersion() { @Override
return 0; public int getVersion(Network network) {
return network.getP2PKHAddressHeader();
} }
public ScriptType getScriptType() { public ScriptType getScriptType() {

View file

@ -1,5 +1,6 @@
package com.sparrowwallet.drongo.address; package com.sparrowwallet.drongo.address;
import com.sparrowwallet.drongo.Network;
import com.sparrowwallet.drongo.protocol.Script; import com.sparrowwallet.drongo.protocol.Script;
import com.sparrowwallet.drongo.protocol.ScriptType; import com.sparrowwallet.drongo.protocol.ScriptType;
@ -8,14 +9,17 @@ public class P2PKHAddress extends Address {
super(pubKeyHash); super(pubKeyHash);
} }
public int getVersion() { @Override
return 0; public int getVersion(Network network) {
return network.getP2PKHAddressHeader();
} }
@Override
public ScriptType getScriptType() { public ScriptType getScriptType() {
return ScriptType.P2PKH; return ScriptType.P2PKH;
} }
@Override
public Script getOutputScript() { public Script getOutputScript() {
return getScriptType().getOutputScript(hash); return getScriptType().getOutputScript(hash);
} }

View file

@ -1,5 +1,6 @@
package com.sparrowwallet.drongo.address; package com.sparrowwallet.drongo.address;
import com.sparrowwallet.drongo.Network;
import com.sparrowwallet.drongo.Utils; import com.sparrowwallet.drongo.Utils;
import com.sparrowwallet.drongo.protocol.Script; import com.sparrowwallet.drongo.protocol.Script;
import com.sparrowwallet.drongo.protocol.ScriptType; import com.sparrowwallet.drongo.protocol.ScriptType;
@ -9,8 +10,9 @@ public class P2SHAddress extends Address {
super(scriptHash); super(scriptHash);
} }
public int getVersion() { @Override
return 5; public int getVersion(Network network) {
return network.getP2SHAddressHeader();
} }
@Override @Override

View file

@ -1,24 +1,26 @@
package com.sparrowwallet.drongo.address; package com.sparrowwallet.drongo.address;
import com.sparrowwallet.drongo.Network;
import com.sparrowwallet.drongo.protocol.Bech32; import com.sparrowwallet.drongo.protocol.Bech32;
import com.sparrowwallet.drongo.protocol.Script; import com.sparrowwallet.drongo.protocol.Script;
import com.sparrowwallet.drongo.protocol.ScriptType; import com.sparrowwallet.drongo.protocol.ScriptType;
public class P2WPKHAddress extends Address { public class P2WPKHAddress extends Address {
public static final String HRP = "bc";
public P2WPKHAddress(byte[] pubKeyHash) { public P2WPKHAddress(byte[] pubKeyHash) {
super(pubKeyHash); super(pubKeyHash);
} }
public int getVersion() { @Override
public int getVersion(Network network) {
return 0; return 0;
} }
public String getAddress() { @Override
return Bech32.encode(HRP, getVersion(), hash); public String getAddress(Network network) {
return Bech32.encode(network.getBech32AddressHRP(), getVersion(), hash);
} }
@Override
public ScriptType getScriptType() { public ScriptType getScriptType() {
return ScriptType.P2WPKH; return ScriptType.P2WPKH;
} }

View file

@ -1,22 +1,24 @@
package com.sparrowwallet.drongo.address; package com.sparrowwallet.drongo.address;
import com.sparrowwallet.drongo.Network;
import com.sparrowwallet.drongo.protocol.*; import com.sparrowwallet.drongo.protocol.*;
import static com.sparrowwallet.drongo.address.P2WPKHAddress.HRP;
public class P2WSHAddress extends Address { public class P2WSHAddress extends Address {
public P2WSHAddress(byte[] scriptHash) { public P2WSHAddress(byte[] scriptHash) {
super(scriptHash); super(scriptHash);
} }
public int getVersion() { @Override
public int getVersion(Network network) {
return 0; return 0;
} }
public String getAddress() { @Override
return Bech32.encode(HRP, getVersion(), hash); public String getAddress(Network network) {
return Bech32.encode(network.getBech32AddressHRP(), getVersion(), hash);
} }
@Override
public ScriptType getScriptType() { public ScriptType getScriptType() {
return ScriptType.P2WSH; return ScriptType.P2WSH;
} }

View file

@ -1,5 +1,7 @@
package com.sparrowwallet.drongo.address; package com.sparrowwallet.drongo.address;
import com.sparrowwallet.drongo.Network;
import org.junit.After;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
@ -23,6 +25,51 @@ public class AddressTest {
Address address4 = Address.fromString("34jnjFM4SbaB7Q8aMtNDG849RQ1gUYgpgo"); Address address4 = Address.fromString("34jnjFM4SbaB7Q8aMtNDG849RQ1gUYgpgo");
Assert.assertTrue(address4 instanceof P2SHAddress); Assert.assertTrue(address4 instanceof P2SHAddress);
Assert.assertEquals("34jnjFM4SbaB7Q8aMtNDG849RQ1gUYgpgo", address4.toString()); Assert.assertEquals("34jnjFM4SbaB7Q8aMtNDG849RQ1gUYgpgo", address4.toString());
Address address5 = Address.fromString(Network.TESTNET, "tb1qawkzyj2l5yck5jq4wyhkc4837x088580y9uyk8");
Assert.assertTrue(address5 instanceof P2WPKHAddress);
Assert.assertEquals("tb1qawkzyj2l5yck5jq4wyhkc4837x088580y9uyk8", address5.toString(Network.TESTNET));
Address address6 = Address.fromString(Network.TESTNET, "tb1q8kdkthp5a6vfrdas84efkpv25ul3s9wpzc755cra8av48xq4a7wsjcsdma");
Assert.assertTrue(address6 instanceof P2WSHAddress);
Assert.assertEquals("tb1q8kdkthp5a6vfrdas84efkpv25ul3s9wpzc755cra8av48xq4a7wsjcsdma", address6.toString(Network.TESTNET));
Address address7 = Address.fromString(Network.TESTNET, "mng6R5oLWBBo8iFWU9Mx4zFy5pWhrWMeW2");
Assert.assertTrue(address7 instanceof P2PKHAddress);
Assert.assertEquals("mng6R5oLWBBo8iFWU9Mx4zFy5pWhrWMeW2", address7.toString(Network.TESTNET));
Address address8 = Address.fromString(Network.TESTNET, "n1S1rnnZm3RdW9iuAF6Hjk3gLZWGc59zDi");
Assert.assertTrue(address8 instanceof P2PKHAddress);
Assert.assertEquals("n1S1rnnZm3RdW9iuAF6Hjk3gLZWGc59zDi", address8.toString(Network.TESTNET));
Address address9 = Address.fromString(Network.TESTNET, "2NCZUtUt6gzXyBiPEQi5yQyrgR6f6F6Ki6A");
Assert.assertTrue(address9 instanceof P2SHAddress);
Assert.assertEquals("2NCZUtUt6gzXyBiPEQi5yQyrgR6f6F6Ki6A", address9.toString(Network.TESTNET));
}
@Test
public void testnetValidAddressTest() throws InvalidAddressException {
Network.set(Network.TESTNET);
Address address5 = Address.fromString("tb1qawkzyj2l5yck5jq4wyhkc4837x088580y9uyk8");
Assert.assertTrue(address5 instanceof P2WPKHAddress);
Assert.assertEquals("tb1qawkzyj2l5yck5jq4wyhkc4837x088580y9uyk8", address5.toString());
Address address6 = Address.fromString("tb1q8kdkthp5a6vfrdas84efkpv25ul3s9wpzc755cra8av48xq4a7wsjcsdma");
Assert.assertTrue(address6 instanceof P2WSHAddress);
Assert.assertEquals("tb1q8kdkthp5a6vfrdas84efkpv25ul3s9wpzc755cra8av48xq4a7wsjcsdma", address6.toString());
Address address7 = Address.fromString("mng6R5oLWBBo8iFWU9Mx4zFy5pWhrWMeW2");
Assert.assertTrue(address7 instanceof P2PKHAddress);
Assert.assertEquals("mng6R5oLWBBo8iFWU9Mx4zFy5pWhrWMeW2", address7.toString());
Address address8 = Address.fromString("n1S1rnnZm3RdW9iuAF6Hjk3gLZWGc59zDi");
Assert.assertTrue(address8 instanceof P2PKHAddress);
Assert.assertEquals("n1S1rnnZm3RdW9iuAF6Hjk3gLZWGc59zDi", address8.toString());
Address address9 = Address.fromString("2NCZUtUt6gzXyBiPEQi5yQyrgR6f6F6Ki6A");
Assert.assertTrue(address9 instanceof P2SHAddress);
Assert.assertEquals("2NCZUtUt6gzXyBiPEQi5yQyrgR6f6F6Ki6A", address9.toString());
} }
@Test @Test
@ -67,4 +114,9 @@ public class AddressTest {
public void invalidChecksumAddressTest2() throws InvalidAddressException { public void invalidChecksumAddressTest2() throws InvalidAddressException {
Address address1 = Address.fromString("bc1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qccfmb3"); Address address1 = Address.fromString("bc1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qccfmb3");
} }
@After
public void tearDown() throws Exception {
Network.set(null);
}
} }

View file

@ -2,10 +2,12 @@ package com.sparrowwallet.drongo.psbt;
import com.sparrowwallet.drongo.ExtendedKey; import com.sparrowwallet.drongo.ExtendedKey;
import com.sparrowwallet.drongo.KeyDerivation; import com.sparrowwallet.drongo.KeyDerivation;
import com.sparrowwallet.drongo.Network;
import com.sparrowwallet.drongo.Utils; import com.sparrowwallet.drongo.Utils;
import com.sparrowwallet.drongo.crypto.ECKey; import com.sparrowwallet.drongo.crypto.ECKey;
import com.sparrowwallet.drongo.protocol.*; import com.sparrowwallet.drongo.protocol.*;
import org.bouncycastle.util.encoders.Hex; import org.bouncycastle.util.encoders.Hex;
import org.junit.After;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
@ -197,6 +199,8 @@ public class PSBTTest {
@Test @Test
public void validP2wshMultisigWithXpubs() throws PSBTParseException { public void validP2wshMultisigWithXpubs() throws PSBTParseException {
Network.set(Network.TESTNET);
String psbt = "cHNidP8BAFICAAAAAZ38ZijCbFiZ/hvT3DOGZb/VXXraEPYiCXPfLTht7BJ2AQAAAAD/////AfA9zR0AAAAAFgAUezoAv9wU0neVwrdJAdCdpu8TNXkAAAAATwEENYfPAto/0AiAAAAAlwSLGtBEWx7IJ1UXcnyHtOTrwYogP/oPlMAVZr046QADUbdDiH7h1A3DKmBDck8tZFmztaTXPa7I+64EcvO8Q+IM2QxqT64AAIAAAACATwEENYfPAto/0AiAAAABuQRSQnE5zXjCz/JES+NTzVhgXj5RMoXlKLQH+uP2FzUD0wpel8itvFV9rCrZp+OcFyLrrGnmaLbyZnzB1nHIPKsM2QxqT64AAIABAACAAAEBKwBlzR0AAAAAIgAgLFSGEmxJeAeagU4TcV1l82RZ5NbMre0mbQUIZFuvpjIBBUdSIQKdoSzbWyNWkrkVNq/v5ckcOrlHPY5DtTODarRWKZyIcSEDNys0I07Xz5wf6l0F1EFVeSe+lUKxYusC4ass6AIkwAtSriIGAp2hLNtbI1aSuRU2r+/lyRw6uUc9jkO1M4NqtFYpnIhxENkMak+uAACAAAAAgAAAAAAiBgM3KzQjTtfPnB/qXQXUQVV5J76VQrFi6wLhqyzoAiTACxDZDGpPrgAAgAEAAIAAAAAAACICA57/H1R6HV+S36K6evaslxpL0DukpzSwMVaiVritOh75EO3kXMUAAACAAAAAgAEAAIAA"; String psbt = "cHNidP8BAFICAAAAAZ38ZijCbFiZ/hvT3DOGZb/VXXraEPYiCXPfLTht7BJ2AQAAAAD/////AfA9zR0AAAAAFgAUezoAv9wU0neVwrdJAdCdpu8TNXkAAAAATwEENYfPAto/0AiAAAAAlwSLGtBEWx7IJ1UXcnyHtOTrwYogP/oPlMAVZr046QADUbdDiH7h1A3DKmBDck8tZFmztaTXPa7I+64EcvO8Q+IM2QxqT64AAIAAAACATwEENYfPAto/0AiAAAABuQRSQnE5zXjCz/JES+NTzVhgXj5RMoXlKLQH+uP2FzUD0wpel8itvFV9rCrZp+OcFyLrrGnmaLbyZnzB1nHIPKsM2QxqT64AAIABAACAAAEBKwBlzR0AAAAAIgAgLFSGEmxJeAeagU4TcV1l82RZ5NbMre0mbQUIZFuvpjIBBUdSIQKdoSzbWyNWkrkVNq/v5ckcOrlHPY5DtTODarRWKZyIcSEDNys0I07Xz5wf6l0F1EFVeSe+lUKxYusC4ass6AIkwAtSriIGAp2hLNtbI1aSuRU2r+/lyRw6uUc9jkO1M4NqtFYpnIhxENkMak+uAACAAAAAgAAAAAAiBgM3KzQjTtfPnB/qXQXUQVV5J76VQrFi6wLhqyzoAiTACxDZDGpPrgAAgAEAAIAAAAAAACICA57/H1R6HV+S36K6evaslxpL0DukpzSwMVaiVritOh75EO3kXMUAAACAAAAAgAEAAIAA";
PSBT psbt1 = PSBT.fromString(psbt); PSBT psbt1 = PSBT.fromString(psbt);
@ -371,4 +375,9 @@ public class PSBTTest {
Assert.assertEquals("0200000000010258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd7500000000da00473044022074018ad4180097b873323c0015720b3684cc8123891048e7dbcd9b55ad679c99022073d369b740e3eb53dcefa33823c8070514ca55a7dd9544f157c167913261118c01483045022100f61038b308dc1da865a34852746f015772934208c6d24454393cd99bdf2217770220056e675a675a6d0a02b85b14e5e29074d8a25a9b5760bea2816f661910a006ea01475221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752aeffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d01000000232200208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b2028903ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f000400473044022062eb7a556107a7c73f45ac4ab5a1dddf6f7075fb1275969a7f383efff784bcb202200c05dbb7470dbf2f08557dd356c7325c1ed30913e996cd3840945db12228da5f01473044022065f45ba5998b59a27ffe1a7bed016af1f1f90d54b3aa8f7450aa5f56a25103bd02207f724703ad1edb96680b284b56d4ffcb88f7fb759eabbe08aa30f29b851383d20147522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae00000000", Utils.bytesToHex(transaction.bitcoinSerialize())); Assert.assertEquals("0200000000010258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd7500000000da00473044022074018ad4180097b873323c0015720b3684cc8123891048e7dbcd9b55ad679c99022073d369b740e3eb53dcefa33823c8070514ca55a7dd9544f157c167913261118c01483045022100f61038b308dc1da865a34852746f015772934208c6d24454393cd99bdf2217770220056e675a675a6d0a02b85b14e5e29074d8a25a9b5760bea2816f661910a006ea01475221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752aeffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d01000000232200208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b2028903ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f000400473044022062eb7a556107a7c73f45ac4ab5a1dddf6f7075fb1275969a7f383efff784bcb202200c05dbb7470dbf2f08557dd356c7325c1ed30913e996cd3840945db12228da5f01473044022065f45ba5998b59a27ffe1a7bed016af1f1f90d54b3aa8f7450aa5f56a25103bd02207f724703ad1edb96680b284b56d4ffcb88f7fb759eabbe08aa30f29b851383d20147522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae00000000", Utils.bytesToHex(transaction.bitcoinSerialize()));
} }
@After
public void tearDown() throws Exception {
Network.set(null);
}
} }