Better error handling in Address.

This commit is contained in:
Mike Hearn 2013-11-30 15:33:24 +01:00
parent ff54085129
commit 2271e7198e

View file

@ -21,6 +21,8 @@ import com.google.bitcoin.params.TestNet3Params;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import static com.google.common.base.Preconditions.checkArgument;
/** /**
* <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 PeerAddress} or {@link AddressMessage} * plus a set of network parameters. Not to be confused with a {@link PeerAddress} or {@link AddressMessage}
@ -43,12 +45,11 @@ public class Address extends VersionedChecksummedBytes {
* *
* <pre>new Address(NetworkParameters.prodNet(), NetworkParameters.getAddressHeader(), Hex.decode("4a22c3c4cbb31e4d03b15550636762bda0baf85a"));</pre> * <pre>new Address(NetworkParameters.prodNet(), NetworkParameters.getAddressHeader(), Hex.decode("4a22c3c4cbb31e4d03b15550636762bda0baf85a"));</pre>
*/ */
public Address(NetworkParameters params, int version, byte[] hash160) { public Address(NetworkParameters params, int version, byte[] hash160) throws WrongNetworkException {
super(version, hash160); super(version, hash160);
checkArgument(hash160.length == 20, "Addresses are 160-bit hashes, so you must provide 20 bytes");
if (!isAcceptableVersion(params, version)) if (!isAcceptableVersion(params, version))
throw new RuntimeException("Unrecognized Address version"); throw new WrongNetworkException(version, params.getAcceptableAddressCodes());
if (hash160.length != 20) // 160 = 8 * 20
throw new RuntimeException("Addresses are 160-bit hashes, so you must provide 20 bytes");
} }
/** /**
@ -57,7 +58,8 @@ public class Address extends VersionedChecksummedBytes {
* <pre>new Address(NetworkParameters.prodNet(), Hex.decode("4a22c3c4cbb31e4d03b15550636762bda0baf85a"));</pre> * <pre>new Address(NetworkParameters.prodNet(), Hex.decode("4a22c3c4cbb31e4d03b15550636762bda0baf85a"));</pre>
*/ */
public Address(NetworkParameters params, byte[] hash160) { public Address(NetworkParameters params, byte[] hash160) {
this(params, params.getAddressHeader(), hash160); super(params.getAddressHeader(), hash160);
checkArgument(hash160.length == 20, "Addresses are 160-bit hashes, so you must provide 20 bytes");
} }
/** /**
@ -70,7 +72,7 @@ public class Address extends VersionedChecksummedBytes {
* @throws AddressFormatException if the given address doesn't parse or the checksum is invalid * @throws AddressFormatException if the given address doesn't parse or the checksum is invalid
* @throws WrongNetworkException if the given address is valid but for a different chain (eg testnet vs prodnet) * @throws WrongNetworkException if the given address is valid but for a different chain (eg testnet vs prodnet)
*/ */
public Address(@Nullable NetworkParameters params, String address) throws AddressFormatException, WrongNetworkException { public Address(@Nullable NetworkParameters params, String address) throws AddressFormatException {
super(address); super(address);
if (params != null) { if (params != null) {
if (!isAcceptableVersion(params, version)) { if (!isAcceptableVersion(params, version)) {
@ -89,7 +91,8 @@ public class Address extends VersionedChecksummedBytes {
* See also https://en.bitcoin.it/wiki/BIP_0013: Address Format for pay-to-script-hash * See also https://en.bitcoin.it/wiki/BIP_0013: Address Format for pay-to-script-hash
*/ */
public boolean isP2SHAddress() { public boolean isP2SHAddress() {
return this.version == getParameters().p2shHeader; final NetworkParameters parameters = getParameters();
return parameters != null && this.version == parameters.p2shHeader;
} }
/** /**
@ -100,6 +103,7 @@ public class Address extends VersionedChecksummedBytes {
* *
* @return a NetworkParameters representing the network the address is intended for, or null if unknown. * @return a NetworkParameters representing the network the address is intended for, or null if unknown.
*/ */
@Nullable
public NetworkParameters getParameters() { public NetworkParameters getParameters() {
// TODO: There should be a more generic way to get all supported networks. // TODO: There should be a more generic way to get all supported networks.
NetworkParameters[] networks = { TestNet3Params.get(), MainNetParams.get() }; NetworkParameters[] networks = { TestNet3Params.get(), MainNetParams.get() };
@ -114,21 +118,22 @@ public class Address extends VersionedChecksummedBytes {
/** /**
* Given an address, examines the version byte and attempts to find a matching NetworkParameters. If you aren't sure * Given an address, examines the version byte and attempts to find a matching NetworkParameters. If you aren't sure
* which network the address is intended for (eg, it was provided by a user), you can use this to decide if it is * which network the address is intended for (eg, it was provided by a user), you can use this to decide if it is
* compatible with the current wallet. You should be able to handle a null response from this method. * compatible with the current wallet.
* @return a NetworkParameters or null if the string wasn't of a known version.
*/ */
@Nullable
public static NetworkParameters getParametersFromAddress(String address) throws AddressFormatException { public static NetworkParameters getParametersFromAddress(String address) throws AddressFormatException {
try { try {
return new Address(null, address).getParameters(); return new Address(null, address).getParameters();
} catch (WrongNetworkException e) { } catch (WrongNetworkException e) {
// Cannot happen. throw new RuntimeException(e); // Cannot happen.
throw new RuntimeException(e);
} }
} }
/** /**
* Check if a given address version is valid given the NetworkParameters. * Check if a given address version is valid given the NetworkParameters.
*/ */
private boolean isAcceptableVersion(NetworkParameters params, int version) { private static boolean isAcceptableVersion(NetworkParameters params, int version) {
for (int v : params.getAcceptableAddressCodes()) { for (int v : params.getAcceptableAddressCodes()) {
if (version == v) { if (version == v) {
return true; return true;