|
5 | 5 | #include "base58.h"
|
6 | 6 |
|
7 | 7 | #include "hash.h"
|
| 8 | +#include "script/script.h" |
8 | 9 | #include "uint256.h"
|
9 | 10 |
|
10 |
| -#include <assert.h> |
11 |
| -#include <stdint.h> |
12 |
| -#include <string.h> |
13 |
| -#include <vector> |
14 |
| -#include <string> |
15 | 11 | #include <boost/variant/apply_visitor.hpp>
|
16 | 12 | #include <boost/variant/static_visitor.hpp>
|
17 | 13 |
|
| 14 | +#include <algorithm> |
| 15 | +#include <assert.h> |
| 16 | +#include <string.h> |
| 17 | + |
| 18 | + |
18 | 19 | /** All alphanumeric characters except for "0", "I", "O", and "l" */
|
19 | 20 | static const char* pszBase58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
|
20 | 21 |
|
@@ -212,86 +213,55 @@ int CBase58Data::CompareTo(const CBase58Data& b58) const
|
212 | 213 |
|
213 | 214 | namespace
|
214 | 215 | {
|
215 |
| -/** base58-encoded Bitcoin addresses. |
216 |
| - * Public-key-hash-addresses have version 0 (or 111 testnet). |
217 |
| - * The data vector contains RIPEMD160(SHA256(pubkey)), where pubkey is the serialized public key. |
218 |
| - * Script-hash-addresses have version 5 (or 196 testnet). |
219 |
| - * The data vector contains RIPEMD160(SHA256(cscript)), where cscript is the serialized redemption script. |
220 |
| - */ |
221 |
| -class CBitcoinAddress : public CBase58Data { |
222 |
| -public: |
223 |
| - bool Set(const CKeyID &id); |
224 |
| - bool Set(const CScriptID &id); |
225 |
| - bool Set(const CTxDestination &dest); |
226 |
| - bool IsValid() const; |
227 |
| - bool IsValid(const CChainParams ¶ms) const; |
228 |
| - |
229 |
| - CBitcoinAddress() {} |
230 |
| - CBitcoinAddress(const CTxDestination &dest) { Set(dest); } |
231 |
| - CBitcoinAddress(const std::string& strAddress) { SetString(strAddress); } |
232 |
| - CBitcoinAddress(const char* pszAddress) { SetString(pszAddress); } |
233 |
| - |
234 |
| - CTxDestination Get() const; |
235 |
| -}; |
236 |
| - |
237 |
| -class CBitcoinAddressVisitor : public boost::static_visitor<bool> |
| 216 | +class DestinationEncoder : public boost::static_visitor<std::string> |
238 | 217 | {
|
239 | 218 | private:
|
240 |
| - CBitcoinAddress* addr; |
| 219 | + const CChainParams& m_params; |
241 | 220 |
|
242 | 221 | public:
|
243 |
| - explicit CBitcoinAddressVisitor(CBitcoinAddress* addrIn) : addr(addrIn) {} |
244 |
| - |
245 |
| - bool operator()(const CKeyID& id) const { return addr->Set(id); } |
246 |
| - bool operator()(const CScriptID& id) const { return addr->Set(id); } |
247 |
| - bool operator()(const CNoDestination& no) const { return false; } |
248 |
| -}; |
249 |
| - |
250 |
| -} // namespace |
251 |
| - |
252 |
| -bool CBitcoinAddress::Set(const CKeyID& id) |
253 |
| -{ |
254 |
| - SetData(Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS), &id, 20); |
255 |
| - return true; |
256 |
| -} |
| 222 | + DestinationEncoder(const CChainParams& params) : m_params(params) {} |
257 | 223 |
|
258 |
| -bool CBitcoinAddress::Set(const CScriptID& id) |
259 |
| -{ |
260 |
| - SetData(Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS), &id, 20); |
261 |
| - return true; |
262 |
| -} |
263 |
| - |
264 |
| -bool CBitcoinAddress::Set(const CTxDestination& dest) |
265 |
| -{ |
266 |
| - return boost::apply_visitor(CBitcoinAddressVisitor(this), dest); |
267 |
| -} |
| 224 | + std::string operator()(const CKeyID& id) const |
| 225 | + { |
| 226 | + std::vector<unsigned char> data = m_params.Base58Prefix(CChainParams::PUBKEY_ADDRESS); |
| 227 | + data.insert(data.end(), id.begin(), id.end()); |
| 228 | + return EncodeBase58Check(data); |
| 229 | + } |
268 | 230 |
|
269 |
| -bool CBitcoinAddress::IsValid() const |
270 |
| -{ |
271 |
| - return IsValid(Params()); |
272 |
| -} |
| 231 | + std::string operator()(const CScriptID& id) const |
| 232 | + { |
| 233 | + std::vector<unsigned char> data = m_params.Base58Prefix(CChainParams::SCRIPT_ADDRESS); |
| 234 | + data.insert(data.end(), id.begin(), id.end()); |
| 235 | + return EncodeBase58Check(data); |
| 236 | + } |
273 | 237 |
|
274 |
| -bool CBitcoinAddress::IsValid(const CChainParams& params) const |
275 |
| -{ |
276 |
| - bool fCorrectSize = vchData.size() == 20; |
277 |
| - bool fKnownVersion = vchVersion == params.Base58Prefix(CChainParams::PUBKEY_ADDRESS) || |
278 |
| - vchVersion == params.Base58Prefix(CChainParams::SCRIPT_ADDRESS); |
279 |
| - return fCorrectSize && fKnownVersion; |
280 |
| -} |
| 238 | + std::string operator()(const CNoDestination& no) const { return ""; } |
| 239 | +}; |
281 | 240 |
|
282 |
| -CTxDestination CBitcoinAddress::Get() const |
| 241 | +CTxDestination DecodeDestination(const std::string& str, const CChainParams& params) |
283 | 242 | {
|
284 |
| - if (!IsValid()) |
285 |
| - return CNoDestination(); |
286 |
| - uint160 id; |
287 |
| - memcpy(&id, vchData.data(), 20); |
288 |
| - if (vchVersion == Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS)) |
289 |
| - return CKeyID(id); |
290 |
| - else if (vchVersion == Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS)) |
291 |
| - return CScriptID(id); |
292 |
| - else |
293 |
| - return CNoDestination(); |
| 243 | + std::vector<unsigned char> data; |
| 244 | + uint160 hash; |
| 245 | + if (DecodeBase58Check(str, data)) { |
| 246 | + // base58-encoded Bitcoin addresses. |
| 247 | + // Public-key-hash-addresses have version 0 (or 111 testnet). |
| 248 | + // The data vector contains RIPEMD160(SHA256(pubkey)), where pubkey is the serialized public key. |
| 249 | + const std::vector<unsigned char>& pubkey_prefix = params.Base58Prefix(CChainParams::PUBKEY_ADDRESS); |
| 250 | + if (data.size() == hash.size() + pubkey_prefix.size() && std::equal(pubkey_prefix.begin(), pubkey_prefix.end(), data.begin())) { |
| 251 | + std::copy(data.begin() + pubkey_prefix.size(), data.end(), hash.begin()); |
| 252 | + return CKeyID(hash); |
| 253 | + } |
| 254 | + // Script-hash-addresses have version 5 (or 196 testnet). |
| 255 | + // The data vector contains RIPEMD160(SHA256(cscript)), where cscript is the serialized redemption script. |
| 256 | + const std::vector<unsigned char>& script_prefix = params.Base58Prefix(CChainParams::SCRIPT_ADDRESS); |
| 257 | + if (data.size() == hash.size() + script_prefix.size() && std::equal(script_prefix.begin(), script_prefix.end(), data.begin())) { |
| 258 | + std::copy(data.begin() + script_prefix.size(), data.end(), hash.begin()); |
| 259 | + return CScriptID(hash); |
| 260 | + } |
| 261 | + } |
| 262 | + return CNoDestination(); |
294 | 263 | }
|
| 264 | +} // namespace |
295 | 265 |
|
296 | 266 | void CBitcoinSecret::SetKey(const CKey& vchSecret)
|
297 | 267 | {
|
@@ -328,22 +298,20 @@ bool CBitcoinSecret::SetString(const std::string& strSecret)
|
328 | 298 |
|
329 | 299 | std::string EncodeDestination(const CTxDestination& dest)
|
330 | 300 | {
|
331 |
| - CBitcoinAddress addr(dest); |
332 |
| - if (!addr.IsValid()) return ""; |
333 |
| - return addr.ToString(); |
| 301 | + return boost::apply_visitor(DestinationEncoder(Params()), dest); |
334 | 302 | }
|
335 | 303 |
|
336 | 304 | CTxDestination DecodeDestination(const std::string& str)
|
337 | 305 | {
|
338 |
| - return CBitcoinAddress(str).Get(); |
| 306 | + return DecodeDestination(str, Params()); |
339 | 307 | }
|
340 | 308 |
|
341 | 309 | bool IsValidDestinationString(const std::string& str, const CChainParams& params)
|
342 | 310 | {
|
343 |
| - return CBitcoinAddress(str).IsValid(params); |
| 311 | + return IsValidDestination(DecodeDestination(str, params)); |
344 | 312 | }
|
345 | 313 |
|
346 | 314 | bool IsValidDestinationString(const std::string& str)
|
347 | 315 | {
|
348 |
| - return CBitcoinAddress(str).IsValid(); |
| 316 | + return IsValidDestinationString(str, Params()); |
349 | 317 | }
|
0 commit comments