1818
1919package org .bitcoinj .core ;
2020
21- import java .io .IOException ;
22- import java .io .ObjectInputStream ;
23- import java .io .ObjectOutputStream ;
21+ import static com .google .common .base .Preconditions .checkArgument ;
22+
23+ import java .util .Arrays ;
24+
25+ import javax .annotation .Nullable ;
2426
2527import org .bitcoinj .params .Networks ;
2628import org .bitcoinj .script .Script ;
2729import org .bitcoinj .script .ScriptPattern ;
2830
29- import javax .annotation .Nullable ;
30-
31- import static com .google .common .base .Preconditions .checkArgument ;
32- import static com .google .common .base .Preconditions .checkNotNull ;
31+ import com .google .common .base .Objects ;
3332
3433/**
3534 * <p>A Bitcoin address looks like 1MsScoe2fTJoq4ZPdQgqyhgWeoNamYPevy and is derived from an elliptic curve public key
@@ -48,7 +47,8 @@ public class Address extends VersionedChecksummedBytes {
4847 */
4948 public static final int LENGTH = 20 ;
5049
51- private transient NetworkParameters params ;
50+ /** True if P2SH, false if P2PKH. */
51+ public final boolean p2sh ;
5252
5353 /**
5454 * Private constructor. Use {@link #fromBase58(NetworkParameters, String)},
@@ -62,13 +62,10 @@ public class Address extends VersionedChecksummedBytes {
6262 * @param hash160
6363 * 20-byte hash of pubkey or script
6464 */
65- private Address (NetworkParameters params , int version , byte [] hash160 ) throws WrongNetworkException {
66- super (version , hash160 );
67- checkNotNull (params );
65+ private Address (NetworkParameters params , boolean p2sh , byte [] hash160 ) throws WrongNetworkException {
66+ super (params , hash160 );
6867 checkArgument (hash160 .length == 20 , "Addresses are 160-bit hashes, so you must provide 20 bytes" );
69- if (!isAcceptableVersion (params , version ))
70- throw new WrongNetworkException (version );
71- this .params = params ;
68+ this .p2sh = p2sh ;
7269 }
7370
7471 /**
@@ -82,7 +79,7 @@ private Address(NetworkParameters params, int version, byte[] hash160) throws Wr
8279 * @return constructed address
8380 */
8481 public static Address fromPubKeyHash (NetworkParameters params , byte [] hash160 ) {
85- return new Address (params , params . getAddressHeader () , hash160 );
82+ return new Address (params , false , hash160 );
8683 }
8784
8885 /**
@@ -96,7 +93,7 @@ public static Address fromKey(NetworkParameters params, ECKey key) {
9693 /** Returns an Address that represents the given P2SH script hash. */
9794 public static Address fromP2SHHash (NetworkParameters params , byte [] hash160 ) {
9895 try {
99- return new Address (params , params . getP2SHHeader () , hash160 );
96+ return new Address (params , true , hash160 );
10097 } catch (WrongNetworkException e ) {
10198 throw new RuntimeException (e ); // Cannot happen.
10299 }
@@ -120,37 +117,35 @@ public static Address fromP2SHScript(NetworkParameters params, Script scriptPubK
120117 * if the given address is valid but for a different chain (eg testnet vs mainnet)
121118 */
122119 public static Address fromBase58 (@ Nullable NetworkParameters params , String base58 ) throws AddressFormatException {
123- return new Address (params , base58 );
120+ byte [] versionAndDataBytes = Base58 .decodeChecked (base58 );
121+ int version = versionAndDataBytes [0 ] & 0xFF ;
122+ byte [] bytes = Arrays .copyOfRange (versionAndDataBytes , 1 , versionAndDataBytes .length );
123+ if (params == null ) {
124+ for (NetworkParameters p : Networks .get ()) {
125+ if (version == p .getAddressHeader ())
126+ return new Address (p , false , bytes );
127+ else if (version == p .getP2SHHeader ())
128+ return new Address (p , true , bytes );
129+ }
130+ throw new AddressFormatException ("No network found for " + base58 );
131+ } else {
132+ if (version == params .getAddressHeader ())
133+ return new Address (params , false , bytes );
134+ else if (version == params .getP2SHHeader ())
135+ return new Address (params , true , bytes );
136+ throw new WrongNetworkException (version );
137+ }
124138 }
125139
126140 /** @deprecated use {@link #fromPubKeyHash(NetworkParameters, byte[])} */
127141 @ Deprecated
128142 public Address (NetworkParameters params , byte [] hash160 ) {
129- this (params , params . getAddressHeader () , hash160 );
143+ this (params , false , hash160 );
130144 }
131145
132- /** @deprecated Use {@link #fromBase58(NetworkParameters, String)} */
133- @ Deprecated
134- public Address (@ Nullable NetworkParameters params , String address ) throws AddressFormatException {
135- super (address );
136- if (params != null ) {
137- if (!isAcceptableVersion (params , version )) {
138- throw new WrongNetworkException (version );
139- }
140- this .params = params ;
141- } else {
142- NetworkParameters paramsFound = null ;
143- for (NetworkParameters p : Networks .get ()) {
144- if (isAcceptableVersion (p , version )) {
145- paramsFound = p ;
146- break ;
147- }
148- }
149- if (paramsFound == null )
150- throw new AddressFormatException ("No network found for " + address );
151-
152- this .params = paramsFound ;
153- }
146+ @ Override
147+ protected int getVersion () {
148+ return p2sh ? params .getP2SHHeader () : params .getAddressHeader ();
154149 }
155150
156151 /** The (big endian) 20 byte hash that is the core of a Bitcoin address. */
@@ -163,20 +158,7 @@ public byte[] getHash160() {
163158 * See also https://github.com/bitcoin/bips/blob/master/bip-0013.mediawiki: Address Format for pay-to-script-hash
164159 */
165160 public boolean isP2SHAddress () {
166- final NetworkParameters parameters = getParameters ();
167- return parameters != null && this .version == parameters .p2shHeader ;
168- }
169-
170- /**
171- * Examines the version byte of the address and attempts to find a matching NetworkParameters. If you aren't sure
172- * which network the address is intended for (eg, it was provided by a user), you can use this to decide if it is
173- * compatible with the current wallet. You should be able to handle a null response from this method. Note that the
174- * parameters returned is not necessarily the same as the one the Address was created with.
175- *
176- * @return a NetworkParameters representing the network the address is intended for.
177- */
178- public NetworkParameters getParameters () {
179- return params ;
161+ return p2sh ;
180162 }
181163
182164 /**
@@ -194,15 +176,19 @@ public static NetworkParameters getParametersFromAddress(String address) throws
194176 }
195177 }
196178
197- /**
198- * Check if a given address version is valid given the NetworkParameters.
199- */
200- private static boolean isAcceptableVersion (NetworkParameters params , int version ) {
201- if (version == params .getAddressHeader ())
202- return true ;
203- if (version == params .getP2SHHeader ())
179+ @ Override
180+ public boolean equals (Object o ) {
181+ if (this == o )
204182 return true ;
205- return false ;
183+ if (o == null || getClass () != o .getClass ())
184+ return false ;
185+ Address other = (Address ) o ;
186+ return super .equals (other ) && this .p2sh == other .p2sh ;
187+ }
188+
189+ @ Override
190+ public int hashCode () {
191+ return Objects .hashCode (super .hashCode (), p2sh );
206192 }
207193
208194 /**
@@ -212,16 +198,4 @@ private static boolean isAcceptableVersion(NetworkParameters params, int version
212198 public Address clone () throws CloneNotSupportedException {
213199 return (Address ) super .clone ();
214200 }
215-
216- // Java serialization
217-
218- private void writeObject (ObjectOutputStream out ) throws IOException {
219- out .defaultWriteObject ();
220- out .writeUTF (params .id );
221- }
222-
223- private void readObject (ObjectInputStream in ) throws IOException , ClassNotFoundException {
224- in .defaultReadObject ();
225- params = NetworkParameters .fromID (in .readUTF ());
226- }
227201}
0 commit comments