18
18
19
19
package org .bitcoinj .core ;
20
20
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 ;
24
26
25
27
import org .bitcoinj .params .Networks ;
26
28
import org .bitcoinj .script .Script ;
27
29
import org .bitcoinj .script .ScriptPattern ;
28
30
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 ;
33
32
34
33
/**
35
34
* <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 {
48
47
*/
49
48
public static final int LENGTH = 20 ;
50
49
51
- private transient NetworkParameters params ;
50
+ /** True if P2SH, false if P2PKH. */
51
+ public final boolean p2sh ;
52
52
53
53
/**
54
54
* Private constructor. Use {@link #fromBase58(NetworkParameters, String)},
@@ -62,13 +62,10 @@ public class Address extends VersionedChecksummedBytes {
62
62
* @param hash160
63
63
* 20-byte hash of pubkey or script
64
64
*/
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 );
68
67
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 ;
72
69
}
73
70
74
71
/**
@@ -82,7 +79,7 @@ private Address(NetworkParameters params, int version, byte[] hash160) throws Wr
82
79
* @return constructed address
83
80
*/
84
81
public static Address fromPubKeyHash (NetworkParameters params , byte [] hash160 ) {
85
- return new Address (params , params . getAddressHeader () , hash160 );
82
+ return new Address (params , false , hash160 );
86
83
}
87
84
88
85
/**
@@ -110,7 +107,7 @@ public static Address fromKey(NetworkParameters params, ECKey key) {
110
107
*/
111
108
public static Address fromP2SHHash (NetworkParameters params , byte [] hash160 ) {
112
109
try {
113
- return new Address (params , params . getP2SHHeader () , hash160 );
110
+ return new Address (params , true , hash160 );
114
111
} catch (WrongNetworkException e ) {
115
112
throw new RuntimeException (e ); // Cannot happen.
116
113
}
@@ -144,37 +141,35 @@ public static Address fromP2SHScript(NetworkParameters params, Script scriptPubK
144
141
* if the given address is valid but for a different chain (eg testnet vs mainnet)
145
142
*/
146
143
public static Address fromBase58 (@ Nullable NetworkParameters params , String base58 ) throws AddressFormatException {
147
- return new Address (params , base58 );
144
+ byte [] versionAndDataBytes = Base58 .decodeChecked (base58 );
145
+ int version = versionAndDataBytes [0 ] & 0xFF ;
146
+ byte [] bytes = Arrays .copyOfRange (versionAndDataBytes , 1 , versionAndDataBytes .length );
147
+ if (params == null ) {
148
+ for (NetworkParameters p : Networks .get ()) {
149
+ if (version == p .getAddressHeader ())
150
+ return new Address (p , false , bytes );
151
+ else if (version == p .getP2SHHeader ())
152
+ return new Address (p , true , bytes );
153
+ }
154
+ throw new AddressFormatException ("No network found for " + base58 );
155
+ } else {
156
+ if (version == params .getAddressHeader ())
157
+ return new Address (params , false , bytes );
158
+ else if (version == params .getP2SHHeader ())
159
+ return new Address (params , true , bytes );
160
+ throw new WrongNetworkException (version );
161
+ }
148
162
}
149
163
150
164
/** @deprecated use {@link #fromPubKeyHash(NetworkParameters, byte[])} */
151
165
@ Deprecated
152
166
public Address (NetworkParameters params , byte [] hash160 ) {
153
- this (params , params . getAddressHeader () , hash160 );
167
+ this (params , false , hash160 );
154
168
}
155
169
156
- /** @deprecated Use {@link #fromBase58(NetworkParameters, String)} */
157
- @ Deprecated
158
- public Address (@ Nullable NetworkParameters params , String address ) throws AddressFormatException {
159
- super (address );
160
- if (params != null ) {
161
- if (!isAcceptableVersion (params , version )) {
162
- throw new WrongNetworkException (version );
163
- }
164
- this .params = params ;
165
- } else {
166
- NetworkParameters paramsFound = null ;
167
- for (NetworkParameters p : Networks .get ()) {
168
- if (isAcceptableVersion (p , version )) {
169
- paramsFound = p ;
170
- break ;
171
- }
172
- }
173
- if (paramsFound == null )
174
- throw new AddressFormatException ("No network found for " + address );
175
-
176
- this .params = paramsFound ;
177
- }
170
+ @ Override
171
+ protected int getVersion () {
172
+ return p2sh ? params .getP2SHHeader () : params .getAddressHeader ();
178
173
}
179
174
180
175
/** The (big endian) 20 byte hash that is the core of a Bitcoin address. */
@@ -187,20 +182,7 @@ public byte[] getHash160() {
187
182
* See also https://github.com/bitcoin/bips/blob/master/bip-0013.mediawiki: Address Format for pay-to-script-hash
188
183
*/
189
184
public boolean isP2SHAddress () {
190
- final NetworkParameters parameters = getParameters ();
191
- return parameters != null && this .version == parameters .p2shHeader ;
192
- }
193
-
194
- /**
195
- * Examines the version byte of the address and attempts to find a matching NetworkParameters. If you aren't sure
196
- * which network the address is intended for (eg, it was provided by a user), you can use this to decide if it is
197
- * compatible with the current wallet. You should be able to handle a null response from this method. Note that the
198
- * parameters returned is not necessarily the same as the one the Address was created with.
199
- *
200
- * @return network the address is valid for
201
- */
202
- public NetworkParameters getParameters () {
203
- return params ;
185
+ return p2sh ;
204
186
}
205
187
206
188
/**
@@ -219,31 +201,23 @@ public static NetworkParameters getParametersFromAddress(String address) throws
219
201
}
220
202
}
221
203
222
- /**
223
- * Check if a given address version is valid given the NetworkParameters.
224
- */
225
- private static boolean isAcceptableVersion (NetworkParameters params , int version ) {
226
- if (version == params .getAddressHeader ())
227
- return true ;
228
- if (version == params .getP2SHHeader ())
204
+ @ Override
205
+ public boolean equals (Object o ) {
206
+ if (this == o )
229
207
return true ;
230
- return false ;
208
+ if (o == null || getClass () != o .getClass ())
209
+ return false ;
210
+ Address other = (Address ) o ;
211
+ return super .equals (other ) && this .p2sh == other .p2sh ;
231
212
}
232
213
233
214
@ Override
234
- public Address clone () throws CloneNotSupportedException {
235
- return ( Address ) super .clone ( );
215
+ public int hashCode () {
216
+ return Objects . hashCode ( super .hashCode (), p2sh );
236
217
}
237
218
238
- // Java serialization
239
-
240
- private void writeObject (ObjectOutputStream out ) throws IOException {
241
- out .defaultWriteObject ();
242
- out .writeUTF (params .id );
243
- }
244
-
245
- private void readObject (ObjectInputStream in ) throws IOException , ClassNotFoundException {
246
- in .defaultReadObject ();
247
- params = NetworkParameters .fromID (in .readUTF ());
219
+ @ Override
220
+ public Address clone () throws CloneNotSupportedException {
221
+ return (Address ) super .clone ();
248
222
}
249
223
}
0 commit comments