mirror of
https://github.com/bitcoinj/bitcoinj.git
synced 2025-03-10 00:09:31 +01:00
BitcoinNetwork: add address validation methods
There are use cases where an already parsed address needs to be validated for a specific network. In one use case the address came from an external source and needs validation with an error message displayed: that's what `isValidAddress(Address)` is for. In the other case we can treat the invalid address as a fatal error. That's `checkAddress(Address)`.
This commit is contained in:
parent
f1a5ebe71e
commit
53a6b3e150
2 changed files with 103 additions and 0 deletions
|
@ -182,6 +182,57 @@ public enum BitcoinNetwork implements Network {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if an address is valid on this network.
|
||||
* This is meant to be used as a precondition for a method or function that expects a valid address. If
|
||||
* you are validating addresses provided externally, you probably want to use
|
||||
* {@link #isValidAddress(Address)} to handle errors more gracefully. This method uses {@link #isValidAddress(Address)}
|
||||
* internally which properly accounts for address normalization.
|
||||
* @param address Address to validate
|
||||
* @return The unmodified address if valid on this network
|
||||
* @throws IllegalArgumentException if address not valid on this network
|
||||
*/
|
||||
public Address checkAddress(Address address) throws IllegalArgumentException {
|
||||
if (!isValidAddress(address)) {
|
||||
throw new IllegalArgumentException(String.format("Address %s not valid on network %s", address, this));
|
||||
}
|
||||
return address;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is address valid for this network. Because we normalize the {@code network()} value in the {@link Address}
|
||||
* type (see the JavaDoc for {@link Address#network()}) this method should be used in preference to simply
|
||||
* verifying that {@code address.network()} returns the desired network type.
|
||||
* @param address Address to validate
|
||||
* @return {@code true} if valid on this network, {@code false} otherwise
|
||||
*/
|
||||
public boolean isValidAddress(Address address) {
|
||||
boolean valid;
|
||||
switch (this) {
|
||||
case MAINNET:
|
||||
valid = address.network() == MAINNET;
|
||||
break;
|
||||
case TESTNET:
|
||||
case SIGNET:
|
||||
// SIGNET uses the same addresses as TESTNET
|
||||
valid = address.network() == TESTNET;
|
||||
break;
|
||||
case REGTEST:
|
||||
if (address instanceof LegacyAddress) {
|
||||
// For Legacy addresses, REGTEST uses TESTNET addresses
|
||||
valid = ((LegacyAddress) address).network == TESTNET;
|
||||
} else {
|
||||
// On segwit, REGTEST has its own address type
|
||||
valid = address.network() == REGTEST;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
valid = false;
|
||||
break;
|
||||
}
|
||||
return valid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the {@code BitcoinNetwork} from a name string, e.g. "mainnet", "testnet" or "signet".
|
||||
* A number of common alternate names are allowed too, e.g. "main" or "prod".
|
||||
|
|
|
@ -18,8 +18,13 @@ package org.bitcoinj.base;
|
|||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.bitcoinj.base.BitcoinNetwork.MAINNET;
|
||||
import static org.bitcoinj.base.BitcoinNetwork.REGTEST;
|
||||
import static org.bitcoinj.base.BitcoinNetwork.SIGNET;
|
||||
import static org.bitcoinj.base.BitcoinNetwork.TESTNET;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class BitcoinNetworkTest {
|
||||
@Test
|
||||
|
@ -79,4 +84,51 @@ public class BitcoinNetworkTest {
|
|||
public void fromIdString_notExisting() {
|
||||
assertFalse(BitcoinNetwork.fromIdString("a.b.c").isPresent());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLegacyAddressValidity() {
|
||||
LegacyAddress m = LegacyAddress.fromBase58("17kzeh4N8g49GFvdDzSf8PjaPfyoD1MndL", MAINNET);
|
||||
LegacyAddress t = LegacyAddress.fromBase58("n4eA2nbYqErp7H6jebchxAN59DmNpksexv", TESTNET);
|
||||
|
||||
assertTrue(MAINNET.isValidAddress(m));
|
||||
assertTrue(TESTNET.isValidAddress(t));
|
||||
assertTrue(SIGNET.isValidAddress(t));
|
||||
assertTrue(REGTEST.isValidAddress(t));
|
||||
|
||||
assertFalse(MAINNET.isValidAddress(t));
|
||||
assertFalse(TESTNET.isValidAddress(m));
|
||||
assertFalse(SIGNET.isValidAddress(m));
|
||||
assertFalse(REGTEST.isValidAddress(m));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSegwitAddressValidity() {
|
||||
SegwitAddress m = SegwitAddress.fromBech32("bc1zw508d6qejxtdg4y5r3zarvaryvaxxpcs", MAINNET);
|
||||
SegwitAddress t = SegwitAddress.fromBech32("tb1pqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvsesf3hn0c", TESTNET);
|
||||
SegwitAddress rt = SegwitAddress.fromBech32("bcrt1qspfueag7fvty7m8htuzare3xs898zvh30fttu2", REGTEST);
|
||||
|
||||
assertTrue(MAINNET.isValidAddress(m));
|
||||
assertTrue(TESTNET.isValidAddress(t));
|
||||
assertTrue(SIGNET.isValidAddress(t));
|
||||
assertTrue(REGTEST.isValidAddress(rt));
|
||||
|
||||
assertFalse(MAINNET.isValidAddress(t));
|
||||
assertFalse(MAINNET.isValidAddress(rt));
|
||||
assertFalse(TESTNET.isValidAddress(m));
|
||||
assertFalse(TESTNET.isValidAddress(rt));
|
||||
assertFalse(SIGNET.isValidAddress(m));
|
||||
assertFalse(SIGNET.isValidAddress(rt));
|
||||
assertFalse(REGTEST.isValidAddress(m));
|
||||
assertFalse(REGTEST.isValidAddress(t));
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testLegacyAddressCheckThrow() {
|
||||
MAINNET.checkAddress(LegacyAddress.fromBase58("n4eA2nbYqErp7H6jebchxAN59DmNpksexv", TESTNET));
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testSegwitAddressCheckThrow() {
|
||||
MAINNET.checkAddress(SegwitAddress.fromBech32("tb1pqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvsesf3hn0c", TESTNET));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue