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,20 +47,25 @@ 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
* Construct an address from parameters, the address version, and the hash160 form. Example:<p>
55
55
*
56
56
* <pre>new Address(MainNetParams.get(), NetworkParameters.getAddressHeader(), Hex.decode("4a22c3c4cbb31e4d03b15550636762bda0baf85a"));</pre>
57
57
*/
58
- public Address (NetworkParameters params , int version , byte [] hash160 ) throws WrongNetworkException {
59
- super (version , hash160 );
60
- checkNotNull (params );
58
+ public Address (NetworkParameters params , boolean p2sh , byte [] hash160 ) throws WrongNetworkException {
59
+ super (params , hash160 );
61
60
checkArgument (hash160 .length == 20 , "Addresses are 160-bit hashes, so you must provide 20 bytes" );
62
- if (!isAcceptableVersion (params , version ))
63
- throw new WrongNetworkException (version );
64
- this .params = params ;
61
+ this .p2sh = p2sh ;
62
+ }
63
+
64
+ /**
65
+ * Constructs a P2PKH address.
66
+ */
67
+ public Address (NetworkParameters params , byte [] hash160 ) throws WrongNetworkException {
68
+ this (params , false , hash160 );
65
69
}
66
70
67
71
/**
@@ -75,7 +79,7 @@ public static Address fromKey(NetworkParameters params, ECKey key) {
75
79
/** Returns an Address that represents the given P2SH script hash. */
76
80
public static Address fromP2SHHash (NetworkParameters params , byte [] hash160 ) {
77
81
try {
78
- return new Address (params , params . getP2SHHeader () , hash160 );
82
+ return new Address (params , true , hash160 );
79
83
} catch (WrongNetworkException e ) {
80
84
throw new RuntimeException (e ); // Cannot happen.
81
85
}
@@ -99,44 +103,31 @@ public static Address fromP2SHScript(NetworkParameters params, Script scriptPubK
99
103
* if the given address is valid but for a different chain (eg testnet vs mainnet)
100
104
*/
101
105
public static Address fromBase58 (@ Nullable NetworkParameters params , String base58 ) throws AddressFormatException {
102
- return new Address (params , base58 );
103
- }
104
-
105
- /**
106
- * Construct an address from parameters and the hash160 form. Example:<p>
107
- *
108
- * <pre>new Address(MainNetParams.get(), Hex.decode("4a22c3c4cbb31e4d03b15550636762bda0baf85a"));</pre>
109
- */
110
- public Address (NetworkParameters params , byte [] hash160 ) {
111
- super (params .getAddressHeader (), hash160 );
112
- checkArgument (hash160 .length == 20 , "Addresses are 160-bit hashes, so you must provide 20 bytes" );
113
- this .params = params ;
114
- }
115
-
116
- /** @deprecated Use {@link #fromBase58(NetworkParameters, String)} */
117
- @ Deprecated
118
- public Address (@ Nullable NetworkParameters params , String address ) throws AddressFormatException {
119
- super (address );
120
- if (params != null ) {
121
- if (!isAcceptableVersion (params , version )) {
122
- throw new WrongNetworkException (version );
123
- }
124
- this .params = params ;
125
- } else {
126
- NetworkParameters paramsFound = null ;
106
+ byte [] versionAndDataBytes = Base58 .decodeChecked (base58 );
107
+ int version = versionAndDataBytes [0 ] & 0xFF ;
108
+ byte [] bytes = Arrays .copyOfRange (versionAndDataBytes , 1 , versionAndDataBytes .length );
109
+ if (params == null ) {
127
110
for (NetworkParameters p : Networks .get ()) {
128
- if (isAcceptableVersion ( p , version )) {
129
- paramsFound = p ;
130
- break ;
131
- }
111
+ if (version == p . getAddressHeader ())
112
+ return new Address ( p , false , bytes ) ;
113
+ else if ( version == p . getP2SHHeader ())
114
+ return new Address ( p , true , bytes );
132
115
}
133
- if (paramsFound == null )
134
- throw new AddressFormatException ("No network found for " + address );
135
-
136
- this .params = paramsFound ;
116
+ throw new AddressFormatException ("No network found for " + base58 );
117
+ } else {
118
+ if (version == params .getAddressHeader ())
119
+ return new Address (params , false , bytes );
120
+ else if (version == params .getP2SHHeader ())
121
+ return new Address (params , true , bytes );
122
+ throw new WrongNetworkException (version );
137
123
}
138
124
}
139
125
126
+ @ Override
127
+ protected int getVersion () {
128
+ return p2sh ? params .getP2SHHeader () : params .getAddressHeader ();
129
+ }
130
+
140
131
/** The (big endian) 20 byte hash that is the core of a Bitcoin address. */
141
132
public byte [] getHash160 () {
142
133
return bytes ;
@@ -147,20 +138,7 @@ public byte[] getHash160() {
147
138
* See also https://github.com/bitcoin/bips/blob/master/bip-0013.mediawiki: Address Format for pay-to-script-hash
148
139
*/
149
140
public boolean isP2SHAddress () {
150
- final NetworkParameters parameters = getParameters ();
151
- return parameters != null && this .version == parameters .p2shHeader ;
152
- }
153
-
154
- /**
155
- * Examines the version byte of the address and attempts to find a matching NetworkParameters. If you aren't sure
156
- * which network the address is intended for (eg, it was provided by a user), you can use this to decide if it is
157
- * compatible with the current wallet. You should be able to handle a null response from this method. Note that the
158
- * parameters returned is not necessarily the same as the one the Address was created with.
159
- *
160
- * @return a NetworkParameters representing the network the address is intended for.
161
- */
162
- public NetworkParameters getParameters () {
163
- return params ;
141
+ return p2sh ;
164
142
}
165
143
166
144
/**
@@ -178,15 +156,19 @@ public static NetworkParameters getParametersFromAddress(String address) throws
178
156
}
179
157
}
180
158
181
- /**
182
- * Check if a given address version is valid given the NetworkParameters.
183
- */
184
- private static boolean isAcceptableVersion (NetworkParameters params , int version ) {
185
- if (version == params .getAddressHeader ())
186
- return true ;
187
- if (version == params .getP2SHHeader ())
159
+ @ Override
160
+ public boolean equals (Object o ) {
161
+ if (this == o )
188
162
return true ;
189
- return false ;
163
+ if (o == null || getClass () != o .getClass ())
164
+ return false ;
165
+ Address other = (Address ) o ;
166
+ return super .equals (other ) && this .p2sh == other .p2sh ;
167
+ }
168
+
169
+ @ Override
170
+ public int hashCode () {
171
+ return Objects .hashCode (super .hashCode (), p2sh );
190
172
}
191
173
192
174
/**
@@ -196,16 +178,4 @@ private static boolean isAcceptableVersion(NetworkParameters params, int version
196
178
public Address clone () throws CloneNotSupportedException {
197
179
return (Address ) super .clone ();
198
180
}
199
-
200
- // Java serialization
201
-
202
- private void writeObject (ObjectOutputStream out ) throws IOException {
203
- out .defaultWriteObject ();
204
- out .writeUTF (params .id );
205
- }
206
-
207
- private void readObject (ObjectInputStream in ) throws IOException , ClassNotFoundException {
208
- in .defaultReadObject ();
209
- params = NetworkParameters .fromID (in .readUTF ());
210
- }
211
181
}
0 commit comments