UNPKG

21.7 kBJavaScriptView Raw
1'use strict';
2
3/* jshint maxstatements: 30 */
4
5var chai = require('chai');
6var should = chai.should();
7var expect = chai.expect;
8
9var bitcore = require('..');
10var PublicKey = bitcore.PublicKey;
11var Address = bitcore.Address;
12var Script = bitcore.Script;
13var Networks = bitcore.Networks;
14
15var validbase58 = require('./data/bitcoind/base58_keys_valid.json');
16var invalidbase58 = require('./data/bitcoind/base58_keys_invalid.json');
17
18describe('Address', function() {
19
20 var pubkeyhash = Buffer.from('3c3fa3d4adcaf8f52d5b1843975e122548269937', 'hex');
21 var buf = Buffer.concat([Buffer.from([0]), pubkeyhash]);
22 var str = '16VZnHwRhwrExfeHFHGjwrgEMq8VcYPs9r';
23
24 it('can\'t build without data', function() {
25 (function() {
26 return new Address();
27 }).should.throw('First argument is required, please include address data.');
28 });
29
30 it('should throw an error because of bad network param', function() {
31 (function() {
32 return new Address(PKHLivenet[0], 'main', 'pubkeyhash');
33 }).should.throw('Second argument must be "livenet" or "testnet".');
34 });
35
36 it('should throw an error because of bad type param', function() {
37 (function() {
38 return new Address(PKHLivenet[0], 'livenet', 'pubkey');
39 }).should.throw('Third argument must be "pubkeyhash", "scripthash", "witnesspubkeyhash", or "witnessscripthash".');
40 });
41
42 describe('bitcoind compliance', function() {
43 validbase58.map(function(d) {
44 if (!d[2].isPrivkey) {
45 it('should describe address ' + d[0] + ' as valid', function() {
46 var type;
47 if (d[2].addrType === 'script') {
48 type = 'scripthash';
49 } else if (d[2].addrType === 'pubkey') {
50 type = 'pubkeyhash';
51 }
52 var network = 'livenet';
53 if (d[2].isTestnet) {
54 network = 'testnet';
55 }
56 return new Address(d[0], network, type);
57 });
58 }
59 });
60 invalidbase58.map(function(d) {
61 it('should describe input ' + d[0].slice(0, 10) + '... as invalid', function() {
62 expect(function() {
63 return new Address(d[0]);
64 }).to.throw(Error);
65 });
66 });
67 });
68
69 // livenet valid
70 var PKHLivenet = [
71 '15vkcKf7gB23wLAnZLmbVuMiiVDc1Nm4a2',
72 '1A6ut1tWnUq1SEQLMr4ttDh24wcbJ5o9TT',
73 '1BpbpfLdY7oBS9gK7aDXgvMgr1DPvNhEB2',
74 '1Jz2yCRd5ST1p2gUqFB5wsSQfdm3jaFfg7',
75 ' 1Jz2yCRd5ST1p2gUqFB5wsSQfdm3jaFfg7 \t\n'
76 ];
77
78 // livenet p2sh
79 var P2SHLivenet = [
80 '342ftSRCvFHfCeFFBuz4xwbeqnDw6BGUey',
81 '33vt8ViH5jsr115AGkW6cEmEz9MpvJSwDk',
82 '37Sp6Rv3y4kVd1nQ1JV5pfqXccHNyZm1x3',
83 '3QjYXhTkvuj8qPaXHTTWb5wjXhdsLAAWVy',
84 '\t \n3QjYXhTkvuj8qPaXHTTWb5wjXhdsLAAWVy \r'
85 ];
86
87 // testnet p2sh
88 var P2SHTestnet = [
89 '2N7FuwuUuoTBrDFdrAZ9KxBmtqMLxce9i1C',
90 '2NEWDzHWwY5ZZp8CQWbB7ouNMLqCia6YRda',
91 '2MxgPqX1iThW3oZVk9KoFcE5M4JpiETssVN',
92 '2NB72XtkjpnATMggui83aEtPawyyKvnbX2o'
93 ];
94
95 //livenet bad checksums
96 var badChecksums = [
97 '15vkcKf7gB23wLAnZLmbVuMiiVDc3nq4a2',
98 '1A6ut1tWnUq1SEQLMr4ttDh24wcbj4w2TT',
99 '1BpbpfLdY7oBS9gK7aDXgvMgr1DpvNH3B2',
100 '1Jz2yCRd5ST1p2gUqFB5wsSQfdmEJaffg7'
101 ];
102
103 //livenet non-base58
104 var nonBase58 = [
105 '15vkcKf7g#23wLAnZLmb$uMiiVDc3nq4a2',
106 '1A601ttWnUq1SEQLMr4ttDh24wcbj4w2TT',
107 '1BpbpfLdY7oBS9gK7aIXgvMgr1DpvNH3B2',
108 '1Jz2yCRdOST1p2gUqFB5wsSQfdmEJaffg7'
109 ];
110
111 //testnet valid
112 var PKHTestnet = [
113 'n28S35tqEMbt6vNad7A5K3mZ7vdn8dZ86X',
114 'n45x3R2w2jaSC62BMa9MeJCd3TXxgvDEmm',
115 'mursDVxqNQmmwWHACpM9VHwVVSfTddGsEM',
116 'mtX8nPZZdJ8d3QNLRJ1oJTiEi26Sj6LQXS'
117 ];
118
119 describe('validation', function() {
120
121 it('getValidationError detects network mismatchs', function() {
122 var error = Address.getValidationError('37BahqRsFrAd3qLiNNwLNV3AWMRD7itxTo', 'testnet');
123 should.exist(error);
124 });
125
126 it('isValid returns true on a valid address', function() {
127 var valid = Address.isValid('37BahqRsFrAd3qLiNNwLNV3AWMRD7itxTo', 'livenet');
128 valid.should.equal(true);
129 });
130
131 it('isValid returns false on network mismatch', function() {
132 var valid = Address.isValid('37BahqRsFrAd3qLiNNwLNV3AWMRD7itxTo', 'testnet');
133 valid.should.equal(false);
134 });
135
136 it('validates correctly the P2PKH test vector', function() {
137 for (var i = 0; i < PKHLivenet.length; i++) {
138 var error = Address.getValidationError(PKHLivenet[i]);
139 should.not.exist(error);
140 }
141 });
142
143 it('validates correctly the P2SH test vector', function() {
144 for (var i = 0; i < P2SHLivenet.length; i++) {
145 var error = Address.getValidationError(P2SHLivenet[i]);
146 should.not.exist(error);
147 }
148 });
149
150 it('validates correctly the P2SH testnet test vector', function() {
151 for (var i = 0; i < P2SHTestnet.length; i++) {
152 var error = Address.getValidationError(P2SHTestnet[i], 'testnet');
153 should.not.exist(error);
154 }
155 });
156
157 it('rejects correctly the P2PKH livenet test vector with "testnet" parameter', function() {
158 for (var i = 0; i < PKHLivenet.length; i++) {
159 var error = Address.getValidationError(PKHLivenet[i], 'testnet');
160 should.exist(error);
161 }
162 });
163
164 it('validates correctly the P2PKH livenet test vector with "livenet" parameter', function() {
165 for (var i = 0; i < PKHLivenet.length; i++) {
166 var error = Address.getValidationError(PKHLivenet[i], 'livenet');
167 should.not.exist(error);
168 }
169 });
170
171 it('should not validate if checksum is invalid', function() {
172 for (var i = 0; i < badChecksums.length; i++) {
173 var error = Address.getValidationError(badChecksums[i], 'livenet', 'pubkeyhash');
174 should.exist(error);
175 error.message.should.equal('Checksum mismatch');
176 }
177 });
178
179 it('should not validate on a network mismatch', function() {
180 var error, i;
181 for (i = 0; i < PKHLivenet.length; i++) {
182 error = Address.getValidationError(PKHLivenet[i], 'testnet', 'pubkeyhash');
183 should.exist(error);
184 error.message.should.equal('Address has mismatched network type.');
185 }
186 for (i = 0; i < PKHTestnet.length; i++) {
187 error = Address.getValidationError(PKHTestnet[i], 'livenet', 'pubkeyhash');
188 should.exist(error);
189 error.message.should.equal('Address has mismatched network type.');
190 }
191 });
192
193 it('should not validate on a type mismatch', function() {
194 for (var i = 0; i < PKHLivenet.length; i++) {
195 var error = Address.getValidationError(PKHLivenet[i], 'livenet', 'scripthash');
196 should.exist(error);
197 error.message.should.equal('Address has mismatched type.');
198 }
199 });
200
201 it('should not validate on non-base58 characters', function() {
202 for (var i = 0; i < nonBase58.length; i++) {
203 var error = Address.getValidationError(nonBase58[i], 'livenet', 'pubkeyhash');
204 should.exist(error);
205 error.message.should.equal('Non-base58 character');
206 }
207 });
208
209 it('testnet addresses are validated correctly', function() {
210 for (var i = 0; i < PKHTestnet.length; i++) {
211 var error = Address.getValidationError(PKHTestnet[i], 'testnet');
212 should.not.exist(error);
213 }
214 });
215
216 it('addresses with whitespace are validated correctly', function() {
217 var ws = ' \r \t \n 1A6ut1tWnUq1SEQLMr4ttDh24wcbJ5o9TT \t \n \r';
218 var error = Address.getValidationError(ws);
219 should.not.exist(error);
220 Address.fromString(ws).toString().should.equal('1A6ut1tWnUq1SEQLMr4ttDh24wcbJ5o9TT');
221 });
222
223 it('testnet addresses are also valid regtest addresses', function() {
224 for (var i = 0; i < P2SHTestnet.length; i++) {
225 var error = Address.getValidationError(P2SHTestnet[i], 'regtest');
226 should.not.exist(error);
227 }
228 });
229 });
230
231 describe('instantiation', function() {
232 it('can be instantiated from another address', function() {
233 var address = Address.fromBuffer(buf);
234 var address2 = new Address({
235 hashBuffer: address.hashBuffer,
236 network: address.network,
237 type: address.type
238 });
239 address.toString().should.equal(address2.toString());
240 });
241 });
242
243 describe('encodings', function() {
244
245 it('should make an address from a buffer', function() {
246 Address.fromBuffer(buf).toString().should.equal(str);
247 new Address(buf).toString().should.equal(str);
248 new Address(buf).toString().should.equal(str);
249 });
250
251 it('should make an address from a string', function() {
252 Address.fromString(str).toString().should.equal(str);
253 new Address(str).toString().should.equal(str);
254 });
255
256 it('should make an address using a non-string network', function() {
257 Address.fromString(str, Networks.livenet).toString().should.equal(str);
258 });
259
260 it('should throw with bad network param', function() {
261 (function(){
262 Address.fromString(str, 'somenet');
263 }).should.throw('Unknown network');
264 });
265
266 it('should error because of unrecognized data format', function() {
267 (function() {
268 return new Address(new Error());
269 }).should.throw(bitcore.errors.InvalidArgument);
270 });
271
272 it('should error because of incorrect format for pubkey hash', function() {
273 (function() {
274 return new Address.fromPublicKeyHash('notahash');
275 }).should.throw('Address supplied is not a buffer.');
276 });
277
278 it('should error because of incorrect format for script hash', function() {
279 (function() {
280 return new Address.fromScriptHash('notascript');
281 }).should.throw('Address supplied is not a buffer.');
282 });
283
284 it('should error because of incorrect type for transform buffer', function() {
285 (function() {
286 return Address._transformBuffer('notabuffer');
287 }).should.throw('Address supplied is not a buffer.');
288 });
289
290 it('should error because of incorrect length buffer for transform buffer', function() {
291 (function() {
292 return Address._transformBuffer(Buffer.alloc(20));
293 }).should.throw('Address buffer is incorrect length.');
294 });
295
296 it('should error because of incorrect type for pubkey transform', function() {
297 (function() {
298 return Address._transformPublicKey(Buffer.alloc(20));
299 }).should.throw('Address must be an instance of PublicKey.');
300 });
301
302 it('should error because of incorrect type for script transform', function() {
303 (function() {
304 return Address._transformScript(Buffer.alloc(20));
305 }).should.throw('Invalid Argument: script must be a Script instance');
306 });
307
308 it('should error because of incorrect type for string transform', function() {
309 (function() {
310 return Address._transformString(Buffer.alloc(20));
311 }).should.throw('data parameter supplied is not a string.');
312 });
313
314 it('should make an address from a pubkey hash buffer', function() {
315 var hash = pubkeyhash; //use the same hash
316 var a = Address.fromPublicKeyHash(hash, 'livenet');
317 a.network.should.equal(Networks.livenet);
318 a.toString().should.equal(str);
319 var b = Address.fromPublicKeyHash(hash, 'testnet');
320 b.network.should.equal(Networks.testnet);
321 b.type.should.equal('pubkeyhash');
322 new Address(hash, 'livenet').toString().should.equal(str);
323 });
324
325 it('should make an address using the default network', function() {
326 var hash = pubkeyhash; //use the same hash
327 var network = Networks.defaultNetwork;
328 Networks.defaultNetwork = Networks.livenet;
329 var a = Address.fromPublicKeyHash(hash);
330 a.network.should.equal(Networks.livenet);
331 // change the default
332 Networks.defaultNetwork = Networks.testnet;
333 var b = Address.fromPublicKeyHash(hash);
334 b.network.should.equal(Networks.testnet);
335 // restore the default
336 Networks.defaultNetwork = network;
337 });
338
339 it('should throw an error for invalid length hashBuffer', function() {
340 (function() {
341 return Address.fromPublicKeyHash(buf);
342 }).should.throw('Address hashbuffers must be either 20 or 32 bytes.');
343 });
344
345 it('should make this address from a compressed pubkey', function() {
346 var pubkey = new PublicKey('0285e9737a74c30a873f74df05124f2aa6f53042c2fc0a130d6cbd7d16b944b004');
347 var address = Address.fromPublicKey(pubkey, 'livenet');
348 address.toString().should.equal('19gH5uhqY6DKrtkU66PsZPUZdzTd11Y7ke');
349 });
350
351 it('should use the default network for pubkey', function() {
352 var pubkey = new PublicKey('0285e9737a74c30a873f74df05124f2aa6f53042c2fc0a130d6cbd7d16b944b004');
353 var address = Address.fromPublicKey(pubkey);
354 address.network.should.equal(Networks.defaultNetwork);
355 });
356
357 it('should make this address from an uncompressed pubkey', function() {
358 var pubkey = new PublicKey('0485e9737a74c30a873f74df05124f2aa6f53042c2fc0a130d6cbd7d16b944b00' +
359 '4833fef26c8be4c4823754869ff4e46755b85d851077771c220e2610496a29d98');
360 var a = Address.fromPublicKey(pubkey, 'livenet');
361 a.toString().should.equal('16JXnhxjJUhxfyx4y6H4sFcxrgt8kQ8ewX');
362 var b = new Address(pubkey, 'livenet', 'pubkeyhash');
363 b.toString().should.equal('16JXnhxjJUhxfyx4y6H4sFcxrgt8kQ8ewX');
364 });
365
366 it('should classify from a custom network', function() {
367 var custom = {
368 name: 'customnetwork',
369 pubkeyhash: 0x1c,
370 privatekey: 0x1e,
371 scripthash: 0x28,
372 xpubkey: 0x02e8de8f,
373 xprivkey: 0x02e8da54,
374 networkMagic: 0x0c110907,
375 port: 7333
376 };
377 var addressString = 'CX4WePxBwq1Y6u7VyMJfmmitE7GiTgC9aE';
378 Networks.add(custom);
379 var network = Networks.get('customnetwork');
380 var address = Address.fromString(addressString);
381 address.type.should.equal(Address.PayToPublicKeyHash);
382 address.network.should.equal(network);
383 Networks.remove(network);
384 });
385
386 describe('from a script', function() {
387 it('should fail to build address from a non p2sh,p2pkh script', function() {
388 var s = new Script('OP_CHECKMULTISIG');
389 (function() {
390 return new Address(s);
391 }).should.throw('needs to be p2pkh in, p2pkh out, p2sh in, or p2sh out');
392 });
393 it('should make this address from a p2pkh output script', function() {
394 var s = new Script('OP_DUP OP_HASH160 20 ' +
395 '0xc8e11b0eb0d2ad5362d894f048908341fa61b6e1 OP_EQUALVERIFY OP_CHECKSIG');
396 var buf = s.toBuffer();
397 var a = Address.fromScript(s, 'livenet');
398 a.toString().should.equal('1KK9oz4bFH8c1t6LmighHaoSEGx3P3FEmc');
399 var b = new Address(s, 'livenet');
400 b.toString().should.equal('1KK9oz4bFH8c1t6LmighHaoSEGx3P3FEmc');
401 });
402
403 it('should make this address from a p2sh input script', function() {
404 var s = Script.fromString('OP_HASH160 20 0xa6ed4af315271e657ee307828f54a4365fa5d20f OP_EQUAL');
405 var a = Address.fromScript(s, 'livenet');
406 a.toString().should.equal('3GueMn6ruWVfQTN4XKBGEbCbGLwRSUhfnS');
407 var b = new Address(s, 'livenet');
408 b.toString().should.equal('3GueMn6ruWVfQTN4XKBGEbCbGLwRSUhfnS');
409 });
410
411 it('returns the same address if the script is a pay to public key hash out', function() {
412 var address = '16JXnhxjJUhxfyx4y6H4sFcxrgt8kQ8ewX';
413 var script = Script.buildPublicKeyHashOut(new Address(address));
414 Address(script, Networks.livenet).toString().should.equal(address);
415 });
416 it('returns the same address if the script is a pay to script hash out', function() {
417 var address = '3BYmEwgV2vANrmfRymr1mFnHXgLjD6gAWm';
418 var script = Script.buildScriptHashOut(new Address(address));
419 Address(script, Networks.livenet).toString().should.equal(address);
420 });
421 });
422
423 it('should derive from this known address string livenet', function() {
424 var address = new Address(str);
425 var buffer = address.toBuffer();
426 var slice = buffer.slice(1);
427 var sliceString = slice.toString('hex');
428 sliceString.should.equal(pubkeyhash.toString('hex'));
429 });
430
431 it('should derive from this known address string testnet', function() {
432 var a = new Address(PKHTestnet[0], 'testnet');
433 var b = new Address(a.toString());
434 b.toString().should.equal(PKHTestnet[0]);
435 b.network.should.equal(Networks.testnet);
436 });
437
438 it('should derive from this known address string livenet scripthash', function() {
439 var a = new Address(P2SHLivenet[0], 'livenet', 'scripthash');
440 var b = new Address(a.toString());
441 b.toString().should.equal(P2SHLivenet[0]);
442 });
443
444 it('should derive from this known address string testnet scripthash', function() {
445 var address = new Address(P2SHTestnet[0], 'testnet', 'scripthash');
446 address = new Address(address.toString());
447 address.toString().should.equal(P2SHTestnet[0]);
448 });
449
450 });
451
452 describe('#toBuffer', function() {
453
454 it('3c3fa3d4adcaf8f52d5b1843975e122548269937 corresponds to hash 16VZnHwRhwrExfeHFHGjwrgEMq8VcYPs9r', function() {
455 var address = new Address(str);
456 address.toBuffer().slice(1).toString('hex').should.equal(pubkeyhash.toString('hex'));
457 });
458
459 });
460
461 describe('#object', function() {
462
463 it('roundtrip to-from-to', function() {
464 var obj = new Address(str).toObject();
465 var address = Address.fromObject(obj);
466 address.toString().should.equal(str);
467 });
468
469 it('will fail with invalid state', function() {
470 expect(function() {
471 return Address.fromObject('¹');
472 }).to.throw(bitcore.errors.InvalidState);
473 });
474 });
475
476 describe('#toString', function() {
477
478 it('livenet pubkeyhash address', function() {
479 var address = new Address(str);
480 address.toString().should.equal(str);
481 });
482
483 it('scripthash address', function() {
484 var address = new Address(P2SHLivenet[0]);
485 address.toString().should.equal(P2SHLivenet[0]);
486 });
487
488 it('testnet scripthash address', function() {
489 var address = new Address(P2SHTestnet[0]);
490 address.toString().should.equal(P2SHTestnet[0]);
491 });
492
493 it('testnet pubkeyhash address', function() {
494 var address = new Address(PKHTestnet[0]);
495 address.toString().should.equal(PKHTestnet[0]);
496 });
497
498 });
499
500 describe('#inspect', function() {
501 it('should output formatted output correctly', function() {
502 var address = new Address(str);
503 var output = '<Address: 16VZnHwRhwrExfeHFHGjwrgEMq8VcYPs9r, type: pubkeyhash, network: livenet>';
504 address.inspect().should.equal(output);
505 });
506 });
507
508 describe('questions about the address', function() {
509 it('should detect a P2SH address', function() {
510 new Address(P2SHLivenet[0]).isPayToScriptHash().should.equal(true);
511 new Address(P2SHLivenet[0]).isPayToPublicKeyHash().should.equal(false);
512 new Address(P2SHTestnet[0]).isPayToScriptHash().should.equal(true);
513 new Address(P2SHTestnet[0]).isPayToPublicKeyHash().should.equal(false);
514 });
515 it('should detect a Pay To PubkeyHash address', function() {
516 new Address(PKHLivenet[0]).isPayToPublicKeyHash().should.equal(true);
517 new Address(PKHLivenet[0]).isPayToScriptHash().should.equal(false);
518 new Address(PKHTestnet[0]).isPayToPublicKeyHash().should.equal(true);
519 new Address(PKHTestnet[0]).isPayToScriptHash().should.equal(false);
520 });
521 });
522
523 it('throws an error if it couldn\'t instantiate', function() {
524 expect(function() {
525 return new Address(1);
526 }).to.throw(TypeError);
527 });
528 it('can roundtrip from/to a object', function() {
529 var address = new Address(P2SHLivenet[0]);
530 expect(new Address(address.toObject()).toString()).to.equal(P2SHLivenet[0]);
531 });
532
533 it('will use the default network for an object', function() {
534 var obj = {
535 hash: '19a7d869032368fd1f1e26e5e73a4ad0e474960e',
536 type: 'scripthash'
537 };
538 var address = new Address(obj);
539 address.network.should.equal(Networks.defaultNetwork);
540 });
541
542 describe('creating a P2SH address from public keys', function() {
543
544 var public1 = '02da5798ed0c055e31339eb9b5cef0d3c0ccdec84a62e2e255eb5c006d4f3e7f5b';
545 var public2 = '0272073bf0287c4469a2a011567361d42529cd1a72ab0d86aa104ecc89342ffeb0';
546 var public3 = '02738a516a78355db138e8119e58934864ce222c553a5407cf92b9c1527e03c1a2';
547 var publics = [public1, public2, public3];
548
549 it('can create an address from a set of public keys', function() {
550 var address = Address.createMultisig(publics, 2, Networks.livenet);
551 address.toString().should.equal('3FtqPRirhPvrf7mVUSkygyZ5UuoAYrTW3y');
552 address = new Address(publics, 2, Networks.livenet);
553 address.toString().should.equal('3FtqPRirhPvrf7mVUSkygyZ5UuoAYrTW3y');
554 });
555
556 it('works on testnet also', function() {
557 var address = Address.createMultisig(publics, 2, Networks.testnet);
558 address.toString().should.equal('2N7T3TAetJrSCruQ39aNrJvYLhG1LJosujf');
559 });
560
561 it('can create an address from a set of public keys with a nested witness program', function() {
562 var address = Address.createMultisig(publics, 2, Networks.livenet, true);
563 address.toString().should.equal('3PpK1bBqUmPK3Q6QPSUK7BQSZ1DMWL6aes');
564 });
565
566 it('can also be created by Address.createMultisig', function() {
567 var address = Address.createMultisig(publics, 2);
568 var address2 = Address.createMultisig(publics, 2);
569 address.toString().should.equal(address2.toString());
570 });
571
572 it('fails if invalid array is provided', function() {
573 expect(function() {
574 return Address.createMultisig([], 3, 'testnet');
575 }).to.throw('Number of required signatures must be less than or equal to the number of public keys');
576 });
577 });
578
579});