diff --git a/Address.js b/Address.js index f8dcf8e..89b8211 100644 --- a/Address.js +++ b/Address.js @@ -16,6 +16,7 @@ Address.prototype.validate = function() { Address.super(this, 'validate', arguments); if(this.data.length !== 21) throw new Error('invalid data length'); }); + if (typeof this.network() === 'undefined') throw new Error('invalid network'); }; Address.prototype.isValid = function() { @@ -38,4 +39,9 @@ Address.prototype.network = function() { return answer; }; +Address.prototype.isScript = function() { + return this.isValid() && this.version() === this.network().addressScript; +}; + + module.exports = require('soop')(Address); diff --git a/Key.js b/Key.js index e81c7b3..97d958f 100644 --- a/Key.js +++ b/Key.js @@ -33,7 +33,7 @@ if (process.versions) { throw new Error('Arg should be a buffer'); } var type = p[0]; - this.compressed = type!==4; + this.compressed = type!==0x04; this._pub = p; }, get: function(){ diff --git a/PrivateKey.js b/PrivateKey.js index 9e2eac6..32adb67 100644 --- a/PrivateKey.js +++ b/PrivateKey.js @@ -19,6 +19,7 @@ PrivateKey.prototype.validate = function() { if (this.data.length < 32 || (this.data.length > 1+32 && !this.compressed()) || (this.data.length==1+32+1 && this.data[1+32+1-1]!=1) || this.data.length>1+32+1) throw new Error('invalid data length'); }); + if (typeof this.network() === 'undefined') throw new Error('invalid network'); }; // get or set the payload data (as a Buffer object) diff --git a/WalletKey.js b/WalletKey.js index 0c2abb5..3ff6214 100644 --- a/WalletKey.js +++ b/WalletKey.js @@ -2,7 +2,7 @@ var imports = require('soop').imports(); var coinUtil = require('./util/util'); var timeUtil = require('./util/time'); -var Key= require('./Key'); +var Key = require('./Key'); var PrivateKey = require('./PrivateKey'); var Address = require('./Address'); @@ -37,12 +37,12 @@ WalletKey.prototype.storeObj = function() { WalletKey.prototype.fromObj = function(obj) { this.created = obj.created; this.privKey = new Key(); - if (obj.priv.length==64) { - this.privKey.private = new Buffer(obj.priv,'hex'); - this.privKey.compressed = true; - } - else { + if (obj.priv.length == 64) { + this.privKey.private = new Buffer(obj.priv, 'hex'); + this.privKey.compressed = typeof obj.compressed === 'undefined'? true: obj.compressed; + } else { var priv = new PrivateKey(obj.priv); + priv.validate(); this.privKey.private = new Buffer(priv.payload()); this.privKey.compressed = priv.compressed(); } diff --git a/test/test.Address.js b/test/test.Address.js index 3e0441f..1982553 100644 --- a/test/test.Address.js +++ b/test/test.Address.js @@ -35,6 +35,9 @@ describe('Address', function() { ['1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62iz', false], // too long Bitcoin address ['1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62izz', false],// too long Bitcoin address ['2cFupjhnEsSn59qHXstmK2ffpLv2', false], // valid base58 invalid data + ['dB7cwYdcPSgiyAwKWL3JwCVwSk6epU2txw', false], // valid base58, valid length, invalid network + ['2MnmgiRH4eGLyLc9eAqStzk7dFgBjFtUCtu', false], // valid base58, valid length, invalid network + ['32QBdjycLwbDTuGafUwaU5p5GxzSLPYoF6', true], // valid base58, valid length, valid network ]; data.forEach(function(datum) { var address = datum[0]; @@ -48,23 +51,36 @@ describe('Address', function() { }); }); it('should be able to detect network from an address', function() { + // livenet var a = new Address('1KfyjCgBSMsLqiCbakfSdeoBUqMqLUiu3T'); a.network().name.should.equal('livenet'); - var a = new Address('1dice8EMZmqKvrGE4Qc9bUFf9PX3xaYDp'); + a = new Address('1dice8EMZmqKvrGE4Qc9bUFf9PX3xaYDp'); a.network().name.should.equal('livenet'); //p2sh - var a = new Address('3QRhucKtEn5P9i7YPxzXCqBtPJTPbRFycn'); + a = new Address('3QRhucKtEn5P9i7YPxzXCqBtPJTPbRFycn'); a.network().name.should.equal('livenet'); //testnet - var a = new Address('mrPnbY1yKDBsdgbHbS7kJ8GVm8F66hWHLE'); + a = new Address('mrPnbY1yKDBsdgbHbS7kJ8GVm8F66hWHLE'); a.network().name.should.equal('testnet'); - var a = new Address('n2ekxibY5keRiMaoKFGfiNfXQCS4zTUpct'); + a = new Address('n2ekxibY5keRiMaoKFGfiNfXQCS4zTUpct'); a.network().name.should.equal('testnet'); //p2sh - var a = new Address('2NBSBcf2KfjPEEqVusmrWdmUeNHRiUTS3Li'); + a = new Address('2NBSBcf2KfjPEEqVusmrWdmUeNHRiUTS3Li'); a.network().name.should.equal('testnet'); }); + it('#isScript should work', function() { + // invalid + new Address('1T').isScript().should.equal(false); + // pubKeyHash livenet + new Address('1KfyjCgBSMsLqiCbakfSdeoBUqMqLUiu3T').isScript().should.equal(false); + // script livenet + new Address('3QRhucKtEn5P9i7YPxzXCqBtPJTPbRFycn').isScript().should.equal(true); + // pubKeyHash testnet + new Address('mrPnbY1yKDBsdgbHbS7kJ8GVm8F66hWHLE').isScript().should.equal(false); + // script testnet + new Address('2NBSBcf2KfjPEEqVusmrWdmUeNHRiUTS3Li').isScript().should.equal(true); + }); }); diff --git a/test/test.Opcode.js b/test/test.Opcode.js index 4c9a5e9..235f26c 100644 --- a/test/test.Opcode.js +++ b/test/test.Opcode.js @@ -20,12 +20,10 @@ describe('Opcode', function() { var oc = new Opcode(); should.exist(oc); }); - it.skip('should be able to create some constants', function() { + it('should be able to create some constants', function() { // TODO: test works in node but not in browser for (var i in Opcode.map) { - console.log('var '+i + ' = ' + Opcode.map[i] + ';'); eval('var '+i + ' = ' + Opcode.map[i] + ';'); - console.log(eval(i)); } should.exist(OP_VER); should.exist(OP_HASH160); diff --git a/test/test.misc.js b/test/test.misc.js index d5528b9..1172b03 100644 --- a/test/test.misc.js +++ b/test/test.misc.js @@ -12,6 +12,10 @@ var bignum = bitcore.bignum; var base58 = bitcore.base58; var base58Check = base58.base58Check; +var Address = bitcore.Address; +var networks = bitcore.networks; +var WalletKey = bitcore.WalletKey; + describe('Miscelaneous stuff', function() { it('should initialze the config object', function() { should.exist(bitcore.config); @@ -38,8 +42,8 @@ describe('Miscelaneous stuff', function() { }); it('should perform basic math operations for bignum', function() { var b = bignum('782910138827292261791972728324982') - .sub('182373273283402171237474774728373') - .div(13); + .sub('182373273283402171237474774728373') + .div(13); b.toNumber().should.equal(46195143503376160811884457968969); }); @@ -63,11 +67,95 @@ describe('Miscelaneous stuff', function() { buffertools.toHex(base58.decode(datum[1])).should.equal(datum[0]); }); }); + testdata.dataBase58KeysValid.forEach(function(datum) { + var b58 = datum[0]; + var hexPayload = datum[1]; + var meta = datum[2]; + var network = meta.isTestnet ? networks.testnet : networks.livenet; + if (meta.isPrivkey) { + describe('base58 private key valid ' + b58, function() { + var k; + var opts = { + network: network + }; + before(function() { + k = new WalletKey(opts); + }); + it('should generate correctly from WIF', function() { + k.fromObj({ + priv: b58 + }); + should.exist(k.privKey); + }); + it('should have compressed state', function() { + k.privKey.compressed.should.equal(meta.isCompressed); + }); + it('private key should have correct payload', function() { + buffertools.toHex(k.privKey.private).should.equal(hexPayload); + }); + it('should not be an Address', function() { + new Address(b58).isValid().should.equal(false); + }); + it('should generate correctly from hex', function() { + var k2 = new WalletKey(opts); + k2.fromObj({ + priv: hexPayload, + compressed: meta.isCompressed + }); + k2.storeObj().priv.should.equal(b58); + }); + }); + } else { + describe('base58 address valid ' + b58, function() { + var a; + var shouldBeScript = meta.addrType === 'script'; + before(function() { + a = new Address(b58); + }); + it('should be valid', function() { + a.isValid().should.equal(true); + }); + it('should be of correct type', function() { + a.isScript().should.equal(shouldBeScript); + }); + it('should get correct network', function() { + a.network().should.equal(network); + }); + it('should generate correctly from hex', function() { + var version = shouldBeScript ? network.addressScript : network.addressPubkey; + var b = new Address(version, new Buffer(hexPayload, 'hex')); + b.toString().should.equal(b58); + }); + }); + } + }); + testdata.dataBase58KeysInvalid.forEach(function(datum) { + var b58 = datum[0]; + it('shouldnt be able to create Address with ' + b58, function() { + var a = new Address(b58); + var invalidAddress = (!a.isValid()); + invalidAddress.should.equal(true); + }); + it('shouldnt be able to create WalletKey with ' + b58, function() { + var kl = new WalletKey({ + network: networks.livenet + }); + var kt = new WalletKey({ + network: networks.livenet + }); + var createLivenet = function() { + kl.fromObj({ + priv: b58 + }); + }; + var createTestnet = function() { + kt.fromObj({ + priv: b58 + }); + }; + createLivenet.should.throw(); + createTestnet.should.throw(); + }); + }); }); - - - - - - diff --git a/test/testdata.js b/test/testdata.js index 217d812..3c7f3fd 100644 --- a/test/testdata.js +++ b/test/testdata.js @@ -11,6 +11,8 @@ var dataUnspent = JSON.parse(fs.readFileSync('test/data/unspent.json')); var dataUnspentSign = JSON.parse(fs.readFileSync('test/data/unspentSign.json')); var dataSigCanonical = JSON.parse(fs.readFileSync('test/data/sig_canonical.json')); var dataSigNonCanonical = JSON.parse(fs.readFileSync('test/data/sig_noncanonical.json')); +var dataBase58KeysValid = JSON.parse(fs.readFileSync('test/data/base58_keys_valid.json')); +var dataBase58KeysInvalid = JSON.parse(fs.readFileSync('test/data/base58_keys_invalid.json')); module.exports.dataValid = dataValid; module.exports.dataInvalid = dataInvalid; @@ -25,3 +27,6 @@ module.exports.dataUnspentSign = dataUnspentSign; module.exports.dataSigCanonical = dataSigCanonical; module.exports.dataSigNonCanonical = dataSigNonCanonical; +module.exports.dataBase58KeysValid = dataBase58KeysValid; +module.exports.dataBase58KeysInvalid = dataBase58KeysInvalid; +