mirror of
https://github.com/bitcoinj/bitcoinj.git
synced 2025-02-24 06:47:54 +01:00
Address: convert to interface
* Migrate protected members to subclasses * Remove constructors * Migrate hashCode and equals to subclasses
This commit is contained in:
parent
6c84ffec85
commit
f9be0b2a3d
4 changed files with 69 additions and 90 deletions
|
@ -21,46 +21,15 @@ import org.bitcoinj.crypto.ECKey;
|
||||||
import org.bitcoinj.core.NetworkParameters;
|
import org.bitcoinj.core.NetworkParameters;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
import static com.google.common.base.Preconditions.checkNotNull;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base class for addresses, e.g. native segwit addresses ({@link SegwitAddress}) or legacy addresses ({@link LegacyAddress}).
|
* Interface for addresses, e.g. native segwit addresses ({@link SegwitAddress}) or legacy addresses ({@link LegacyAddress}).
|
||||||
* <p>
|
* <p>
|
||||||
* Use an implementation of {@link AddressParser#parseAddress(String, Network)} to conveniently construct any kind of address from its textual
|
* Use an implementation of {@link AddressParser#parseAddress(String, Network)} to conveniently construct any kind of address from its textual
|
||||||
* form.
|
* form.
|
||||||
*/
|
*/
|
||||||
public abstract class Address implements Comparable<Address> {
|
public interface Address extends Comparable<Address> {
|
||||||
protected final Network network;
|
|
||||||
protected final byte[] bytes;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Construct an address from its binary form.
|
|
||||||
*
|
|
||||||
* @param params the network this address is valid for
|
|
||||||
* @param bytes the binary address data
|
|
||||||
* @deprecated Use {@link Address#Address(Network, byte[])}
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
protected Address(NetworkParameters params, byte[] bytes) {
|
|
||||||
this.network = checkNotNull(params).network();
|
|
||||||
this.bytes = checkNotNull(bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Construct an address from its binary form.
|
|
||||||
*
|
|
||||||
* @param network the network this address is valid for
|
|
||||||
* @param bytes the binary address data
|
|
||||||
*/
|
|
||||||
protected Address(Network network, byte[] bytes) {
|
|
||||||
this.network = checkNotNull(network);
|
|
||||||
this.bytes = checkNotNull(bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct an address from its textual form.
|
* Construct an address from its textual form.
|
||||||
*
|
*
|
||||||
|
@ -76,7 +45,7 @@ public abstract class Address implements Comparable<Address> {
|
||||||
* @deprecated Use {@link org.bitcoinj.wallet.Wallet#parseAddress(String)} or {@link AddressParser#parseAddress(String, Network)}
|
* @deprecated Use {@link org.bitcoinj.wallet.Wallet#parseAddress(String)} or {@link AddressParser#parseAddress(String, Network)}
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public static Address fromString(@Nullable NetworkParameters params, String str)
|
static Address fromString(@Nullable NetworkParameters params, String str)
|
||||||
throws AddressFormatException {
|
throws AddressFormatException {
|
||||||
AddressParser addressParser = DefaultAddressParser.fromNetworks();
|
AddressParser addressParser = DefaultAddressParser.fromNetworks();
|
||||||
return (params != null)
|
return (params != null)
|
||||||
|
@ -97,7 +66,7 @@ public abstract class Address implements Comparable<Address> {
|
||||||
* @deprecated Use {@link ECKey#toAddress(ScriptType, Network)}
|
* @deprecated Use {@link ECKey#toAddress(ScriptType, Network)}
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public static Address fromKey(final NetworkParameters params, final ECKey key, final ScriptType outputScriptType) {
|
static Address fromKey(final NetworkParameters params, final ECKey key, final ScriptType outputScriptType) {
|
||||||
return key.toAddress(outputScriptType, params.network());
|
return key.toAddress(outputScriptType, params.network());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,21 +75,8 @@ public abstract class Address implements Comparable<Address> {
|
||||||
* @deprecated Use {@link #network()}
|
* @deprecated Use {@link #network()}
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public final NetworkParameters getParameters() {
|
default NetworkParameters getParameters() {
|
||||||
return NetworkParameters.of(network);
|
return NetworkParameters.of(network());
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return Objects.hash(network, Arrays.hashCode(bytes));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object o) {
|
|
||||||
if (this == o) return true;
|
|
||||||
if (o == null || getClass() != o.getClass()) return false;
|
|
||||||
Address other = (Address) o;
|
|
||||||
return this.network == other.network && Arrays.equals(this.bytes, other.bytes);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -128,14 +84,14 @@ public abstract class Address implements Comparable<Address> {
|
||||||
*
|
*
|
||||||
* @return hash that is encoded in the address
|
* @return hash that is encoded in the address
|
||||||
*/
|
*/
|
||||||
public abstract byte[] getHash();
|
byte[] getHash();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the type of output script that will be used for sending to the address.
|
* Get the type of output script that will be used for sending to the address.
|
||||||
*
|
*
|
||||||
* @return type of output script
|
* @return type of output script
|
||||||
*/
|
*/
|
||||||
public abstract ScriptType getOutputScriptType();
|
ScriptType getOutputScriptType();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Comparison field order for addresses is:
|
* Comparison field order for addresses is:
|
||||||
|
@ -152,26 +108,26 @@ public abstract class Address implements Comparable<Address> {
|
||||||
* @return comparison result
|
* @return comparison result
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
abstract public int compareTo(Address o);
|
int compareTo(Address o);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the network this address works on. Use of {@link BitcoinNetwork} is preferred to use of {@link NetworkParameters}
|
* Get the network this address works on. Use of {@link BitcoinNetwork} is preferred to use of {@link NetworkParameters}
|
||||||
* when you need to know what network an address is for.
|
* when you need to know what network an address is for.
|
||||||
* @return the Network.
|
* @return the Network.
|
||||||
*/
|
*/
|
||||||
public Network network() {
|
Network network();
|
||||||
return network;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Comparator for the first two comparison fields in {@code Address} comparisons, see {@link Address#compareTo(Address)}.
|
* Comparator for the first two comparison fields in {@code Address} comparisons, see {@link Address#compareTo(Address)}.
|
||||||
* Used by {@link LegacyAddress#compareTo(Address)} and {@link SegwitAddress#compareTo(Address)}.
|
* Used by {@link LegacyAddress#compareTo(Address)} and {@link SegwitAddress#compareTo(Address)}.
|
||||||
|
* For use by implementing classes only.
|
||||||
*/
|
*/
|
||||||
protected static final Comparator<Address> PARTIAL_ADDRESS_COMPARATOR = Comparator
|
Comparator<Address> PARTIAL_ADDRESS_COMPARATOR = Comparator
|
||||||
.comparing((Address a) -> a.network.id()) // First compare network
|
.comparing((Address a) -> a.network().id()) // First compare network
|
||||||
.thenComparing(Address::compareTypes); // Then compare address type (subclass)
|
.thenComparing(Address::compareTypes); // Then compare address type (subclass)
|
||||||
|
|
||||||
private static int compareTypes(Address a, Address b) {
|
/* private */
|
||||||
|
static int compareTypes(Address a, Address b) {
|
||||||
if (a instanceof LegacyAddress && b instanceof SegwitAddress) {
|
if (a instanceof LegacyAddress && b instanceof SegwitAddress) {
|
||||||
return -1; // Legacy addresses (starting with 1 or 3) come before Segwit addresses.
|
return -1; // Legacy addresses (starting with 1 or 3) come before Segwit addresses.
|
||||||
} else if (a instanceof SegwitAddress && b instanceof LegacyAddress) {
|
} else if (a instanceof SegwitAddress && b instanceof LegacyAddress) {
|
||||||
|
|
|
@ -29,6 +29,8 @@ import java.util.Arrays;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>A Bitcoin address looks like 1MsScoe2fTJoq4ZPdQgqyhgWeoNamYPevy and is derived from an elliptic curve public key
|
* <p>A Bitcoin address looks like 1MsScoe2fTJoq4ZPdQgqyhgWeoNamYPevy and is derived from an elliptic curve public key
|
||||||
* plus a set of network parameters. Not to be confused with a {@link org.bitcoinj.core.PeerAddress}
|
* plus a set of network parameters. Not to be confused with a {@link org.bitcoinj.core.PeerAddress}
|
||||||
|
@ -40,12 +42,14 @@ import java.util.Objects;
|
||||||
* should be interpreted. Whilst almost all addresses today are hashes of public keys, another (currently unsupported
|
* should be interpreted. Whilst almost all addresses today are hashes of public keys, another (currently unsupported
|
||||||
* type) can contain a hash of a script instead.</p>
|
* type) can contain a hash of a script instead.</p>
|
||||||
*/
|
*/
|
||||||
public class LegacyAddress extends Address {
|
public class LegacyAddress implements Address {
|
||||||
/**
|
/**
|
||||||
* An address is a RIPEMD160 hash of a public key, therefore is always 160 bits or 20 bytes.
|
* An address is a RIPEMD160 hash of a public key, therefore is always 160 bits or 20 bytes.
|
||||||
*/
|
*/
|
||||||
public static final int LENGTH = 20;
|
public static final int LENGTH = 20;
|
||||||
|
|
||||||
|
protected final Network network;
|
||||||
|
protected final byte[] bytes;
|
||||||
/** True if P2SH, false if P2PKH. */
|
/** True if P2SH, false if P2PKH. */
|
||||||
public final boolean p2sh;
|
public final boolean p2sh;
|
||||||
|
|
||||||
|
@ -62,7 +66,8 @@ public class LegacyAddress extends Address {
|
||||||
* 20-byte hash of pubkey or script
|
* 20-byte hash of pubkey or script
|
||||||
*/
|
*/
|
||||||
private LegacyAddress(Network network, boolean p2sh, byte[] hash160) throws AddressFormatException {
|
private LegacyAddress(Network network, boolean p2sh, byte[] hash160) throws AddressFormatException {
|
||||||
super(normalizeNetwork(network), hash160);
|
this.network = normalizeNetwork(checkNotNull(network));
|
||||||
|
this.bytes = checkNotNull(hash160);
|
||||||
if (hash160.length != 20)
|
if (hash160.length != 20)
|
||||||
throw new AddressFormatException.InvalidDataLength(
|
throw new AddressFormatException.InvalidDataLength(
|
||||||
"Legacy addresses are 20 byte (160 bit) hashes, but got: " + hash160.length);
|
"Legacy addresses are 20 byte (160 bit) hashes, but got: " + hash160.length);
|
||||||
|
@ -194,6 +199,16 @@ public class LegacyAddress extends Address {
|
||||||
throw new AddressFormatException.WrongNetwork(version);
|
throw new AddressFormatException.WrongNetwork(version);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the network this address works on. Use of {@link BitcoinNetwork} is preferred to use of {@link NetworkParameters}
|
||||||
|
* when you need to know what network an address is for.
|
||||||
|
* @return the Network.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Network network() {
|
||||||
|
return network;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the version header of an address. This is the first byte of a base58 encoded address.
|
* Get the version header of an address. This is the first byte of a base58 encoded address.
|
||||||
*
|
*
|
||||||
|
@ -250,12 +265,12 @@ public class LegacyAddress extends Address {
|
||||||
if (o == null || getClass() != o.getClass())
|
if (o == null || getClass() != o.getClass())
|
||||||
return false;
|
return false;
|
||||||
LegacyAddress other = (LegacyAddress) o;
|
LegacyAddress other = (LegacyAddress) o;
|
||||||
return super.equals(other) && this.p2sh == other.p2sh;
|
return this.network == other.network && Arrays.equals(this.bytes, other.bytes) && this.p2sh == other.p2sh;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return Objects.hash(super.hashCode(), p2sh);
|
return Objects.hash(network, Arrays.hashCode(bytes), p2sh);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -263,15 +278,10 @@ public class LegacyAddress extends Address {
|
||||||
return toBase58();
|
return toBase58();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public LegacyAddress clone() throws CloneNotSupportedException {
|
|
||||||
return (LegacyAddress) super.clone();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Comparator for LegacyAddress, left argument must be LegacyAddress, right argument can be any Address
|
// Comparator for LegacyAddress, left argument must be LegacyAddress, right argument can be any Address
|
||||||
private static final Comparator<Address> LEGACY_ADDRESS_COMPARATOR = Address.PARTIAL_ADDRESS_COMPARATOR
|
private static final Comparator<Address> LEGACY_ADDRESS_COMPARATOR = Address.PARTIAL_ADDRESS_COMPARATOR
|
||||||
.thenComparingInt(a -> ((LegacyAddress) a).getVersion()) // Then compare Legacy address version byte
|
.thenComparingInt(a -> ((LegacyAddress) a).getVersion()) // Then compare Legacy address version byte
|
||||||
.thenComparing(a -> a.bytes, ByteUtils.arrayUnsignedComparator()); // Then compare Legacy bytes
|
.thenComparing(a -> ((LegacyAddress) a).bytes, ByteUtils.arrayUnsignedComparator()); // Then compare Legacy bytes
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
|
|
|
@ -24,12 +24,14 @@ import org.bitcoinj.core.NetworkParameters;
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import static com.google.common.base.Preconditions.checkArgument;
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
import static org.bitcoinj.base.BitcoinNetwork.*;
|
import static org.bitcoinj.base.BitcoinNetwork.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -49,7 +51,7 @@ import static org.bitcoinj.base.BitcoinNetwork.*;
|
||||||
* {@link #fromHash(org.bitcoinj.base.Network, byte[])} or {@link ECKey#toAddress(ScriptType, Network)}
|
* {@link #fromHash(org.bitcoinj.base.Network, byte[])} or {@link ECKey#toAddress(ScriptType, Network)}
|
||||||
* to construct a native segwit address.</p>
|
* to construct a native segwit address.</p>
|
||||||
*/
|
*/
|
||||||
public class SegwitAddress extends Address {
|
public class SegwitAddress implements Address {
|
||||||
public static final int WITNESS_PROGRAM_LENGTH_PKH = 20;
|
public static final int WITNESS_PROGRAM_LENGTH_PKH = 20;
|
||||||
public static final int WITNESS_PROGRAM_LENGTH_SH = 32;
|
public static final int WITNESS_PROGRAM_LENGTH_SH = 32;
|
||||||
public static final int WITNESS_PROGRAM_LENGTH_TR = 32;
|
public static final int WITNESS_PROGRAM_LENGTH_TR = 32;
|
||||||
|
@ -119,6 +121,9 @@ public class SegwitAddress extends Address {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected final Network network;
|
||||||
|
protected final byte[] bytes;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Private constructor. Use {@link #fromBech32(Network, String)},
|
* Private constructor. Use {@link #fromBech32(Network, String)},
|
||||||
* {@link #fromHash(Network, byte[])} or {@link ECKey#toAddress(ScriptType, Network)}.
|
* {@link #fromHash(Network, byte[])} or {@link ECKey#toAddress(ScriptType, Network)}.
|
||||||
|
@ -169,7 +174,8 @@ public class SegwitAddress extends Address {
|
||||||
* if any of the sanity checks fail
|
* if any of the sanity checks fail
|
||||||
*/
|
*/
|
||||||
private SegwitAddress(Network network, byte[] data) throws AddressFormatException {
|
private SegwitAddress(Network network, byte[] data) throws AddressFormatException {
|
||||||
super(normalizeNetwork(network), data);
|
this.network = normalizeNetwork(checkNotNull(network));
|
||||||
|
this.bytes = checkNotNull(data);
|
||||||
if (data.length < 1)
|
if (data.length < 1)
|
||||||
throw new AddressFormatException.InvalidDataLength("Zero data found");
|
throw new AddressFormatException.InvalidDataLength("Zero data found");
|
||||||
final int witnessVersion = getWitnessVersion();
|
final int witnessVersion = getWitnessVersion();
|
||||||
|
@ -380,6 +386,29 @@ public class SegwitAddress extends Address {
|
||||||
return (SegwitAddress) key.toAddress(ScriptType.P2WPKH, params.network());
|
return (SegwitAddress) key.toAddress(ScriptType.P2WPKH, params.network());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the network this address works on. Use of {@link BitcoinNetwork} is preferred to use of {@link NetworkParameters}
|
||||||
|
* when you need to know what network an address is for.
|
||||||
|
* @return the Network.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Network network() {
|
||||||
|
return network;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(network, Arrays.hashCode(bytes));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
SegwitAddress other = (SegwitAddress) o;
|
||||||
|
return this.network == other.network && Arrays.equals(this.bytes, other.bytes);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the textual form of the address.
|
* Returns the textual form of the address.
|
||||||
*
|
*
|
||||||
|
@ -426,7 +455,7 @@ public class SegwitAddress extends Address {
|
||||||
|
|
||||||
// Comparator for SegwitAddress, left argument must be SegwitAddress, right argument can be any Address
|
// Comparator for SegwitAddress, left argument must be SegwitAddress, right argument can be any Address
|
||||||
private static final Comparator<Address> SEGWIT_ADDRESS_COMPARATOR = Address.PARTIAL_ADDRESS_COMPARATOR
|
private static final Comparator<Address> SEGWIT_ADDRESS_COMPARATOR = Address.PARTIAL_ADDRESS_COMPARATOR
|
||||||
.thenComparing(a -> a.bytes, ByteUtils.arrayUnsignedComparator()); // Then compare Segwit bytes
|
.thenComparing(a -> ((SegwitAddress) a).bytes, ByteUtils.arrayUnsignedComparator()); // Then compare Segwit bytes
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
|
|
|
@ -16,22 +16,6 @@
|
||||||
|
|
||||||
package org.bitcoinj.base;
|
package org.bitcoinj.base;
|
||||||
|
|
||||||
import nl.jqno.equalsverifier.EqualsVerifier;
|
// TODO: Maybe add some tests here. Address has minimal functionality now, however -- see LegacyAddress and SegwitAddress
|
||||||
import nl.jqno.equalsverifier.Warning;
|
|
||||||
import org.bitcoinj.base.Address;
|
|
||||||
import org.bitcoinj.core.NetworkParameters;
|
|
||||||
import org.bitcoinj.params.MainNetParams;
|
|
||||||
import org.bitcoinj.params.TestNet3Params;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
public class AddressTest {
|
public class AddressTest {
|
||||||
@Test
|
|
||||||
public void equalsContract() {
|
|
||||||
EqualsVerifier.forClass(Address.class)
|
|
||||||
.withPrefabValues(NetworkParameters.class, MainNetParams.get(), TestNet3Params.get())
|
|
||||||
.suppress(Warning.NULL_FIELDS)
|
|
||||||
.suppress(Warning.TRANSIENT_FIELDS)
|
|
||||||
.usingGetClass()
|
|
||||||
.verify();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue