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 javax.annotation.Nullable;
|
||||
import java.util.Arrays;
|
||||
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>
|
||||
* Use an implementation of {@link AddressParser#parseAddress(String, Network)} to conveniently construct any kind of address from its textual
|
||||
* form.
|
||||
*/
|
||||
public abstract class Address implements 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);
|
||||
}
|
||||
|
||||
public interface Address extends Comparable<Address> {
|
||||
/**
|
||||
* 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
|
||||
public static Address fromString(@Nullable NetworkParameters params, String str)
|
||||
static Address fromString(@Nullable NetworkParameters params, String str)
|
||||
throws AddressFormatException {
|
||||
AddressParser addressParser = DefaultAddressParser.fromNetworks();
|
||||
return (params != null)
|
||||
|
@ -97,7 +66,7 @@ public abstract class Address implements Comparable<Address> {
|
|||
* @deprecated Use {@link ECKey#toAddress(ScriptType, Network)}
|
||||
*/
|
||||
@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());
|
||||
}
|
||||
|
||||
|
@ -106,21 +75,8 @@ public abstract class Address implements Comparable<Address> {
|
|||
* @deprecated Use {@link #network()}
|
||||
*/
|
||||
@Deprecated
|
||||
public final NetworkParameters getParameters() {
|
||||
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);
|
||||
default NetworkParameters getParameters() {
|
||||
return NetworkParameters.of(network());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -128,14 +84,14 @@ public abstract class Address implements Comparable<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.
|
||||
*
|
||||
* @return type of output script
|
||||
*/
|
||||
public abstract ScriptType getOutputScriptType();
|
||||
ScriptType getOutputScriptType();
|
||||
|
||||
/**
|
||||
* Comparison field order for addresses is:
|
||||
|
@ -152,26 +108,26 @@ public abstract class Address implements Comparable<Address> {
|
|||
* @return comparison result
|
||||
*/
|
||||
@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}
|
||||
* when you need to know what network an address is for.
|
||||
* @return the Network.
|
||||
*/
|
||||
public Network network() {
|
||||
return network;
|
||||
}
|
||||
Network network();
|
||||
|
||||
/**
|
||||
* 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)}.
|
||||
* For use by implementing classes only.
|
||||
*/
|
||||
protected static final Comparator<Address> PARTIAL_ADDRESS_COMPARATOR = Comparator
|
||||
.comparing((Address a) -> a.network.id()) // First compare network
|
||||
Comparator<Address> PARTIAL_ADDRESS_COMPARATOR = Comparator
|
||||
.comparing((Address a) -> a.network().id()) // First compare network
|
||||
.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) {
|
||||
return -1; // Legacy addresses (starting with 1 or 3) come before Segwit addresses.
|
||||
} else if (a instanceof SegwitAddress && b instanceof LegacyAddress) {
|
||||
|
|
|
@ -29,6 +29,8 @@ import java.util.Arrays;
|
|||
import java.util.Comparator;
|
||||
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
|
||||
* 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
|
||||
* 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.
|
||||
*/
|
||||
public static final int LENGTH = 20;
|
||||
|
||||
protected final Network network;
|
||||
protected final byte[] bytes;
|
||||
/** True if P2SH, false if P2PKH. */
|
||||
public final boolean p2sh;
|
||||
|
||||
|
@ -62,7 +66,8 @@ public class LegacyAddress extends Address {
|
|||
* 20-byte hash of pubkey or script
|
||||
*/
|
||||
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)
|
||||
throw new AddressFormatException.InvalidDataLength(
|
||||
"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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
|
@ -250,12 +265,12 @@ public class LegacyAddress extends Address {
|
|||
if (o == null || getClass() != o.getClass())
|
||||
return false;
|
||||
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
|
||||
public int hashCode() {
|
||||
return Objects.hash(super.hashCode(), p2sh);
|
||||
return Objects.hash(network, Arrays.hashCode(bytes), p2sh);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -263,15 +278,10 @@ public class LegacyAddress extends Address {
|
|||
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
|
||||
private static final Comparator<Address> LEGACY_ADDRESS_COMPARATOR = Address.PARTIAL_ADDRESS_COMPARATOR
|
||||
.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}
|
||||
|
|
|
@ -24,12 +24,14 @@ import org.bitcoinj.core.NetworkParameters;
|
|||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
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.*;
|
||||
|
||||
/**
|
||||
|
@ -49,7 +51,7 @@ import static org.bitcoinj.base.BitcoinNetwork.*;
|
|||
* {@link #fromHash(org.bitcoinj.base.Network, byte[])} or {@link ECKey#toAddress(ScriptType, Network)}
|
||||
* 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_SH = 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)},
|
||||
* {@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
|
||||
*/
|
||||
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)
|
||||
throw new AddressFormatException.InvalidDataLength("Zero data found");
|
||||
final int witnessVersion = getWitnessVersion();
|
||||
|
@ -380,6 +386,29 @@ public class SegwitAddress extends Address {
|
|||
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.
|
||||
*
|
||||
|
@ -426,7 +455,7 @@ public class SegwitAddress extends 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
|
||||
.thenComparing(a -> a.bytes, ByteUtils.arrayUnsignedComparator()); // Then compare Segwit bytes
|
||||
.thenComparing(a -> ((SegwitAddress) a).bytes, ByteUtils.arrayUnsignedComparator()); // Then compare Segwit bytes
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
|
|
|
@ -16,22 +16,6 @@
|
|||
|
||||
package org.bitcoinj.base;
|
||||
|
||||
import nl.jqno.equalsverifier.EqualsVerifier;
|
||||
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;
|
||||
|
||||
// TODO: Maybe add some tests here. Address has minimal functionality now, however -- see LegacyAddress and SegwitAddress
|
||||
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