mirror of
https://github.com/sparrowwallet/drongo.git
synced 2024-12-27 02:26:44 +00:00
address parsing support
This commit is contained in:
parent
24cde9d073
commit
c4dd1cb9dd
5 changed files with 151 additions and 1 deletions
|
@ -1,8 +1,13 @@
|
||||||
package com.sparrowwallet.drongo.address;
|
package com.sparrowwallet.drongo.address;
|
||||||
|
|
||||||
import com.sparrowwallet.drongo.protocol.Base58;
|
import com.sparrowwallet.drongo.protocol.Base58;
|
||||||
|
import com.sparrowwallet.drongo.protocol.Bech32;
|
||||||
import com.sparrowwallet.drongo.protocol.ScriptType;
|
import com.sparrowwallet.drongo.protocol.ScriptType;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
@ -42,4 +47,53 @@ public abstract class Address {
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return getAddress().hashCode();
|
return getAddress().hashCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Address fromString(String address) throws InvalidAddressException {
|
||||||
|
Exception nested = null;
|
||||||
|
|
||||||
|
if(address != null && (address.startsWith("1") || address.startsWith("3"))) {
|
||||||
|
try {
|
||||||
|
byte[] decodedBytes = Base58.decodeChecked(address);
|
||||||
|
if(decodedBytes.length == 21) {
|
||||||
|
int version = decodedBytes[0];
|
||||||
|
byte[] hash = Arrays.copyOfRange(decodedBytes, 1, 21);
|
||||||
|
if(version == 0) {
|
||||||
|
return new P2PKHAddress(hash);
|
||||||
|
}
|
||||||
|
if(version == 5) {
|
||||||
|
return new P2SHAddress(hash);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
nested = e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(address != null && address.startsWith(HRP)) {
|
||||||
|
try {
|
||||||
|
Bech32.Bech32Data data = Bech32.decode(address);
|
||||||
|
if (data.hrp.equals(HRP)) {
|
||||||
|
int witnessVersion = data.data[0];
|
||||||
|
if (witnessVersion == 0) {
|
||||||
|
byte[] convertedProgram = Arrays.copyOfRange(data.data, 1, data.data.length);
|
||||||
|
byte[] witnessProgram = Bech32.convertBits(convertedProgram, 0, convertedProgram.length, 5, 8, false);
|
||||||
|
if (witnessProgram.length == 20) {
|
||||||
|
return new P2WPKHAddress(witnessProgram);
|
||||||
|
}
|
||||||
|
if (witnessProgram.length == 32) {
|
||||||
|
return new P2WSHAddress(witnessProgram);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
nested = e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(nested != null) {
|
||||||
|
throw new InvalidAddressException("Could not parse invalid address " + address, nested);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new InvalidAddressException("Could not parse invalid address " + address);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
package com.sparrowwallet.drongo.address;
|
||||||
|
|
||||||
|
public class InvalidAddressException extends Exception {
|
||||||
|
public InvalidAddressException() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public InvalidAddressException(String msg) {
|
||||||
|
super(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
public InvalidAddressException(Throwable cause) {
|
||||||
|
super(cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
public InvalidAddressException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
}
|
|
@ -178,7 +178,7 @@ public class Bech32 {
|
||||||
/**
|
/**
|
||||||
* Helper for re-arranging bits into groups.
|
* Helper for re-arranging bits into groups.
|
||||||
*/
|
*/
|
||||||
private static byte[] convertBits(final byte[] in, final int inStart, final int inLen, final int fromBits,
|
public static byte[] convertBits(final byte[] in, final int inStart, final int inLen, final int fromBits,
|
||||||
final int toBits, final boolean pad) {
|
final int toBits, final boolean pad) {
|
||||||
int acc = 0;
|
int acc = 0;
|
||||||
int bits = 0;
|
int bits = 0;
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
package com.sparrowwallet.drongo.wallet;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
public interface UtxoSelector {
|
||||||
|
Collection<BlockTransactionHashIndex> select(long targetValue, Collection<BlockTransactionHashIndex> candidates);
|
||||||
|
}
|
|
@ -0,0 +1,70 @@
|
||||||
|
package com.sparrowwallet.drongo.address;
|
||||||
|
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.security.SecureRandom;
|
||||||
|
|
||||||
|
public class AddressTest {
|
||||||
|
@Test
|
||||||
|
public void validAddressTest() throws InvalidAddressException {
|
||||||
|
Address address1 = Address.fromString("bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4");
|
||||||
|
Assert.assertTrue(address1 instanceof P2WPKHAddress);
|
||||||
|
Assert.assertEquals("bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4", address1.toString());
|
||||||
|
|
||||||
|
Address address2 = Address.fromString("bc1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qccfmv3");
|
||||||
|
Assert.assertTrue(address2 instanceof P2WSHAddress);
|
||||||
|
Assert.assertEquals("bc1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qccfmv3", address2.toString());
|
||||||
|
|
||||||
|
Address address3 = Address.fromString("19Sp9dLinHy3dKo2Xxj53ouuZWAoVGGhg8");
|
||||||
|
Assert.assertTrue(address3 instanceof P2PKHAddress);
|
||||||
|
Assert.assertEquals("19Sp9dLinHy3dKo2Xxj53ouuZWAoVGGhg8", address3.toString());
|
||||||
|
|
||||||
|
Address address4 = Address.fromString("34jnjFM4SbaB7Q8aMtNDG849RQ1gUYgpgo");
|
||||||
|
Assert.assertTrue(address4 instanceof P2SHAddress);
|
||||||
|
Assert.assertEquals("34jnjFM4SbaB7Q8aMtNDG849RQ1gUYgpgo", address4.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void validRandomAddressTest() throws InvalidAddressException {
|
||||||
|
SecureRandom random = new SecureRandom();
|
||||||
|
byte[] values = new byte[20];
|
||||||
|
|
||||||
|
for(int i = 0; i < 100; i++) {
|
||||||
|
random.nextBytes(values);
|
||||||
|
Address address = (i % 2 == 0 ? new P2PKHAddress(values) : new P2WPKHAddress(values));
|
||||||
|
String strAddress = address.toString();
|
||||||
|
Address checkAddress = Address.fromString(strAddress);
|
||||||
|
Assert.assertArrayEquals(values, checkAddress.getHash());
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] values32 = new byte[32];
|
||||||
|
for(int i = 0; i < 100; i++) {
|
||||||
|
random.nextBytes(values32);
|
||||||
|
Address address = new P2WSHAddress(values32);
|
||||||
|
String strAddress = address.toString();
|
||||||
|
Address checkAddress = Address.fromString(strAddress);
|
||||||
|
Assert.assertArrayEquals(values32, checkAddress.getHash());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = InvalidAddressException.class)
|
||||||
|
public void invalidCharacterAddressTest() throws InvalidAddressException {
|
||||||
|
Address address1 = Address.fromString("bc1qw508d6qejxtdg4y5R3zarvary0c5xw7kv8f3t4");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = InvalidAddressException.class)
|
||||||
|
public void invalidVersionAddressTest() throws InvalidAddressException {
|
||||||
|
Address address1 = Address.fromString("44jnjFM4SbaB7Q8aMtNDG849RQ1gUYgpgo");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = InvalidAddressException.class)
|
||||||
|
public void invalidChecksumAddressTest() throws InvalidAddressException {
|
||||||
|
Address address1 = Address.fromString("34jnjFM4SbaB7Q7aMtNDG849RQ1gUYgpgo");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = InvalidAddressException.class)
|
||||||
|
public void invalidChecksumAddressTest2() throws InvalidAddressException {
|
||||||
|
Address address1 = Address.fromString("bc1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qccfmb3");
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue