Skip to content

Addresses

An Address is a Base58Check encoding of a 20-byte hash, together with a version byte that says which network and which kind of Output it is for. Bitcoin4J implements the original (legacy) format through Address and its one subclass, LegacyAddress. The addresses appendix in the Developer Guide explains the encoding.

Let’s create an Address for Alice’s Public Key.

PrivateKey privateKey = PrivateKey.fromWIF("cVVvUsNHhbrgd7aW3gnuGo2qJM45LhHhTCVXrDSJDDcNGE6qmyCs");
// We always say which network the Address is for. TEST_PKH for testnet, MAIN_PKH for mainnet.
Address testnet = Address.fromKey(NetworkAddressType.TEST_PKH, privateKey.getPublicKey());
Address mainnet = Address.fromKey(NetworkAddressType.MAIN_PKH, privateKey.getPublicKey());

The first argument is a NetworkAddressType. That is MAIN_PKH or TEST_PKH for pay-to-public-key-hash Addresses, and MAIN_P2SH or TEST_P2SH for script-hash Addresses.

The network is always explicit. Address.fromKey() has no default network, and neither PrivateKey nor PublicKey has a toAddress() method, so a testnet key never turns into a mainnet Address by accident. The flip side of this is that the key’s own network (from its WIF) is not used. We pass the Address type that matches the network we are working on.

// We pass the network we expect. A null network accepts either, and tells us which it was.
Address address = Address.fromString(NetworkType.TEST, "mu4DpTaD75nheE4z5CQazqm1ivej1vzL4L");
Address unknown = Address.fromString(null, "mu4DpTaD75nheE4z5CQazqm1ivej1vzL4L");
byte[] pubkeyHash = address.getHash();
NetworkType network = unknown.getNetworkType();

getHash() returns the 20-byte hash inside, which is what a P2PKH Locking Script contains. new P2PKHLockBuilder(address) uses it.

Parsing checks the checksum and, when we pass a network, the version byte. Both failures are AddressFormatExceptions, which are unchecked.

// A testnet Address read as a mainnet one is rejected.
assertThrows(AddressFormatException.WrongNetwork.class,
() -> Address.fromString(NetworkType.MAIN, "mu4DpTaD75nheE4z5CQazqm1ivej1vzL4L"));
// A typo breaks the checksum, and is rejected too.
assertThrows(AddressFormatException.class,
() -> Address.fromString(NetworkType.TEST, "mu4DpTaD75nheE4z5CQazqm1ivej1vzL4M"));

A P2SH Address encodes the hash of a redeem script rather than a Public Key hash.

Script redeemScript = new ScriptBuilder().smallNum(1).build();
byte[] scriptHash = Utils.sha256hash160(redeemScript.getProgram());
LegacyAddress address = LegacyAddress.fromScriptHash(NetworkType.MAIN, scriptHash);

LegacyAddress.p2sh tells the two kinds apart.

Please note that P2SH is a legacy Output type on BSV. Have a look at the P2SH page before you use it.