diff --git a/core/src/main/java/com/google/bitcoin/core/Address.java b/core/src/main/java/com/google/bitcoin/core/Address.java index 649a7f2a..f488f20d 100644 --- a/core/src/main/java/com/google/bitcoin/core/Address.java +++ b/core/src/main/java/com/google/bitcoin/core/Address.java @@ -18,10 +18,12 @@ package com.google.bitcoin.core; import com.google.bitcoin.params.MainNetParams; import com.google.bitcoin.params.TestNet3Params; +import com.google.bitcoin.script.Script; import javax.annotation.Nullable; import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; /** *
A Bitcoin address looks like 1MsScoe2fTJoq4ZPdQgqyhgWeoNamYPevy and is derived from an elliptic curve public key @@ -47,11 +49,27 @@ public class Address extends VersionedChecksummedBytes { */ public Address(NetworkParameters params, int version, byte[] hash160) throws WrongNetworkException { super(version, hash160); + checkNotNull(params); checkArgument(hash160.length == 20, "Addresses are 160-bit hashes, so you must provide 20 bytes"); if (!isAcceptableVersion(params, version)) throw new WrongNetworkException(version, params.getAcceptableAddressCodes()); } + /** Returns an Address that represents the given P2SH script hash. */ + public static Address fromP2SHScript(NetworkParameters params, byte[] hash160) { + try { + return new Address(params, params.getP2SHHeader(), hash160); + } catch (WrongNetworkException e) { + throw new RuntimeException(e); // Cannot happen. + } + } + + /** Returns an Address that represents the script hash extracted from the given scriptPubKey */ + public static Address fromP2SHScript(NetworkParameters params, Script scriptPubKey) { + checkArgument(scriptPubKey.isPayToScriptHash(), "Not a P2SH script"); + return fromP2SHScript(params, scriptPubKey.getPubKeyHash()); + } + /** * Construct an address from parameters and the hash160 form. Example:
* diff --git a/core/src/main/java/com/google/bitcoin/script/ScriptBuilder.java b/core/src/main/java/com/google/bitcoin/script/ScriptBuilder.java index 2e128f6f..aa83483d 100644 --- a/core/src/main/java/com/google/bitcoin/script/ScriptBuilder.java +++ b/core/src/main/java/com/google/bitcoin/script/ScriptBuilder.java @@ -136,4 +136,14 @@ public class ScriptBuilder { builder.data(signature); return builder.build(); } + + /** + * Creates a scriptPubKey that sends to the given script hash. Read + * BIP 16 to learn more about this + * kind of script. + */ + public static Script createP2SHOutputScript(byte[] hash) { + checkArgument(hash.length == 20); + return new ScriptBuilder().op(OP_HASH160).data(hash).op(OP_EQUAL).build(); + } } diff --git a/core/src/test/java/com/google/bitcoin/core/AddressTest.java b/core/src/test/java/com/google/bitcoin/core/AddressTest.java index 913c4d78..e1a7e4b1 100644 --- a/core/src/test/java/com/google/bitcoin/core/AddressTest.java +++ b/core/src/test/java/com/google/bitcoin/core/AddressTest.java @@ -18,6 +18,7 @@ package com.google.bitcoin.core; import com.google.bitcoin.params.MainNetParams; import com.google.bitcoin.params.TestNet3Params; +import com.google.bitcoin.script.ScriptBuilder; import org.junit.Test; import org.spongycastle.util.encoders.Hex; @@ -110,9 +111,12 @@ public class AddressTest { assertEquals(TestNet3Params.get().getId(), testNetParams.getId()); // Test that we can convert them from hashes - Address a = new Address(mainParams, MainNetParams.get().p2shHeader, Hex.decode("2ac4b0b501117cc8119c5797b519538d4942e90e")); + byte[] hex = Hex.decode("2ac4b0b501117cc8119c5797b519538d4942e90e"); + Address a = Address.fromP2SHScript(mainParams, hex); assertEquals("35b9vsyH1KoFT5a5KtrKusaCcPLkiSo1tU", a.toString()); - Address b = new Address(testParams, TestNet3Params.get().p2shHeader, Hex.decode("18a0e827269b5211eb51a4af1b2fa69333efa722")); + Address b = Address.fromP2SHScript(testParams, Hex.decode("18a0e827269b5211eb51a4af1b2fa69333efa722")); assertEquals("2MuVSxtfivPKJe93EC1Tb9UhJtGhsoWEHCe", b.toString()); + Address c = Address.fromP2SHScript(mainParams, ScriptBuilder.createP2SHOutputScript(hex)); + assertEquals("35b9vsyH1KoFT5a5KtrKusaCcPLkiSo1tU", c.toString()); } }