diff --git a/.travis.yml b/.travis.yml index 9761f002e..26f05da87 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,7 +5,8 @@ node_js: - "0.11" - "0.10" env: - - TEST_SUITE=unit - - TEST_SUITE=integration - TEST_SUITE=coveralls + - TEST_SUITE=integration + - TEST_SUITE=standard + - TEST_SUITE=unit script: "npm run-script $TEST_SUITE" diff --git a/README.md b/README.md index 587bbb09a..045332e77 100644 --- a/README.md +++ b/README.md @@ -105,11 +105,10 @@ The below examples are implemented as integration tests, they should be very eas - [Coinkite](https://coinkite.com) - [Coinpunk](https://coinpunk.com) - [Dark Wallet](https://darkwallet.unsystem.net) -- [DecentralBank](http://decentralbank.co) +- [DecentralBank](http://decentralbank.com/) - [Dogechain Wallet](https://dogechain.info) - [GreenAddress](https://greenaddress.it) - [Hive Wallet](https://www.hivewallet.com) -- [Justchain Exchange](https://justcoin.com) - [QuickCoin](https://wallet.quickcoin.co) - [Robocoin](https://wallet.robocoin.com) - [Skyhook ATM](http://projectskyhook.com) diff --git a/jshint.json b/jshint.json deleted file mode 100644 index ab6fd1b05..000000000 --- a/jshint.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "asi": true, - "camelcase": true, - "freeze": true, - "immed": true, - "indent": 2, - "latedef": true, - "maxcomplexity": 10, - "maxlen": 120, - "noarg": true, - "noempty": true, - "nonbsp": true, - "node": true, - "nonew": true, - "undef": true, - "unused": true, - "strict": false, - "trailing": true -} diff --git a/package.json b/package.json index b75fdd521..fd4259be2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "bitcoinjs-lib", - "version": "1.4.5", + "version": "1.5.0", "description": "Client-side Bitcoin JavaScript library", "main": "./src/index.js", "keywords": [ @@ -36,7 +36,7 @@ "coverage": "istanbul cover _mocha -- test/*.js", "coveralls": "npm run-script coverage && coveralls < coverage/lcov.info", "integration": "mocha --reporter list test/integration/*.js", - "jshint": "jshint --config jshint.json src/*.js ; true", + "standard": "standard", "test": "npm run-script unit", "unit": "istanbul test mocha -- --reporter list test/*.js" }, @@ -57,9 +57,9 @@ "cb-helloblock": "^0.4.10", "coveralls": "^2.11.2", "istanbul": "^0.3.5", - "jshint": "^2.5.11", "mocha": "^2.1.0", "mocha-lcov-reporter": "0.0.1", - "sinon": "^1.12.2" + "sinon": "^1.12.2", + "standard": "^2.7.3" } } diff --git a/src/address.js b/src/address.js index e87351598..4d8c67a26 100644 --- a/src/address.js +++ b/src/address.js @@ -4,7 +4,7 @@ var typeForce = require('typeforce') var networks = require('./networks') var scripts = require('./scripts') -function findScriptTypeByVersion(version) { +function findScriptTypeByVersion (version) { for (var networkName in networks) { var network = networks[networkName] @@ -13,7 +13,7 @@ function findScriptTypeByVersion(version) { } } -function Address(hash, version) { +function Address (hash, version) { typeForce('Buffer', hash) assert.strictEqual(hash.length, 20, 'Invalid hash length') @@ -23,7 +23,7 @@ function Address(hash, version) { this.version = version } -Address.fromBase58Check = function(string) { +Address.fromBase58Check = function (string) { var payload = base58check.decode(string) var version = payload.readUInt8(0) var hash = payload.slice(1) @@ -31,7 +31,7 @@ Address.fromBase58Check = function(string) { return new Address(hash, version) } -Address.fromOutputScript = function(script, network) { +Address.fromOutputScript = function (script, network) { network = network || networks.bitcoin if (scripts.isPubKeyHashOutput(script)) return new Address(script.chunks[2], network.pubKeyHash) @@ -48,7 +48,7 @@ Address.prototype.toBase58Check = function () { return base58check.encode(payload) } -Address.prototype.toOutputScript = function() { +Address.prototype.toOutputScript = function () { var scriptType = findScriptTypeByVersion(this.version) if (scriptType === 'pubkeyhash') return scripts.pubKeyHashOutput(this.hash) diff --git a/src/base58check.js b/src/base58check.js deleted file mode 100644 index 8108a0b05..000000000 --- a/src/base58check.js +++ /dev/null @@ -1,18 +0,0 @@ -var bs58check = require('bs58check') - -function decode() { - console.warn('bs58check will be removed in 2.0.0. require("bs58check") instead.'); - - return bs58check.decode.apply(undefined, arguments) -} - -function encode() { - console.warn('bs58check will be removed in 2.0.0. require("bs58check") instead.'); - - return bs58check.encode.apply(undefined, arguments) -} - -module.exports = { - decode: decode, - encode: encode -} diff --git a/src/block.js b/src/block.js index 3bef1655b..dca1f4cf3 100644 --- a/src/block.js +++ b/src/block.js @@ -3,9 +3,8 @@ var bufferutils = require('./bufferutils') var crypto = require('./crypto') var Transaction = require('./transaction') -var Script = require('./script') -function Block() { +function Block () { this.version = 1 this.prevHash = null this.merkleRoot = null @@ -14,16 +13,16 @@ function Block() { this.nonce = 0 } -Block.fromBuffer = function(buffer) { +Block.fromBuffer = function (buffer) { assert(buffer.length >= 80, 'Buffer too small (< 80 bytes)') var offset = 0 - function readSlice(n) { + function readSlice (n) { offset += n return buffer.slice(offset - n, offset) } - function readUInt32() { + function readUInt32 () { var i = buffer.readUInt32LE(offset) offset += 4 return i @@ -39,14 +38,14 @@ Block.fromBuffer = function(buffer) { if (buffer.length === 80) return block - function readVarInt() { + function readVarInt () { var vi = bufferutils.readVarInt(buffer, offset) offset += vi.size return vi.number } // FIXME: poor performance - function readTransaction() { + function readTransaction () { var tx = Transaction.fromBuffer(buffer.slice(offset), true) offset += tx.toBuffer().length @@ -64,35 +63,35 @@ Block.fromBuffer = function(buffer) { return block } -Block.fromHex = function(hex) { +Block.fromHex = function (hex) { return Block.fromBuffer(new Buffer(hex, 'hex')) } -Block.prototype.getHash = function() { +Block.prototype.getHash = function () { return crypto.hash256(this.toBuffer(true)) } -Block.prototype.getId = function() { +Block.prototype.getId = function () { return bufferutils.reverse(this.getHash()).toString('hex') } -Block.prototype.getUTCDate = function() { +Block.prototype.getUTCDate = function () { var date = new Date(0) // epoch date.setUTCSeconds(this.timestamp) return date } -Block.prototype.toBuffer = function(headersOnly) { +Block.prototype.toBuffer = function (headersOnly) { var buffer = new Buffer(80) var offset = 0 - function writeSlice(slice) { + function writeSlice (slice) { slice.copy(buffer, offset) offset += slice.length } - function writeUInt32(i) { + function writeUInt32 (i) { buffer.writeUInt32LE(i, offset) offset += 4 } @@ -107,14 +106,14 @@ Block.prototype.toBuffer = function(headersOnly) { if (headersOnly || !this.transactions) return buffer var txLenBuffer = bufferutils.varIntBuffer(this.transactions.length) - var txBuffers = this.transactions.map(function(tx) { + var txBuffers = this.transactions.map(function (tx) { return tx.toBuffer() }) return Buffer.concat([buffer, txLenBuffer].concat(txBuffers)) } -Block.prototype.toHex = function(headersOnly) { +Block.prototype.toHex = function (headersOnly) { return this.toBuffer(headersOnly).toString('hex') } diff --git a/src/bufferutils.js b/src/bufferutils.js index 644db884c..afe03e622 100644 --- a/src/bufferutils.js +++ b/src/bufferutils.js @@ -2,21 +2,21 @@ var assert = require('assert') var opcodes = require('./opcodes') // https://github.com/feross/buffer/blob/master/index.js#L1127 -function verifuint(value, max) { +function verifuint (value, max) { assert(typeof value === 'number', 'cannot write a non-number as a number') assert(value >= 0, 'specified a negative value for writing an unsigned value') assert(value <= max, 'value is larger than maximum value for type') assert(Math.floor(value) === value, 'value has a fractional component') } -function pushDataSize(i) { +function pushDataSize (i) { return i < opcodes.OP_PUSHDATA1 ? 1 - : i < 0xff ? 2 - : i < 0xffff ? 3 - : 5 + : i < 0xff ? 2 + : i < 0xffff ? 3 + : 5 } -function readPushDataInt(buffer, offset) { +function readPushDataInt (buffer, offset) { var opcode = buffer.readUInt8(offset) var number, size @@ -41,7 +41,6 @@ function readPushDataInt(buffer, offset) { number = buffer.readUInt32LE(offset + 1) size = 5 - } return { @@ -51,7 +50,7 @@ function readPushDataInt(buffer, offset) { } } -function readUInt64LE(buffer, offset) { +function readUInt64LE (buffer, offset) { var a = buffer.readUInt32LE(offset) var b = buffer.readUInt32LE(offset + 4) b *= 0x100000000 @@ -61,7 +60,7 @@ function readUInt64LE(buffer, offset) { return b + a } -function readVarInt(buffer, offset) { +function readVarInt (buffer, offset) { var t = buffer.readUInt8(offset) var number, size @@ -92,7 +91,7 @@ function readVarInt(buffer, offset) { } } -function writePushDataInt(buffer, number, offset) { +function writePushDataInt (buffer, number, offset) { var size = pushDataSize(number) // ~6 bit @@ -113,27 +112,26 @@ function writePushDataInt(buffer, number, offset) { } else { buffer.writeUInt8(opcodes.OP_PUSHDATA4, offset) buffer.writeUInt32LE(number, offset + 1) - } return size } -function writeUInt64LE(buffer, value, offset) { +function writeUInt64LE (buffer, value, offset) { verifuint(value, 0x001fffffffffffff) buffer.writeInt32LE(value & -1, offset) buffer.writeUInt32LE(Math.floor(value / 0x100000000), offset + 4) } -function varIntSize(i) { - return i < 253 ? 1 - : i < 0x10000 ? 3 - : i < 0x100000000 ? 5 - : 9 +function varIntSize (i) { + return i < 253 ? 1 + : i < 0x10000 ? 3 + : i < 0x100000000 ? 5 + : 9 } -function writeVarInt(buffer, number, offset) { +function writeVarInt (buffer, number, offset) { var size = varIntSize(number) // 8 bit @@ -159,7 +157,7 @@ function writeVarInt(buffer, number, offset) { return size } -function varIntBuffer(i) { +function varIntBuffer (i) { var size = varIntSize(i) var buffer = new Buffer(size) writeVarInt(buffer, i, 0) @@ -167,13 +165,24 @@ function varIntBuffer(i) { return buffer } -function reverse(buffer) { +function equal (a, b) { + if (a.length !== b.length) return false + + for (var i = 0; i < a.length; ++i) { + if (a[i] !== b[i]) return false + } + + return true +} + +function reverse (buffer) { var buffer2 = new Buffer(buffer) Array.prototype.reverse.call(buffer2) return buffer2 } module.exports = { + equal: equal, pushDataSize: pushDataSize, readPushDataInt: readPushDataInt, readUInt64LE: readUInt64LE, diff --git a/src/crypto.js b/src/crypto.js index e62e14b87..dec8a79bf 100644 --- a/src/crypto.js +++ b/src/crypto.js @@ -1,42 +1,29 @@ var crypto = require('crypto') -function hash160(buffer) { +function hash160 (buffer) { return ripemd160(sha256(buffer)) } -function hash256(buffer) { +function hash256 (buffer) { return sha256(sha256(buffer)) } -function ripemd160(buffer) { +function ripemd160 (buffer) { return crypto.createHash('rmd160').update(buffer).digest() } -function sha1(buffer) { +function sha1 (buffer) { return crypto.createHash('sha1').update(buffer).digest() } -function sha256(buffer) { +function sha256 (buffer) { return crypto.createHash('sha256').update(buffer).digest() } -// FIXME: Name not consistent with others -function HmacSHA256(buffer, secret) { - console.warn('Hmac* functions are deprecated for removal in 2.0.0, use node crypto instead') - return crypto.createHmac('sha256', secret).update(buffer).digest() -} - -function HmacSHA512(buffer, secret) { - console.warn('Hmac* functions are deprecated for removal in 2.0.0, use node crypto instead') - return crypto.createHmac('sha512', secret).update(buffer).digest() -} - module.exports = { - ripemd160: ripemd160, - sha1: sha1, - sha256: sha256, hash160: hash160, hash256: hash256, - HmacSHA256: HmacSHA256, - HmacSHA512: HmacSHA512 + ripemd160: ripemd160, + sha1: sha1, + sha256: sha256 } diff --git a/src/ecdsa.js b/src/ecdsa.js index 63c5ceffc..0455d198b 100644 --- a/src/ecdsa.js +++ b/src/ecdsa.js @@ -9,37 +9,10 @@ var ZERO = new Buffer([0]) var ONE = new Buffer([1]) // https://tools.ietf.org/html/rfc6979#section-3.2 -function deterministicGenerateK(curve, hash, d, checkSig) { +function deterministicGenerateK (curve, hash, d, checkSig) { typeForce('Buffer', hash) typeForce('BigInteger', d) - - // FIXME: remove/uncomment for 2.0.0 -// typeForce('Function', checkSig) - - if (typeof checkSig !== 'function') { - console.warn('deterministicGenerateK requires a checkSig callback in 2.0.0, see #337 for more information') - - checkSig = function(k) { - var G = curve.G - var n = curve.n - var e = BigInteger.fromBuffer(hash) - - var Q = G.multiply(k) - - if (curve.isInfinity(Q)) - return false - - var r = Q.affineX.mod(n) - if (r.signum() === 0) - return false - - var s = k.modInverse(n).multiply(e.add(d.multiply(r))).mod(n) - if (s.signum() === 0) - return false - - return true - } - } + typeForce('Function', checkSig) // sanity check assert.equal(hash.length, 32, 'Hash must be 256 bit') @@ -101,14 +74,14 @@ function deterministicGenerateK(curve, hash, d, checkSig) { return T } -function sign(curve, hash, d) { +function sign (curve, hash, d) { var r, s var e = BigInteger.fromBuffer(hash) var n = curve.n var G = curve.G - deterministicGenerateK(curve, hash, d, function(k) { + deterministicGenerateK(curve, hash, d, function (k) { var Q = G.multiply(k) if (curve.isInfinity(Q)) @@ -135,7 +108,7 @@ function sign(curve, hash, d) { return new ECSignature(r, s) } -function verifyRaw(curve, e, signature, Q) { +function verifyRaw (curve, e, signature, Q) { var n = curve.n var G = curve.G @@ -165,7 +138,7 @@ function verifyRaw(curve, e, signature, Q) { return v.equals(r) } -function verify(curve, hash, signature, Q) { +function verify (curve, hash, signature, Q) { // 1.4.2 H = Hash(M), already done by the user // 1.4.3 e = H var e = BigInteger.fromBuffer(hash) @@ -181,7 +154,7 @@ function verify(curve, hash, signature, Q) { * * http://www.secg.org/download/aid-780/sec1-v2.pdf */ -function recoverPubKey(curve, e, signature, i) { +function recoverPubKey (curve, e, signature, i) { assert.strictEqual(i & 3, i, 'Recovery param is more than two bits') var n = curve.n @@ -232,7 +205,7 @@ function recoverPubKey(curve, e, signature, i) { * This function simply tries all four cases and returns the value * that resulted in a successful pubkey recovery. */ -function calcPubKeyRecoveryParam(curve, e, signature, Q) { +function calcPubKeyRecoveryParam (curve, e, signature, Q) { for (var i = 0; i < 4; i++) { var Qprime = recoverPubKey(curve, e, signature, i) diff --git a/src/eckey.js b/src/eckey.js index 74ba93c76..af7fda20b 100644 --- a/src/eckey.js +++ b/src/eckey.js @@ -11,7 +11,7 @@ var ECPubKey = require('./ecpubkey') var ecurve = require('ecurve') var secp256k1 = ecurve.getCurveByName('secp256k1') -function ECKey(d, compressed) { +function ECKey (d, compressed) { assert(d.signum() > 0, 'Private key must be greater than 0') assert(d.compareTo(ECKey.curve.n) < 0, 'Private key must be less than the curve order') @@ -25,7 +25,7 @@ function ECKey(d, compressed) { ECKey.curve = secp256k1 // Static constructors -ECKey.fromWIF = function(string) { +ECKey.fromWIF = function (string) { var payload = base58check.decode(string) var compressed = false @@ -46,7 +46,7 @@ ECKey.fromWIF = function(string) { return new ECKey(d, compressed) } -ECKey.makeRandom = function(compressed, rng) { +ECKey.makeRandom = function (compressed, rng) { rng = rng || crypto.randomBytes var buffer = rng(32) @@ -60,7 +60,7 @@ ECKey.makeRandom = function(compressed, rng) { } // Export functions -ECKey.prototype.toWIF = function(network) { +ECKey.prototype.toWIF = function (network) { network = network || networks.bitcoin var bufferLen = this.pub.compressed ? 34 : 33 @@ -77,7 +77,7 @@ ECKey.prototype.toWIF = function(network) { } // Operations -ECKey.prototype.sign = function(hash) { +ECKey.prototype.sign = function (hash) { return ecdsa.sign(ECKey.curve, hash, this.d) } diff --git a/src/ecpubkey.js b/src/ecpubkey.js index 860e415a6..ecc37bc51 100644 --- a/src/ecpubkey.js +++ b/src/ecpubkey.js @@ -8,8 +8,10 @@ var Address = require('./address') var ecurve = require('ecurve') var secp256k1 = ecurve.getCurveByName('secp256k1') -function ECPubKey(Q, compressed) { - if (compressed === undefined) compressed = true +function ECPubKey (Q, compressed) { + if (compressed === undefined) { + compressed = true + } typeForce('Point', Q) typeForce('Boolean', compressed) @@ -22,32 +24,32 @@ function ECPubKey(Q, compressed) { ECPubKey.curve = secp256k1 // Static constructors -ECPubKey.fromBuffer = function(buffer) { +ECPubKey.fromBuffer = function (buffer) { var Q = ecurve.Point.decodeFrom(ECPubKey.curve, buffer) return new ECPubKey(Q, Q.compressed) } -ECPubKey.fromHex = function(hex) { +ECPubKey.fromHex = function (hex) { return ECPubKey.fromBuffer(new Buffer(hex, 'hex')) } // Operations -ECPubKey.prototype.getAddress = function(network) { +ECPubKey.prototype.getAddress = function (network) { network = network || networks.bitcoin return new Address(crypto.hash160(this.toBuffer()), network.pubKeyHash) } -ECPubKey.prototype.verify = function(hash, signature) { +ECPubKey.prototype.verify = function (hash, signature) { return ecdsa.verify(ECPubKey.curve, hash, signature, this.Q) } // Export functions -ECPubKey.prototype.toBuffer = function() { +ECPubKey.prototype.toBuffer = function () { return this.Q.getEncoded(this.compressed) } -ECPubKey.prototype.toHex = function() { +ECPubKey.prototype.toHex = function () { return this.toBuffer().toString('hex') } diff --git a/src/ecsignature.js b/src/ecsignature.js index 11f2287c3..abab16154 100644 --- a/src/ecsignature.js +++ b/src/ecsignature.js @@ -3,7 +3,7 @@ var typeForce = require('typeforce') var BigInteger = require('bigi') -function ECSignature(r, s) { +function ECSignature (r, s) { typeForce('BigInteger', r) typeForce('BigInteger', s) @@ -11,7 +11,7 @@ function ECSignature(r, s) { this.s = s } -ECSignature.parseCompact = function(buffer) { +ECSignature.parseCompact = function (buffer) { assert.equal(buffer.length, 65, 'Invalid signature length') var i = buffer.readUInt8(0) - 27 @@ -32,7 +32,7 @@ ECSignature.parseCompact = function(buffer) { } } -ECSignature.fromDER = function(buffer) { +ECSignature.fromDER = function (buffer) { assert.equal(buffer.readUInt8(0), 0x30, 'Not a DER sequence') assert.equal(buffer.readUInt8(1), buffer.length - 2, 'Invalid sequence length') assert.equal(buffer.readUInt8(2), 0x02, 'Expected a DER integer') @@ -69,7 +69,7 @@ ECSignature.fromDER = function(buffer) { } // BIP62: 1 byte hashType flag (only 0x01, 0x02, 0x03, 0x81, 0x82 and 0x83 are allowed) -ECSignature.parseScriptSignature = function(buffer) { +ECSignature.parseScriptSignature = function (buffer) { var hashType = buffer.readUInt8(buffer.length - 1) var hashTypeMod = hashType & ~0x80 @@ -81,8 +81,11 @@ ECSignature.parseScriptSignature = function(buffer) { } } -ECSignature.prototype.toCompact = function(i, compressed) { - if (compressed) i += 4 +ECSignature.prototype.toCompact = function (i, compressed) { + if (compressed) { + i += 4 + } + i += 27 var buffer = new Buffer(65) @@ -94,7 +97,7 @@ ECSignature.prototype.toCompact = function(i, compressed) { return buffer } -ECSignature.prototype.toDER = function() { +ECSignature.prototype.toDER = function () { var rBa = this.r.toDERInteger() var sBa = this.s.toDERInteger() @@ -114,7 +117,7 @@ ECSignature.prototype.toDER = function() { return new Buffer(sequence) } -ECSignature.prototype.toScriptSignature = function(hashType) { +ECSignature.prototype.toScriptSignature = function (hashType) { var hashTypeMod = hashType & ~0x80 assert(hashTypeMod > 0x00 && hashTypeMod < 0x04, 'Invalid hashType ' + hashType) diff --git a/src/hdnode.js b/src/hdnode.js index e81dc4ecb..f0aa61399 100644 --- a/src/hdnode.js +++ b/src/hdnode.js @@ -12,13 +12,11 @@ var ECPubKey = require('./ecpubkey') var ecurve = require('ecurve') var curve = ecurve.getCurveByName('secp256k1') -function findBIP32NetworkByVersion(version) { +function findBIP32NetworkByVersion (version) { for (var name in networks) { var network = networks[name] - if (version === network.bip32.private || - version === network.bip32.public) { - + if (version === network.bip32.private || version === network.bip32.public) { return network } } @@ -26,7 +24,7 @@ function findBIP32NetworkByVersion(version) { assert(false, 'Could not find network for ' + version.toString(16)) } -function HDNode(K, chainCode, network) { +function HDNode (K, chainCode, network) { network = network || networks.bitcoin typeForce('Buffer', chainCode) @@ -43,6 +41,12 @@ function HDNode(K, chainCode, network) { if (K instanceof BigInteger) { this.privKey = new ECKey(K, true) this.pubKey = this.privKey.pub + } else if (K instanceof ECKey) { + assert(K.pub.compressed, 'ECKey must be compressed') + this.privKey = K + } else if (K instanceof ECPubKey) { + assert(K.compressed, 'ECPubKey must be compressed') + this.pubKey = K } else { this.pubKey = new ECPubKey(K, true) } @@ -52,7 +56,7 @@ HDNode.MASTER_SECRET = new Buffer('Bitcoin seed') HDNode.HIGHEST_BIT = 0x80000000 HDNode.LENGTH = 78 -HDNode.fromSeedBuffer = function(seed, network) { +HDNode.fromSeedBuffer = function (seed, network) { typeForce('Buffer', seed) assert(seed.length >= 16, 'Seed should be at least 128 bits') @@ -69,27 +73,19 @@ HDNode.fromSeedBuffer = function(seed, network) { return new HDNode(pIL, IR, network) } -HDNode.fromSeedHex = function(hex, network) { +HDNode.fromSeedHex = function (hex, network) { return HDNode.fromSeedBuffer(new Buffer(hex, 'hex'), network) } -HDNode.fromBase58 = function(string, network) { - return HDNode.fromBuffer(base58check.decode(string), network, true) -} - -// FIXME: remove in 2.x.y -HDNode.fromBuffer = function(buffer, network, __ignoreDeprecation) { - if (!__ignoreDeprecation) { - console.warn('HDNode.fromBuffer() is deprecated for removal in 2.x.y, use fromBase58 instead') - } - +HDNode.fromBase58 = function (string, network) { + var buffer = base58check.decode(string) assert.strictEqual(buffer.length, HDNode.LENGTH, 'Invalid buffer length') // 4 byte: version bytes var version = buffer.readUInt32BE(0) if (network) { - assert(version === network.bip32.private || version === network.bip32.public, 'Network doesn\'t match') + assert(version === network.bip32.private || version === network.bip32.public, "Network doesn't match") // auto-detect } else { @@ -141,24 +137,19 @@ HDNode.fromBuffer = function(buffer, network, __ignoreDeprecation) { return hd } -// FIXME: remove in 2.x.y -HDNode.fromHex = function(hex, network) { - return HDNode.fromBuffer(new Buffer(hex, 'hex'), network) -} - -HDNode.prototype.getIdentifier = function() { +HDNode.prototype.getIdentifier = function () { return bcrypto.hash160(this.pubKey.toBuffer()) } -HDNode.prototype.getFingerprint = function() { +HDNode.prototype.getFingerprint = function () { return this.getIdentifier().slice(0, 4) } -HDNode.prototype.getAddress = function() { +HDNode.prototype.getAddress = function () { return this.pubKey.getAddress(this.network) } -HDNode.prototype.neutered = function() { +HDNode.prototype.neutered = function () { var neutered = new HDNode(this.pubKey.Q, this.chainCode, this.network) neutered.depth = this.depth neutered.index = this.index @@ -167,26 +158,11 @@ HDNode.prototype.neutered = function() { return neutered } -HDNode.prototype.toBase58 = function(isPrivate) { - return base58check.encode(this.toBuffer(isPrivate, true)) -} - -// FIXME: remove in 2.x.y -HDNode.prototype.toBuffer = function(isPrivate, __ignoreDeprecation) { - if (isPrivate === undefined) { - isPrivate = !!this.privKey - - // FIXME: remove in 2.x.y - } else { - console.warn('isPrivate flag is deprecated, please use the .neutered() method instead') - } - - if (!__ignoreDeprecation) { - console.warn('HDNode.toBuffer() is deprecated for removal in 2.x.y, use toBase58 instead') - } +HDNode.prototype.toBase58 = function (__isPrivate) { + assert.strictEqual(__isPrivate, undefined, 'Unsupported argument in 2.0.0') // Version - var version = isPrivate ? this.network.bip32.private : this.network.bip32.public + var version = this.privKey ? this.network.bip32.private : this.network.bip32.public var buffer = new Buffer(HDNode.LENGTH) // 4 bytes: version bytes @@ -206,30 +182,23 @@ HDNode.prototype.toBuffer = function(isPrivate, __ignoreDeprecation) { // 32 bytes: the chain code this.chainCode.copy(buffer, 13) - // 33 bytes: the public key or private key data - if (isPrivate) { - // FIXME: remove in 2.x.y - assert(this.privKey, 'Missing private key') - + // 33 bytes: the private key, or + if (this.privKey) { // 0x00 + k for private keys buffer.writeUInt8(0, 45) this.privKey.d.toBuffer(32).copy(buffer, 46) - } else { + // 33 bytes: the public key + } else { // X9.62 encoding for public keys this.pubKey.toBuffer().copy(buffer, 45) } - return buffer -} - -// FIXME: remove in 2.x.y -HDNode.prototype.toHex = function(isPrivate) { - return this.toBuffer(isPrivate).toString('hex') + return base58check.encode(buffer) } // https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#child-key-derivation-ckd-functions -HDNode.prototype.derive = function(index) { +HDNode.prototype.derive = function (index) { var isHardened = index >= HDNode.HIGHEST_BIT var indexBuffer = new Buffer(4) indexBuffer.writeUInt32BE(index, 0) @@ -301,7 +270,7 @@ HDNode.prototype.derive = function(index) { return hd } -HDNode.prototype.deriveHardened = function(index) { +HDNode.prototype.deriveHardened = function (index) { // Only derives hardened private keys by default return this.derive(index + HDNode.HIGHEST_BIT) } diff --git a/src/index.js b/src/index.js index 5dc683f48..3b5317bce 100644 --- a/src/index.js +++ b/src/index.js @@ -1,6 +1,5 @@ module.exports = { Address: require('./address'), - base58check: require('./base58check'), Block: require('./block'), bufferutils: require('./bufferutils'), crypto: require('./crypto'), @@ -8,13 +7,12 @@ module.exports = { ECKey: require('./eckey'), ECPubKey: require('./ecpubkey'), ECSignature: require('./ecsignature'), - Message: require('./message'), + message: require('./message'), opcodes: require('./opcodes'), HDNode: require('./hdnode'), Script: require('./script'), scripts: require('./scripts'), Transaction: require('./transaction'), TransactionBuilder: require('./transaction_builder'), - networks: require('./networks'), - Wallet: require('./wallet') + networks: require('./networks') } diff --git a/src/message.js b/src/message.js index 6305a691c..ecb1f1858 100644 --- a/src/message.js +++ b/src/message.js @@ -10,7 +10,7 @@ var ECSignature = require('./ecsignature') var ecurve = require('ecurve') var ecparams = ecurve.getCurveByName('secp256k1') -function magicHash(message, network) { +function magicHash (message, network) { var magicPrefix = new Buffer(network.magicPrefix) var messageBuffer = new Buffer(message) var lengthBuffer = bufferutils.varIntBuffer(messageBuffer.length) @@ -19,7 +19,7 @@ function magicHash(message, network) { return crypto.hash256(buffer) } -function sign(privKey, message, network) { +function sign (privKey, message, network) { network = network || networks.bitcoin var hash = magicHash(message, network) @@ -31,7 +31,7 @@ function sign(privKey, message, network) { } // TODO: network could be implied from address -function verify(address, signature, message, network) { +function verify (address, signature, message, network) { if (!Buffer.isBuffer(signature)) { signature = new Buffer(signature, 'base64') } diff --git a/src/networks.js b/src/networks.js index db5aab6ee..7395aa4b3 100644 --- a/src/networks.js +++ b/src/networks.js @@ -127,16 +127,16 @@ var networks = { } } -function estimateFee(type) { - return function(tx) { +function estimateFee (type) { + return function (tx) { var network = networks[type] var baseFee = network.feePerKb var byteSize = tx.toBuffer().length var fee = baseFee * Math.ceil(byteSize / 1000) - if (network.dustSoftThreshold == undefined) return fee + if (network.dustSoftThreshold === undefined) return fee - tx.outs.forEach(function(e){ + tx.outs.forEach(function (e) { if (e.value < network.dustSoftThreshold) { fee += baseFee } diff --git a/src/opcodes.js b/src/opcodes.js index 974c8d03b..2805dfb9b 100644 --- a/src/opcodes.js +++ b/src/opcodes.js @@ -1,138 +1,138 @@ module.exports = { // push value - OP_FALSE : 0, - OP_0 : 0, - OP_PUSHDATA1 : 76, - OP_PUSHDATA2 : 77, - OP_PUSHDATA4 : 78, - OP_1NEGATE : 79, - OP_RESERVED : 80, - OP_1 : 81, - OP_TRUE : 81, - OP_2 : 82, - OP_3 : 83, - OP_4 : 84, - OP_5 : 85, - OP_6 : 86, - OP_7 : 87, - OP_8 : 88, - OP_9 : 89, - OP_10 : 90, - OP_11 : 91, - OP_12 : 92, - OP_13 : 93, - OP_14 : 94, - OP_15 : 95, - OP_16 : 96, + OP_FALSE: 0, + OP_0: 0, + OP_PUSHDATA1: 76, + OP_PUSHDATA2: 77, + OP_PUSHDATA4: 78, + OP_1NEGATE: 79, + OP_RESERVED: 80, + OP_1: 81, + OP_TRUE: 81, + OP_2: 82, + OP_3: 83, + OP_4: 84, + OP_5: 85, + OP_6: 86, + OP_7: 87, + OP_8: 88, + OP_9: 89, + OP_10: 90, + OP_11: 91, + OP_12: 92, + OP_13: 93, + OP_14: 94, + OP_15: 95, + OP_16: 96, // control - OP_NOP : 97, - OP_VER : 98, - OP_IF : 99, - OP_NOTIF : 100, - OP_VERIF : 101, - OP_VERNOTIF : 102, - OP_ELSE : 103, - OP_ENDIF : 104, - OP_VERIFY : 105, - OP_RETURN : 106, + OP_NOP: 97, + OP_VER: 98, + OP_IF: 99, + OP_NOTIF: 100, + OP_VERIF: 101, + OP_VERNOTIF: 102, + OP_ELSE: 103, + OP_ENDIF: 104, + OP_VERIFY: 105, + OP_RETURN: 106, // stack ops - OP_TOALTSTACK : 107, - OP_FROMALTSTACK : 108, - OP_2DROP : 109, - OP_2DUP : 110, - OP_3DUP : 111, - OP_2OVER : 112, - OP_2ROT : 113, - OP_2SWAP : 114, - OP_IFDUP : 115, - OP_DEPTH : 116, - OP_DROP : 117, - OP_DUP : 118, - OP_NIP : 119, - OP_OVER : 120, - OP_PICK : 121, - OP_ROLL : 122, - OP_ROT : 123, - OP_SWAP : 124, - OP_TUCK : 125, + OP_TOALTSTACK: 107, + OP_FROMALTSTACK: 108, + OP_2DROP: 109, + OP_2DUP: 110, + OP_3DUP: 111, + OP_2OVER: 112, + OP_2ROT: 113, + OP_2SWAP: 114, + OP_IFDUP: 115, + OP_DEPTH: 116, + OP_DROP: 117, + OP_DUP: 118, + OP_NIP: 119, + OP_OVER: 120, + OP_PICK: 121, + OP_ROLL: 122, + OP_ROT: 123, + OP_SWAP: 124, + OP_TUCK: 125, // splice ops - OP_CAT : 126, - OP_SUBSTR : 127, - OP_LEFT : 128, - OP_RIGHT : 129, - OP_SIZE : 130, + OP_CAT: 126, + OP_SUBSTR: 127, + OP_LEFT: 128, + OP_RIGHT: 129, + OP_SIZE: 130, // bit logic - OP_INVERT : 131, - OP_AND : 132, - OP_OR : 133, - OP_XOR : 134, - OP_EQUAL : 135, - OP_EQUALVERIFY : 136, - OP_RESERVED1 : 137, - OP_RESERVED2 : 138, + OP_INVERT: 131, + OP_AND: 132, + OP_OR: 133, + OP_XOR: 134, + OP_EQUAL: 135, + OP_EQUALVERIFY: 136, + OP_RESERVED1: 137, + OP_RESERVED2: 138, // numeric - OP_1ADD : 139, - OP_1SUB : 140, - OP_2MUL : 141, - OP_2DIV : 142, - OP_NEGATE : 143, - OP_ABS : 144, - OP_NOT : 145, - OP_0NOTEQUAL : 146, + OP_1ADD: 139, + OP_1SUB: 140, + OP_2MUL: 141, + OP_2DIV: 142, + OP_NEGATE: 143, + OP_ABS: 144, + OP_NOT: 145, + OP_0NOTEQUAL: 146, - OP_ADD : 147, - OP_SUB : 148, - OP_MUL : 149, - OP_DIV : 150, - OP_MOD : 151, - OP_LSHIFT : 152, - OP_RSHIFT : 153, + OP_ADD: 147, + OP_SUB: 148, + OP_MUL: 149, + OP_DIV: 150, + OP_MOD: 151, + OP_LSHIFT: 152, + OP_RSHIFT: 153, - OP_BOOLAND : 154, - OP_BOOLOR : 155, - OP_NUMEQUAL : 156, - OP_NUMEQUALVERIFY : 157, - OP_NUMNOTEQUAL : 158, - OP_LESSTHAN : 159, - OP_GREATERTHAN : 160, - OP_LESSTHANOREQUAL : 161, - OP_GREATERTHANOREQUAL : 162, - OP_MIN : 163, - OP_MAX : 164, + OP_BOOLAND: 154, + OP_BOOLOR: 155, + OP_NUMEQUAL: 156, + OP_NUMEQUALVERIFY: 157, + OP_NUMNOTEQUAL: 158, + OP_LESSTHAN: 159, + OP_GREATERTHAN: 160, + OP_LESSTHANOREQUAL: 161, + OP_GREATERTHANOREQUAL: 162, + OP_MIN: 163, + OP_MAX: 164, - OP_WITHIN : 165, + OP_WITHIN: 165, // crypto - OP_RIPEMD160 : 166, - OP_SHA1 : 167, - OP_SHA256 : 168, - OP_HASH160 : 169, - OP_HASH256 : 170, - OP_CODESEPARATOR : 171, - OP_CHECKSIG : 172, - OP_CHECKSIGVERIFY : 173, - OP_CHECKMULTISIG : 174, - OP_CHECKMULTISIGVERIFY : 175, + OP_RIPEMD160: 166, + OP_SHA1: 167, + OP_SHA256: 168, + OP_HASH160: 169, + OP_HASH256: 170, + OP_CODESEPARATOR: 171, + OP_CHECKSIG: 172, + OP_CHECKSIGVERIFY: 173, + OP_CHECKMULTISIG: 174, + OP_CHECKMULTISIGVERIFY: 175, // expansion - OP_NOP1 : 176, - OP_NOP2 : 177, - OP_NOP3 : 178, - OP_NOP4 : 179, - OP_NOP5 : 180, - OP_NOP6 : 181, - OP_NOP7 : 182, - OP_NOP8 : 183, - OP_NOP9 : 184, - OP_NOP10 : 185, + OP_NOP1: 176, + OP_NOP2: 177, + OP_NOP3: 178, + OP_NOP4: 179, + OP_NOP5: 180, + OP_NOP6: 181, + OP_NOP7: 182, + OP_NOP8: 183, + OP_NOP9: 184, + OP_NOP10: 185, // template matching params - OP_PUBKEYHASH : 253, - OP_PUBKEY : 254, - OP_INVALIDOPCODE : 255 + OP_PUBKEYHASH: 253, + OP_PUBKEY: 254, + OP_INVALIDOPCODE: 255 } diff --git a/src/script.js b/src/script.js index 812970e1a..b35bfdf14 100644 --- a/src/script.js +++ b/src/script.js @@ -4,7 +4,7 @@ var crypto = require('./crypto') var typeForce = require('typeforce') var opcodes = require('./opcodes') -function Script(buffer, chunks) { +function Script (buffer, chunks) { typeForce('Buffer', buffer) typeForce('Array', chunks) @@ -12,13 +12,14 @@ function Script(buffer, chunks) { this.chunks = chunks } -Script.fromASM = function(asm) { +Script.fromASM = function (asm) { var strChunks = asm.split(' ') - - var chunks = strChunks.map(function(strChunk) { + var chunks = strChunks.map(function (strChunk) { + // opcode if (strChunk in opcodes) { return opcodes[strChunk] + // data chunk } else { return new Buffer(strChunk, 'hex') } @@ -27,13 +28,14 @@ Script.fromASM = function(asm) { return Script.fromChunks(chunks) } -Script.fromBuffer = function(buffer) { +Script.fromBuffer = function (buffer) { var chunks = [] var i = 0 while (i < buffer.length) { var opcode = buffer.readUInt8(i) + // data chunk if ((opcode > opcodes.OP_0) && (opcode <= opcodes.OP_PUSHDATA4)) { var d = bufferutils.readPushDataInt(buffer, i) i += d.size @@ -43,6 +45,7 @@ Script.fromBuffer = function(buffer) { chunks.push(data) + // opcode } else { chunks.push(opcode) @@ -53,27 +56,31 @@ Script.fromBuffer = function(buffer) { return new Script(buffer, chunks) } -Script.fromChunks = function(chunks) { +Script.fromChunks = function (chunks) { typeForce('Array', chunks) - var bufferSize = chunks.reduce(function(accum, chunk) { + var bufferSize = chunks.reduce(function (accum, chunk) { + // data chunk if (Buffer.isBuffer(chunk)) { return accum + bufferutils.pushDataSize(chunk.length) + chunk.length } + // opcode return accum + 1 }, 0.0) var buffer = new Buffer(bufferSize) var offset = 0 - chunks.forEach(function(chunk) { + chunks.forEach(function (chunk) { + // data chunk if (Buffer.isBuffer(chunk)) { offset += bufferutils.writePushDataInt(buffer, chunk.length, offset) chunk.copy(buffer, offset) offset += chunk.length + // opcode } else { buffer.writeUInt8(chunk, offset) offset += 1 @@ -84,19 +91,19 @@ Script.fromChunks = function(chunks) { return new Script(buffer, chunks) } -Script.fromHex = function(hex) { +Script.fromHex = function (hex) { return Script.fromBuffer(new Buffer(hex, 'hex')) } Script.EMPTY = Script.fromChunks([]) -Script.prototype.getHash = function() { +Script.prototype.getHash = function () { return crypto.hash160(this.buffer) } // FIXME: doesn't work for data chunks, maybe time to use buffertools.compare... -Script.prototype.without = function(needle) { - return Script.fromChunks(this.chunks.filter(function(op) { +Script.prototype.without = function (needle) { + return Script.fromChunks(this.chunks.filter(function (op) { return op !== needle })) } @@ -107,22 +114,24 @@ for (var op in opcodes) { reverseOps[code] = op } -Script.prototype.toASM = function() { - return this.chunks.map(function(chunk) { +Script.prototype.toASM = function () { + return this.chunks.map(function (chunk) { + // data chunk if (Buffer.isBuffer(chunk)) { return chunk.toString('hex') + // opcode } else { return reverseOps[chunk] } }).join(' ') } -Script.prototype.toBuffer = function() { +Script.prototype.toBuffer = function () { return this.buffer } -Script.prototype.toHex = function() { +Script.prototype.toHex = function () { return this.toBuffer().toString('hex') } diff --git a/src/scripts.js b/src/scripts.js index 4ad20a9fd..387618429 100644 --- a/src/scripts.js +++ b/src/scripts.js @@ -8,13 +8,14 @@ var curve = ecurve.getCurveByName('secp256k1') var ECSignature = require('./ecsignature') var Script = require('./script') -function isCanonicalPubKey(buffer) { +function isCanonicalPubKey (buffer) { if (!Buffer.isBuffer(buffer)) return false try { ecurve.Point.decodeFrom(curve, buffer) } catch (e) { - if (!(e.message.match(/Invalid sequence (length|tag)/))) throw e + if (!(e.message.match(/Invalid sequence (length|tag)/))) + throw e return false } @@ -22,13 +23,15 @@ function isCanonicalPubKey(buffer) { return true } -function isCanonicalSignature(buffer) { +function isCanonicalSignature (buffer) { if (!Buffer.isBuffer(buffer)) return false try { ECSignature.parseScriptSignature(buffer) - } catch(e) { - if (!(e.message.match(/Not a DER sequence|Invalid sequence length|Expected a DER integer|R length is zero|S length is zero|R value excessively padded|S value excessively padded|R value is negative|S value is negative|Invalid hashType/))) throw e + } catch (e) { + if (!(e.message.match(/Not a DER sequence|Invalid sequence length|Expected a DER integer|R length is zero|S length is zero|R value excessively padded|S value excessively padded|R value is negative|S value is negative|Invalid hashType/))) { + throw e + } return false } @@ -36,13 +39,13 @@ function isCanonicalSignature(buffer) { return true } -function isPubKeyHashInput(script) { +function isPubKeyHashInput (script) { return script.chunks.length === 2 && isCanonicalSignature(script.chunks[0]) && isCanonicalPubKey(script.chunks[1]) } -function isPubKeyHashOutput(script) { +function isPubKeyHashOutput (script) { return script.chunks.length === 5 && script.chunks[0] === ops.OP_DUP && script.chunks[1] === ops.OP_HASH160 && @@ -52,18 +55,18 @@ function isPubKeyHashOutput(script) { script.chunks[4] === ops.OP_CHECKSIG } -function isPubKeyInput(script) { +function isPubKeyInput (script) { return script.chunks.length === 1 && isCanonicalSignature(script.chunks[0]) } -function isPubKeyOutput(script) { +function isPubKeyOutput (script) { return script.chunks.length === 2 && isCanonicalPubKey(script.chunks[0]) && script.chunks[1] === ops.OP_CHECKSIG } -function isScriptHashInput(script, allowIncomplete) { +function isScriptHashInput (script, allowIncomplete) { if (script.chunks.length < 2) return false var lastChunk = script.chunks[script.chunks.length - 1] @@ -81,7 +84,7 @@ function isScriptHashInput(script, allowIncomplete) { return classifyInput(scriptSig, allowIncomplete) === classifyOutput(scriptPubKey) } -function isScriptHashOutput(script) { +function isScriptHashOutput (script) { return script.chunks.length === 3 && script.chunks[0] === ops.OP_HASH160 && Buffer.isBuffer(script.chunks[1]) && @@ -91,12 +94,12 @@ function isScriptHashOutput(script) { // allowIncomplete is to account for combining signatures // See https://github.com/bitcoin/bitcoin/blob/f425050546644a36b0b8e0eb2f6934a3e0f6f80f/src/script/sign.cpp#L195-L197 -function isMultisigInput(script, allowIncomplete) { +function isMultisigInput (script, allowIncomplete) { if (script.chunks.length < 2) return false if (script.chunks[0] !== ops.OP_0) return false if (allowIncomplete) { - return script.chunks.slice(1).every(function(chunk) { + return script.chunks.slice(1).every(function (chunk) { return chunk === ops.OP_0 || isCanonicalSignature(chunk) }) } @@ -104,7 +107,7 @@ function isMultisigInput(script, allowIncomplete) { return script.chunks.slice(1).every(isCanonicalSignature) } -function isMultisigOutput(script) { +function isMultisigOutput (script) { if (script.chunks.length < 4) return false if (script.chunks[script.chunks.length - 1] !== ops.OP_CHECKMULTISIG) return false @@ -128,11 +131,11 @@ function isMultisigOutput(script) { return pubKeys.every(isCanonicalPubKey) } -function isNullDataOutput(script) { +function isNullDataOutput (script) { return script.chunks[0] === ops.OP_RETURN } -function classifyOutput(script) { +function classifyOutput (script) { typeForce('Script', script) if (isPubKeyHashOutput(script)) { @@ -150,7 +153,7 @@ function classifyOutput(script) { return 'nonstandard' } -function classifyInput(script, allowIncomplete) { +function classifyInput (script, allowIncomplete) { typeForce('Script', script) if (isPubKeyHashInput(script)) { @@ -168,7 +171,7 @@ function classifyInput(script, allowIncomplete) { // Standard Script Templates // {pubKey} OP_CHECKSIG -function pubKeyOutput(pubKey) { +function pubKeyOutput (pubKey) { return Script.fromChunks([ pubKey.toBuffer(), ops.OP_CHECKSIG @@ -176,7 +179,7 @@ function pubKeyOutput(pubKey) { } // OP_DUP OP_HASH160 {pubKeyHash} OP_EQUALVERIFY OP_CHECKSIG -function pubKeyHashOutput(hash) { +function pubKeyHashOutput (hash) { typeForce('Buffer', hash) return Script.fromChunks([ @@ -189,7 +192,7 @@ function pubKeyHashOutput(hash) { } // OP_HASH160 {scriptHash} OP_EQUAL -function scriptHashOutput(hash) { +function scriptHashOutput (hash) { typeForce('Buffer', hash) return Script.fromChunks([ @@ -200,12 +203,12 @@ function scriptHashOutput(hash) { } // m [pubKeys ...] n OP_CHECKMULTISIG -function multisigOutput(m, pubKeys) { +function multisigOutput (m, pubKeys) { typeForce(['ECPubKey'], pubKeys) assert(pubKeys.length >= m, 'Not enough pubKeys provided') - var pubKeyBuffers = pubKeys.map(function(pubKey) { + var pubKeyBuffers = pubKeys.map(function (pubKey) { return pubKey.toBuffer() }) var n = pubKeys.length @@ -219,21 +222,21 @@ function multisigOutput(m, pubKeys) { } // {signature} -function pubKeyInput(signature) { +function pubKeyInput (signature) { typeForce('Buffer', signature) return Script.fromChunks([signature]) } // {signature} {pubKey} -function pubKeyHashInput(signature, pubKey) { +function pubKeyHashInput (signature, pubKey) { typeForce('Buffer', signature) return Script.fromChunks([signature, pubKey.toBuffer()]) } // {serialized scriptPubKey script} -function scriptHashInput(scriptSig, scriptPubKey) { +function scriptHashInput (scriptSig, scriptPubKey) { return Script.fromChunks([].concat( scriptSig.chunks, scriptPubKey.toBuffer() @@ -241,7 +244,7 @@ function scriptHashInput(scriptSig, scriptPubKey) { } // OP_0 [signatures ...] -function multisigInput(signatures, scriptPubKey) { +function multisigInput (signatures, scriptPubKey) { if (scriptPubKey) { assert(isMultisigOutput(scriptPubKey)) @@ -251,7 +254,7 @@ function multisigInput(signatures, scriptPubKey) { var n = nOp - (ops.OP_1 - 1) var count = 0 - signatures.forEach(function(signature) { + signatures.forEach(function (signature) { count += (signature !== ops.OP_0) }) @@ -262,7 +265,7 @@ function multisigInput(signatures, scriptPubKey) { return Script.fromChunks([].concat(ops.OP_0, signatures)) } -function nullDataOutput(data) { +function nullDataOutput (data) { return Script.fromChunks([ops.OP_RETURN, data]) } @@ -288,9 +291,5 @@ module.exports = { pubKeyHashInput: pubKeyHashInput, scriptHashInput: scriptHashInput, multisigInput: multisigInput, - dataOutput: function(data) { - console.warn('dataOutput is deprecated, use nullDataOutput by 2.0.0') - return nullDataOutput(data) - }, nullDataOutput: nullDataOutput } diff --git a/src/transaction.js b/src/transaction.js index ad6179d7a..fa1b18a7d 100644 --- a/src/transaction.js +++ b/src/transaction.js @@ -3,13 +3,10 @@ var bufferutils = require('./bufferutils') var crypto = require('./crypto') var typeForce = require('typeforce') var opcodes = require('./opcodes') -var scripts = require('./scripts') -var Address = require('./address') -var ECSignature = require('./ecsignature') var Script = require('./script') -function Transaction() { +function Transaction () { this.version = 1 this.locktime = 0 this.ins = [] @@ -22,36 +19,36 @@ Transaction.SIGHASH_NONE = 0x02 Transaction.SIGHASH_SINGLE = 0x03 Transaction.SIGHASH_ANYONECANPAY = 0x80 -Transaction.fromBuffer = function(buffer, __disableAssert) { +Transaction.fromBuffer = function (buffer, __disableAssert) { var offset = 0 - function readSlice(n) { + function readSlice (n) { offset += n return buffer.slice(offset - n, offset) } - function readUInt32() { + function readUInt32 () { var i = buffer.readUInt32LE(offset) offset += 4 return i } - function readUInt64() { + function readUInt64 () { var i = bufferutils.readUInt64LE(buffer, offset) offset += 8 return i } - function readVarInt() { + function readVarInt () { var vi = bufferutils.readVarInt(buffer, offset) offset += vi.size return vi.number } - function readScript() { + function readScript () { return Script.fromBuffer(readSlice(readVarInt())) } - function readGenerationScript() { + function readGenerationScript () { return new Script(readSlice(readVarInt()), []) } @@ -69,7 +66,6 @@ Transaction.fromBuffer = function(buffer, __disableAssert) { script: readGenerationScript(), sequence: readUInt32() }) - } else { tx.ins.push({ hash: hash, @@ -97,42 +93,23 @@ Transaction.fromBuffer = function(buffer, __disableAssert) { return tx } -Transaction.fromHex = function(hex) { +Transaction.fromHex = function (hex) { return Transaction.fromBuffer(new Buffer(hex, 'hex')) } -Transaction.isCoinbaseHash = function(buffer) { - return Array.prototype.every.call(buffer, function(x) { +Transaction.isCoinbaseHash = function (buffer) { + return Array.prototype.every.call(buffer, function (x) { return x === 0 }) } -/** - * Create a new txIn. - * - * Can be called with any of: - * - * - A transaction and an index - * - A transaction hash and an index - * - * Note that this method does not sign the created input. - */ -Transaction.prototype.addInput = function(hash, index, sequence, script) { +Transaction.prototype.addInput = function (hash, index, sequence, script) { if (sequence === undefined || sequence === null) { sequence = Transaction.DEFAULT_SEQUENCE } script = script || Script.EMPTY - if (typeof hash === 'string') { - // TxId hex is big-endian, we need little-endian - hash = bufferutils.reverse(new Buffer(hash, 'hex')) - - } else if (hash instanceof Transaction) { - hash = hash.getHash() - - } - typeForce('Buffer', hash) typeForce('Number', index) typeForce('Number', sequence) @@ -149,26 +126,7 @@ Transaction.prototype.addInput = function(hash, index, sequence, script) { }) - 1) } -/** - * Create a new txOut. - * - * Can be called with: - * - * - A base58 address string and a value - * - An Address object and a value - * - A scriptPubKey Script and a value - */ -Transaction.prototype.addOutput = function(scriptPubKey, value) { - // Attempt to get a valid address if it's a base58 address string - if (typeof scriptPubKey === 'string') { - scriptPubKey = Address.fromBase58Check(scriptPubKey) - } - - // Attempt to get a valid script if it's an Address object - if (scriptPubKey instanceof Address) { - scriptPubKey = scriptPubKey.toOutputScript() - } - +Transaction.prototype.addOutput = function (scriptPubKey, value) { typeForce('Script', scriptPubKey) typeForce('Number', value) @@ -184,7 +142,7 @@ Transaction.prototype.clone = function () { newTx.version = this.version newTx.locktime = this.locktime - newTx.ins = this.ins.map(function(txIn) { + newTx.ins = this.ins.map(function (txIn) { return { hash: txIn.hash, index: txIn.index, @@ -193,7 +151,7 @@ Transaction.prototype.clone = function () { } }) - newTx.outs = this.outs.map(function(txOut) { + newTx.outs = this.outs.map(function (txOut) { return { script: txOut.script, value: txOut.value @@ -206,22 +164,12 @@ Transaction.prototype.clone = function () { /** * Hash transaction for signing a specific input. * - * Bitcoin uses a different hash for each signed transaction input. This - * method copies the transaction, makes the necessary changes based on the - * hashType, serializes and finally hashes the result. This hash can then be - * used to sign the transaction input in question. + * Bitcoin uses a different hash for each signed transaction input. + * This method copies the transaction, makes the necessary changes based on the + * hashType, and then hashes the result. + * This hash can then be used to sign the provided transaction input. */ -Transaction.prototype.hashForSignature = function(inIndex, prevOutScript, hashType) { - // FIXME: remove in 2.x.y - if (arguments[0] instanceof Script) { - console.warn('hashForSignature(prevOutScript, inIndex, ...) has been deprecated. Use hashForSignature(inIndex, prevOutScript, ...)') - - // swap the arguments (must be stored in tmp, arguments is special) - var tmp = arguments[0] - inIndex = arguments[1] - prevOutScript = tmp - } - +Transaction.prototype.hashForSignature = function (inIndex, prevOutScript, hashType) { typeForce('Number', inIndex) typeForce('Script', prevOutScript) typeForce('Number', hashType) @@ -233,18 +181,17 @@ Transaction.prototype.hashForSignature = function(inIndex, prevOutScript, hashTy var hashScript = prevOutScript.without(opcodes.OP_CODESEPARATOR) // Blank out other inputs' signatures - txTmp.ins.forEach(function(txIn) { + txTmp.ins.forEach(function (txIn) { txIn.script = Script.EMPTY }) txTmp.ins[inIndex].script = hashScript var hashTypeModifier = hashType & 0x1f + if (hashTypeModifier === Transaction.SIGHASH_NONE) { assert(false, 'SIGHASH_NONE not yet supported') - } else if (hashTypeModifier === Transaction.SIGHASH_SINGLE) { assert(false, 'SIGHASH_SINGLE not yet supported') - } if (hashType & Transaction.SIGHASH_ANYONECANPAY) { @@ -268,7 +215,7 @@ Transaction.prototype.getId = function () { } Transaction.prototype.toBuffer = function () { - function scriptSize(script) { + function scriptSize (script) { var length = script.buffer.length return bufferutils.varIntSize(length) + length @@ -278,27 +225,27 @@ Transaction.prototype.toBuffer = function () { 8 + bufferutils.varIntSize(this.ins.length) + bufferutils.varIntSize(this.outs.length) + - this.ins.reduce(function(sum, input) { return sum + 40 + scriptSize(input.script) }, 0) + - this.outs.reduce(function(sum, output) { return sum + 8 + scriptSize(output.script) }, 0) + this.ins.reduce(function (sum, input) { return sum + 40 + scriptSize(input.script) }, 0) + + this.outs.reduce(function (sum, output) { return sum + 8 + scriptSize(output.script) }, 0) ) var offset = 0 - function writeSlice(slice) { + function writeSlice (slice) { slice.copy(buffer, offset) offset += slice.length } - function writeUInt32(i) { + function writeUInt32 (i) { buffer.writeUInt32LE(i, offset) offset += 4 } - function writeUInt64(i) { + function writeUInt64 (i) { bufferutils.writeUInt64LE(buffer, i, offset) offset += 8 } - function writeVarInt(i) { + function writeVarInt (i) { var n = bufferutils.writeVarInt(buffer, i, offset) offset += n } @@ -306,7 +253,7 @@ Transaction.prototype.toBuffer = function () { writeUInt32(this.version) writeVarInt(this.ins.length) - this.ins.forEach(function(txIn) { + this.ins.forEach(function (txIn) { writeSlice(txIn.hash) writeUInt32(txIn.index) writeVarInt(txIn.script.buffer.length) @@ -315,7 +262,7 @@ Transaction.prototype.toBuffer = function () { }) writeVarInt(this.outs.length) - this.outs.forEach(function(txOut) { + this.outs.forEach(function (txOut) { writeUInt64(txOut.value) writeVarInt(txOut.script.buffer.length) writeSlice(txOut.script.buffer) @@ -326,48 +273,15 @@ Transaction.prototype.toBuffer = function () { return buffer } -Transaction.prototype.toHex = function() { +Transaction.prototype.toHex = function () { return this.toBuffer().toString('hex') } -Transaction.prototype.setInputScript = function(index, script) { +Transaction.prototype.setInputScript = function (index, script) { typeForce('Number', index) typeForce('Script', script) this.ins[index].script = script } -// FIXME: remove in 2.x.y -Transaction.prototype.sign = function(index, privKey, hashType) { - console.warn("Transaction.prototype.sign is deprecated. Use TransactionBuilder instead.") - - var prevOutScript = privKey.pub.getAddress().toOutputScript() - var signature = this.signInput(index, prevOutScript, privKey, hashType) - - var scriptSig = scripts.pubKeyHashInput(signature, privKey.pub) - this.setInputScript(index, scriptSig) -} - -// FIXME: remove in 2.x.y -Transaction.prototype.signInput = function(index, prevOutScript, privKey, hashType) { - console.warn("Transaction.prototype.signInput is deprecated. Use TransactionBuilder instead.") - - hashType = hashType || Transaction.SIGHASH_ALL - - var hash = this.hashForSignature(index, prevOutScript, hashType) - var signature = privKey.sign(hash) - - return signature.toScriptSignature(hashType) -} - -// FIXME: remove in 2.x.y -Transaction.prototype.validateInput = function(index, prevOutScript, pubKey, buffer) { - console.warn("Transaction.prototype.validateInput is deprecated. Use TransactionBuilder instead.") - - var parsed = ECSignature.parseScriptSignature(buffer) - var hash = this.hashForSignature(index, prevOutScript, parsed.hashType) - - return pubKey.verify(hash, parsed.signature) -} - module.exports = Transaction diff --git a/src/transaction_builder.js b/src/transaction_builder.js index a45b06b88..924f177e5 100644 --- a/src/transaction_builder.js +++ b/src/transaction_builder.js @@ -2,12 +2,13 @@ var assert = require('assert') var ops = require('./opcodes') var scripts = require('./scripts') +var Address = require('./address') var ECPubKey = require('./ecpubkey') var ECSignature = require('./ecsignature') var Script = require('./script') var Transaction = require('./transaction') -function extractInput(txIn) { +function extractInput (txIn) { var redeemScript var scriptSig = txIn.script var prevOutScript @@ -21,7 +22,6 @@ function extractInput(txIn) { scriptSig = Script.fromChunks(scriptSig.chunks.slice(0, -1)) scriptType = scripts.classifyInput(scriptSig, true) - } else { scriptType = prevOutType } @@ -53,7 +53,7 @@ function extractInput(txIn) { } case 'multisig': { - signatures = scriptSig.chunks.slice(1).map(function(chunk) { + signatures = scriptSig.chunks.slice(1).map(function (chunk) { if (chunk === ops.OP_0) return chunk var parsed = ECSignature.parseScriptSignature(chunk) @@ -81,7 +81,7 @@ function extractInput(txIn) { } } -function TransactionBuilder() { +function TransactionBuilder () { this.prevTxMap = {} this.prevOutScripts = {} this.prevOutTypes = {} @@ -90,7 +90,7 @@ function TransactionBuilder() { this.tx = new Transaction() } -TransactionBuilder.fromTransaction = function(transaction) { +TransactionBuilder.fromTransaction = function (transaction) { var txb = new TransactionBuilder() // Copy other transaction fields @@ -98,17 +98,17 @@ TransactionBuilder.fromTransaction = function(transaction) { txb.tx.locktime = transaction.locktime // Extract/add inputs - transaction.ins.forEach(function(txIn) { + transaction.ins.forEach(function (txIn) { txb.addInput(txIn.hash, txIn.index, txIn.sequence) }) // Extract/add outputs - transaction.outs.forEach(function(txOut) { + transaction.outs.forEach(function (txOut) { txb.addOutput(txOut.script, txOut.value) }) // Extract/add signatures - txb.inputs = transaction.ins.map(function(txIn) { + txb.inputs = transaction.ins.map(function (txIn) { // TODO: remove me after testcase added assert(!Transaction.isCoinbaseHash(txIn.hash), 'coinbase inputs not supported') @@ -121,22 +121,17 @@ TransactionBuilder.fromTransaction = function(transaction) { return txb } -TransactionBuilder.prototype.addInput = function(prevTx, index, sequence, prevOutScript) { - var prevOutHash - - if (typeof prevTx === 'string') { - prevOutHash = new Buffer(prevTx, 'hex') - - // TxId hex is big-endian, we want little-endian hash - Array.prototype.reverse.call(prevOutHash) - - } else if (prevTx instanceof Transaction) { - prevOutHash = prevTx.getHash() - prevOutScript = prevTx.outs[index].script - - } else { - prevOutHash = prevTx - +TransactionBuilder.prototype.addInput = function (txHash, vout, sequence, prevOutScript) { + // is it a txId? + if (typeof txHash === 'string') { + // a txId is big-endian hex, we want a little-endian Buffer + txHash = new Buffer(txHash, 'hex') + Array.prototype.reverse.call(txHash) + + // is it a Transaction? + } else if (txHash instanceof Transaction) { + prevOutScript = txHash.outs[vout].script + txHash = txHash.getHash() } var input = {} @@ -145,13 +140,15 @@ TransactionBuilder.prototype.addInput = function(prevTx, index, sequence, prevOu // if we can, extract pubKey information switch (prevOutType) { - case 'multisig': + case 'multisig': { input.pubKeys = prevOutScript.chunks.slice(1, -2).map(ECPubKey.fromBuffer) break + } - case 'pubkey': + case 'pubkey': { input.pubKeys = prevOutScript.chunks.slice(0, 1).map(ECPubKey.fromBuffer) break + } } if (prevOutType !== 'scripthash') { @@ -162,38 +159,56 @@ TransactionBuilder.prototype.addInput = function(prevTx, index, sequence, prevOu input.prevOutType = prevOutType } - assert(this.inputs.every(function(input2) { + assert(this.inputs.every(function (input2) { if (input2.hashType === undefined) return true return input2.hashType & Transaction.SIGHASH_ANYONECANPAY }), 'No, this would invalidate signatures') - var prevOut = prevOutHash.toString('hex') + ':' + index + var prevOut = txHash.toString('hex') + ':' + vout assert(!(prevOut in this.prevTxMap), 'Transaction is already an input') - var vin = this.tx.addInput(prevOutHash, index, sequence) + var vin = this.tx.addInput(txHash, vout, sequence) this.inputs[vin] = input this.prevTxMap[prevOut] = vin return vin } -TransactionBuilder.prototype.addOutput = function(scriptPubKey, value) { - assert(this.inputs.every(function(input) { +TransactionBuilder.prototype.addOutput = function (scriptPubKey, value) { + assert(this.inputs.every(function (input) { if (input.hashType === undefined) return true return (input.hashType & 0x1f) === Transaction.SIGHASH_SINGLE }), 'No, this would invalidate signatures') + // Attempt to get a valid address if it's a base58 address string + if (typeof scriptPubKey === 'string') { + scriptPubKey = Address.fromBase58Check(scriptPubKey) + } + + // Attempt to get a valid script if it's an Address object + if (scriptPubKey instanceof Address) { + scriptPubKey = scriptPubKey.toOutputScript() + } + return this.tx.addOutput(scriptPubKey, value) } -TransactionBuilder.prototype.build = function() { return this.__build(false) } -TransactionBuilder.prototype.buildIncomplete = function() { return this.__build(true) } +TransactionBuilder.prototype.build = function () { + return this.__build(false) +} +TransactionBuilder.prototype.buildIncomplete = function () { + return this.__build(true) +} -var canSignTypes = { 'pubkeyhash': true, 'multisig': true, 'pubkey': true } +var canSignTypes = { + 'pubkeyhash': true, + 'multisig': true, + 'pubkey': true +} -TransactionBuilder.prototype.__build = function(allowIncomplete) { +TransactionBuilder.prototype.__build = function (allowIncomplete) { if (!allowIncomplete) { assert(this.tx.ins.length > 0, 'Transaction has no inputs') assert(this.tx.outs.length > 0, 'Transaction has no outputs') @@ -202,7 +217,7 @@ TransactionBuilder.prototype.__build = function(allowIncomplete) { var tx = this.tx.clone() // Create script signatures from signature meta-data - this.inputs.forEach(function(input, index) { + this.inputs.forEach(function (input, index) { var scriptType = input.scriptType var scriptSig @@ -214,14 +229,15 @@ TransactionBuilder.prototype.__build = function(allowIncomplete) { if (input.signatures) { switch (scriptType) { - case 'pubkeyhash': + case 'pubkeyhash': { var pkhSignature = input.signatures[0].toScriptSignature(input.hashType) scriptSig = scripts.pubKeyHashInput(pkhSignature, input.pubKeys[0]) break + } - case 'multisig': + case 'multisig': { // Array.prototype.map is sparse-compatible - var msSignatures = input.signatures.map(function(signature) { + var msSignatures = input.signatures.map(function (signature) { return signature.toScriptSignature(input.hashType) }) @@ -235,11 +251,13 @@ TransactionBuilder.prototype.__build = function(allowIncomplete) { var redeemScript = allowIncomplete ? undefined : input.redeemScript scriptSig = scripts.multisigInput(msSignatures, redeemScript) break + } - case 'pubkey': + case 'pubkey': { var pkSignature = input.signatures[0].toScriptSignature(input.hashType) scriptSig = scripts.pubKeyInput(pkSignature) break + } } } @@ -257,17 +275,17 @@ TransactionBuilder.prototype.__build = function(allowIncomplete) { return tx } -TransactionBuilder.prototype.sign = function(index, privKey, redeemScript, hashType) { +TransactionBuilder.prototype.sign = function (index, privKey, redeemScript, hashType) { assert(index in this.inputs, 'No input at index: ' + index) hashType = hashType || Transaction.SIGHASH_ALL var input = this.inputs[index] var canSign = input.hashType && - input.prevOutScript && - input.prevOutType && - input.pubKeys && - input.scriptType && - input.signatures + input.prevOutScript && + input.prevOutType && + input.pubKeys && + input.scriptType && + input.signatures // are we almost ready to sign? if (canSign) { @@ -280,6 +298,7 @@ TransactionBuilder.prototype.sign = function(index, privKey, redeemScript, hashT // no? prepare } else { + // must be pay-to-scriptHash? if (redeemScript) { // if we have a prevOutScript, enforce scriptHash equality to the redeemScript if (input.prevOutScript) { @@ -294,21 +313,24 @@ TransactionBuilder.prototype.sign = function(index, privKey, redeemScript, hashT var pubKeys = [] switch (scriptType) { - case 'multisig': + case 'multisig': { pubKeys = redeemScript.chunks.slice(1, -2).map(ECPubKey.fromBuffer) break + } - case 'pubkeyhash': + case 'pubkeyhash': { var pkh1 = redeemScript.chunks[2] var pkh2 = privKey.pub.getAddress().hash assert.deepEqual(pkh1, pkh2, 'privateKey cannot sign for this input') pubKeys = [privKey.pub] break + } - case 'pubkey': + case 'pubkey': { pubKeys = redeemScript.chunks.slice(0, 1).map(ECPubKey.fromBuffer) break + } } if (!input.prevOutScript) { @@ -320,10 +342,11 @@ TransactionBuilder.prototype.sign = function(index, privKey, redeemScript, hashT input.redeemScript = redeemScript input.scriptType = scriptType + // cannot be pay-to-scriptHash } else { assert.notEqual(input.prevOutType, 'scripthash', 'PrevOutScript is P2SH, missing redeemScript') - // can we sign this? + // can we otherwise sign this? if (input.scriptType) { assert(input.pubKeys, input.scriptType + ' not supported') @@ -333,7 +356,6 @@ TransactionBuilder.prototype.sign = function(index, privKey, redeemScript, hashT input.prevOutType = 'pubkeyhash' input.pubKeys = [privKey.pub] input.scriptType = input.prevOutType - } } @@ -342,7 +364,7 @@ TransactionBuilder.prototype.sign = function(index, privKey, redeemScript, hashT } // enforce in order signing of public keys - assert(input.pubKeys.some(function(pubKey, i) { + assert(input.pubKeys.some(function (pubKey, i) { if (!privKey.pub.Q.equals(pubKey.Q)) return false assert(!input.signatures[i], 'Signature already exists') diff --git a/src/wallet.js b/src/wallet.js deleted file mode 100644 index 3e3ab7799..000000000 --- a/src/wallet.js +++ /dev/null @@ -1,361 +0,0 @@ -var assert = require('assert') -var bufferutils = require('./bufferutils') -var crypto = require('crypto') -var typeForce = require('typeforce') -var networks = require('./networks') - -var Address = require('./address') -var HDNode = require('./hdnode') -var TransactionBuilder = require('./transaction_builder') -var Script = require('./script') - -function Wallet(seed, network) { - console.warn('Wallet is deprecated and will be removed in 2.0.0, see #296') - - seed = seed || crypto.randomBytes(32) - network = network || networks.bitcoin - - // Stored in a closure to make accidental serialization less likely - var masterKey = HDNode.fromSeedBuffer(seed, network) - - // HD first-level child derivation method should be hardened - // See https://bitcointalk.org/index.php?topic=405179.msg4415254#msg4415254 - var accountZero = masterKey.deriveHardened(0) - var externalAccount = accountZero.derive(0) - var internalAccount = accountZero.derive(1) - - this.addresses = [] - this.changeAddresses = [] - this.network = network - this.unspents = [] - - // FIXME: remove in 2.0.0 - this.unspentMap = {} - - // FIXME: remove in 2.0.0 - var me = this - this.newMasterKey = function(seed) { - console.warn('newMasterKey is deprecated, please make a new Wallet instance instead') - - seed = seed || crypto.randomBytes(32) - masterKey = HDNode.fromSeedBuffer(seed, network) - - accountZero = masterKey.deriveHardened(0) - externalAccount = accountZero.derive(0) - internalAccount = accountZero.derive(1) - - me.addresses = [] - me.changeAddresses = [] - - me.unspents = [] - me.unspentMap = {} - } - - this.getMasterKey = function() { return masterKey } - this.getAccountZero = function() { return accountZero } - this.getExternalAccount = function() { return externalAccount } - this.getInternalAccount = function() { return internalAccount } -} - -Wallet.prototype.createTransaction = function(to, value, options) { - // FIXME: remove in 2.0.0 - if (typeof options !== 'object') { - if (options !== undefined) { - console.warn('Non options object parameters are deprecated, use options object instead') - - options = { - fixedFee: arguments[2], - changeAddress: arguments[3] - } - } - } - - options = options || {} - - assert(value > this.network.dustThreshold, value + ' must be above dust threshold (' + this.network.dustThreshold + ' Satoshis)') - - var changeAddress = options.changeAddress - var fixedFee = options.fixedFee - var minConf = options.minConf === undefined ? 0 : options.minConf // FIXME: change minConf:1 by default in 2.0.0 - - // filter by minConf, then pending and sort by descending value - var unspents = this.unspents.filter(function(unspent) { - return unspent.confirmations >= minConf - }).filter(function(unspent) { - return !unspent.pending - }).sort(function(o1, o2) { - return o2.value - o1.value - }) - - var accum = 0 - var addresses = [] - var subTotal = value - - var txb = new TransactionBuilder() - txb.addOutput(to, value) - - for (var i = 0; i < unspents.length; ++i) { - var unspent = unspents[i] - addresses.push(unspent.address) - - txb.addInput(unspent.txHash, unspent.index) - - var fee = fixedFee === undefined ? estimatePaddedFee(txb.buildIncomplete(), this.network) : fixedFee - - accum += unspent.value - subTotal = value + fee - - if (accum >= subTotal) { - var change = accum - subTotal - - if (change > this.network.dustThreshold) { - txb.addOutput(changeAddress || this.getChangeAddress(), change) - } - - break - } - } - - assert(accum >= subTotal, 'Not enough funds (incl. fee): ' + accum + ' < ' + subTotal) - - return this.signWith(txb, addresses).build() -} - -// FIXME: remove in 2.0.0 -Wallet.prototype.processPendingTx = function(tx){ - this.__processTx(tx, true) -} - -// FIXME: remove in 2.0.0 -Wallet.prototype.processConfirmedTx = function(tx){ - this.__processTx(tx, false) -} - -// FIXME: remove in 2.0.0 -Wallet.prototype.__processTx = function(tx, isPending) { - console.warn('processTransaction is considered harmful, see issue #260 for more information') - - var txId = tx.getId() - var txHash = tx.getHash() - - tx.outs.forEach(function(txOut, i) { - var address - - try { - address = Address.fromOutputScript(txOut.script, this.network).toString() - } catch(e) { - if (!(e.message.match(/has no matching Address/))) throw e - } - - var myAddresses = this.addresses.concat(this.changeAddresses) - if (myAddresses.indexOf(address) > -1) { - var lookup = txId + ':' + i - if (lookup in this.unspentMap) return - - // its unique, add it - var unspent = { - address: address, - confirmations: 0, // no way to determine this without more information - index: i, - txHash: txHash, - txId: txId, - value: txOut.value, - pending: isPending - } - - this.unspentMap[lookup] = unspent - this.unspents.push(unspent) - } - }, this) - - tx.ins.forEach(function(txIn, i) { - // copy and convert to big-endian hex - var txInId = bufferutils.reverse(txIn.hash).toString('hex') - - var lookup = txInId + ':' + txIn.index - if (!(lookup in this.unspentMap)) return - - var unspent = this.unspentMap[lookup] - - if (isPending) { - unspent.pending = true - unspent.spent = true - - } else { - delete this.unspentMap[lookup] - - this.unspents = this.unspents.filter(function(unspent2) { - return unspent !== unspent2 - }) - } - }, this) -} - -Wallet.prototype.generateAddress = function() { - var k = this.addresses.length - var address = this.getExternalAccount().derive(k).getAddress() - - this.addresses.push(address.toString()) - - return this.getReceiveAddress() -} - -Wallet.prototype.generateChangeAddress = function() { - var k = this.changeAddresses.length - var address = this.getInternalAccount().derive(k).getAddress() - - this.changeAddresses.push(address.toString()) - - return this.getChangeAddress() -} - -Wallet.prototype.getAddress = function() { - if (this.addresses.length === 0) { - this.generateAddress() - } - - return this.addresses[this.addresses.length - 1] -} - -Wallet.prototype.getBalance = function(minConf) { - minConf = minConf || 0 - - return this.unspents.filter(function(unspent) { - return unspent.confirmations >= minConf - - // FIXME: remove spent filter in 2.0.0 - }).filter(function(unspent) { - return !unspent.spent - }).reduce(function(accum, unspent) { - return accum + unspent.value - }, 0) -} - -Wallet.prototype.getChangeAddress = function() { - if (this.changeAddresses.length === 0) { - this.generateChangeAddress() - } - - return this.changeAddresses[this.changeAddresses.length - 1] -} - -Wallet.prototype.getInternalPrivateKey = function(index) { - return this.getInternalAccount().derive(index).privKey -} - -Wallet.prototype.getPrivateKey = function(index) { - return this.getExternalAccount().derive(index).privKey -} - -Wallet.prototype.getPrivateKeyForAddress = function(address) { - var index - - if ((index = this.addresses.indexOf(address)) > -1) { - return this.getPrivateKey(index) - } - - if ((index = this.changeAddresses.indexOf(address)) > -1) { - return this.getInternalPrivateKey(index) - } - - assert(false, 'Unknown address. Make sure the address is from the keychain and has been generated') -} - -Wallet.prototype.getUnspentOutputs = function(minConf) { - minConf = minConf || 0 - - return this.unspents.filter(function(unspent) { - return unspent.confirmations >= minConf - - // FIXME: remove spent filter in 2.0.0 - }).filter(function(unspent) { - return !unspent.spent - }).map(function(unspent) { - return { - address: unspent.address, - confirmations: unspent.confirmations, - index: unspent.index, - txId: unspent.txId, - value: unspent.value, - - // FIXME: remove in 2.0.0 - hash: unspent.txId, - pending: unspent.pending - } - }) -} - -Wallet.prototype.setUnspentOutputs = function(unspents) { - this.unspentMap = {} - this.unspents = unspents.map(function(unspent) { - // FIXME: remove unspent.hash in 2.0.0 - var txId = unspent.txId || unspent.hash - var index = unspent.index - - // FIXME: remove in 2.0.0 - if (unspent.hash !== undefined) { - console.warn('unspent.hash is deprecated, use unspent.txId instead') - } - - // FIXME: remove in 2.0.0 - if (index === undefined) { - console.warn('unspent.outputIndex is deprecated, use unspent.index instead') - index = unspent.outputIndex - } - - typeForce('String', txId) - typeForce('Number', index) - typeForce('Number', unspent.value) - - assert.equal(txId.length, 64, 'Expected valid txId, got ' + txId) - assert.doesNotThrow(function() { Address.fromBase58Check(unspent.address) }, 'Expected Base58 Address, got ' + unspent.address) - assert(isFinite(index), 'Expected finite index, got ' + index) - - // FIXME: remove branch in 2.0.0 - if (unspent.confirmations !== undefined) { - typeForce('Number', unspent.confirmations) - } - - var txHash = bufferutils.reverse(new Buffer(txId, 'hex')) - - unspent = { - address: unspent.address, - confirmations: unspent.confirmations || 0, - index: index, - txHash: txHash, - txId: txId, - value: unspent.value, - - // FIXME: remove in 2.0.0 - pending: unspent.pending || false - } - - // FIXME: remove in 2.0.0 - this.unspentMap[txId + ':' + index] = unspent - - return unspent - }, this) -} - -Wallet.prototype.signWith = function(tx, addresses) { - addresses.forEach(function(address, i) { - var privKey = this.getPrivateKeyForAddress(address) - - tx.sign(i, privKey) - }, this) - - return tx -} - -function estimatePaddedFee(tx, network) { - var tmpTx = tx.clone() - tmpTx.addOutput(Script.EMPTY, network.dustSoftThreshold || 0) - - return network.estimateFee(tmpTx) -} - -// FIXME: 1.0.0 shims, remove in 2.0.0 -Wallet.prototype.getReceiveAddress = Wallet.prototype.getAddress -Wallet.prototype.createTx = Wallet.prototype.createTransaction - -module.exports = Wallet diff --git a/test/address.js b/test/address.js index 0e29f0d93..82230cae7 100644 --- a/test/address.js +++ b/test/address.js @@ -1,3 +1,5 @@ +/* global describe, it */ + var assert = require('assert') var networks = require('../src/networks') @@ -6,10 +8,10 @@ var Script = require('../src/script') var fixtures = require('./fixtures/address.json') -describe('Address', function() { - describe('Constructor', function() { - it('does not mutate the input', function() { - fixtures.valid.forEach(function(f) { +describe('Address', function () { + describe('Constructor', function () { + it('does not mutate the input', function () { + fixtures.valid.forEach(function (f) { var hash = new Buffer(f.hash, 'hex') var addr = new Address(hash, f.version) @@ -19,9 +21,9 @@ describe('Address', function() { }) }) - describe('fromBase58Check', function() { - fixtures.valid.forEach(function(f) { - it('imports ' + f.script + ' (' + f.network + ') correctly', function() { + describe('fromBase58Check', function () { + fixtures.valid.forEach(function (f) { + it('imports ' + f.script + ' (' + f.network + ') correctly', function () { var addr = Address.fromBase58Check(f.base58check) assert.equal(addr.version, f.version) @@ -29,18 +31,18 @@ describe('Address', function() { }) }) - fixtures.invalid.fromBase58Check.forEach(function(f) { - it('throws on ' + f.description, function() { - assert.throws(function() { + fixtures.invalid.fromBase58Check.forEach(function (f) { + it('throws on ' + f.description, function () { + assert.throws(function () { Address.fromBase58Check(f.base58check) }, new RegExp(f.exception)) }) }) }) - describe('fromOutputScript', function() { - fixtures.valid.forEach(function(f) { - it('imports ' + f.script + ' (' + f.network + ') correctly', function() { + describe('fromOutputScript', function () { + fixtures.valid.forEach(function (f) { + it('imports ' + f.script + ' (' + f.network + ') correctly', function () { var script = Script.fromASM(f.script) var addr = Address.fromOutputScript(script, networks[f.network]) @@ -49,20 +51,20 @@ describe('Address', function() { }) }) - fixtures.invalid.fromOutputScript.forEach(function(f) { - it('throws when ' + f.description, function() { + fixtures.invalid.fromOutputScript.forEach(function (f) { + it('throws when ' + f.description, function () { var script = Script.fromASM(f.script) - assert.throws(function() { + assert.throws(function () { Address.fromOutputScript(script) }, new RegExp(f.description)) }) }) }) - describe('toBase58Check', function() { - fixtures.valid.forEach(function(f) { - it('exports ' + f.script + ' (' + f.network + ') correctly', function() { + describe('toBase58Check', function () { + fixtures.valid.forEach(function (f) { + it('exports ' + f.script + ' (' + f.network + ') correctly', function () { var addr = Address.fromBase58Check(f.base58check) var result = addr.toBase58Check() @@ -71,9 +73,9 @@ describe('Address', function() { }) }) - describe('toOutputScript', function() { - fixtures.valid.forEach(function(f) { - it('imports ' + f.script + ' (' + f.network + ') correctly', function() { + describe('toOutputScript', function () { + fixtures.valid.forEach(function (f) { + it('imports ' + f.script + ' (' + f.network + ') correctly', function () { var addr = Address.fromBase58Check(f.base58check) var script = addr.toOutputScript() @@ -81,11 +83,11 @@ describe('Address', function() { }) }) - fixtures.invalid.toOutputScript.forEach(function(f) { - it('throws when ' + f.description, function() { + fixtures.invalid.toOutputScript.forEach(function (f) { + it('throws when ' + f.description, function () { var addr = new Address(new Buffer(f.hash, 'hex'), f.version) - assert.throws(function() { + assert.throws(function () { addr.toOutputScript() }, new RegExp(f.description)) }) diff --git a/test/base58check.js b/test/base58check.js deleted file mode 100644 index 030fb09c0..000000000 --- a/test/base58check.js +++ /dev/null @@ -1,28 +0,0 @@ -var assert = require('assert') -var base58check = require('../src/base58check') -var bs58check = require('bs58check') -var sinon = require('sinon') - -describe('base58check', function() { - var param - - beforeEach(function() { - param = {} - }) - - it('wraps bs58check.decode', sinon.test(function() { - var expectation = this.mock(bs58check).expects('decode') - expectation.once().calledWith(param) - expectation.onCall(0).returns('foo') - - assert.equal(base58check.decode(param), 'foo') - })) - - it('wraps bs58check.encode', sinon.test(function() { - var expectation = this.mock(bs58check).expects('encode') - expectation.once().calledWith(param) - expectation.onCall(0).returns('foo') - - assert.equal(base58check.encode(param), 'foo') - })) -}) diff --git a/test/bitcoin.core.js b/test/bitcoin.core.js index eadb07641..33066653e 100644 --- a/test/bitcoin.core.js +++ b/test/bitcoin.core.js @@ -1,40 +1,43 @@ -var assert = require('assert') +/* global describe, it */ +var assert = require('assert') var base58 = require('bs58') -//var base58check = require('bs58check') +var base58check = require('bs58check') var Bitcoin = require('../') var Address = Bitcoin.Address -var base58check = Bitcoin.base58check -var networks = Bitcoin.networks +var Block = Bitcoin.Block var ECKey = Bitcoin.ECKey var ECSignature = Bitcoin.ECSignature var Transaction = Bitcoin.Transaction var Script = Bitcoin.Script -var base58_encode_decode = require("./fixtures/core/base58_encode_decode.json") -var base58_keys_invalid = require("./fixtures/core/base58_keys_invalid.json") -var base58_keys_valid = require("./fixtures/core/base58_keys_valid.json") -var sig_canonical = require("./fixtures/core/sig_canonical.json") -var sig_noncanonical = require("./fixtures/core/sig_noncanonical.json") -var sighash = require("./fixtures/core/sighash.json") -var tx_valid = require("./fixtures/core/tx_valid.json") +var networks = Bitcoin.networks -describe('Bitcoin-core', function() { +var base58_encode_decode = require('./fixtures/core/base58_encode_decode.json') +var base58_keys_invalid = require('./fixtures/core/base58_keys_invalid.json') +var base58_keys_valid = require('./fixtures/core/base58_keys_valid.json') +var blocks_valid = require('./fixtures/core/blocks.json') +var sig_canonical = require('./fixtures/core/sig_canonical.json') +var sig_noncanonical = require('./fixtures/core/sig_noncanonical.json') +var sighash = require('./fixtures/core/sighash.json') +var tx_valid = require('./fixtures/core/tx_valid.json') + +describe('Bitcoin-core', function () { // base58_encode_decode - describe('base58', function() { - base58_encode_decode.forEach(function(f) { + describe('base58', function () { + base58_encode_decode.forEach(function (f) { var fhex = f[0] var fb58 = f[1] - it('can decode ' + fb58, function() { + it('can decode ' + fb58, function () { var buffer = base58.decode(fb58) var actual = new Buffer(buffer).toString('hex') assert.equal(actual, fhex) }) - it('can encode ' + fhex, function() { + it('can encode ' + fhex, function () { var buffer = new Buffer(fhex, 'hex') var actual = base58.encode(buffer) @@ -44,32 +47,33 @@ describe('Bitcoin-core', function() { }) // base58_keys_valid - describe('Address', function() { - base58_keys_valid.forEach(function(f) { + describe('Address', function () { + var typeMap = { + 'pubkey': 'pubKeyHash', + 'script': 'scriptHash' + } + + base58_keys_valid.forEach(function (f) { var string = f[0] var hex = f[1] var params = f[2] var network = networks.bitcoin if (params.isPrivkey) return - if (params.isTestnet) network = networks.testnet + if (params.isTestnet) + network = networks.testnet - it('can import ' + string, function() { + it('can import ' + string, function () { var address = Address.fromBase58Check(string) assert.equal(address.hash.toString('hex'), hex) - if (params.addrType === 'pubkey') { - assert.equal(address.version, network.pubKeyHash) - - } else if (params.addrType === 'script') { - assert.equal(address.version, network.scriptHash) - } + assert.equal(address.version, network[typeMap[params.addrType]]) }) }) }) // base58_keys_invalid - describe('Address', function() { + describe('Address', function () { var allowedNetworks = [ networks.bitcoin.pubkeyhash, networks.bitcoin.scripthash, @@ -77,11 +81,11 @@ describe('Bitcoin-core', function() { networks.testnet.scripthash ] - base58_keys_invalid.forEach(function(f) { + base58_keys_invalid.forEach(function (f) { var string = f[0] - it('throws on ' + string, function() { - assert.throws(function() { + it('throws on ' + string, function () { + assert.throws(function () { var address = Address.fromBase58Check(string) assert.notEqual(allowedNetworks.indexOf(address.version), -1, 'Invalid network') @@ -91,8 +95,8 @@ describe('Bitcoin-core', function() { }) // base58_keys_valid - describe('ECKey', function() { - base58_keys_valid.forEach(function(f) { + describe('ECKey', function () { + base58_keys_valid.forEach(function (f) { var string = f[0] var hex = f[1] var params = f[2] @@ -101,29 +105,29 @@ describe('Bitcoin-core', function() { if (!params.isPrivkey) return var privKey = ECKey.fromWIF(string) - it('imports ' + string + ' correctly', function() { + it('imports ' + string + ' correctly', function () { assert.equal(privKey.d.toHex(), hex) assert.equal(privKey.pub.compressed, params.isCompressed) }) - it('exports ' + hex + ' to ' + string, function() { + it('exports ' + hex + ' to ' + string, function () { assert.equal(privKey.toWIF(network), string) }) }) }) // base58_keys_invalid - describe('ECKey', function() { + describe('ECKey', function () { var allowedNetworks = [ networks.bitcoin.wif, networks.testnet.wif ] - base58_keys_invalid.forEach(function(f) { + base58_keys_invalid.forEach(function (f) { var string = f[0] - it('throws on ' + string, function() { - assert.throws(function() { + it('throws on ' + string, function () { + assert.throws(function () { ECKey.fromWIF(string) var version = base58check.decode(string).readUInt8(0) @@ -133,24 +137,35 @@ describe('Bitcoin-core', function() { }) }) + describe('Block', function () { + blocks_valid.forEach(function (f) { + it('fromHex can parse ' + f.id, function () { + var block = Block.fromHex(f.hex) + + assert.equal(block.getId(), f.id) + assert.equal(block.transactions.length, f.transactions) + }) + }) + }) + // tx_valid - describe('Transaction', function() { - tx_valid.forEach(function(f) { + describe('Transaction', function () { + tx_valid.forEach(function (f) { // Objects that are only a single string are ignored if (f.length === 1) return var inputs = f[0] var fhex = f[1] - // var verifyFlags = f[2] // TODO: do we need to test this? + // var verifyFlags = f[2] // TODO: do we need to test this? - it('can decode ' + fhex, function() { + it('can decode ' + fhex, function () { var transaction = Transaction.fromHex(fhex) - transaction.ins.forEach(function(txin, i) { + transaction.ins.forEach(function (txin, i) { var input = inputs[i] var prevOutHash = input[0] var prevOutIndex = input[1] - // var prevOutScriptPubKey = input[2] // TODO: we don't have a ASM parser + // var prevOutScriptPubKey = input[2] // TODO: we don't have a ASM parser var actualHash = txin.hash @@ -167,8 +182,8 @@ describe('Bitcoin-core', function() { }) // sighash - describe('Transaction', function() { - sighash.forEach(function(f) { + describe('Transaction', function () { + sighash.forEach(function (f) { // Objects that are only a single string are ignored if (f.length === 1) return @@ -178,7 +193,7 @@ describe('Bitcoin-core', function() { var hashType = f[3] var expectedHash = f[4] - it('should hash ' + txHex + ' correctly', function() { + it('should hash ' + txHex + ' correctly', function () { var transaction = Transaction.fromHex(txHex) assert.equal(transaction.toHex(), txHex) @@ -190,7 +205,8 @@ describe('Bitcoin-core', function() { actualHash = transaction.hashForSignature(inIndex, script, hashType) } catch (e) { // don't fail if we don't support it yet, TODO - if (!e.message.match(/not yet supported/)) throw e + if (!e.message.match(/not yet supported/)) + throw e } if (actualHash !== undefined) { @@ -203,18 +219,18 @@ describe('Bitcoin-core', function() { }) }) - describe('ECSignature', function() { - sig_canonical.forEach(function(hex) { + describe('ECSignature', function () { + sig_canonical.forEach(function (hex) { var buffer = new Buffer(hex, 'hex') - it('can parse ' + hex, function() { + it('can parse ' + hex, function () { var parsed = ECSignature.parseScriptSignature(buffer) var actual = parsed.signature.toScriptSignature(parsed.hashType) assert.equal(actual.toString('hex'), hex) }) }) - sig_noncanonical.forEach(function(hex, i) { + sig_noncanonical.forEach(function (hex, i) { if (i === 0) return if (i % 2 !== 0) return @@ -223,8 +239,8 @@ describe('Bitcoin-core', function() { var buffer = new Buffer(hex, 'hex') - it('throws on ' + description, function() { - assert.throws(function() { + it('throws on ' + description, function () { + assert.throws(function () { ECSignature.parseScriptSignature(buffer) }) }) diff --git a/test/block.js b/test/block.js index c5099804a..a91e24877 100644 --- a/test/block.js +++ b/test/block.js @@ -1,13 +1,15 @@ +/* global describe, it, beforeEach */ + var assert = require('assert') var Block = require('../src/block') var fixtures = require('./fixtures/block') -describe('Block', function() { - describe('fromBuffer/fromHex', function() { - fixtures.valid.forEach(function(f) { - it('imports the block: ' + f.description + ' correctly', function() { +describe('Block', function () { + describe('fromBuffer/fromHex', function () { + fixtures.valid.forEach(function (f) { + it('imports the block: ' + f.description + ' correctly', function () { var block = Block.fromHex(f.hex) assert.equal(block.version, f.version) @@ -19,66 +21,66 @@ describe('Block', function() { }) }) - fixtures.invalid.forEach(function(f) { - it('throws on ' + f.exception, function() { - assert.throws(function() { + fixtures.invalid.forEach(function (f) { + it('throws on ' + f.exception, function () { + assert.throws(function () { Block.fromHex(f.hex) }, new RegExp(f.exception)) }) }) }) - describe('toBuffer/toHex', function() { - fixtures.valid.forEach(function(f) { + describe('toBuffer/toHex', function () { + fixtures.valid.forEach(function (f) { var block - beforeEach(function() { + beforeEach(function () { block = Block.fromHex(f.hex) }) - it('exports the block: ' + f.description + ' correctly', function() { + it('exports the block: ' + f.description + ' correctly', function () { assert.equal(block.toHex(), f.hex) }) }) }) - describe('getHash', function() { - fixtures.valid.forEach(function(f) { + describe('getHash', function () { + fixtures.valid.forEach(function (f) { var block - beforeEach(function() { + beforeEach(function () { block = Block.fromHex(f.hex) }) - it('calculates ' + f.hash + ' for the block: ' + f.description, function() { + it('calculates ' + f.hash + ' for the block: ' + f.description, function () { assert.equal(block.getHash().toString('hex'), f.hash) }) }) }) - describe('getId', function() { - fixtures.valid.forEach(function(f) { + describe('getId', function () { + fixtures.valid.forEach(function (f) { var block - beforeEach(function() { + beforeEach(function () { block = Block.fromHex(f.hex) }) - it('calculates ' + f.id + ' for the block: ' + f.description, function() { + it('calculates ' + f.id + ' for the block: ' + f.description, function () { assert.equal(block.getId(), f.id) }) }) }) - describe('getUTCDate', function() { - fixtures.valid.forEach(function(f) { + describe('getUTCDate', function () { + fixtures.valid.forEach(function (f) { var block - beforeEach(function() { + beforeEach(function () { block = Block.fromHex(f.hex) }) - it('returns UTC date of ' + f.id, function() { + it('returns UTC date of ' + f.id, function () { var utcDate = block.getUTCDate().getTime() assert.equal(utcDate, f.timestamp * 1e3) diff --git a/test/bufferutils.js b/test/bufferutils.js index 8fc054cb0..485447b2e 100644 --- a/test/bufferutils.js +++ b/test/bufferutils.js @@ -1,12 +1,14 @@ +/* global describe, it */ + var assert = require('assert') var bufferutils = require('../src/bufferutils') var fixtures = require('./fixtures/bufferutils.json') -describe('bufferutils', function() { - describe('pushDataSize', function() { - fixtures.valid.forEach(function(f) { - it('determines the pushDataSize of ' + f.dec + ' correctly', function() { +describe('bufferutils', function () { + describe('pushDataSize', function () { + fixtures.valid.forEach(function (f) { + it('determines the pushDataSize of ' + f.dec + ' correctly', function () { if (!f.hexPD) return var size = bufferutils.pushDataSize(f.dec) @@ -16,11 +18,11 @@ describe('bufferutils', function() { }) }) - describe('readPushDataInt', function() { - fixtures.valid.forEach(function(f) { + describe('readPushDataInt', function () { + fixtures.valid.forEach(function (f) { if (!f.hexPD) return - it('decodes ' + f.hexPD + ' correctly', function() { + it('decodes ' + f.hexPD + ' correctly', function () { var buffer = new Buffer(f.hexPD, 'hex') var d = bufferutils.readPushDataInt(buffer, 0) var fopcode = parseInt(f.hexPD.substr(0, 2), 16) @@ -32,9 +34,9 @@ describe('bufferutils', function() { }) }) - describe('readUInt64LE', function() { - fixtures.valid.forEach(function(f) { - it('decodes ' + f.hex64 + ' correctly', function() { + describe('readUInt64LE', function () { + fixtures.valid.forEach(function (f) { + it('decodes ' + f.hex64 + ' correctly', function () { var buffer = new Buffer(f.hex64, 'hex') var number = bufferutils.readUInt64LE(buffer, 0) @@ -42,20 +44,20 @@ describe('bufferutils', function() { }) }) - fixtures.invalid.forEach(function(f) { - it('throws on ' + f.description, function() { + fixtures.invalid.forEach(function (f) { + it('throws on ' + f.description, function () { var buffer = new Buffer(f.hex64, 'hex') - assert.throws(function() { + assert.throws(function () { bufferutils.readUInt64LE(buffer, 0) }, new RegExp(f.exception)) }) }) }) - describe('readVarInt', function() { - fixtures.valid.forEach(function(f) { - it('decodes ' + f.hexVI + ' correctly', function() { + describe('readVarInt', function () { + fixtures.valid.forEach(function (f) { + it('decodes ' + f.hexVI + ' correctly', function () { var buffer = new Buffer(f.hexVI, 'hex') var d = bufferutils.readVarInt(buffer, 0) @@ -64,20 +66,36 @@ describe('bufferutils', function() { }) }) - fixtures.invalid.forEach(function(f) { - it('throws on ' + f.description, function() { + fixtures.invalid.forEach(function (f) { + it('throws on ' + f.description, function () { var buffer = new Buffer(f.hexVI, 'hex') - assert.throws(function() { + assert.throws(function () { bufferutils.readVarInt(buffer, 0) }, new RegExp(f.exception)) }) }) }) - describe('reverse', function() { - fixtures.valid.forEach(function(f) { - it('reverses ' + f.hex64 + ' correctly', function() { + describe('equal', function () { + fixtures.valid.forEach(function (f) { + describe('for ' + f.hexVI, function () { + fixtures.valid.forEach(function (f2) { + it('equates the string comparison: ' + f.hexVI + ' === ' + f2.hexVI, function () { + var a = new Buffer(f.hexVI, 'hex') + var b = new Buffer(f2.hexVI, 'hex') + var expected = f.hexVI === f2.hexVI + + assert.equal(bufferutils.equal(a, b), expected) + }) + }) + }) + }) + }) + + describe('reverse', function () { + fixtures.valid.forEach(function (f) { + it('reverses ' + f.hex64 + ' correctly', function () { var buffer = new Buffer(f.hex64, 'hex') var buffer2 = bufferutils.reverse(buffer) @@ -88,9 +106,9 @@ describe('bufferutils', function() { }) }) - describe('varIntBuffer', function() { - fixtures.valid.forEach(function(f) { - it('encodes ' + f.dec + ' correctly', function() { + describe('varIntBuffer', function () { + fixtures.valid.forEach(function (f) { + it('encodes ' + f.dec + ' correctly', function () { var buffer = bufferutils.varIntBuffer(f.dec) assert.equal(buffer.toString('hex'), f.hexVI) @@ -98,9 +116,9 @@ describe('bufferutils', function() { }) }) - describe('varIntSize', function() { - fixtures.valid.forEach(function(f) { - it('determines the varIntSize of ' + f.dec + ' correctly', function() { + describe('varIntSize', function () { + fixtures.valid.forEach(function (f) { + it('determines the varIntSize of ' + f.dec + ' correctly', function () { var size = bufferutils.varIntSize(f.dec) assert.equal(size, f.hexVI.length / 2) @@ -108,11 +126,11 @@ describe('bufferutils', function() { }) }) - describe('writePushDataInt', function() { - fixtures.valid.forEach(function(f) { + describe('writePushDataInt', function () { + fixtures.valid.forEach(function (f) { if (!f.hexPD) return - it('encodes ' + f.dec + ' correctly', function() { + it('encodes ' + f.dec + ' correctly', function () { var buffer = new Buffer(5) buffer.fill(0) @@ -122,9 +140,9 @@ describe('bufferutils', function() { }) }) - describe('writeUInt64LE', function() { - fixtures.valid.forEach(function(f) { - it('encodes ' + f.dec + ' correctly', function() { + describe('writeUInt64LE', function () { + fixtures.valid.forEach(function (f) { + it('encodes ' + f.dec + ' correctly', function () { var buffer = new Buffer(8) buffer.fill(0) @@ -133,21 +151,21 @@ describe('bufferutils', function() { }) }) - fixtures.invalid.forEach(function(f) { - it('throws on ' + f.description, function() { + fixtures.invalid.forEach(function (f) { + it('throws on ' + f.description, function () { var buffer = new Buffer(8) buffer.fill(0) - assert.throws(function() { + assert.throws(function () { bufferutils.writeUInt64LE(buffer, f.dec, 0) }, new RegExp(f.exception)) }) }) }) - describe('writeVarInt', function() { - fixtures.valid.forEach(function(f) { - it('encodes ' + f.dec + ' correctly', function() { + describe('writeVarInt', function () { + fixtures.valid.forEach(function (f) { + it('encodes ' + f.dec + ' correctly', function () { var buffer = new Buffer(9) buffer.fill(0) @@ -156,12 +174,12 @@ describe('bufferutils', function() { }) }) - fixtures.invalid.forEach(function(f) { - it('throws on ' + f.description, function() { + fixtures.invalid.forEach(function (f) { + it('throws on ' + f.description, function () { var buffer = new Buffer(9) buffer.fill(0) - assert.throws(function() { + assert.throws(function () { bufferutils.writeVarInt(buffer, f.dec, 0) }, new RegExp(f.exception)) }) diff --git a/test/crypto.js b/test/crypto.js index a6dd92c60..91827ca3a 100644 --- a/test/crypto.js +++ b/test/crypto.js @@ -1,84 +1,23 @@ +/* global describe, it */ + var assert = require('assert') var crypto = require('../src/crypto') -var fixtures = require('./fixtures/crypto.json') - -describe('Crypto', function() { - describe('HASH160', function() { - it('matches the test vectors', function() { - fixtures.before.hex.forEach(function(hex, i) { - var data = new Buffer(hex, 'hex') - var actual = crypto.hash160(data).toString('hex') - - assert.equal(actual, fixtures.after.hash160[i]) - }) - }) - }) - - describe('HASH256', function() { - it('matches the test vectors', function() { - fixtures.before.hex.forEach(function(hex, i) { - var data = new Buffer(hex, 'hex') - var actual = crypto.hash256(data).toString('hex') - - assert.equal(actual, fixtures.after.hash256[i]) - }) - }) - }) - - describe('RIPEMD160', function() { - it('matches the test vectors', function() { - fixtures.before.hex.forEach(function(hex, i) { - var data = new Buffer(hex, 'hex') - var actual = crypto.ripemd160(data).toString('hex') - - assert.equal(actual, fixtures.after.ripemd160[i]) - }) - }) - }) - - describe('SHA1', function() { - it('matches the test vectors', function() { - fixtures.before.hex.forEach(function(hex, i) { - var data = new Buffer(hex, 'hex') - var actual = crypto.sha1(data).toString('hex') - - assert.equal(actual, fixtures.after.sha1[i]) - }) - }) - }) - - describe('SHA256', function() { - it('matches the test vectors', function() { - fixtures.before.hex.forEach(function(hex, i) { - var data = new Buffer(hex, 'hex') - var actual = crypto.sha256(data).toString('hex') +var fixtures = require('./fixtures/crypto') - assert.equal(actual, fixtures.after.sha256[i]) - }) - }) - }) - - describe('HmacSHA256', function() { - it('matches the test vectors', function() { - fixtures.before.hex.forEach(function(hex, i) { - var data = new Buffer(hex, 'hex') - var secret = new Buffer(fixtures.before.secret) - var actual = crypto.HmacSHA256(data, secret).toString('hex') - - assert.equal(actual, fixtures.after.hmacsha256[i]) - }) - }) - }) +describe('Crypto', function () { + ['hash160', 'hash256', 'ripemd160', 'sha1', 'sha256'].forEach(function (algorithm) { + describe(algorithm, function () { + fixtures.valid.forEach(function (f) { + var fn = crypto[algorithm] + var expected = f[algorithm] - describe('HmacSHA512', function() { - it('matches the test vectors', function() { - fixtures.before.hex.forEach(function(hex, i) { - var data = new Buffer(hex, 'hex') - var secret = new Buffer(fixtures.before.secret) - var actual = crypto.HmacSHA512(data, secret).toString('hex') + it('returns ' + expected + ' for ' + f.hex, function () { + var data = new Buffer(f.hex, 'hex') + var actual = fn(data).toString('hex') - assert.equal(actual, fixtures.after.hmacsha512[i]) + assert.equal(actual, expected) + }) }) }) }) diff --git a/test/ecdsa.js b/test/ecdsa.js index b95397775..a5ff8a5a4 100644 --- a/test/ecdsa.js +++ b/test/ecdsa.js @@ -1,3 +1,5 @@ +/* global describe, it */ + var assert = require('assert') var crypto = require('../src/crypto') var ecdsa = require('../src/ecdsa') @@ -13,12 +15,14 @@ var curve = ecurve.getCurveByName('secp256k1') var fixtures = require('./fixtures/ecdsa.json') -describe('ecdsa', function() { - describe('deterministicGenerateK', function() { - function checkSig() { return true } +describe('ecdsa', function () { + describe('deterministicGenerateK', function () { + function checkSig () { + return true + } - fixtures.valid.ecdsa.forEach(function(f) { - it('for \"' + f.message + '\"', function() { + fixtures.valid.ecdsa.forEach(function (f) { + it('for "' + f.message + '"', function () { var d = BigInteger.fromHex(f.d) var h1 = crypto.sha256(f.message) @@ -27,18 +31,7 @@ describe('ecdsa', function() { }) }) - // FIXME: remove in 2.0.0 - fixtures.valid.ecdsa.forEach(function(f) { - it('(deprecated) for \"' + f.message + '\"', function() { - var d = BigInteger.fromHex(f.d) - var h1 = crypto.sha256(f.message) - - var k = ecdsa.deterministicGenerateK(curve, h1, d) // default checkSig - assert.equal(k.toHex(), f.k) - }) - }) - - it('loops until an appropriate k value is found', sinon.test(function() { + it('loops until an appropriate k value is found', sinon.test(function () { this.mock(BigInteger).expects('fromBuffer') .exactly(3) .onCall(0).returns(new BigInteger('0')) // < 1 @@ -52,7 +45,7 @@ describe('ecdsa', function() { assert.equal(k.toString(), '42') })) - it('loops until a suitable signature is found', sinon.test(function() { + it('loops until a suitable signature is found', sinon.test(function () { this.mock(BigInteger).expects('fromBuffer') .exactly(4) .onCall(0).returns(new BigInteger('0')) // < 1 @@ -72,13 +65,13 @@ describe('ecdsa', function() { assert.equal(k.toString(), '53') })) - fixtures.valid.rfc6979.forEach(function(f) { - it('produces the expected k values for ' + f.message + ' if k wasn\'t suitable', function() { + fixtures.valid.rfc6979.forEach(function (f) { + it('produces the expected k values for ' + f.message + " if k wasn't suitable", function () { var d = BigInteger.fromHex(f.d) var h1 = crypto.sha256(f.message) var results = [] - ecdsa.deterministicGenerateK(curve, h1, d, function(k) { + ecdsa.deterministicGenerateK(curve, h1, d, function (k) { results.push(k) return results.length === 16 @@ -91,9 +84,9 @@ describe('ecdsa', function() { }) }) - describe('recoverPubKey', function() { - fixtures.valid.ecdsa.forEach(function(f) { - it('recovers the pubKey for ' + f.d, function() { + describe('recoverPubKey', function () { + fixtures.valid.ecdsa.forEach(function (f) { + it('recovers the pubKey for ' + f.d, function () { var d = BigInteger.fromHex(f.d) var Q = curve.G.multiply(d) var signature = { @@ -108,7 +101,7 @@ describe('ecdsa', function() { }) }) - describe('with i ∈ {0,1,2,3}', function() { + describe('with i ∈ {0,1,2,3}', function () { var hash = message.magicHash('1111', networks.bitcoin) var e = BigInteger.fromBuffer(hash) @@ -121,8 +114,8 @@ describe('ecdsa', function() { '027eea09d46ac7fb6aa2e96f9c576677214ffdc238eb167734a9b39d1eb4c3d30d' ] - points.forEach(function(expectedHex, i) { - it('recovers an expected point for i of ' + i, function() { + points.forEach(function (expectedHex, i) { + it('recovers an expected point for i of ' + i, function () { var Qprime = ecdsa.recoverPubKey(curve, e, signature, i) var QprimeHex = Qprime.getEncoded().toString('hex') @@ -131,21 +124,21 @@ describe('ecdsa', function() { }) }) - fixtures.invalid.recoverPubKey.forEach(function(f) { - it('throws on ' + f.description, function() { + fixtures.invalid.recoverPubKey.forEach(function (f) { + it('throws on ' + f.description, function () { var e = BigInteger.fromHex(f.e) var signature = new ECSignature(new BigInteger(f.signature.r), new BigInteger(f.signature.s)) - assert.throws(function() { + assert.throws(function () { ecdsa.recoverPubKey(curve, e, signature, f.i) }, new RegExp(f.exception)) }) }) }) - describe('sign', function() { - fixtures.valid.ecdsa.forEach(function(f) { - it('produces a deterministic signature for \"' + f.message + '\"', function() { + describe('sign', function () { + fixtures.valid.ecdsa.forEach(function (f) { + it('produces a deterministic signature for "' + f.message + '"', function () { var d = BigInteger.fromHex(f.d) var hash = crypto.sha256(f.message) var signature = ecdsa.sign(curve, hash, d) @@ -155,7 +148,7 @@ describe('ecdsa', function() { }) }) - it('should sign with low S value', function() { + it('should sign with low S value', function () { var hash = crypto.sha256('Vires in numeris') var sig = ecdsa.sign(curve, hash, BigInteger.ONE) @@ -165,16 +158,13 @@ describe('ecdsa', function() { }) }) - describe('verify/verifyRaw', function() { - fixtures.valid.ecdsa.forEach(function(f) { - it('verifies a valid signature for \"' + f.message + '\"', function() { + describe('verify/verifyRaw', function () { + fixtures.valid.ecdsa.forEach(function (f) { + it('verifies a valid signature for "' + f.message + '"', function () { var d = BigInteger.fromHex(f.d) var H = crypto.sha256(f.message) var e = BigInteger.fromBuffer(H) - var signature = new ECSignature( - new BigInteger(f.signature.r), - new BigInteger(f.signature.s) - ) + var signature = new ECSignature(new BigInteger(f.signature.r), new BigInteger(f.signature.s)) var Q = curve.G.multiply(d) assert(ecdsa.verify(curve, H, signature, Q)) @@ -182,15 +172,12 @@ describe('ecdsa', function() { }) }) - fixtures.invalid.verifyRaw.forEach(function(f) { - it('fails to verify with ' + f.description, function() { + fixtures.invalid.verifyRaw.forEach(function (f) { + it('fails to verify with ' + f.description, function () { var H = crypto.sha256(f.message) var e = BigInteger.fromBuffer(H) var d = BigInteger.fromHex(f.d) - var signature = new ECSignature( - new BigInteger(f.signature.r), - new BigInteger(f.signature.s) - ) + var signature = new ECSignature(new BigInteger(f.signature.r), new BigInteger(f.signature.s)) var Q = curve.G.multiply(d) assert.equal(ecdsa.verify(curve, H, signature, Q), false) diff --git a/test/eckey.js b/test/eckey.js index 271e5f75a..16ce3d0cb 100644 --- a/test/eckey.js +++ b/test/eckey.js @@ -1,3 +1,6 @@ +/* global describe, it, beforeEach, afterEach */ +/* eslint-disable no-new */ + var assert = require('assert') var crypto = require('crypto') var ecurve = require('ecurve') @@ -9,22 +12,22 @@ var ECKey = require('../src/eckey') var fixtures = require('./fixtures/eckey.json') -describe('ECKey', function() { - describe('constructor', function() { - it('defaults to compressed', function() { +describe('ECKey', function () { + describe('constructor', function () { + it('defaults to compressed', function () { var privKey = new ECKey(BigInteger.ONE) assert.equal(privKey.pub.compressed, true) }) - it('supports the uncompressed flag', function() { + it('supports the uncompressed flag', function () { var privKey = new ECKey(BigInteger.ONE, false) assert.equal(privKey.pub.compressed, false) }) - fixtures.valid.forEach(function(f) { - it('calculates the matching pubKey for ' + f.d, function() { + fixtures.valid.forEach(function (f) { + it('calculates the matching pubKey for ' + f.d, function () { var d = new BigInteger(f.d) var privKey = new ECKey(d) @@ -32,18 +35,18 @@ describe('ECKey', function() { }) }) - fixtures.invalid.constructor.forEach(function(f) { - it('throws on ' + f.d, function() { + fixtures.invalid.constructor.forEach(function (f) { + it('throws on ' + f.d, function () { var d = new BigInteger(f.d) - assert.throws(function() { + assert.throws(function () { new ECKey(d) }, new RegExp(f.exception)) }) }) }) - it('uses the secp256k1 curve by default', function() { + it('uses the secp256k1 curve by default', function () { var secp256k1 = ecurve.getCurveByName('secp256k1') for (var property in secp256k1) { @@ -58,10 +61,10 @@ describe('ECKey', function() { } }) - describe('fromWIF', function() { - fixtures.valid.forEach(function(f) { - f.WIFs.forEach(function(wif) { - it('imports ' + wif.string + ' correctly', function() { + describe('fromWIF', function () { + fixtures.valid.forEach(function (f) { + f.WIFs.forEach(function (wif) { + it('imports ' + wif.string + ' correctly', function () { var privKey = ECKey.fromWIF(wif.string) assert.equal(privKey.d.toString(), f.d) @@ -70,19 +73,19 @@ describe('ECKey', function() { }) }) - fixtures.invalid.WIF.forEach(function(f) { - it('throws on ' + f.string, function() { - assert.throws(function() { + fixtures.invalid.WIF.forEach(function (f) { + it('throws on ' + f.string, function () { + assert.throws(function () { ECKey.fromWIF(f.string) }, new RegExp(f.exception)) }) }) }) - describe('toWIF', function() { - fixtures.valid.forEach(function(f) { - f.WIFs.forEach(function(wif) { - it('exports ' + wif.string + ' correctly', function() { + describe('toWIF', function () { + fixtures.valid.forEach(function (f) { + f.WIFs.forEach(function (wif) { + it('exports ' + wif.string + ' correctly', function () { var privKey = ECKey.fromWIF(wif.string) var network = networks[wif.network] var result = privKey.toWIF(network) @@ -93,34 +96,34 @@ describe('ECKey', function() { }) }) - describe('makeRandom', function() { + describe('makeRandom', function () { var exWIF = 'KwMWvwRJeFqxYyhZgNwYuYjbQENDAPAudQx5VEmKJrUZcq6aL2pv' var exPrivKey = ECKey.fromWIF(exWIF) var exBuffer = exPrivKey.d.toBuffer(32) - describe('uses default crypto RNG', function() { - beforeEach(function() { + describe('uses default crypto RNG', function () { + beforeEach(function () { sinon.stub(crypto, 'randomBytes').returns(exBuffer) }) - afterEach(function() { + afterEach(function () { crypto.randomBytes.restore() }) - it('generates a ECKey', function() { + it('generates a ECKey', function () { var privKey = ECKey.makeRandom() assert.equal(privKey.toWIF(), exWIF) }) - it('supports compression', function() { + it('supports compression', function () { assert.equal(ECKey.makeRandom(true).pub.compressed, true) assert.equal(ECKey.makeRandom(false).pub.compressed, false) }) }) - it('allows a custom RNG to be used', function() { - function rng(size) { + it('allows a custom RNG to be used', function () { + function rng (size) { return exBuffer.slice(0, size) } @@ -129,16 +132,16 @@ describe('ECKey', function() { }) }) - describe('signing', function() { + describe('signing', function () { var hash = crypto.randomBytes(32) var priv = ECKey.makeRandom() var signature = priv.sign(hash) - it('should verify against the public key', function() { + it('should verify against the public key', function () { assert(priv.pub.verify(hash, signature)) }) - it('should not verify against the wrong public key', function() { + it('should not verify against the wrong public key', function () { var priv2 = ECKey.makeRandom() assert(!priv2.pub.verify(hash, signature)) diff --git a/test/ecpubkey.js b/test/ecpubkey.js index bf4ac5a52..76943ed3e 100644 --- a/test/ecpubkey.js +++ b/test/ecpubkey.js @@ -1,3 +1,5 @@ +/* global describe, it, beforeEach */ + var assert = require('assert') var crypto = require('../src/crypto') var networks = require('../src/networks') @@ -10,10 +12,10 @@ var curve = ecurve.getCurveByName('secp256k1') var fixtures = require('./fixtures/ecpubkey.json') -describe('ECPubKey', function() { +describe('ECPubKey', function () { var Q - beforeEach(function() { + beforeEach(function () { Q = ecurve.Point.fromAffine( curve, new BigInteger(fixtures.Q.x), @@ -21,21 +23,21 @@ describe('ECPubKey', function() { ) }) - describe('constructor', function() { - it('defaults to compressed', function() { + describe('constructor', function () { + it('defaults to compressed', function () { var pubKey = new ECPubKey(Q) assert.equal(pubKey.compressed, true) }) - it('supports the uncompressed flag', function() { + it('supports the uncompressed flag', function () { var pubKey = new ECPubKey(Q, false) assert.equal(pubKey.compressed, false) }) }) - it('uses the secp256k1 curve by default', function() { + it('uses the secp256k1 curve by default', function () { var secp256k1 = ecurve.getCurveByName('secp256k1') for (var property in secp256k1) { @@ -50,8 +52,8 @@ describe('ECPubKey', function() { } }) - describe('fromHex/toHex', function() { - it('supports compressed points', function() { + describe('fromHex/toHex', function () { + it('supports compressed points', function () { var pubKey = ECPubKey.fromHex(fixtures.compressed.hex) assert(pubKey.Q.equals(Q)) @@ -59,7 +61,7 @@ describe('ECPubKey', function() { assert.equal(pubKey.compressed, true) }) - it('supports uncompressed points', function() { + it('supports uncompressed points', function () { var pubKey = ECPubKey.fromHex(fixtures.uncompressed.hex) assert(pubKey.Q.equals(Q)) @@ -68,22 +70,22 @@ describe('ECPubKey', function() { }) }) - describe('getAddress', function() { - it('calculates the expected hash (compressed)', function() { + describe('getAddress', function () { + it('calculates the expected hash (compressed)', function () { var pubKey = new ECPubKey(Q, true) var address = pubKey.getAddress() assert.equal(address.hash.toString('hex'), fixtures.compressed.hash160) }) - it('calculates the expected hash (uncompressed)', function() { + it('calculates the expected hash (uncompressed)', function () { var pubKey = new ECPubKey(Q, false) var address = pubKey.getAddress() assert.equal(address.hash.toString('hex'), fixtures.uncompressed.hash160) }) - it('supports alternative networks', function() { + it('supports alternative networks', function () { var pubKey = new ECPubKey(Q) var address = pubKey.getAddress(networks.testnet) @@ -92,9 +94,9 @@ describe('ECPubKey', function() { }) }) - describe('verify', function() { + describe('verify', function () { var pubKey, signature - beforeEach(function() { + beforeEach(function () { pubKey = new ECPubKey(Q) signature = { @@ -103,13 +105,13 @@ describe('ECPubKey', function() { } }) - it('verifies a valid signature', function() { + it('verifies a valid signature', function () { var hash = crypto.sha256(fixtures.message) assert(pubKey.verify(hash, signature)) }) - it('doesn\'t verify the wrong signature', function() { + it("doesn't verify the wrong signature", function () { var hash = crypto.sha256('mushrooms') assert(!pubKey.verify(hash, signature)) diff --git a/test/ecsignature.js b/test/ecsignature.js index 1866ac24e..908876f4b 100644 --- a/test/ecsignature.js +++ b/test/ecsignature.js @@ -1,3 +1,5 @@ +/* global describe, it */ + var assert = require('assert') var BigInteger = require('bigi') @@ -5,14 +7,11 @@ var ECSignature = require('../src/ecsignature') var fixtures = require('./fixtures/ecsignature.json') -describe('ECSignature', function() { - describe('toCompact', function() { - fixtures.valid.forEach(function(f) { - it('exports ' + f.compact.hex + ' correctly', function() { - var signature = new ECSignature( - new BigInteger(f.signature.r), - new BigInteger(f.signature.s) - ) +describe('ECSignature', function () { + describe('toCompact', function () { + fixtures.valid.forEach(function (f) { + it('exports ' + f.compact.hex + ' correctly', function () { + var signature = new ECSignature(new BigInteger(f.signature.r), new BigInteger(f.signature.s)) var buffer = signature.toCompact(f.compact.i, f.compact.compressed) assert.equal(buffer.toString('hex'), f.compact.hex) @@ -20,9 +19,9 @@ describe('ECSignature', function() { }) }) - describe('parseCompact', function() { - fixtures.valid.forEach(function(f) { - it('imports ' + f.compact.hex + ' correctly', function() { + describe('parseCompact', function () { + fixtures.valid.forEach(function (f) { + it('imports ' + f.compact.hex + ' correctly', function () { var buffer = new Buffer(f.compact.hex, 'hex') var parsed = ECSignature.parseCompact(buffer) @@ -33,24 +32,21 @@ describe('ECSignature', function() { }) }) - fixtures.invalid.compact.forEach(function(f) { - it('throws on ' + f.hex, function() { + fixtures.invalid.compact.forEach(function (f) { + it('throws on ' + f.hex, function () { var buffer = new Buffer(f.hex, 'hex') - assert.throws(function() { + assert.throws(function () { ECSignature.parseCompact(buffer) }, new RegExp(f.exception)) }) }) }) - describe('toDER', function() { - fixtures.valid.forEach(function(f) { - it('exports ' + f.DER + ' correctly', function() { - var signature = new ECSignature( - new BigInteger(f.signature.r), - new BigInteger(f.signature.s) - ) + describe('toDER', function () { + fixtures.valid.forEach(function (f) { + it('exports ' + f.DER + ' correctly', function () { + var signature = new ECSignature(new BigInteger(f.signature.r), new BigInteger(f.signature.s)) var DER = signature.toDER() assert.equal(DER.toString('hex'), f.DER) @@ -58,9 +54,9 @@ describe('ECSignature', function() { }) }) - describe('fromDER', function() { - fixtures.valid.forEach(function(f) { - it('imports ' + f.DER + ' correctly', function() { + describe('fromDER', function () { + fixtures.valid.forEach(function (f) { + it('imports ' + f.DER + ' correctly', function () { var buffer = new Buffer(f.DER, 'hex') var signature = ECSignature.fromDER(buffer) @@ -69,47 +65,41 @@ describe('ECSignature', function() { }) }) - fixtures.invalid.DER.forEach(function(f) { - it('throws on ' + f.hex, function() { + fixtures.invalid.DER.forEach(function (f) { + it('throws on ' + f.hex, function () { var buffer = new Buffer(f.hex, 'hex') - assert.throws(function() { + assert.throws(function () { ECSignature.fromDER(buffer) }, new RegExp(f.exception)) }) }) }) - describe('toScriptSignature', function() { - fixtures.valid.forEach(function(f) { - it('exports ' + f.scriptSignature.hex + ' correctly', function() { - var signature = new ECSignature( - new BigInteger(f.signature.r), - new BigInteger(f.signature.s) - ) + describe('toScriptSignature', function () { + fixtures.valid.forEach(function (f) { + it('exports ' + f.scriptSignature.hex + ' correctly', function () { + var signature = new ECSignature(new BigInteger(f.signature.r), new BigInteger(f.signature.s)) var scriptSignature = signature.toScriptSignature(f.scriptSignature.hashType) assert.equal(scriptSignature.toString('hex'), f.scriptSignature.hex) }) }) - fixtures.invalid.scriptSignature.forEach(function(f) { - it('throws ' + f.exception, function() { - var signature = new ECSignature( - new BigInteger(f.signature.r), - new BigInteger(f.signature.s) - ) + fixtures.invalid.scriptSignature.forEach(function (f) { + it('throws ' + f.exception, function () { + var signature = new ECSignature(new BigInteger(f.signature.r), new BigInteger(f.signature.s)) - assert.throws(function() { + assert.throws(function () { signature.toScriptSignature(f.hashType) }, new RegExp(f.exception)) }) }) }) - describe('parseScriptSignature', function() { - fixtures.valid.forEach(function(f) { - it('imports ' + f.scriptSignature.hex + ' correctly', function() { + describe('parseScriptSignature', function () { + fixtures.valid.forEach(function (f) { + it('imports ' + f.scriptSignature.hex + ' correctly', function () { var buffer = new Buffer(f.scriptSignature.hex, 'hex') var parsed = ECSignature.parseScriptSignature(buffer) @@ -119,11 +109,11 @@ describe('ECSignature', function() { }) }) - fixtures.invalid.scriptSignature.forEach(function(f) { - it('throws on ' + f.hex, function() { + fixtures.invalid.scriptSignature.forEach(function (f) { + it('throws on ' + f.hex, function () { var buffer = new Buffer(f.hex, 'hex') - assert.throws(function() { + assert.throws(function () { ECSignature.parseScriptSignature(buffer) }, new RegExp(f.exception)) }) diff --git a/test/fixtures/core/blocks.json b/test/fixtures/core/blocks.json new file mode 100644 index 000000000..1a769ae62 --- /dev/null +++ b/test/fixtures/core/blocks.json @@ -0,0 +1,27 @@ +[ + { + "id": "0000000000013b8ab2cd513b0261a14096412195a72a0c4827d229dcc7e0f7af", + "transactions": 9, + "hex": "0100000090f0a9f110702f808219ebea1173056042a714bad51b916cb6800000000000005275289558f51c9966699404ae2294730c3c9f9bda53523ce50e9b95e558da2fdb261b4d4c86041b1ab1bf930901000000010000000000000000000000000000000000000000000000000000000000000000ffffffff07044c86041b0146ffffffff0100f2052a01000000434104e18f7afbe4721580e81e8414fc8c24d7cfacf254bb5c7b949450c3e997c2dc1242487a8169507b631eb3771f2b425483fb13102c4eb5d858eef260fe70fbfae0ac00000000010000000196608ccbafa16abada902780da4dc35dafd7af05fa0da08cf833575f8cf9e836000000004a493046022100dab24889213caf43ae6adc41cf1c9396c08240c199f5225acf45416330fd7dbd022100fe37900e0644bf574493a07fc5edba06dbc07c311b947520c2d514bc5725dcb401ffffffff0100f2052a010000001976a914f15d1921f52e4007b146dfa60f369ed2fc393ce288ac000000000100000001fb766c1288458c2bafcfec81e48b24d98ec706de6b8af7c4e3c29419bfacb56d000000008c493046022100f268ba165ce0ad2e6d93f089cfcd3785de5c963bb5ea6b8c1b23f1ce3e517b9f022100da7c0f21adc6c401887f2bfd1922f11d76159cbc597fbd756a23dcbb00f4d7290141042b4e8625a96127826915a5b109852636ad0da753c9e1d5606a50480cd0c40f1f8b8d898235e571fe9357d9ec842bc4bba1827daaf4de06d71844d0057707966affffffff0280969800000000001976a9146963907531db72d0ed1a0cfb471ccb63923446f388ac80d6e34c000000001976a914f0688ba1c0d1ce182c7af6741e02658c7d4dfcd388ac000000000100000002c40297f730dd7b5a99567eb8d27b78758f607507c52292d02d4031895b52f2ff010000008b483045022100f7edfd4b0aac404e5bab4fd3889e0c6c41aa8d0e6fa122316f68eddd0a65013902205b09cc8b2d56e1cd1f7f2fafd60a129ed94504c4ac7bdc67b56fe67512658b3e014104732012cb962afa90d31b25d8fb0e32c94e513ab7a17805c14ca4c3423e18b4fb5d0e676841733cb83abaf975845c9f6f2a8097b7d04f4908b18368d6fc2d68ecffffffffca5065ff9617cbcba45eb23726df6498a9b9cafed4f54cbab9d227b0035ddefb000000008a473044022068010362a13c7f9919fa832b2dee4e788f61f6f5d344a7c2a0da6ae740605658022006d1af525b9a14a35c003b78b72bd59738cd676f845d1ff3fc25049e01003614014104732012cb962afa90d31b25d8fb0e32c94e513ab7a17805c14ca4c3423e18b4fb5d0e676841733cb83abaf975845c9f6f2a8097b7d04f4908b18368d6fc2d68ecffffffff01001ec4110200000043410469ab4181eceb28985b9b4e895c13fa5e68d85761b7eee311db5addef76fa8621865134a221bd01f28ec9999ee3e021e60766e9d1f3458c115fb28650605f11c9ac000000000100000001cdaf2f758e91c514655e2dc50633d1e4c84989f8aa90a0dbc883f0d23ed5c2fa010000008b48304502207ab51be6f12a1962ba0aaaf24a20e0b69b27a94fac5adf45aa7d2d18ffd9236102210086ae728b370e5329eead9accd880d0cb070aea0c96255fae6c4f1ddcce1fd56e014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff02404b4c00000000001976a9142b6ba7c9d796b75eef7942fc9288edd37c32f5c388ac002d3101000000001976a9141befba0cdc1ad56529371864d9f6cb042faa06b588ac000000000100000001b4a47603e71b61bc3326efd90111bf02d2f549b067f4c4a8fa183b57a0f800cb010000008a4730440220177c37f9a505c3f1a1f0ce2da777c339bd8339ffa02c7cb41f0a5804f473c9230220585b25a2ee80eb59292e52b987dad92acb0c64eced92ed9ee105ad153cdb12d001410443bd44f683467e549dae7d20d1d79cbdb6df985c6e9c029c8d0c6cb46cc1a4d3cf7923c5021b27f7a0b562ada113bc85d5fda5a1b41e87fe6e8802817cf69996ffffffff0280651406000000001976a9145505614859643ab7b547cd7f1f5e7e2a12322d3788ac00aa0271000000001976a914ea4720a7a52fc166c55ff2298e07baf70ae67e1b88ac00000000010000000586c62cd602d219bb60edb14a3e204de0705176f9022fe49a538054fb14abb49e010000008c493046022100f2bc2aba2534becbdf062eb993853a42bbbc282083d0daf9b4b585bd401aa8c9022100b1d7fd7ee0b95600db8535bbf331b19eed8d961f7a8e54159c53675d5f69df8c014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff03ad0e58ccdac3df9dc28a218bcf6f1997b0a93306faaa4b3a28ae83447b2179010000008b483045022100be12b2937179da88599e27bb31c3525097a07cdb52422d165b3ca2f2020ffcf702200971b51f853a53d644ebae9ec8f3512e442b1bcb6c315a5b491d119d10624c83014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff2acfcab629bbc8685792603762c921580030ba144af553d271716a95089e107b010000008b483045022100fa579a840ac258871365dd48cd7552f96c8eea69bd00d84f05b283a0dab311e102207e3c0ee9234814cfbb1b659b83671618f45abc1326b9edcc77d552a4f2a805c0014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffffdcdc6023bbc9944a658ddc588e61eacb737ddf0a3cd24f113b5a8634c517fcd2000000008b4830450221008d6df731df5d32267954bd7d2dda2302b74c6c2a6aa5c0ca64ecbabc1af03c75022010e55c571d65da7701ae2da1956c442df81bbf076cdbac25133f99d98a9ed34c014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffffe15557cd5ce258f479dfd6dc6514edf6d7ed5b21fcfa4a038fd69f06b83ac76e010000008b483045022023b3e0ab071eb11de2eb1cc3a67261b866f86bf6867d4558165f7c8c8aca2d86022100dc6e1f53a91de3efe8f63512850811f26284b62f850c70ca73ed5de8771fb451014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff01404b4c00000000001976a9142b6ba7c9d796b75eef7942fc9288edd37c32f5c388ac00000000010000000166d7577163c932b4f9690ca6a80b6e4eb001f0a2fa9023df5595602aae96ed8d000000008a4730440220262b42546302dfb654a229cefc86432b89628ff259dc87edd1154535b16a67e102207b4634c020a97c3e7bbd0d4d19da6aa2269ad9dded4026e896b213d73ca4b63f014104979b82d02226b3a4597523845754d44f13639e3bf2df5e82c6aab2bdc79687368b01b1ab8b19875ae3c90d661a3d0a33161dab29934edeb36aa01976be3baf8affffffff02404b4c00000000001976a9144854e695a02af0aeacb823ccbc272134561e0a1688ac40420f00000000001976a914abee93376d6b37b5c2940655a6fcaf1c8e74237988ac0000000001000000014e3f8ef2e91349a9059cb4f01e54ab2597c1387161d3da89919f7ea6acdbb371010000008c49304602210081f3183471a5ca22307c0800226f3ef9c353069e0773ac76bb580654d56aa523022100d4c56465bdc069060846f4fbf2f6b20520b2a80b08b168b31e66ddb9c694e240014104976c79848e18251612f8940875b2b08d06e6dc73b9840e8860c066b7e87432c477e9a59a453e71e6d76d5fe34058b800a098fc1740ce3012e8fc8a00c96af966ffffffff02c0e1e400000000001976a9144134e75a6fcb6042034aab5e18570cf1f844f54788ac404b4c00000000001976a9142b6ba7c9d796b75eef7942fc9288edd37c32f5c388ac00000000" + }, + { + "id": "000000005a4ded781e667e06ceefafb71410b511fe0d5adc3e5a27ecbec34ae6", + "transactions": 4, + "hex": "0100000075616236cc2126035fadb38deb65b9102cc2c41c09cdf29fc051906800000000fe7d5e12ef0ff901f6050211249919b1c0653771832b3a80c66cea42847f0ae1d4d26e49ffff001d00f0a4410401000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0804ffff001d029105ffffffff0100f2052a010000004341046d8709a041d34357697dfcb30a9d05900a6294078012bf3bb09c6f9b525f1d16d5503d7905db1ada9501446ea00728668fc5719aa80be2fdfc8a858a4dbdd4fbac00000000010000000255605dc6f5c3dc148b6da58442b0b2cd422be385eab2ebea4119ee9c268d28350000000049483045022100aa46504baa86df8a33b1192b1b9367b4d729dc41e389f2c04f3e5c7f0559aae702205e82253a54bf5c4f65b7428551554b2045167d6d206dfe6a2e198127d3f7df1501ffffffff55605dc6f5c3dc148b6da58442b0b2cd422be385eab2ebea4119ee9c268d2835010000004847304402202329484c35fa9d6bb32a55a70c0982f606ce0e3634b69006138683bcd12cbb6602200c28feb1e2555c3210f1dddb299738b4ff8bbe9667b68cb8764b5ac17b7adf0001ffffffff0200e1f505000000004341046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac00180d8f000000004341044a656f065871a353f216ca26cef8dde2f03e8c16202d2e8ad769f02032cb86a5eb5e56842e92e19141d60a01928f8dd2c875a390f67c1f6c94cfc617c0ea45afac0000000001000000025f9a06d3acdceb56be1bfeaa3e8a25e62d182fa24fefe899d1c17f1dad4c2028000000004847304402205d6058484157235b06028c30736c15613a28bdb768ee628094ca8b0030d4d6eb0220328789c9a2ec27ddaec0ad5ef58efded42e6ea17c2e1ce838f3d6913f5e95db601ffffffff5f9a06d3acdceb56be1bfeaa3e8a25e62d182fa24fefe899d1c17f1dad4c2028010000004a493046022100c45af050d3cea806cedd0ab22520c53ebe63b987b8954146cdca42487b84bdd6022100b9b027716a6b59e640da50a864d6dd8a0ef24c76ce62391fa3eabaf4d2886d2d01ffffffff0200e1f505000000004341046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac00180d8f000000004341046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac000000000100000002e2274e5fea1bf29d963914bd301aa63b64daaf8a3e88f119b5046ca5738a0f6b0000000048473044022016e7a727a061ea2254a6c358376aaa617ac537eb836c77d646ebda4c748aac8b0220192ce28bf9f2c06a6467e6531e27648d2b3e2e2bae85159c9242939840295ba501ffffffffe2274e5fea1bf29d963914bd301aa63b64daaf8a3e88f119b5046ca5738a0f6b010000004a493046022100b7a1a755588d4190118936e15cd217d133b0e4a53c3c15924010d5648d8925c9022100aaef031874db2114f2d869ac2de4ae53908fbfea5b2b1862e181626bb9005c9f01ffffffff0200e1f505000000004341044a656f065871a353f216ca26cef8dde2f03e8c16202d2e8ad769f02032cb86a5eb5e56842e92e19141d60a01928f8dd2c875a390f67c1f6c94cfc617c0ea45afac00180d8f000000004341046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac00000000" + }, + { + "id": "000000005a4ded781e667e06ceefafb71410b511fe0d5adc3e5a27ecbec34ae6", + "transactions": 4, + "hex": "0100000075616236cc2126035fadb38deb65b9102cc2c41c09cdf29fc051906800000000fe7d5e12ef0ff901f6050211249919b1c0653771832b3a80c66cea42847f0ae1d4d26e49ffff001d00f0a4410401000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0804ffff001d029105ffffffff0100f2052a010000004341046d8709a041d34357697dfcb30a9d05900a6294078012bf3bb09c6f9b525f1d16d5503d7905db1ada9501446ea00728668fc5719aa80be2fdfc8a858a4dbdd4fbac00000000010000000255605dc6f5c3dc148b6da58442b0b2cd422be385eab2ebea4119ee9c268d28350000000049483045022100aa46504baa86df8a33b1192b1b9367b4d729dc41e389f2c04f3e5c7f0559aae702205e82253a54bf5c4f65b7428551554b2045167d6d206dfe6a2e198127d3f7df1501ffffffff55605dc6f5c3dc148b6da58442b0b2cd422be385eab2ebea4119ee9c268d2835010000004847304402202329484c35fa9d6bb32a55a70c0982f606ce0e3634b69006138683bcd12cbb6602200c28feb1e2555c3210f1dddb299738b4ff8bbe9667b68cb8764b5ac17b7adf0001ffffffff0200e1f505000000004341046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac00180d8f000000004341044a656f065871a353f216ca26cef8dde2f03e8c16202d2e8ad769f02032cb86a5eb5e56842e92e19141d60a01928f8dd2c875a390f67c1f6c94cfc617c0ea45afac0000000001000000025f9a06d3acdceb56be1bfeaa3e8a25e62d182fa24fefe899d1c17f1dad4c2028000000004847304402205d6058484157235b06028c30736c15613a28bdb768ee628094ca8b0030d4d6eb0220328789c9a2ec27ddaec0ad5ef58efded42e6ea17c2e1ce838f3d6913f5e95db601ffffffff5f9a06d3acdceb56be1bfeaa3e8a25e62d182fa24fefe899d1c17f1dad4c2028010000004a493046022100c45af050d3cea806cedd0ab22520c53ebe63b987b8954146cdca42487b84bdd6022100b9b027716a6b59e640da50a864d6dd8a0ef24c76ce62391fa3eabaf4d2886d2d01ffffffff0200e1f505000000004341046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac00180d8f000000004341046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac000000000100000002e2274e5fea1bf29d963914bd301aa63b64daaf8a3e88f119b5046ca5738a0f6b0000000048473044022016e7a727a061ea2254a6c358376aaa617ac537eb836c77d646ebda4c748aac8b0220192ce28bf9f2c06a6467e6531e27648d2b3e2e2bae85159c9242939840295ba501ffffffffe2274e5fea1bf29d963914bd301aa63b64daaf8a3e88f119b5046ca5738a0f6b010000004a493046022100b7a1a755588d4190118936e15cd217d133b0e4a53c3c15924010d5648d8925c9022100aaef031874db2114f2d869ac2de4ae53908fbfea5b2b1862e181626bb9005c9f01ffffffff0200e1f505000000004341044a656f065871a353f216ca26cef8dde2f03e8c16202d2e8ad769f02032cb86a5eb5e56842e92e19141d60a01928f8dd2c875a390f67c1f6c94cfc617c0ea45afac00180d8f000000004341046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac00000000" + }, + { + "id": "000000000000dab0130bbcc991d3d7ae6b81aa6f50a798888dfe62337458dc45", + "transactions": 1, + "hex": "0100000079cda856b143d9db2c1caff01d1aecc8630d30625d10e8b4b8b0000000000000b50cc069d6a3e33e3ff84a5c41d9d3febe7c770fdcc96b2c3ff60abe184f196367291b4d4c86041b8fa45d630101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff08044c86041b020a02ffffffff0100f2052a01000000434104ecd3229b0571c3be876feaac0442a9f13c5a572742927af1dc623353ecf8c202225f64868137a18cdd85cbbb4c74fbccfd4f49639cf1bdc94a5672bb15ad5d4cac00000000" + }, + { + "id": "000000000000b731f2eef9e8c63173adfb07e41bd53eb0ef0a6b720d6cb6dea4", + "transactions": 7, + "hex": "0100000082bb869cf3a793432a66e826e05a6fc37469f8efb7421dc880670100000000007f16c5962e8bd963659c793ce370d95f093bc7e367117b3c30c1f8fdd0d9728776381b4d4c86041b554b85290701000000010000000000000000000000000000000000000000000000000000000000000000ffffffff07044c86041b0136ffffffff0100f2052a01000000434104eaafc2314def4ca98ac970241bcab022b9c1e1f4ea423a20f134c876f2c01ec0f0dd5b2e86e7168cefe0d81113c3807420ce13ad1357231a2252247d97a46a91ac000000000100000001bcad20a6a29827d1424f08989255120bf7f3e9e3cdaaa6bb31b0737fe048724300000000494830450220356e834b046cadc0f8ebb5a8a017b02de59c86305403dad52cd77b55af062ea10221009253cd6c119d4729b77c978e1e2aa19f5ea6e0e52b3f16e32fa608cd5bab753901ffffffff02008d380c010000001976a9142b4b8072ecbba129b6453c63e129e643207249ca88ac0065cd1d000000001976a9141b8dd13b994bcfc787b32aeadf58ccb3615cbd5488ac000000000100000003fdacf9b3eb077412e7a968d2e4f11b9a9dee312d666187ed77ee7d26af16cb0b000000008c493046022100ea1608e70911ca0de5af51ba57ad23b9a51db8d28f82c53563c56a05c20f5a87022100a8bdc8b4a8acc8634c6b420410150775eb7f2474f5615f7fccd65af30f310fbf01410465fdf49e29b06b9a1582287b6279014f834edc317695d125ef623c1cc3aaece245bd69fcad7508666e9c74a49dc9056d5fc14338ef38118dc4afae5fe2c585caffffffff309e1913634ecb50f3c4f83e96e70b2df071b497b8973a3e75429df397b5af83000000004948304502202bdb79c596a9ffc24e96f4386199aba386e9bc7b6071516e2b51dda942b3a1ed022100c53a857e76b724fc14d45311eac5019650d415c3abb5428f3aae16d8e69bec2301ffffffff2089e33491695080c9edc18a428f7d834db5b6d372df13ce2b1b0e0cbcb1e6c10000000049483045022100d4ce67c5896ee251c810ac1ff9ceccd328b497c8f553ab6e08431e7d40bad6b5022033119c0c2b7d792d31f1187779c7bd95aefd93d90a715586d73801d9b47471c601ffffffff0100714460030000001976a914c7b55141d097ea5df7a0ed330cf794376e53ec8d88ac0000000001000000045bf0e214aa4069a3e792ecee1e1bf0c1d397cde8dd08138f4b72a00681743447000000008b48304502200c45de8c4f3e2c1821f2fc878cba97b1e6f8807d94930713aa1c86a67b9bf1e40221008581abfef2e30f957815fc89978423746b2086375ca8ecf359c85c2a5b7c88ad01410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95ffffffffd669f7d7958d40fc59d2253d88e0f248e29b599c80bbcec344a83dda5f9aa72c000000008a473044022078124c8beeaa825f9e0b30bff96e564dd859432f2d0cb3b72d3d5d93d38d7e930220691d233b6c0f995be5acb03d70a7f7a65b6bc9bdd426260f38a1346669507a3601410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95fffffffff878af0d93f5229a68166cf051fd372bb7a537232946e0a46f53636b4dafdaa4000000008c493046022100c717d1714551663f69c3c5759bdbb3a0fcd3fab023abc0e522fe6440de35d8290221008d9cbe25bffc44af2b18e81c58eb37293fd7fe1c2e7b46fc37ee8c96c50ab1e201410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95ffffffff27f2b668859cd7f2f894aa0fd2d9e60963bcd07c88973f425f999b8cbfd7a1e2000000008c493046022100e00847147cbf517bcc2f502f3ddc6d284358d102ed20d47a8aa788a62f0db780022100d17b2d6fa84dcaf1c95d88d7e7c30385aecf415588d749afd3ec81f6022cecd701410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95ffffffff0100c817a8040000001976a914b6efd80d99179f4f4ff6f4dd0a007d018c385d2188ac000000000100000001834537b2f1ce8ef9373a258e10545ce5a50b758df616cd4356e0032554ebd3c4000000008b483045022100e68f422dd7c34fdce11eeb4509ddae38201773dd62f284e8aa9d96f85099d0b002202243bd399ff96b649a0fad05fa759d6a882f0af8c90cf7632c2840c29070aec20141045e58067e815c2f464c6a2a15f987758374203895710c2d452442e28496ff38ba8f5fd901dc20e29e88477167fe4fc299bf818fd0d9e1632d467b2a3d9503b1aaffffffff0280d7e636030000001976a914f34c3e10eb387efe872acb614c89e78bfca7815d88ac404b4c00000000001976a914a84e272933aaf87e1715d7786c51dfaeb5b65a6f88ac00000000010000000143ac81c8e6f6ef307dfe17f3d906d999e23e0189fda838c5510d850927e03ae7000000008c4930460221009c87c344760a64cb8ae6685a3eec2c1ac1bed5b88c87de51acd0e124f266c16602210082d07c037359c3a257b5c63ebd90f5a5edf97b2ac1c434b08ca998839f346dd40141040ba7e521fa7946d12edbb1d1e95a15c34bd4398195e86433c92b431cd315f455fe30032ede69cad9d1e1ed6c3c4ec0dbfced53438c625462afb792dcb098544bffffffff0240420f00000000001976a9144676d1b820d63ec272f1900d59d43bc6463d96f888ac40420f00000000001976a914648d04341d00d7968b3405c034adc38d4d8fb9bd88ac00000000010000000248cc917501ea5c55f4a8d2009c0567c40cfe037c2e71af017d0a452ff705e3f1000000008b483045022100bf5fdc86dc5f08a5d5c8e43a8c9d5b1ed8c65562e280007b52b133021acd9acc02205e325d613e555f772802bf413d36ba807892ed1a690a77811d3033b3de226e0a01410429fa713b124484cb2bd7b5557b2c0b9df7b2b1fee61825eadc5ae6c37a9920d38bfccdc7dc3cb0c47d7b173dbc9db8d37db0a33ae487982c59c6f8606e9d1791ffffffff41ed70551dd7e841883ab8f0b16bf04176b7d1480e4f0af9f3d4c3595768d068000000008b4830450221008513ad65187b903aed1102d1d0c47688127658c51106753fed0151ce9c16b80902201432b9ebcb87bd04ceb2de66035fbbaf4bf8b00d1cfe41f1a1f7338f9ad79d210141049d4cf80125bf50be1709f718c07ad15d0fc612b7da1f5570dddc35f2a352f0f27c978b06820edca9ef982c35fda2d255afba340068c5035552368bc7200c1488ffffffff0100093d00000000001976a9148edb68822f1ad580b043c7b3df2e400f8699eb4888ac00000000" + } +] diff --git a/test/fixtures/crypto.json b/test/fixtures/crypto.json index 0875eb7b4..aa66fec1c 100644 --- a/test/fixtures/crypto.json +++ b/test/fixtures/crypto.json @@ -1,55 +1,36 @@ { - "before": { - "secret": "vires is numeris", - "hex": [ - "0000000000000001", - "0101010101010101", - "FFFFFFFFFFFFFFFF", - "4c6f72656d20697073756d20646f6c6f722073697420616d65742c20636f6e73656374657475722061646970697363696e6720656c69742e20446f6e65632061742066617563696275732073617069656e2c2076656c20666163696c6973697320617263752e20536564207574206d61737361206e6962682e205574206d6f6c6c69732070756c76696e6172206d617373612e20557420756c6c616d636f7270657220646f6c6f7220656e696d2c20696e206d6f6c657374696520656e696d20636f6e64696d656e74756d2061632e20416c697175616d206572617420766f6c75747061742e204e756c6c6120736f64616c657320617420647569206e656320" - ] - }, - "after": { - "hash160": [ - "cdb00698f02afd929ffabea308340fa99ac2afa8", - "abaf1119f83e384210fe8e222eac76e2f0da39dc", - "f86221f5a1fca059a865c0b7d374dfa9d5f3aeb4", - "9763e6b367c363bd6b88a7b361c98e6beee243a5" - ], - "hash256": [ - "3ae5c198d17634e79059c2cd735491553d22c4e09d1d9fea3ecf214565df2284", - "728338d99f356175c4945ef5cccfa61b7b56143cbbf426ddd0e0fc7cfe8c3c23", - "752adad0a7b9ceca853768aebb6965eca126a62965f698a0c1bc43d83db632ad", - "033588797115feb3545052670cac2a46584ab3cb460de63756ee0275e66b5799" - ], - "ripemd160": [ - "8d1a05d1bc08870968eb8a81ad4393fd3aac6633", - "5825701b4b9767fd35063b286dca3582853e0630", - "cb760221600ed34337ca3ab70016b5f58c838120", - "cad8593dcdef12ee334c97bab9787f07b3f3a1a5" - ], - "sha1": [ - "cb473678976f425d6ec1339838f11011007ad27d", - "c0357a32ed1f6a03be92dd094476f7f1a2e214ec", - "be673e8a56eaa9d8c1d35064866701c11ef8e089", - "10d96fb43aca84e342206887bbeed3065d4e4344" - ], - "sha256": [ - "cd2662154e6d76b2b2b92e70c0cac3ccf534f9b74eb5b89819ec509083d00a50", - "04abc8821a06e5a30937967d11ad10221cb5ac3b5273e434f1284ee87129a061", - "12a3ae445661ce5dee78d0650d33362dec29c4f82af05e7e57fb595bbbacf0ca", - "a7fb8276035057ed6479c5f2305a96da100ac43f0ac10f277e5ab8c5457429da" - ], - "hmacsha256": [ - "73442dc8dd7f71a106a20fddd49d31856b1db12956c75070c8186b0b3eb71251", - "7204c72af7c73f5e84447a752dc8a2708f91b896f29de5fcf4b7f42f13a30c6e", - "a03c2ac6e9ca86678b5608a3d8682de46d17026f5fac4fd7147d2e5022061833", - "a780cd6e5c29cf11f756536ea5779992687c1b3b5e37f31b027a392d94e91fb8" - ], - "hmacsha512": [ - "4c0595aed1f5d066ea9f797727c060eb86cb55ff29d4d4fd2cd0ad3a012386763aea604c030619c79aa7fd8d03cda1b73a9ebd17906a3d2a350108d1a98b24ac", - "f80b90d63b804b3d2ab03b9bfb3ac94ee271352eb8bddfb6b4f5cf2a4fc9176acea35f517728e64943d1eb8af1e4674a114082c81bc8874d88b408b3b406d6a4", - "134cf60c30a5cd412c7a5cd6c3f878279e139b47c19550b7456fa137fbf90e580ae0a923a22052f42ec801ac658db32821e271161b563eac4926285ba6b8f410", - "7dee95aa3c462d3eb7ecb61536cb215e471d1fa73d8643a967905946e26c536588c5058abd5a049a22b987db95a7fb420f3bff12359dc53d03d7ce7df714e029" - ] - } + "valid": [ + { + "hex": "0000000000000001", + "hash160": "cdb00698f02afd929ffabea308340fa99ac2afa8", + "hash256": "3ae5c198d17634e79059c2cd735491553d22c4e09d1d9fea3ecf214565df2284", + "ripemd160": "8d1a05d1bc08870968eb8a81ad4393fd3aac6633", + "sha1": "cb473678976f425d6ec1339838f11011007ad27d", + "sha256": "cd2662154e6d76b2b2b92e70c0cac3ccf534f9b74eb5b89819ec509083d00a50" + }, + { + "hex": "0101010101010101", + "hash160": "abaf1119f83e384210fe8e222eac76e2f0da39dc", + "hash256": "728338d99f356175c4945ef5cccfa61b7b56143cbbf426ddd0e0fc7cfe8c3c23", + "ripemd160": "5825701b4b9767fd35063b286dca3582853e0630", + "sha1": "c0357a32ed1f6a03be92dd094476f7f1a2e214ec", + "sha256": "04abc8821a06e5a30937967d11ad10221cb5ac3b5273e434f1284ee87129a061" + }, + { + "hex": "ffffffffffffffff", + "hash160": "f86221f5a1fca059a865c0b7d374dfa9d5f3aeb4", + "hash256": "752adad0a7b9ceca853768aebb6965eca126a62965f698a0c1bc43d83db632ad", + "ripemd160": "cb760221600ed34337ca3ab70016b5f58c838120", + "sha1": "be673e8a56eaa9d8c1d35064866701c11ef8e089", + "sha256": "12a3ae445661ce5dee78d0650d33362dec29c4f82af05e7e57fb595bbbacf0ca" + }, + { + "hex": "4c6f72656d20697073756d20646f6c6f722073697420616d65742c20636f6e73656374657475722061646970697363696e6720656c69742e20446f6e65632061742066617563696275732073617069656e2c2076656c20666163696c6973697320617263752e20536564207574206d61737361206e6962682e205574206d6f6c6c69732070756c76696e6172206d617373612e20557420756c6c616d636f7270657220646f6c6f7220656e696d2c20696e206d6f6c657374696520656e696d20636f6e64696d656e74756d2061632e20416c697175616d206572617420766f6c75747061742e204e756c6c6120736f64616c657320617420647569206e656320", + "hash160": "9763e6b367c363bd6b88a7b361c98e6beee243a5", + "hash256": "033588797115feb3545052670cac2a46584ab3cb460de63756ee0275e66b5799", + "ripemd160": "cad8593dcdef12ee334c97bab9787f07b3f3a1a5", + "sha1": "10d96fb43aca84e342206887bbeed3065d4e4344", + "sha256": "a7fb8276035057ed6479c5f2305a96da100ac43f0ac10f277e5ab8c5457429da" + } + ] } \ No newline at end of file diff --git a/test/fixtures/mainnet_tx.json b/test/fixtures/mainnet_tx.json deleted file mode 100644 index f78f876a5..000000000 --- a/test/fixtures/mainnet_tx.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "prevTx": "0100000001e0214ebebb0fd3414d3fdc0dbf3b0f4b247a296cafc984558622c3041b0fcc9b010000008b48304502206becda98cecf7a545d1a640221438ff8912d9b505ede67e0138485111099f696022100ccd616072501310acba10feb97cecc918e21c8e92760cd35144efec7622938f30141040cd2d2ce17a1e9b2b3b2cb294d40eecf305a25b7e7bfdafae6bb2639f4ee399b3637706c3d377ec4ab781355add443ae864b134c5e523001c442186ea60f0eb8ffffffff03a0860100000000001976a91400ea3576c8fcb0bc8392f10e23a3425ae24efea888ac40420f00000000001976a91477890e8ec967c5fd4316c489d171fd80cf86997188acf07cd210000000001976a9146fb93c557ee62b109370fd9003e456917401cbfa88ac00000000", - "tx": "0100000001576bc3c3285dbdccd8c3cbd8c03e10d7f77a5c839c744f34c3eb00511059b80c000000006b483045022100a82a31607b837c1ae510ae3338d1d3c7cbd57c15e322ab6e5dc927d49bffa66302205f0db6c90f1fae3c8db4ebfa753d7da1b2343d653ce0331aa94ed375e6ba366c0121020497bfc87c3e97e801414fed6a0db4b8c2e01c46e2cf9dff59b406b52224a76bffffffff02409c0000000000001976a9143443bc45c560866cfeabf1d52f50a6ed358c69f288ac50c30000000000001976a91477890e8ec967c5fd4316c489d171fd80cf86997188ac00000000", - "bigTx": "010000000ee7b73e229790c1e79a02f0c871813b3cf26a4156c5b8d942e88b38fe8d3f43a0000000008c493046022100fd3d8fef44fb0962ba3f07bee1d4cafb84e60e38e6c7d9274504b3638a8d2f520221009fce009044e615b6883d4bf62e04c48f9fe236e19d644b082b2f0ae5c98e045c014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffff7bfc005f3880a606027c7cd7dd02a0f6a6572eeb84a91aa158311be13695a7ea010000008b483045022100e2e61c40f26e2510b76dc72ea2f568ec514fce185c719e18bca9caaef2b20e9e02207f1100fc79eb0584e970c7f18fb226f178951d481767b4092d50d13c50ccba8b014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffff0e0f8e6bf951fbb84d7d8ef833a1cbf5bb046ea7251973ac6e7661c755386ee3010000008a473044022048f1611e403710f248f7caf479965a6a5f63cdfbd9a714fef4ec1b68331ade1d022074919e79376c363d4575b2fc21513d5949471703efebd4c5ca2885e810eb1fa4014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffffe6f17f35bf9f0aa7a4242ab3e29edbdb74c5274bf263e53043dddb8045cb585b000000008b483045022100886c07cad489dfcf4b364af561835d5cf985f07adf8bd1d5bd6ddea82b0ce6b2022045bdcbcc2b5fc55191bb997039cf59ff70e8515c56b62f293a9add770ba26738014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffffe6f17f35bf9f0aa7a4242ab3e29edbdb74c5274bf263e53043dddb8045cb585b010000008a4730440220535d49b819fdf294d27d82aff2865ed4e18580f0ca9796d793f611cb43a44f47022019584d5e300c415f642e37ba2a814a1e1106b4a9b91dc2a30fb57ceafe041181014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffffd3051677216ea53baa2e6d7f6a75434ac338438c59f314801c8496d1e6d1bf6d010000008b483045022100bf612b0fa46f49e70ab318ca3458d1ed5f59727aa782f7fac5503f54d9b43a590220358d7ed0e3cee63a5a7e972d9fad41f825d95de2fd0c5560382468610848d489014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffff1e751ccc4e7d973201e9174ec78ece050ef2fadd6a108f40f76a9fa314979c31010000008b483045022006e263d5f73e05c48a603e3bd236e8314e5420721d5e9020114b93e8c9220e1102210099d3dead22f4a792123347a238c87e67b55b28a94a0bb7793144cc7ad94a0168014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffff25c4cf2c61743b3f4252d921d937cca942cf32e4f3fa4a544d0b26f014337084010000008a47304402207d6e87588be47bf2d97eaf427bdd992e9d6b306255711328aee38533366a88b50220623099595ae442cb77eaddb3f91753a4fc9df56fde69cfec584c7f97e05533c8014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffffecd93c87eb43c48481e6694904305349bdea94b01104579fa9f02bff66c89663010000008a473044022020f59498aee0cf82cb113768ef3cb721000346d381ff439adb4d405f791252510220448de723aa59412266fabbc689ec25dc94b1688c27a614982047513a80173514014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffffa1fdc0a79ff98d5b6154176e321c22f4f8450dbd950bd013ad31135f5604411e010000008b48304502210088167867f87327f9c0db0444267ff0b6a026eedd629d8f16fe44a34c18e706bf0220675c8baebf89930e2d6e4463adefc50922653af99375242e38f5ee677418738a014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffffb89e8249c3573b58bf1ec7433185452dd57ab8e1daab01c3cc6ddc8b66ad3de8000000008b4830450220073d50ac5ec8388d5b3906921f9368c31ad078c8e1fb72f26d36b533f35ee327022100c398b23e6692e11dca8a1b64aae2ff70c6a781ed5ee99181b56a2f583a967cd4014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffff45ee07e182084454dacfad1e61b04ffdf9c7b01003060a6c841a01f4fff8a5a0010000008b483045022100991d1bf60c41358f08b20e53718a24e05ac0608915df4f6305a5b47cb61e5da7022003f14fc1cc5b737e2c3279a4f9be1852b49dbb3d9d6cc4c8af6a666f600dced8014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffff4cba12549f1d70f8e60aea8b546c8357f7c099e7c7d9d8691d6ee16e7dfa3170010000008c493046022100f14e2b0ef8a8e206db350413d204bc0a5cd779e556b1191c2d30b5ec023cde6f022100b90b2d2bf256c98a88f7c3a653b93cec7d25bb6a517db9087d11dbd189e8851c014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffffa4b3aed39eb2a1dc6eae4609d9909724e211c153927c230d02bd33add3026959010000008b483045022100a8cebb4f1c58f5ba1af91cb8bd4a2ed4e684e9605f5a9dc8b432ed00922d289d0220251145d2d56f06d936fd0c51fa884b4a6a5fafd0c3318f72fb05a5c9aa372195014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffff0240d52303000000001976a914167c3e1f10cc3b691c73afbdb211e156e3e3f25c88ac15462e00000000001976a914290f7d617b75993e770e5606335fa0999a28d71388ac00000000" -} diff --git a/test/fixtures/transaction_builder.json b/test/fixtures/transaction_builder.json index 1845a703b..a1c5529f3 100644 --- a/test/fixtures/transaction_builder.json +++ b/test/fixtures/transaction_builder.json @@ -44,6 +44,28 @@ } ] }, + { + "description": "Transaction w/ scriptHash(pubKeyHash) -> pubKeyHash", + "txHex": "0100000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000085483045022100a3b254e1c10b5d039f36c05f323995d6e5a367d98dd78a13d5bbc3991b35720e022022fccea3897d594de0689601fbd486588d5bfa6915be2386db0397ee9a6e80b601210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f817981976a914751e76e8199196d454941c45d1b3a323f1433bd688acffffffff0110270000000000001976a914aa4d7985c57e011a8b3dd8e0e5a73aaef41629c588ac00000000", + "inputs": [ + { + "txId": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "vout": 0, + "signs": [ + { + "privKey": "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn", + "redeemScript": "OP_DUP OP_HASH160 751e76e8199196d454941c45d1b3a323f1433bd6 OP_EQUALVERIFY OP_CHECKSIG" + } + ] + } + ], + "outputs": [ + { + "script": "OP_DUP OP_HASH160 aa4d7985c57e011a8b3dd8e0e5a73aaef41629c5 OP_EQUALVERIFY OP_CHECKSIG", + "value": 10000 + } + ] + }, { "description": "Transaction w/ scriptHash(multisig 2-of-2) -> pubKeyHash", "txHex": "0100000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000fd1b0100483045022100b7a9bab60c4307349de9571ce0bd26ebb9d68d4e9ab3f9173e1f736f1390a04a022020931ff70e87033cdd94bdf434e865993b2258065c5c222a53f29d077bcfa4480147304402206d79ad83f1ab12fc9feee9e66412de842fcbf8de0632beb4433d469f24f0fb4e022079e6df186582f2686a3292bde8e50dac36cb9bec3991995fe331e1daef7df8a4014c8752410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a52aeffffffff0110270000000000001976a914faf1d99bf040ea9c7f8cc9f14ac6733ad75ce24688ac00000000", diff --git a/test/hdnode.js b/test/hdnode.js index a1cb97a14..342f0f5ff 100644 --- a/test/hdnode.js +++ b/test/hdnode.js @@ -1,7 +1,12 @@ +/* global describe, it */ +/* eslint-disable no-new */ + var assert = require('assert') var networks = require('../src/networks') var BigInteger = require('bigi') +var ECKey = require('../src/eckey') +var ECPubKey = require('../src/ecpubkey') var HDNode = require('../src/hdnode') var ecurve = require('ecurve') @@ -9,20 +14,50 @@ var curve = ecurve.getCurveByName('secp256k1') var fixtures = require('./fixtures/hdnode.json') -describe('HDNode', function() { - describe('Constructor', function() { +describe('HDNode', function () { + describe('Constructor', function () { var d = BigInteger.ONE var Q = curve.G.multiply(d) var chainCode = new Buffer(32) chainCode.fill(1) - it('calculates the publicKey from a BigInteger', function() { + it('calculates the publicKey from a BigInteger', function () { var hd = new HDNode(d, chainCode) assert(hd.pubKey.Q.equals(Q)) }) - it('only uses compressed points', function() { + it('allows initialization directly from an ECKey', function () { + var ek = new ECKey(d) + var hd = new HDNode(ek, chainCode) + + assert.equal(hd.privKey, ek) + }) + + it('allows initialization directly from an ECPubKey', function () { + var ek = new ECPubKey(Q) + var hd = new HDNode(ek, chainCode) + + assert.equal(hd.pubKey, ek) + }) + + it('throws if ECKey is not compressed', function () { + var ek = new ECKey(d, false) + + assert.throws(function () { + new HDNode(ek, chainCode) + }, /ECKey must be compressed/) + }) + + it('throws if ECPubKey is not compressed', function () { + var ek = new ECPubKey(Q, false) + + assert.throws(function () { + new HDNode(ek, chainCode) + }, /ECPubKey must be compressed/) + }) + + it('only uses compressed points', function () { var hd = new HDNode(Q, chainCode) var hdP = new HDNode(d, chainCode) @@ -30,41 +65,41 @@ describe('HDNode', function() { assert.strictEqual(hdP.pubKey.compressed, true) }) - it('has a default depth/index of 0', function() { + it('has a default depth/index of 0', function () { var hd = new HDNode(Q, chainCode) assert.strictEqual(hd.depth, 0) assert.strictEqual(hd.index, 0) }) - it('defaults to the bitcoin network', function() { + it('defaults to the bitcoin network', function () { var hd = new HDNode(Q, chainCode) assert.equal(hd.network, networks.bitcoin) }) - it('supports alternative networks', function() { + it('supports alternative networks', function () { var hd = new HDNode(Q, chainCode, networks.testnet) assert.equal(hd.network, networks.testnet) }) - it('throws when an invalid length chain code is given', function() { - assert.throws(function() { + it('throws when an invalid length chain code is given', function () { + assert.throws(function () { new HDNode(d, chainCode.slice(0, 20), networks.testnet) }, /Expected chainCode length of 32, got 20/) }) - it('throws when an unknown network is given', function() { - assert.throws(function() { + it('throws when an unknown network is given', function () { + assert.throws(function () { new HDNode(d, chainCode, {}) }, /Unknown BIP32 constants for network/) }) }) - describe('fromSeed*', function() { - fixtures.valid.forEach(function(f) { - it('calculates privKey and chainCode for ' + f.master.fingerprint, function() { + describe('fromSeed*', function () { + fixtures.valid.forEach(function (f) { + it('calculates privKey and chainCode for ' + f.master.fingerprint, function () { var network = networks[f.network] var hd = HDNode.fromSeedHex(f.master.seed, network) @@ -73,22 +108,22 @@ describe('HDNode', function() { }) }) - it('throws on low entropy seed', function() { - assert.throws(function() { + it('throws on low entropy seed', function () { + assert.throws(function () { HDNode.fromSeedHex('ffffffffff') }, /Seed should be at least 128 bits/) }) - it('throws on too high entropy seed', function() { - assert.throws(function() { + it('throws on too high entropy seed', function () { + assert.throws(function () { HDNode.fromSeedHex('ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff') }, /Seed should be at most 512 bits/) }) }) - describe('toBase58', function() { - fixtures.valid.forEach(function(f) { - it('exports ' + f.master.base58 + ' (public) correctly', function() { + describe('toBase58', function () { + fixtures.valid.forEach(function (f) { + it('exports ' + f.master.base58 + ' (public) correctly', function () { var network = networks[f.network] var hd = HDNode.fromSeedHex(f.master.seed, network).neutered() @@ -96,45 +131,36 @@ describe('HDNode', function() { }) }) - fixtures.valid.forEach(function(f) { - it('exports ' + f.master.base58Priv + ' (private) correctly', function() { + fixtures.valid.forEach(function (f) { + it('exports ' + f.master.base58Priv + ' (private) correctly', function () { var network = networks[f.network] var hd = HDNode.fromSeedHex(f.master.seed, network) assert.equal(hd.toBase58(), f.master.base58Priv) }) }) - - // FIXME: remove in 2.x.y - it('fails when there is no private key', function() { - var hd = HDNode.fromBase58(fixtures.valid[0].master.base58) - - assert.throws(function() { - hd.toBase58(true) - }, /Missing private key/) - }) }) - describe('fromBase58', function() { - fixtures.valid.forEach(function(f) { - it('imports ' + f.master.base58 + ' (public) correctly', function() { + describe('fromBase58', function () { + fixtures.valid.forEach(function (f) { + it('imports ' + f.master.base58 + ' (public) correctly', function () { var hd = HDNode.fromBase58(f.master.base58) assert.equal(hd.toBase58(), f.master.base58) }) }) - fixtures.valid.forEach(function(f) { - it('imports ' + f.master.base58Priv + ' (private) correctly', function() { + fixtures.valid.forEach(function (f) { + it('imports ' + f.master.base58Priv + ' (private) correctly', function () { var hd = HDNode.fromBase58(f.master.base58Priv) assert.equal(hd.toBase58(), f.master.base58Priv) }) }) - fixtures.invalid.fromBase58.forEach(function(f) { - it('throws on ' + f.string, function() { - assert.throws(function() { + fixtures.invalid.fromBase58.forEach(function (f) { + it('throws on ' + f.string, function () { + assert.throws(function () { var network = networks[f.network] HDNode.fromBase58(f.string, network) @@ -143,83 +169,29 @@ describe('HDNode', function() { }) }) - describe('fromBuffer/fromHex', function() { - fixtures.valid.forEach(function(f) { - it('imports ' + f.master.hex + ' (public) correctly', function() { - var hd = HDNode.fromHex(f.master.hex) - - assert.equal(hd.toBuffer().toString('hex'), f.master.hex) - }) - }) - - fixtures.valid.forEach(function(f) { - it('imports ' + f.master.hexPriv + ' (private) correctly', function() { - var hd = HDNode.fromHex(f.master.hexPriv) - - assert.equal(hd.toBuffer().toString('hex'), f.master.hexPriv) - }) - }) - - fixtures.invalid.fromBuffer.forEach(function(f) { - it('throws on ' + f.hex, function() { - assert.throws(function() { - HDNode.fromHex(f.hex) - }, new RegExp(f.exception)) - }) - }) - }) - - describe('toBuffer/toHex', function() { - fixtures.valid.forEach(function(f) { - it('exports ' + f.master.hex + ' (public) correctly', function() { - var hd = HDNode.fromSeedHex(f.master.seed).neutered() - - assert.equal(hd.toHex(), f.master.hex) - }) - }) - - fixtures.valid.forEach(function(f) { - it('exports ' + f.master.hexPriv + ' (private) correctly', function() { - var network = networks[f.network] - var hd = HDNode.fromSeedHex(f.master.seed, network) - - assert.equal(hd.toHex(), f.master.hexPriv) - }) - }) - - // FIXME: remove in 2.x.y - it('fails when there is no private key', function() { - var hd = HDNode.fromHex(fixtures.valid[0].master.hex) - - assert.throws(function() { - hd.toHex(true) - }, /Missing private key/) - }) - }) - - describe('getIdentifier', function() { + describe('getIdentifier', function () { var f = fixtures.valid[0] - it('returns the identifier for ' + f.master.fingerprint, function() { + it('returns the identifier for ' + f.master.fingerprint, function () { var hd = HDNode.fromBase58(f.master.base58) assert.equal(hd.getIdentifier().toString('hex'), f.master.identifier) }) }) - describe('getFingerprint', function() { + describe('getFingerprint', function () { var f = fixtures.valid[0] - it('returns the fingerprint for ' + f.master.fingerprint, function() { + it('returns the fingerprint for ' + f.master.fingerprint, function () { var hd = HDNode.fromBase58(f.master.base58) assert.equal(hd.getFingerprint().toString('hex'), f.master.fingerprint) }) }) - describe('getAddress', function() { - fixtures.valid.forEach(function(f) { - it('returns ' + f.master.address + ' for ' + f.master.fingerprint, function() { + describe('getAddress', function () { + fixtures.valid.forEach(function (f) { + it('returns ' + f.master.address + ' for ' + f.master.fingerprint, function () { var hd = HDNode.fromBase58(f.master.base58) assert.equal(hd.getAddress().toString(), f.master.address) @@ -227,10 +199,10 @@ describe('HDNode', function() { }) }) - describe('neutered', function() { + describe('neutered', function () { var f = fixtures.valid[0] - it('strips all private information', function() { + it('strips all private information', function () { var hd = HDNode.fromBase58(f.master.base58) var hdn = hd.neutered() @@ -242,8 +214,8 @@ describe('HDNode', function() { }) }) - describe('derive', function() { - function verifyVector(hd, network, v, depth) { + describe('derive', function () { + function verifyVector (hd, network, v, depth) { assert.equal(hd.privKey.toWIF(network), v.wif) assert.equal(hd.pubKey.toHex(), v.pubKey) assert.equal(hd.chainCode.toString('hex'), v.chainCode) @@ -256,16 +228,15 @@ describe('HDNode', function() { } } - fixtures.valid.forEach(function(f) { + fixtures.valid.forEach(function (f) { var network = networks[f.network] var hd = HDNode.fromSeedHex(f.master.seed, network) // FIXME: test data is only testing Private -> private for now - f.children.forEach(function(c, i) { - it(c.description + ' from ' + f.master.fingerprint, function() { + f.children.forEach(function (c, i) { + it(c.description + ' from ' + f.master.fingerprint, function () { if (c.hardened) { hd = hd.deriveHardened(c.m) - } else { hd = hd.derive(c.m) } @@ -275,7 +246,7 @@ describe('HDNode', function() { }) }) - it('works for Private -> public (neutered)', function() { + it('works for Private -> public (neutered)', function () { var f = fixtures.valid[1] var c = f.children[0] @@ -285,7 +256,7 @@ describe('HDNode', function() { assert.equal(child.toBase58(), c.base58) }) - it('works for Private -> public (neutered, hardened)', function() { + it('works for Private -> public (neutered, hardened)', function () { var f = fixtures.valid[0] var c = f.children[0] @@ -295,7 +266,7 @@ describe('HDNode', function() { assert.equal(child.toBase58(), c.base58) }) - it('works for Public -> public', function() { + it('works for Public -> public', function () { var f = fixtures.valid[1] var c = f.children[0] @@ -305,13 +276,13 @@ describe('HDNode', function() { assert.equal(child.toBase58(), c.base58) }) - it('throws on Public -> public (hardened)', function() { + it('throws on Public -> public (hardened)', function () { var f = fixtures.valid[0] var c = f.children[0] var master = HDNode.fromBase58(f.master.base58) - assert.throws(function() { + assert.throws(function () { master.deriveHardened(c.m) }, /Could not derive hardened child key/) }) diff --git a/test/integration/advanced.js b/test/integration/advanced.js index 482d316f8..3d2022851 100644 --- a/test/integration/advanced.js +++ b/test/integration/advanced.js @@ -1,34 +1,36 @@ +/* global describe, it */ + var assert = require('assert') var bitcoin = require('../../') var blockchain = new (require('cb-helloblock'))('testnet') -describe('bitcoinjs-lib (advanced)', function() { - it('can sign a Bitcoin message', function() { +describe('bitcoinjs-lib (advanced)', function () { + it('can sign a Bitcoin message', function () { var key = bitcoin.ECKey.fromWIF('5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss') var message = 'This is an example of a signed message.' - var signature = bitcoin.Message.sign(key, message) + var signature = bitcoin.message.sign(key, message) assert.equal(signature.toString('base64'), 'G9L5yLFjti0QTHhPyFrZCT1V/MMnBtXKmoiKDZ78NDBjERki6ZTQZdSMCtkgoNmp17By9ItJr8o7ChX0XxY91nk=') }) - it('can verify a Bitcoin message', function() { + it('can verify a Bitcoin message', function () { var address = '1HZwkjkeaoZfTSaJxDw6aKkxp45agDiEzN' var signature = 'HJLQlDWLyb1Ef8bQKEISzFbDAKctIlaqOpGbrk3YVtRsjmC61lpE5ErkPRUFtDKtx98vHFGUWlFhsh3DiW6N0rE' var message = 'This is an example of a signed message.' - assert(bitcoin.Message.verify(address, signature, message)) + assert(bitcoin.message.verify(address, signature, message)) }) - it('can create an OP_RETURN transaction', function(done) { + it('can create an OP_RETURN transaction', function (done) { this.timeout(20000) - var key = bitcoin.ECKey.fromWIF("L1uyy5qTuGrVXrmrsvHWHgVzW9kKdrp27wBC7Vs6nZDTF2BRUVwy") + var key = bitcoin.ECKey.fromWIF('L1uyy5qTuGrVXrmrsvHWHgVzW9kKdrp27wBC7Vs6nZDTF2BRUVwy') var address = key.pub.getAddress(bitcoin.networks.testnet).toString() - blockchain.addresses.__faucetWithdraw(address, 2e4, function(err) { + blockchain.addresses.__faucetWithdraw(address, 2e4, function (err) { if (err) return done(err) - blockchain.addresses.unspents(address, function(err, unspents) { + blockchain.addresses.unspents(address, function (err, unspents) { if (err) return done(err) var tx = new bitcoin.TransactionBuilder() @@ -43,11 +45,11 @@ describe('bitcoinjs-lib (advanced)', function() { var txBuilt = tx.build() - blockchain.transactions.propagate(txBuilt.toHex(), function(err) { + blockchain.transactions.propagate(txBuilt.toHex(), function (err) { if (err) return done(err) // check that the message was propagated - blockchain.transactions.get(txBuilt.getId(), function(err, transaction) { + blockchain.transactions.get(txBuilt.getId(), function (err, transaction) { if (err) return done(err) var actual = bitcoin.Transaction.fromHex(transaction.txHex) diff --git a/test/integration/basic.js b/test/integration/basic.js index 8e0b3d86a..069a535e0 100644 --- a/test/integration/basic.js +++ b/test/integration/basic.js @@ -1,11 +1,13 @@ +/* global describe, it */ + var assert = require('assert') var bigi = require('bigi') var bitcoin = require('../../') var crypto = require('crypto') var sinon = require('sinon') -describe('bitcoinjs-lib (basic)', function() { - it('can generate a random bitcoin address', sinon.test(function() { +describe('bitcoinjs-lib (basic)', function () { + it('can generate a random bitcoin address', sinon.test(function () { // for testing only this.mock(crypto).expects('randomBytes') .onCall(0).returns(new Buffer('zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz')) @@ -17,7 +19,7 @@ describe('bitcoinjs-lib (basic)', function() { assert.equal(address, '1F5VhMHukdnUES9kfXqzPzMeF1GPHKiF64') })) - it('can generate an address from a SHA256 hash', function() { + it('can generate an address from a SHA256 hash', function () { var hash = bitcoin.crypto.sha256('correct horse battery staple') var d = bigi.fromBuffer(hash) @@ -26,19 +28,19 @@ describe('bitcoinjs-lib (basic)', function() { assert.equal(key.pub.getAddress().toString(), '1C7zdTfnkzmr13HfA2vNm5SJYRK6nEKyq8') }) - it('can import an address via WIF', function() { + it('can import an address via WIF', function () { var key = bitcoin.ECKey.fromWIF('Kxr9tQED9H44gCmp6HAdmemAzU3n84H3dGkuWTKvE23JgHMW8gct') var address = key.pub.getAddress().toString() assert.equal(address, '19AAjaTUbRjQCMuVczepkoPswiZRhjtg31') }) - it('can create a Transaction', function() { - var key = bitcoin.ECKey.fromWIF("L1uyy5qTuGrVXrmrsvHWHgVzW9kKdrp27wBC7Vs6nZDTF2BRUVwy") + it('can create a Transaction', function () { + var key = bitcoin.ECKey.fromWIF('L1uyy5qTuGrVXrmrsvHWHgVzW9kKdrp27wBC7Vs6nZDTF2BRUVwy') var tx = new bitcoin.TransactionBuilder() - tx.addInput("aa94ab02c182214f090e99a0d57021caffd0f195a81c24602b1028b130b63e31", 0) - tx.addOutput("1Gokm82v6DmtwKEB8AiVhm82hyFSsEvBDK", 15000) + tx.addInput('aa94ab02c182214f090e99a0d57021caffd0f195a81c24602b1028b130b63e31', 0) + tx.addOutput('1Gokm82v6DmtwKEB8AiVhm82hyFSsEvBDK', 15000) tx.sign(0, key) assert.equal(tx.build().toHex(), '0100000001313eb630b128102b60241ca895f1d0ffca2170d5a0990e094f2182c102ab94aa000000006b483045022100aefbcf847900b01dd3e3debe054d3b6d03d715d50aea8525f5ea3396f168a1fb022013d181d05b15b90111808b22ef4f9ebe701caf2ab48db269691fdf4e9048f4f60121029f50f51d63b345039a290c94bffd3180c99ed659ff6ea6b1242bca47eb93b59fffffffff01983a0000000000001976a914ad618cf4333b3b248f9744e8e81db2964d0ae39788ac00000000') diff --git a/test/integration/crypto.js b/test/integration/crypto.js index 06e3cf18a..631809235 100644 --- a/test/integration/crypto.js +++ b/test/integration/crypto.js @@ -1,3 +1,5 @@ +/* global describe, it */ + var assert = require('assert') var async = require('async') var bigi = require('bigi') @@ -5,8 +7,8 @@ var bitcoin = require('../../') var blockchain = new (require('cb-helloblock'))('bitcoin') var crypto = require('crypto') -describe('bitcoinjs-lib (crypto)', function() { - it('can generate a single-key stealth address', function() { +describe('bitcoinjs-lib (crypto)', function () { + it('can generate a single-key stealth address', function () { var receiver = bitcoin.ECKey.fromWIF('5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss') // XXX: ephemeral, must be random (and secret to sender) to preserve privacy @@ -39,10 +41,10 @@ describe('bitcoinjs-lib (crypto)', function() { }) // TODO - it.skip('can generate a dual-key stealth address', function() {}) + it.skip('can generate a dual-key stealth address', function () {}) - it('can recover a parent private key from the parent\'s public key and a derived non-hardened child private key', function() { - function recoverParent(master, child) { + it("can recover a parent private key from the parent's public key and a derived non-hardened child private key", function () { + function recoverParent (master, child) { assert(!master.privKey, 'You already have the parent private key') assert(child.privKey, 'Missing child private key') @@ -87,33 +89,35 @@ describe('bitcoinjs-lib (crypto)', function() { assert.equal(recovered.toBase58(), master.toBase58()) }) - it('can recover a private key from duplicate R values', function() { + it('can recover a private key from duplicate R values', function () { var inputs = [ { - txId: "f4c16475f2a6e9c602e4a287f9db3040e319eb9ece74761a4b84bc820fbeef50", + txId: 'f4c16475f2a6e9c602e4a287f9db3040e319eb9ece74761a4b84bc820fbeef50', vout: 0 }, { - txId: "f4c16475f2a6e9c602e4a287f9db3040e319eb9ece74761a4b84bc820fbeef50", + txId: 'f4c16475f2a6e9c602e4a287f9db3040e319eb9ece74761a4b84bc820fbeef50', vout: 1 } ] - var txIds = inputs.map(function(x) { return x.txId }) + var txIds = inputs.map(function (x) { + return x.txId + }) // first retrieve the relevant transactions - blockchain.transactions.get(txIds, function(err, results) { + blockchain.transactions.get(txIds, function (err, results) { assert.ifError(err) var transactions = {} - results.forEach(function(tx) { + results.forEach(function (tx) { transactions[tx.txId] = bitcoin.Transaction.fromHex(tx.txHex) }) var tasks = [] // now we need to collect/transform a bit of data from the selected inputs - inputs.forEach(function(input) { + inputs.forEach(function (input) { var transaction = transactions[input.txId] var script = transaction.ins[input.vout].script assert(bitcoin.scripts.isPubKeyHashInput(script), 'Expected pubKeyHash script') @@ -121,8 +125,8 @@ describe('bitcoinjs-lib (crypto)', function() { var prevOutTxId = bitcoin.bufferutils.reverse(transaction.ins[input.vout].hash).toString('hex') var prevVout = transaction.ins[input.vout].index - tasks.push(function(callback) { - blockchain.transactions.get(prevOutTxId, function(err, result) { + tasks.push(function (callback) { + blockchain.transactions.get(prevOutTxId, function (err, result) { if (err) return callback(err) var prevOut = bitcoin.Transaction.fromHex(result.txHex) @@ -144,8 +148,9 @@ describe('bitcoinjs-lib (crypto)', function() { }) // finally, run the tasks, then on to the math - async.parallel(tasks, function(err) { - if (err) throw err + async.parallel(tasks, function (err) { + if (err) + throw err var n = bitcoin.ECKey.curve.n for (var i = 0; i < inputs.length; ++i) { @@ -170,8 +175,8 @@ describe('bitcoinjs-lib (crypto)', function() { // d1 = (s1 * k - z1) / r // d2 = (s2 * k - z2) / r var k = zz.multiply(ss.modInverse(n)).mod(n) - var d1 = (( s1.multiply(k).mod(n) ).subtract(z1).mod(n) ).multiply(rInv).mod(n) - var d2 = (( s2.multiply(k).mod(n) ).subtract(z2).mod(n) ).multiply(rInv).mod(n) + var d1 = ((s1.multiply(k).mod(n)).subtract(z1).mod(n)).multiply(rInv).mod(n) + var d2 = ((s2.multiply(k).mod(n)).subtract(z2).mod(n)).multiply(rInv).mod(n) // enforce matching private keys assert.equal(d1.toString(), d2.toString()) diff --git a/test/integration/multisig.js b/test/integration/multisig.js index 911affddb..fabaad998 100644 --- a/test/integration/multisig.js +++ b/test/integration/multisig.js @@ -1,9 +1,11 @@ +/* global describe, it */ + var assert = require('assert') var bitcoin = require('../../') var blockchain = new (require('cb-helloblock'))('testnet') -describe('bitcoinjs-lib (multisig)', function() { - it('can create a 2-of-3 multisig P2SH address', function() { +describe('bitcoinjs-lib (multisig)', function () { + it('can create a 2-of-3 multisig P2SH address', function () { var pubKeys = [ '026477115981fe981a6918a6297d9803c4dc04f328f22041bedff886bbc2962e01', '02c96db2302d19b43d4c69368babace7854cc84eb9e061cde51cfa77ca4a22b8b9', @@ -17,29 +19,33 @@ describe('bitcoinjs-lib (multisig)', function() { assert.equal(address, '36NUkt6FWUi3LAWBqWRdDmdTWbt91Yvfu7') }) - it('can spend from a 2-of-2 multsig P2SH address', function(done) { + it('can spend from a 2-of-2 multsig P2SH address', function (done) { this.timeout(20000) var privKeys = [ '91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx', '91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgww7vXtT' ].map(bitcoin.ECKey.fromWIF) - var pubKeys = privKeys.map(function(x) { return x.pub }) + var pubKeys = privKeys.map(function (x) { + return x.pub + }) var redeemScript = bitcoin.scripts.multisigOutput(2, pubKeys) // 2 of 2 var scriptPubKey = bitcoin.scripts.scriptHashOutput(redeemScript.getHash()) var address = bitcoin.Address.fromOutputScript(scriptPubKey, bitcoin.networks.testnet).toString() // Attempt to send funds to the source address - blockchain.addresses.__faucetWithdraw(address, 2e4, function(err) { + blockchain.addresses.__faucetWithdraw(address, 2e4, function (err) { if (err) return done(err) // get latest unspents from the address - blockchain.addresses.unspents(address, function(err, unspents) { + blockchain.addresses.unspents(address, function (err, unspents) { if (err) return done(err) // filter small unspents - unspents = unspents.filter(function(unspent) { return unspent.value > 1e4 }) + unspents = unspents.filter(function (unspent) { + return unspent.value > 1e4 + }) // use the oldest unspent var unspent = unspents.pop() @@ -52,16 +58,16 @@ describe('bitcoinjs-lib (multisig)', function() { txb.addOutput(targetAddress, 1e4) // sign w/ each private key - privKeys.forEach(function(privKey) { + privKeys.forEach(function (privKey) { txb.sign(0, privKey, redeemScript) }) // broadcast our transaction - blockchain.transactions.propagate(txb.build().toHex(), function(err) { + blockchain.transactions.propagate(txb.build().toHex(), function (err) { if (err) return done(err) // check that the funds (1e4 Satoshis) indeed arrived at the intended address - blockchain.addresses.summary(targetAddress, function(err, result) { + blockchain.addresses.summary(targetAddress, function (err, result) { if (err) return done(err) assert.equal(result.balance, 1e4) diff --git a/test/message.js b/test/message.js index 37ed1d872..e982a4533 100644 --- a/test/message.js +++ b/test/message.js @@ -1,65 +1,67 @@ +/* global describe, it */ + var assert = require('assert') +var message = require('../src/message') var networks = require('../src/networks') var Address = require('../src/address') var BigInteger = require('bigi') var ECKey = require('../src/eckey') -var Message = require('../src/message') var fixtures = require('./fixtures/message.json') -describe('Message', function() { - describe('magicHash', function() { - fixtures.valid.magicHash.forEach(function(f) { - it('produces the correct magicHash for \"' + f.message + '\" (' + f.network + ')', function() { +describe('message', function () { + describe('magicHash', function () { + fixtures.valid.magicHash.forEach(function (f) { + it('produces the correct magicHash for "' + f.message + '" (' + f.network + ')', function () { var network = networks[f.network] - var actual = Message.magicHash(f.message, network) + var actual = message.magicHash(f.message, network) assert.equal(actual.toString('hex'), f.magicHash) }) }) }) - describe('verify', function() { - it('accepts an Address object', function() { + describe('verify', function () { + it('accepts an Address object', function () { var f = fixtures.valid.verify[0] var network = networks[f.network] var address = Address.fromBase58Check(f.address) - assert(Message.verify(address, f.signature, f.message, network)) + assert(message.verify(address, f.signature, f.message, network)) }) - fixtures.valid.verify.forEach(function(f) { - it('verifies a valid signature for \"' + f.message + '\" (' + f.network + ')', function() { + fixtures.valid.verify.forEach(function (f) { + it('verifies a valid signature for "' + f.message + '" (' + f.network + ')', function () { var network = networks[f.network] - assert(Message.verify(f.address, f.signature, f.message, network)) + assert(message.verify(f.address, f.signature, f.message, network)) if (f.compressed) { - assert(Message.verify(f.compressed.address, f.compressed.signature, f.message, network)) + assert(message.verify(f.compressed.address, f.compressed.signature, f.message, network)) } }) }) - fixtures.invalid.verify.forEach(function(f) { - it(f.description, function() { - assert(!Message.verify(f.address, f.signature, f.message)) + fixtures.invalid.verify.forEach(function (f) { + it(f.description, function () { + assert(!message.verify(f.address, f.signature, f.message)) }) }) }) - describe('signing', function() { - fixtures.valid.signing.forEach(function(f) { - it(f.description, function() { + describe('signing', function () { + fixtures.valid.signing.forEach(function (f) { + it(f.description, function () { var network = networks[f.network] var privKey = new ECKey(new BigInteger(f.d), false) - var signature = Message.sign(privKey, f.message, network) + var signature = message.sign(privKey, f.message, network) assert.equal(signature.toString('base64'), f.signature) if (f.compressed) { var compressedPrivKey = new ECKey(new BigInteger(f.d)) - var compressedSignature = Message.sign(compressedPrivKey, f.message) + var compressedSignature = message.sign(compressedPrivKey, f.message) assert.equal(compressedSignature.toString('base64'), f.compressed.signature) } diff --git a/test/network.js b/test/network.js index b4cd89f77..aef09e0e2 100644 --- a/test/network.js +++ b/test/network.js @@ -1,3 +1,5 @@ +/* global describe, it, before, after */ + var assert = require('assert') var networks = require('../src/networks') var sinon = require('sinon') @@ -7,36 +9,36 @@ var Transaction = require('../src/transaction') var fixtures = require('./fixtures/network') -describe('networks', function() { +describe('networks', function () { var txToBuffer - before(function(){ - txToBuffer = sinon.stub(Transaction.prototype, "toBuffer") + before(function () { + txToBuffer = sinon.stub(Transaction.prototype, 'toBuffer') }) - after(function(){ + after(function () { Transaction.prototype.toBuffer.restore() }) - describe('constants', function() { - fixtures.valid.constants.forEach(function(f) { + describe('constants', function () { + fixtures.valid.constants.forEach(function (f) { var network = networks[f.network] - Object.keys(f.bip32).forEach(function(name) { + Object.keys(f.bip32).forEach(function (name) { var extb58 = f.bip32[name] - it('resolves ' + extb58 + ' to ' + f.network, function() { + it('resolves ' + extb58 + ' to ' + f.network, function () { assert.equal(HDNode.fromBase58(extb58, network).network, network) }) }) }) }) - describe('estimateFee', function() { - fixtures.valid.estimateFee.forEach(function(f) { - describe('(' + f.network + ')', function() { + describe('estimateFee', function () { + fixtures.valid.estimateFee.forEach(function (f) { + describe('(' + f.network + ')', function () { var network = networks[f.network] - it('calculates the fee correctly for ' + f.description, function() { + it('calculates the fee correctly for ' + f.description, function () { var buffer = new Buffer(f.txSize) txToBuffer.returns(buffer) diff --git a/test/script.js b/test/script.js index d8d080fbd..7017522e4 100644 --- a/test/script.js +++ b/test/script.js @@ -1,3 +1,6 @@ +/* global describe, it */ +/* eslint-disable no-new */ + var assert = require('assert') var opcodes = require('../src/opcodes') @@ -5,9 +8,9 @@ var Script = require('../src/script') var fixtures = require('./fixtures/script.json') -describe('Script', function() { - describe('constructor', function() { - it('accepts valid parameters', function() { +describe('Script', function () { + describe('constructor', function () { + it('accepts valid parameters', function () { var buffer = new Buffer([1]) var chunks = [1] var script = new Script(buffer, chunks) @@ -16,30 +19,32 @@ describe('Script', function() { assert.equal(script.chunks, chunks) }) - it('throws an error when input is not an array', function() { - assert.throws(function(){ new Script({}) }, /Expected Buffer, got/) + it('throws an error when input is not an array', function () { + assert.throws(function () { + new Script({}) + }, /Expected Buffer, got/) }) }) - describe('fromASM/toASM', function() { - fixtures.valid.forEach(function(f) { - it('decodes/encodes ' + f.description, function() { + describe('fromASM/toASM', function () { + fixtures.valid.forEach(function (f) { + it('decodes/encodes ' + f.description, function () { assert.equal(Script.fromASM(f.asm).toASM(), f.asm) }) }) }) - describe('fromHex/toHex', function() { - fixtures.valid.forEach(function(f) { - it('decodes/encodes ' + f.description, function() { + describe('fromHex/toHex', function () { + fixtures.valid.forEach(function (f) { + it('decodes/encodes ' + f.description, function () { assert.equal(Script.fromHex(f.hex).toHex(), f.hex) }) }) }) - describe('getHash', function() { - fixtures.valid.forEach(function(f) { - it('produces a HASH160 of \"' + f.asm + '\"', function() { + describe('getHash', function () { + fixtures.valid.forEach(function (f) { + it('produces a HASH160 of "' + f.asm + '"', function () { var script = Script.fromHex(f.hex) assert.equal(script.getHash().toString('hex'), f.hash) @@ -47,8 +52,8 @@ describe('Script', function() { }) }) - describe('fromChunks', function() { - it('should match expected behaviour', function() { + describe('fromChunks', function () { + it('should match expected behaviour', function () { var hash = new Buffer(32) hash.fill(0) @@ -62,17 +67,17 @@ describe('Script', function() { }) }) - describe('without', function() { + describe('without', function () { var hex = 'a914e8c300c87986efa94c37c0519929019ef86eb5b487' var script = Script.fromHex(hex) - it('should return a script without the given value', function() { + it('should return a script without the given value', function () { var subScript = script.without(opcodes.OP_HASH160) assert.equal(subScript.toHex(), '14e8c300c87986efa94c37c0519929019ef86eb5b487') }) - it('shouldnt mutate the original script', function() { + it('shouldnt mutate the original script', function () { var subScript = script.without(opcodes.OP_EQUAL) assert.notEqual(subScript.toHex(), hex) diff --git a/test/scripts.js b/test/scripts.js index 13ebe1ab6..ccfee0b13 100644 --- a/test/scripts.js +++ b/test/scripts.js @@ -1,3 +1,5 @@ +/* global describe, it */ + var assert = require('assert') var ops = require('../src/opcodes') var scripts = require('../src/scripts') @@ -7,16 +9,16 @@ var Script = require('../src/script') var fixtures = require('./fixtures/scripts.json') -describe('Scripts', function() { +describe('Scripts', function () { // TODO - describe.skip('isCanonicalPubKey', function() {}) - describe.skip('isCanonicalSignature', function() {}) + describe.skip('isCanonicalPubKey', function () {}) + describe.skip('isCanonicalSignature', function () {}) - describe('classifyInput', function() { - fixtures.valid.forEach(function(f) { + describe('classifyInput', function () { + fixtures.valid.forEach(function (f) { if (!f.scriptSig) return - it('classifies ' + f.scriptSig + ' as ' + f.type, function() { + it('classifies ' + f.scriptSig + ' as ' + f.type, function () { var script = Script.fromASM(f.scriptSig) var type = scripts.classifyInput(script) @@ -24,11 +26,11 @@ describe('Scripts', function() { }) }) - fixtures.valid.forEach(function(f) { + fixtures.valid.forEach(function (f) { if (!f.scriptSig) return if (!f.typeIncomplete) return - it('classifies incomplete ' + f.scriptSig + ' as ' + f.typeIncomplete, function() { + it('classifies incomplete ' + f.scriptSig + ' as ' + f.typeIncomplete, function () { var script = Script.fromASM(f.scriptSig) var type = scripts.classifyInput(script, true) @@ -37,11 +39,11 @@ describe('Scripts', function() { }) }) - describe('classifyOutput', function() { - fixtures.valid.forEach(function(f) { + describe('classifyOutput', function () { + fixtures.valid.forEach(function (f) { if (!f.scriptPubKey) return - it('classifies ' + f.scriptPubKey + ' as ' + f.type, function() { + it('classifies ' + f.scriptPubKey + ' as ' + f.type, function () { var script = Script.fromASM(f.scriptPubKey) var type = scripts.classifyOutput(script) @@ -50,19 +52,19 @@ describe('Scripts', function() { }) }) - ;['PubKey', 'PubKeyHash', 'ScriptHash', 'Multisig', 'NullData'].forEach(function(type) { + ;['PubKey', 'PubKeyHash', 'ScriptHash', 'Multisig', 'NullData'].forEach(function (type) { var inputFnName = 'is' + type + 'Input' var outputFnName = 'is' + type + 'Output' var inputFn = scripts[inputFnName] - var outputFn= scripts[outputFnName] + var outputFn = scripts[outputFnName] - describe('is' + type + 'Input', function() { - fixtures.valid.forEach(function(f) { + describe('is' + type + 'Input', function () { + fixtures.valid.forEach(function (f) { var expected = type.toLowerCase() === f.type if (inputFn && f.scriptSig) { - it('returns ' + expected + ' for ' + f.scriptSig, function() { + it('returns ' + expected + ' for ' + f.scriptSig, function () { var script = Script.fromASM(f.scriptSig) assert.equal(inputFn(script), expected) @@ -71,7 +73,7 @@ describe('Scripts', function() { if (f.typeIncomplete) { var expectedIncomplete = type.toLowerCase() === f.typeIncomplete - it('returns ' + expected + ' for ' + f.scriptSig, function() { + it('returns ' + expected + ' for ' + f.scriptSig, function () { var script = Script.fromASM(f.scriptSig) assert.equal(inputFn(script, true), expectedIncomplete) @@ -82,9 +84,9 @@ describe('Scripts', function() { if (!(inputFnName in fixtures.invalid)) return - fixtures.invalid[inputFnName].forEach(function(f) { + fixtures.invalid[inputFnName].forEach(function (f) { if (inputFn && f.scriptSig) { - it('returns false for ' + f.scriptSig, function() { + it('returns false for ' + f.scriptSig, function () { var script = Script.fromASM(f.scriptSig) assert.equal(inputFn(script), false) @@ -93,12 +95,12 @@ describe('Scripts', function() { }) }) - describe('is' + type + 'Output', function() { - fixtures.valid.forEach(function(f) { + describe('is' + type + 'Output', function () { + fixtures.valid.forEach(function (f) { var expected = type.toLowerCase() === f.type if (outputFn && f.scriptPubKey) { - it('returns ' + expected + ' for ' + f.scriptPubKey, function() { + it('returns ' + expected + ' for ' + f.scriptPubKey, function () { var script = Script.fromASM(f.scriptPubKey) assert.equal(outputFn(script), expected) @@ -108,9 +110,9 @@ describe('Scripts', function() { if (!(outputFnName in fixtures.invalid)) return - fixtures.invalid[outputFnName].forEach(function(f) { + fixtures.invalid[outputFnName].forEach(function (f) { if (outputFn && f.scriptPubKey) { - it('returns false for ' + f.scriptPubKey, function() { + it('returns false for ' + f.scriptPubKey, function () { var script = Script.fromASM(f.scriptPubKey) assert.equal(outputFn(script), false) @@ -120,11 +122,11 @@ describe('Scripts', function() { }) }) - describe('pubKeyInput', function() { - fixtures.valid.forEach(function(f) { + describe('pubKeyInput', function () { + fixtures.valid.forEach(function (f) { if (f.type !== 'pubkey') return - it('returns ' + f.scriptSig, function() { + it('returns ' + f.scriptSig, function () { var signature = new Buffer(f.signature, 'hex') var scriptSig = scripts.pubKeyInput(signature) @@ -133,11 +135,11 @@ describe('Scripts', function() { }) }) - describe('pubKeyOutput', function() { - fixtures.valid.forEach(function(f) { + describe('pubKeyOutput', function () { + fixtures.valid.forEach(function (f) { if (f.type !== 'pubkey') return - it('returns ' + f.scriptPubKey, function() { + it('returns ' + f.scriptPubKey, function () { var pubKey = ECPubKey.fromHex(f.pubKey) var scriptPubKey = scripts.pubKeyOutput(pubKey) @@ -146,13 +148,13 @@ describe('Scripts', function() { }) }) - describe('pubKeyHashInput', function() { - fixtures.valid.forEach(function(f) { + describe('pubKeyHashInput', function () { + fixtures.valid.forEach(function (f) { if (f.type !== 'pubkeyhash') return var pubKey = ECPubKey.fromHex(f.pubKey) - it('returns ' + f.scriptSig, function() { + it('returns ' + f.scriptSig, function () { var signature = new Buffer(f.signature, 'hex') var scriptSig = scripts.pubKeyHashInput(signature, pubKey) @@ -161,26 +163,26 @@ describe('Scripts', function() { }) }) - describe('pubKeyHashOutput', function() { - fixtures.valid.forEach(function(f) { + describe('pubKeyHashOutput', function () { + fixtures.valid.forEach(function (f) { if (f.type !== 'pubkeyhash') return var pubKey = ECPubKey.fromHex(f.pubKey) var address = pubKey.getAddress() - it('returns ' + f.scriptPubKey, function() { + it('returns ' + f.scriptPubKey, function () { var scriptPubKey = scripts.pubKeyHashOutput(address.hash) assert.equal(scriptPubKey.toASM(), f.scriptPubKey) }) }) }) - describe('multisigInput', function() { - fixtures.valid.forEach(function(f) { + describe('multisigInput', function () { + fixtures.valid.forEach(function (f) { if (f.type !== 'multisig') return - it('returns ' + f.scriptSig, function() { - var signatures = f.signatures.map(function(signature) { + it('returns ' + f.scriptSig, function () { + var signatures = f.signatures.map(function (signature) { return signature ? new Buffer(signature, 'hex') : ops.OP_0 }) @@ -189,53 +191,53 @@ describe('Scripts', function() { }) }) - fixtures.invalid.multisigInput.forEach(function(f) { + fixtures.invalid.multisigInput.forEach(function (f) { var pubKeys = f.pubKeys.map(ECPubKey.fromHex) var scriptPubKey = scripts.multisigOutput(pubKeys.length, pubKeys) - it('throws on ' + f.exception, function() { - var signatures = f.signatures.map(function(signature) { + it('throws on ' + f.exception, function () { + var signatures = f.signatures.map(function (signature) { return signature ? new Buffer(signature, 'hex') : ops.OP_0 }) - assert.throws(function() { + assert.throws(function () { scripts.multisigInput(signatures, scriptPubKey) }, new RegExp(f.exception)) }) }) }) - describe('multisigOutput', function() { - fixtures.valid.forEach(function(f) { + describe('multisigOutput', function () { + fixtures.valid.forEach(function (f) { if (f.type !== 'multisig') return var pubKeys = f.pubKeys.map(ECPubKey.fromHex) var scriptPubKey = scripts.multisigOutput(pubKeys.length, pubKeys) - it('returns ' + f.scriptPubKey, function() { + it('returns ' + f.scriptPubKey, function () { assert.equal(scriptPubKey.toASM(), f.scriptPubKey) }) }) - fixtures.invalid.multisigOutput.forEach(function(f) { + fixtures.invalid.multisigOutput.forEach(function (f) { var pubKeys = f.pubKeys.map(ECPubKey.fromHex) - it('throws on ' + f.exception, function() { - assert.throws(function() { + it('throws on ' + f.exception, function () { + assert.throws(function () { scripts.multisigOutput(f.m, pubKeys) }, new RegExp(f.exception)) }) }) }) - describe('scriptHashInput', function() { - fixtures.valid.forEach(function(f) { + describe('scriptHashInput', function () { + fixtures.valid.forEach(function (f) { if (f.type !== 'scripthash') return var redeemScript = Script.fromASM(f.redeemScript) var redeemScriptSig = Script.fromASM(f.redeemScriptSig) - it('returns ' + f.scriptSig, function() { + it('returns ' + f.scriptSig, function () { var scriptSig = scripts.scriptHashInput(redeemScriptSig, redeemScript) assert.equal(scriptSig.toASM(), f.scriptSig) @@ -243,13 +245,13 @@ describe('Scripts', function() { }) }) - describe('scriptHashOutput', function() { - fixtures.valid.forEach(function(f) { + describe('scriptHashOutput', function () { + fixtures.valid.forEach(function (f) { if (f.type !== 'scripthash') return var redeemScript = Script.fromASM(f.redeemScript) - it('returns ' + f.scriptPubKey, function() { + it('returns ' + f.scriptPubKey, function () { var scriptPubKey = scripts.scriptHashOutput(redeemScript.getHash()) assert.equal(scriptPubKey.toASM(), f.scriptPubKey) @@ -257,14 +259,14 @@ describe('Scripts', function() { }) }) - describe('nullDataOutput', function() { - fixtures.valid.forEach(function(f) { + describe('nullDataOutput', function () { + fixtures.valid.forEach(function (f) { if (f.type !== 'nulldata') return var data = new Buffer(f.data, 'hex') var scriptPubKey = scripts.nullDataOutput(data) - it('returns ' + f.scriptPubKey, function() { + it('returns ' + f.scriptPubKey, function () { assert.equal(scriptPubKey.toASM(), f.scriptPubKey) }) }) diff --git a/test/transaction.js b/test/transaction.js index c7fd4f87f..4a64493f1 100644 --- a/test/transaction.js +++ b/test/transaction.js @@ -1,26 +1,24 @@ +/* global describe, it, beforeEach */ + var assert = require('assert') -var scripts = require('../src/scripts') -var Address = require('../src/address') -var ECKey = require('../src/eckey') var Transaction = require('../src/transaction') var Script = require('../src/script') var fixtures = require('./fixtures/transaction') -describe('Transaction', function() { - function fromRaw(raw) { +describe('Transaction', function () { + function fromRaw (raw) { var tx = new Transaction() tx.version = raw.version tx.locktime = raw.locktime - raw.ins.forEach(function(txIn) { + raw.ins.forEach(function (txIn) { var txHash = new Buffer(txIn.hash, 'hex') var script if (txIn.data) { script = new Script(new Buffer(txIn.data, 'hex'), []) - } else if (txIn.script) { script = Script.fromASM(txIn.script) } @@ -28,34 +26,34 @@ describe('Transaction', function() { tx.addInput(txHash, txIn.index, txIn.sequence, script) }) - raw.outs.forEach(function(txOut) { + raw.outs.forEach(function (txOut) { tx.addOutput(Script.fromASM(txOut.script), txOut.value) }) return tx } - describe('fromBuffer/fromHex', function() { - fixtures.valid.forEach(function(f) { - it('imports ' + f.id + ' correctly', function() { + describe('fromBuffer/fromHex', function () { + fixtures.valid.forEach(function (f) { + it('imports ' + f.id + ' correctly', function () { var actual = Transaction.fromHex(f.hex) assert.deepEqual(actual.toHex(), f.hex) }) }) - fixtures.invalid.fromBuffer.forEach(function(f) { - it('throws on ' + f.exception, function() { - assert.throws(function() { + fixtures.invalid.fromBuffer.forEach(function (f) { + it('throws on ' + f.exception, function () { + assert.throws(function () { Transaction.fromHex(f.hex) }, new RegExp(f.exception)) }) }) }) - describe('toBuffer/toHex', function() { - fixtures.valid.forEach(function(f) { - it('exports ' + f.id + ' correctly', function() { + describe('toBuffer/toHex', function () { + fixtures.valid.forEach(function (f) { + it('exports ' + f.id + ' correctly', function () { var actual = fromRaw(f.raw) assert.deepEqual(actual.toHex(), f.hex) @@ -63,185 +61,108 @@ describe('Transaction', function() { }) }) - describe('addInput', function() { - // FIXME: not as pretty as could be - // Probably a bit representative of the API - var prevTxHash, prevTxId, prevTx - beforeEach(function() { + describe('addInput', function () { + var prevTxHash + beforeEach(function () { var f = fixtures.valid[0] - prevTx = Transaction.fromHex(f.hex) - prevTxHash = prevTx.getHash() - prevTxId = prevTx.getId() - }) - - it('accepts a transaction id', function() { - var tx = new Transaction() - tx.addInput(prevTxId, 0) - - assert.deepEqual(tx.ins[0].hash, prevTxHash) + prevTxHash = new Buffer(f.hash, 'hex') }) - it('accepts a transaction hash', function() { + it('accepts a transaction hash', function () { var tx = new Transaction() tx.addInput(prevTxHash, 0) assert.deepEqual(tx.ins[0].hash, prevTxHash) }) - it('accepts a Transaction object', function() { - var tx = new Transaction() - tx.addInput(prevTx, 0) - - assert.deepEqual(tx.ins[0].hash, prevTxHash) - }) - - it('returns an index', function() { + it('returns an index', function () { var tx = new Transaction() assert.equal(tx.addInput(prevTxHash, 0), 0) assert.equal(tx.addInput(prevTxHash, 0), 1) }) - it('defaults to DEFAULT_SEQUENCE', function() { + it('defaults to DEFAULT_SEQUENCE', function () { var tx = new Transaction() tx.addInput(prevTxHash, 0) assert.equal(tx.ins[0].sequence, Transaction.DEFAULT_SEQUENCE) }) - it('defaults to empty script', function() { + it('defaults to empty script', function () { var tx = new Transaction() tx.addInput(prevTxHash, 0) assert.equal(tx.ins[0].script, Script.EMPTY) }) - fixtures.invalid.addInput.forEach(function(f) { - it('throws on ' + f.exception, function() { + fixtures.invalid.addInput.forEach(function (f) { + it('throws on ' + f.exception, function () { var tx = new Transaction() var hash = new Buffer(f.hash, 'hex') - assert.throws(function() { + assert.throws(function () { tx.addInput(hash, f.index) }, new RegExp(f.exception)) }) }) }) - describe('addOutput', function() { - // FIXME: not as pretty as could be - // Probably a bit representative of the API - var destAddressB58, destAddress, destScript - beforeEach(function() { - destAddressB58 = '15mMHKL96tWAUtqF3tbVf99Z8arcmnJrr3' - destAddress = Address.fromBase58Check(destAddressB58) - destScript = destAddress.toOutputScript() - }) - - it('accepts an address string', function() { - var tx = new Transaction() - tx.addOutput(destAddressB58, 40000) - - assert.deepEqual(tx.outs[0].script, destScript) - assert.equal(tx.outs[0].value, 40000) - }) - - it('accepts an Address', function() { - var tx = new Transaction() - tx.addOutput(destAddress, 40000) - - assert.deepEqual(tx.outs[0].script, destScript) - assert.equal(tx.outs[0].value, 40000) - }) - - it('accepts a scriptPubKey', function() { - var tx = new Transaction() - tx.addOutput(destScript, 40000) + describe('addOutput', function () { + fixtures.valid.forEach(function (f) { + it('should add the outputs for ' + f.id + ' correctly', function () { + var tx = new Transaction() - assert.deepEqual(tx.outs[0].script, destScript) - assert.equal(tx.outs[0].value, 40000) - }) + f.raw.outs.forEach(function (txOut, i) { + var scriptPubKey = Script.fromASM(txOut.script) + var j = tx.addOutput(scriptPubKey, txOut.value) - it('returns an index', function() { - var tx = new Transaction() - assert.equal(tx.addOutput(destScript, 40000), 0) - assert.equal(tx.addOutput(destScript, 40000), 1) + assert.equal(i, j) + assert.equal(tx.outs[i].script, scriptPubKey) + assert.equal(tx.outs[i].value, txOut.value) + }) + }) }) }) - describe('clone', function() { - fixtures.valid.forEach(function(f) { + describe('clone', function () { + fixtures.valid.forEach(function (f) { var actual, expected - beforeEach(function() { + beforeEach(function () { expected = Transaction.fromHex(f.hex) actual = expected.clone() }) - it('should have value equality', function() { + it('should have value equality', function () { assert.deepEqual(actual, expected) }) - it('should not have reference equality', function() { + it('should not have reference equality', function () { assert.notEqual(actual, expected) }) }) }) - describe('getId', function() { - fixtures.valid.forEach(function(f) { - it('should return the id for ' + f.id, function() { + describe('getId', function () { + fixtures.valid.forEach(function (f) { + it('should return the id for ' + f.id, function () { var tx = Transaction.fromHex(f.hex) - var actual = tx.getId() - assert.equal(actual, f.id) + assert.equal(tx.getId(), f.id) }) }) }) - describe('getHash', function() { - fixtures.valid.forEach(function(f) { - it('should return the hash for ' + f.id, function() { + describe('getHash', function () { + fixtures.valid.forEach(function (f) { + it('should return the hash for ' + f.id, function () { var tx = Transaction.fromHex(f.hex) - var actual = tx.getHash().toString('hex') - assert.equal(actual, f.hash) + assert.deepEqual(tx.getHash().toString('hex'), f.hash) }) }) }) // TODO: // hashForSignature: [Function], - - // FIXME: remove in 2.x.y - describe('signInput/validateInput', function() { - it('works for multi-sig redeem script', function() { - var tx = new Transaction() - tx.addInput('d6f72aab8ff86ff6289842a0424319bf2ddba85dc7c52757912297f948286389', 0) - tx.addOutput('mrCDrCybB6J1vRfbwM5hemdJz73FwDBC8r', 1) - - var privKeys = [ - '5HpHagT65TZzG1PH3CSu63k8DbpvD8s5ip4nEB3kEsreAnchuDf', - '5HpHagT65TZzG1PH3CSu63k8DbpvD8s5ip4nEB3kEsreAvUcVfH' - ].map(function(wif) { - return ECKey.fromWIF(wif) - }) - var pubKeys = privKeys.map(function(eck) { return eck.pub }) - var redeemScript = scripts.multisigOutput(2, pubKeys) - - var signatures = privKeys.map(function(privKey) { - return tx.signInput(0, redeemScript, privKey) - }) - - var redeemScriptSig = scripts.multisigInput(signatures) - var scriptSig = scripts.scriptHashInput(redeemScriptSig, redeemScript) - tx.setInputScript(0, scriptSig) - - signatures.forEach(function(sig, i){ - assert(tx.validateInput(0, redeemScript, privKeys[i].pub, sig)) - }) - - var expected = '010000000189632848f99722915727c5c75da8db2dbf194342a0429828f66ff88fab2af7d600000000fd1b0100483045022100e5be20d440b2bbbc886161f9095fa6d0bca749a4e41d30064f30eb97adc7a1f5022061af132890d8e4e90fedff5e9365aeeb77021afd8ef1d5c114d575512e9a130a0147304402205054e38e9d7b5c10481b6b4991fde5704cd94d49e344406e3c2ce4d18a43bf8e022051d7ba8479865b53a48bee0cce86e89a25633af5b2918aa276859489e232f51c014c8752410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a52aeffffffff0101000000000000001976a914751e76e8199196d454941c45d1b3a323f1433bd688ac00000000' - assert.equal(tx.toHex(), expected) - }) - }) }) diff --git a/test/transaction_builder.js b/test/transaction_builder.js index cf14df6b0..350011be2 100644 --- a/test/transaction_builder.js +++ b/test/transaction_builder.js @@ -1,5 +1,8 @@ +/* global describe, it, beforeEach */ + var assert = require('assert') +var Address = require('../src/address') var BigInteger = require('bigi') var ECKey = require('../src/eckey') var Script = require('../src/script') @@ -8,8 +11,8 @@ var TransactionBuilder = require('../src/transaction_builder') var fixtures = require('./fixtures/transaction_builder') -function construct(txb, f, sign) { - f.inputs.forEach(function(input) { +function construct (txb, f, sign) { + f.inputs.forEach(function (input) { var prevTxScript if (input.prevTxScript) { @@ -19,15 +22,15 @@ function construct(txb, f, sign) { txb.addInput(input.txId, input.vout, input.sequence, prevTxScript) }) - f.outputs.forEach(function(output) { + f.outputs.forEach(function (output) { var script = Script.fromASM(output.script) txb.addOutput(script, output.value) }) if (sign === undefined || sign) { - f.inputs.forEach(function(input, index) { - input.signs.forEach(function(sign) { + f.inputs.forEach(function (input, index) { + input.signs.forEach(function (sign) { var privKey = ECKey.fromWIF(sign.privKey) var redeemScript @@ -41,22 +44,27 @@ function construct(txb, f, sign) { } // FIXME: add support for locktime/version in TransactionBuilder API - if (f.version !== undefined) txb.tx.version = f.version - if (f.locktime !== undefined) txb.tx.locktime = f.locktime + if (f.version !== undefined) { + txb.tx.version = f.version + } + + if (f.locktime !== undefined) { + txb.tx.locktime = f.locktime + } } -describe('TransactionBuilder', function() { +describe('TransactionBuilder', function () { var privAddress, privScript var prevTx, prevTxHash var privKey var txb - beforeEach(function() { + beforeEach(function () { txb = new TransactionBuilder() prevTx = new Transaction() - prevTx.addOutput('1BgGZ9tcN4rm9KBzDn7KprQz87SZ26SAMH', 0) - prevTx.addOutput('1cMh228HTCiwS8ZsaakH8A8wze1JR5ZsP', 1) + prevTx.addOutput(Address.fromBase58Check('1BgGZ9tcN4rm9KBzDn7KprQz87SZ26SAMH').toOutputScript(), 0) + prevTx.addOutput(Address.fromBase58Check('1cMh228HTCiwS8ZsaakH8A8wze1JR5ZsP').toOutputScript(), 1) prevTxHash = prevTx.getHash() privKey = new ECKey(BigInteger.ONE, false) @@ -64,8 +72,8 @@ describe('TransactionBuilder', function() { privScript = privAddress.toOutputScript() }) - describe('addInput', function() { - it('accepts a txHash, index [and sequence number]', function() { + describe('addInput', function () { + it('accepts a txHash, index [and sequence number]', function () { var vin = txb.addInput(prevTxHash, 1, 54) assert.equal(vin, 0) @@ -76,7 +84,7 @@ describe('TransactionBuilder', function() { assert.equal(txb.inputs[0].prevOutScript, undefined) }) - it('accepts a txHash, index [, sequence number and scriptPubKey]', function() { + it('accepts a txHash, index [, sequence number and scriptPubKey]', function () { var vin = txb.addInput(prevTxHash, 1, 54, prevTx.outs[1].script) assert.equal(vin, 0) @@ -87,7 +95,7 @@ describe('TransactionBuilder', function() { assert.equal(txb.inputs[0].prevOutScript, prevTx.outs[1].script) }) - it('accepts a prevTx, index [and sequence number]', function() { + it('accepts a prevTx, index [and sequence number]', function () { var vin = txb.addInput(prevTx, 1, 54) assert.equal(vin, 0) @@ -98,40 +106,67 @@ describe('TransactionBuilder', function() { assert.equal(txb.inputs[0].prevOutScript, prevTx.outs[1].script) }) - it('returns the input index', function() { + it('returns the input index', function () { assert.equal(txb.addInput(prevTxHash, 0), 0) assert.equal(txb.addInput(prevTxHash, 1), 1) }) - it('throws if SIGHASH_ALL has been used to sign any existing scriptSigs', function() { + it('throws if SIGHASH_ALL has been used to sign any existing scriptSigs', function () { txb.addInput(prevTxHash, 0) txb.sign(0, privKey) - assert.throws(function() { + assert.throws(function () { txb.addInput(prevTxHash, 0) }, /No, this would invalidate signatures/) }) }) - describe('addOutput', function() { - it('throws if SIGHASH_ALL has been used to sign any existing scriptSigs', function() { + describe('addOutput', function () { + it('accepts an address string and value', function () { + var vout = txb.addOutput(privAddress.toBase58Check(), 1000) + assert.equal(vout, 0) + + var txout = txb.tx.outs[0] + assert.deepEqual(txout.script, privScript) + assert.equal(txout.value, 1000) + }) + + it('accepts an Address object and value', function () { + var vout = txb.addOutput(privAddress, 1000) + assert.equal(vout, 0) + + var txout = txb.tx.outs[0] + assert.deepEqual(txout.script, privScript) + assert.equal(txout.value, 1000) + }) + + it('accepts a ScriptPubKey and value', function () { + var vout = txb.addOutput(privScript, 1000) + assert.equal(vout, 0) + + var txout = txb.tx.outs[0] + assert.deepEqual(txout.script, privScript) + assert.equal(txout.value, 1000) + }) + + it('throws if SIGHASH_ALL has been used to sign any existing scriptSigs', function () { txb.addInput(prevTxHash, 0) txb.addOutput(privScript, 2000) txb.sign(0, privKey) - assert.throws(function() { + assert.throws(function () { txb.addOutput(privScript, 9000) }, /No, this would invalidate signatures/) }) }) - describe('sign', function() { - fixtures.invalid.sign.forEach(function(f) { - it('throws on ' + f.exception + ' (' + f.description + ')', function() { + describe('sign', function () { + fixtures.invalid.sign.forEach(function (f) { + it('throws on ' + f.exception + ' (' + f.description + ')', function () { construct(txb, f, false) - f.inputs.forEach(function(input, index) { - input.signs.forEach(function(sign) { + f.inputs.forEach(function (input, index) { + input.signs.forEach(function (sign) { var privKey = ECKey.fromWIF(sign.privKey) var redeemScript @@ -141,9 +176,8 @@ describe('TransactionBuilder', function() { if (!sign.throws) { txb.sign(index, privKey, redeemScript, sign.hashType) - } else { - assert.throws(function() { + assert.throws(function () { txb.sign(index, privKey, redeemScript, sign.hashType) }, new RegExp(f.exception)) } @@ -153,9 +187,9 @@ describe('TransactionBuilder', function() { }) }) - describe('build', function() { - fixtures.valid.build.forEach(function(f) { - it('builds \"' + f.description + '\"', function() { + describe('build', function () { + fixtures.valid.build.forEach(function (f) { + it('builds "' + f.description + '"', function () { construct(txb, f) var tx = txb.build() @@ -163,35 +197,34 @@ describe('TransactionBuilder', function() { }) }) - fixtures.invalid.build.forEach(function(f) { - describe('for ' + (f.description || f.exception), function() { - beforeEach(function() { + fixtures.invalid.build.forEach(function (f) { + describe('for ' + (f.description || f.exception), function () { + beforeEach(function () { if (f.txHex) { var tx = Transaction.fromHex(f.txHex) txb = TransactionBuilder.fromTransaction(tx) - } else { construct(txb, f) } }) - it('throws', function() { - assert.throws(function() { + it('throws', function () { + assert.throws(function () { txb.build() }, new RegExp(f.exception)) }) if (f.alwaysThrows) return - it('doesn\'t throw if building incomplete', function() { + it("doesn't throw if building incomplete", function () { txb.buildIncomplete() }) }) }) }) - describe('fromTransaction', function() { - fixtures.valid.build.forEach(function(f) { - it('builds the correct TransactionBuilder for ' + f.description, function() { + describe('fromTransaction', function () { + fixtures.valid.build.forEach(function (f) { + it('builds the correct TransactionBuilder for ' + f.description, function () { var tx = Transaction.fromHex(f.txHex) var txb = TransactionBuilder.fromTransaction(tx) @@ -199,25 +232,25 @@ describe('TransactionBuilder', function() { }) }) - fixtures.invalid.fromTransaction.forEach(function(f) { - it('throws on ' + f.exception, function() { + fixtures.invalid.fromTransaction.forEach(function (f) { + it('throws on ' + f.exception, function () { var tx = Transaction.fromHex(f.txHex) - assert.throws(function() { + assert.throws(function () { TransactionBuilder.fromTransaction(tx) }, new RegExp(f.exception)) }) }) - it('works for the out-of-order P2SH multisig case', function() { + it('works for the out-of-order P2SH multisig case', function () { var privKeys = [ - "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgww7vXtT", - "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx" + '91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgww7vXtT', + '91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx' ].map(ECKey.fromWIF) - var redeemScript = Script.fromASM("OP_2 0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 04c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a OP_2 OP_CHECKMULTISIG") + var redeemScript = Script.fromASM('OP_2 0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 04c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a OP_2 OP_CHECKMULTISIG') - txb.addInput("4971f016798a167331bcbc67248313fbc444c6e92e4416efd06964425588f5cf", 0) - txb.addOutput("1BgGZ9tcN4rm9KBzDn7KprQz87SZ26SAMH", 10000) + txb.addInput('4971f016798a167331bcbc67248313fbc444c6e92e4416efd06964425588f5cf', 0) + txb.addOutput('1BgGZ9tcN4rm9KBzDn7KprQz87SZ26SAMH', 10000) txb.sign(0, privKeys[0], redeemScript) var tx = txb.buildIncomplete() diff --git a/test/wallet.js b/test/wallet.js deleted file mode 100644 index ccb5f2269..000000000 --- a/test/wallet.js +++ /dev/null @@ -1,700 +0,0 @@ -var assert = require('assert') -var bufferutils = require('../src/bufferutils') -var crypto = require('../src/crypto') -var networks = require('../src/networks') -var sinon = require('sinon') -var scripts = require('../src/scripts') - -var Address = require('../src/address') -var HDNode = require('../src/hdnode') -var Transaction = require('../src/transaction') -var TransactionBuilder = require('../src/transaction_builder') -var Wallet = require('../src/wallet') - -var fixtureTxes = require('./fixtures/mainnet_tx') -var fixtureTx1Hex = fixtureTxes.prevTx -var fixtureTx2Hex = fixtureTxes.tx - -function fakeTxHash(i) { - var hash = new Buffer(32) - hash.fill(i) - return hash -} - -function fakeTxId(i) { - var hash = fakeTxHash(i) - Array.prototype.reverse.call(hash) - return hash.toString('hex') -} - -describe('Wallet', function() { - var seed - beforeEach(function() { - seed = crypto.sha256("don't use a string seed like this in real life") - }) - - describe('constructor', function() { - var wallet - beforeEach(function() { - wallet = new Wallet(seed) - }) - - it('defaults to Bitcoin network', function() { - assert.equal(wallet.getMasterKey().network, networks.bitcoin) - }) - - it("generates m/0' as the main account", function() { - var mainAccount = wallet.getAccountZero() - assert.equal(mainAccount.index, 0 + HDNode.HIGHEST_BIT) - assert.equal(mainAccount.depth, 1) - }) - - it("generates m/0'/0 as the external account", function() { - var account = wallet.getExternalAccount() - assert.equal(account.index, 0) - assert.equal(account.depth, 2) - }) - - it("generates m/0'/1 as the internal account", function() { - var account = wallet.getInternalAccount() - assert.equal(account.index, 1) - assert.equal(account.depth, 2) - }) - - describe('when seed is not specified', function() { - it('generates a seed', function() { - var wallet = new Wallet() - assert(wallet.getMasterKey()) - }) - }) - - describe('constructor options', function() { - beforeEach(function() { - wallet = new Wallet(seed, networks.testnet) - }) - - it('uses the network if specified', function() { - assert.equal(wallet.getMasterKey().network, networks.testnet) - }) - }) - }) - - describe('newMasterKey', function() { - it('resets accounts', function() { - var wallet = new Wallet() - var oldAccountZero = wallet.getAccountZero() - var oldExternalAccount = wallet.getExternalAccount() - var oldInternalAccount = wallet.getInternalAccount() - - wallet.newMasterKey(seed) - assertNotEqual(wallet.getAccountZero(), oldAccountZero) - assertNotEqual(wallet.getExternalAccount(), oldExternalAccount) - assertNotEqual(wallet.getInternalAccount(), oldInternalAccount) - }) - - it('resets addresses', function() { - var wallet = new Wallet() - wallet.generateAddress() - wallet.generateChangeAddress() - var oldAddresses = wallet.addresses - var oldChangeAddresses = wallet.changeAddresses - assert.notDeepEqual(oldAddresses, []) - assert.notDeepEqual(oldChangeAddresses, []) - - wallet.newMasterKey(seed) - assert.deepEqual(wallet.addresses, []) - assert.deepEqual(wallet.changeAddresses, []) - }) - }) - - describe('generateAddress', function() { - it('generate receiving addresses', function() { - var wallet = new Wallet(seed, networks.testnet) - var expectedAddresses = [ - "n1GyUANZand9Kw6hGSV9837cCC9FFUQzQa", - "n2fiWrHqD6GM5GiEqkbWAc6aaZQp3ba93X" - ] - - assert.equal(wallet.generateAddress(), expectedAddresses[0]) - assert.equal(wallet.generateAddress(), expectedAddresses[1]) - assert.deepEqual(wallet.addresses, expectedAddresses) - }) - }) - - describe('generateChangeAddress', function() { - var wallet - beforeEach(function() { - wallet = new Wallet(seed) - }) - - it('generates change addresses', function() { - var wallet = new Wallet(seed, networks.testnet) - var expectedAddresses = ["mnXiDR4MKsFxcKJEZjx4353oXvo55iuptn"] - - assert.equal(wallet.generateChangeAddress(), expectedAddresses[0]) - assert.deepEqual(wallet.changeAddresses, expectedAddresses) - }) - }) - - describe('getPrivateKey', function() { - var wallet - beforeEach(function() { - wallet = new Wallet(seed) - }) - - it('returns the private key at the given index of external account', function() { - var wallet = new Wallet(seed, networks.testnet) - - assertEqual(wallet.getPrivateKey(0), wallet.getExternalAccount().derive(0).privKey) - assertEqual(wallet.getPrivateKey(1), wallet.getExternalAccount().derive(1).privKey) - }) - }) - - describe('getInternalPrivateKey', function() { - var wallet - beforeEach(function() { - wallet = new Wallet(seed) - }) - - it('returns the private key at the given index of internal account', function() { - var wallet = new Wallet(seed, networks.testnet) - - assertEqual(wallet.getInternalPrivateKey(0), wallet.getInternalAccount().derive(0).privKey) - assertEqual(wallet.getInternalPrivateKey(1), wallet.getInternalAccount().derive(1).privKey) - }) - }) - - describe('getPrivateKeyForAddress', function() { - var wallet - beforeEach(function() { - wallet = new Wallet(seed) - }) - - it('returns the private key for the given address', function() { - var wallet = new Wallet(seed, networks.testnet) - wallet.generateChangeAddress() - wallet.generateAddress() - wallet.generateAddress() - - assertEqual( - wallet.getPrivateKeyForAddress("n2fiWrHqD6GM5GiEqkbWAc6aaZQp3ba93X"), - wallet.getExternalAccount().derive(1).privKey - ) - assertEqual( - wallet.getPrivateKeyForAddress("mnXiDR4MKsFxcKJEZjx4353oXvo55iuptn"), - wallet.getInternalAccount().derive(0).privKey - ) - }) - - it('raises an error when address is not found', function() { - var wallet = new Wallet(seed, networks.testnet) - - assert.throws(function() { - wallet.getPrivateKeyForAddress("n2fiWrHqD6GM5GiEqkbWAc6aaZQp3ba93X") - }, /Unknown address. Make sure the address is from the keychain and has been generated/) - }) - }) - - describe('Unspent Outputs', function() { - var utxo, expectedOutputKey - var wallet - - beforeEach(function() { - utxo = { - "address" : "1AZpKpcfCzKDUeTFBQUL4MokQai3m3HMXv", - "confirmations": 1, - "index": 0, - "txId": fakeTxId(6), - "value": 20000, - "pending": false - } - }) - - describe('on construction', function() { - beforeEach(function() { - wallet = new Wallet(seed, networks.bitcoin) - wallet.setUnspentOutputs([utxo]) - }) - - it('matches the expected behaviour', function() { - var output = wallet.unspents[0] - - assert.equal(output.address, utxo.address) - assert.equal(output.value, utxo.value) - }) - }) - - describe('getBalance', function() { - beforeEach(function() { - var utxo1 = cloneObject(utxo) - utxo1.hash = fakeTxId(5) - - wallet = new Wallet(seed, networks.bitcoin) - wallet.setUnspentOutputs([utxo, utxo1]) - }) - - it('sums over utxo values', function() { - assert.equal(wallet.getBalance(), 40000) - }) - }) - - describe('getUnspentOutputs', function() { - beforeEach(function() { - wallet = new Wallet(seed, networks.bitcoin) - wallet.setUnspentOutputs([utxo]) - }) - - it('parses wallet unspents to the expected format', function() { - var outputs = wallet.getUnspentOutputs() - var output = outputs[0] - - assert.equal(utxo.address, output.address) - assert.equal(utxo.index, output.index) - assert.equal(utxo.value, output.value) - - // FIXME: remove in 2.0.0 - assert.equal(utxo.txId, output.hash) - assert.equal(utxo.pending, output.pending) - - // new in 2.0.0 - assert.equal(utxo.txId, output.txId) - assert.equal(utxo.confirmations, output.confirmations) - }) - - it("ignores spent unspents (outputs with 'spent' property)", function() { - var unspent = wallet.unspents[0] - unspent.pending = true - unspent.spent = true - assert.deepEqual(wallet.getUnspentOutputs(), []) - }) - }) - }) - - describe('setUnspentOutputs', function() { - var utxo - var expectedOutputKey - var wallet - - beforeEach(function() { - utxo = { - hash: fakeTxId(0), - index: 0, - address: '115qa7iPZqn6as57hxLL8E9VUnhmGQxKWi', - value: 500000 - } - - wallet = new Wallet(seed, networks.bitcoin) - }) - - it('matches the expected behaviour', function() { - wallet.setUnspentOutputs([utxo]) - - var output = wallet.unspents[0] - assert.equal(output.value, utxo.value) - assert.equal(output.address, utxo.address) - }) - - describe('required fields', function() { - ['index', 'address', 'hash', 'value'].forEach(function(field){ - it("throws an error when " + field + " is missing", function() { - delete utxo[field] - - assert.throws(function() { - wallet.setUnspentOutputs([utxo]) - }) - }) - }) - }) - }) - - describe('Process transaction', function() { - var wallet - beforeEach(function() { - wallet = new Wallet(seed) - }) - - var addresses - var tx - - beforeEach(function() { - addresses = [ - '115qa7iPZqn6as57hxLL8E9VUnhmGQxKWi', - '1Bu3bhwRmevHLAy1JrRB6AfcxfgDG2vXRd', - '1BBjuhF2jHxu7tPinyQGCuaNhEs6f5u59u' - ] - - tx = Transaction.fromHex(fixtureTx1Hex) - }) - - describe("processPendingTx", function() { - it("incoming: sets the pending flag on output", function() { - wallet.addresses = [addresses[0]] - wallet.processPendingTx(tx) - - verifyOutputAdded(0, true) - }) - - describe("when tx ins outpoint contains a known txhash:i", function() { - var spendTx - beforeEach(function() { - wallet.addresses = [addresses[0]] - wallet.processConfirmedTx(tx) - - spendTx = Transaction.fromHex(fixtureTx2Hex) - }) - - it("outgoing: sets the pending flag and 'spent' on output", function() { - var txIn = spendTx.ins[0] - var txInId = new Buffer(txIn.hash) - Array.prototype.reverse.call(txInId) - txInId = txInId.toString('hex') - - var unspent = wallet.unspents[0] - assert(!unspent.pending) - - wallet.processPendingTx(spendTx) - assert(unspent.pending) - assert(unspent.spent, true) - }) - }) - }) - - describe('processConfirmedTx', function() { - it('does not throw on scripts with no corresponding Address', function() { - var pubKey = wallet.getPrivateKey(0).pub - var script = scripts.pubKeyOutput(pubKey) - var tx2 = new Transaction() - - tx2.addInput(fakeTxHash(1), 0) - tx2.addOutput(script, 10000) - - wallet.processConfirmedTx(tx2) - }) - - describe("when tx outs contains an address owned by the wallet, an 'output' gets added to wallet.unspentMap", function() { - it("works for receive address", function() { - var totalOuts = outputCount() - - wallet.addresses = [addresses[0]] - wallet.processConfirmedTx(tx) - - assert.equal(outputCount(), totalOuts + 1) - verifyOutputAdded(0, false) - }) - - it("works for change address", function() { - var totalOuts = outputCount() - wallet.changeAddresses = [addresses[1]] - - wallet.processConfirmedTx(tx) - - assert.equal(outputCount(), totalOuts + 1) - verifyOutputAdded(1, false) - }) - - function outputCount() { - return Object.keys(wallet.unspentMap).length - } - }) - - describe("when tx ins contains a known txhash:i", function() { - var spendTx - beforeEach(function() { - wallet.addresses = [addresses[0]] // the address fixtureTx2 used as input - wallet.processConfirmedTx(tx) - - spendTx = Transaction.fromHex(fixtureTx2Hex) - }) - - it("does not add to wallet.unspentMap", function() { - wallet.processConfirmedTx(spendTx) - assert.deepEqual(wallet.unspentMap, {}) - }) - - it("deletes corresponding 'unspent'", function() { - var txIn = spendTx.ins[0] - var txInId = bufferutils.reverse(txIn.hash).toString('hex') - - var expected = txInId + ':' + txIn.index - assert(expected in wallet.unspentMap) - - wallet.processConfirmedTx(spendTx) - assert(!(expected in wallet.unspentMap)) - }) - }) - }) - - it("does nothing when none of the involved addresses belong to the wallet", function() { - wallet.processConfirmedTx(tx) - assert.deepEqual(wallet.unspentMap, {}) - }) - - - function verifyOutputAdded(index, pending) { - var txOut = tx.outs[index] - - var key = tx.getId() + ":" + index - var output = wallet.unspentMap[key] - assert.deepEqual(output.txHash, tx.getHash()) - assert.equal(output.value, txOut.value) - assert.equal(output.pending, pending) - - var txOutAddress = Address.fromOutputScript(txOut.script).toString() - assert.equal(output.address, txOutAddress) - } - }) - - describe('createTx', function() { - var wallet - var address1, address2 - var to, value - - beforeEach(function() { - to = 'mt7MyTVVEWnbwpF5hBn6fgnJcv95Syk2ue' - value = 500000 - - address1 = "n1GyUANZand9Kw6hGSV9837cCC9FFUQzQa" - address2 = "n2fiWrHqD6GM5GiEqkbWAc6aaZQp3ba93X" - - // set up 3 utxos - var utxos = [ - { - "txId": fakeTxId(1), - "index": 0, - "address": address1, - "value": 400000 // not enough for value - }, - { - "txId": fakeTxId(2), - "index": 1, - "address": address1, - "value": 500000 // enough for only value - }, - { - "txId": fakeTxId(3), - "index": 0, - "address" : address2, - "value": 510000 // enough for value and fee - } - ] - - wallet = new Wallet(seed, networks.testnet) - wallet.setUnspentOutputs(utxos) - wallet.generateAddress() - wallet.generateAddress() - }) - - describe('transaction fee', function() { - it('allows fee to be specified', function() { - var fee = 30000 - var tx = wallet.createTx(to, value, { fixedFee: fee }) - - assert.equal(getFee(wallet, tx), fee) - }) - - it('allows fee to be set to zero', function() { - value = 510000 - var fee = 0 - var tx = wallet.createTx(to, value, { fixedFee: fee }) - - assert.equal(getFee(wallet, tx), fee) - }) - - it('does not overestimate fees when network has dustSoftThreshold', function() { - var utxo = { - txId: fakeTxId(0), - index: 0, - address: "LeyySKbQrRRwodKEj1W4a8y3YQupPLw5os", - value: 500000 - } - - var wallet = new Wallet(seed, networks.litecoin) - wallet.setUnspentOutputs([utxo]) - wallet.generateAddress() - - value = 200000 - var tx = wallet.createTx(utxo.address, value) - - assert.equal(getFee(wallet, tx), 100000) - }) - - function getFee(wallet, tx) { - var inputValue = tx.ins.reduce(function(accum, input) { - var txId = bufferutils.reverse(input.hash).toString('hex') - - return accum + wallet.unspentMap[txId + ':' + input.index].value - }, 0) - - return tx.outs.reduce(function(accum, output) { - return accum - output.value - }, inputValue) - } - }) - - describe('choosing utxo', function() { - it('takes fees into account', function() { - var tx = wallet.createTx(to, value) - - assert.equal(tx.ins.length, 1) - assert.deepEqual(tx.ins[0].hash, fakeTxHash(3)) - assert.equal(tx.ins[0].index, 0) - }) - - it('uses confirmed outputs', function() { - var tx2 = new Transaction() - tx2.addInput(fakeTxId(4), 0) - tx2.addOutput(address2, 530000) - - wallet.processConfirmedTx(tx2) - var tx = wallet.createTx(to, value) - - assert.equal(tx.ins.length, 1) - assert.deepEqual(tx.ins[0].hash, tx2.getHash()) - assert.equal(tx.ins[0].index, 0) - }) - - it('ignores pending outputs', function() { - var tx2 = new Transaction() - tx2.addInput(fakeTxId(4), 0) - tx2.addOutput(address2, 530000) - - wallet.processPendingTx(tx2) - var tx = wallet.createTx(to, value) - - assert.equal(tx.ins.length, 1) - assert.deepEqual(tx.ins[0].hash, fakeTxHash(3)) - assert.equal(tx.ins[0].index, 0) - }) - }) - - describe('changeAddress', function() { - it('should allow custom changeAddress', function() { - var changeAddress = 'mfrFjnKZUvTcvdAK2fUX5D8v1Epu5H8JCk' - var fromValue = 510000 - var toValue = fromValue / 2 - var fee = 1e3 - - var tx = wallet.createTx(to, toValue, { - fixedFee: fee, - changeAddress: changeAddress - }) - assert.equal(tx.outs.length, 2) - - var outAddress0 = Address.fromOutputScript(tx.outs[0].script, networks.testnet) - var outAddress1 = Address.fromOutputScript(tx.outs[1].script, networks.testnet) - - assert.equal(outAddress0.toString(), to) - assert.equal(tx.outs[0].value, toValue) - - assert.equal(outAddress1.toString(), changeAddress) - assert.equal(tx.outs[1].value, fromValue - (toValue + fee)) - }) - }) - - describe('transaction outputs', function() { - it('includes the specified address and amount', function() { - var tx = wallet.createTx(to, value) - - assert.equal(tx.outs.length, 1) - var out = tx.outs[0] - var outAddress = Address.fromOutputScript(out.script, networks.testnet) - - assert.equal(outAddress.toString(), to) - assert.equal(out.value, value) - }) - - describe('change', function() { - it('uses the last change address if there is any', function() { - var fee = 0 - wallet.generateChangeAddress() - wallet.generateChangeAddress() - var tx = wallet.createTx(to, value, { fixedFee: fee }) - - assert.equal(tx.outs.length, 2) - var out = tx.outs[1] - var outAddress = Address.fromOutputScript(out.script, networks.testnet) - - assert.equal(outAddress.toString(), wallet.changeAddresses[1]) - assert.equal(out.value, 10000) - }) - - it('generates a change address if there is not any', function() { - var fee = 0 - assert.equal(wallet.changeAddresses.length, 0) - - var tx = wallet.createTx(to, value, { fixedFee: fee }) - - assert.equal(wallet.changeAddresses.length, 1) - var out = tx.outs[1] - var outAddress = Address.fromOutputScript(out.script, networks.testnet) - - assert.equal(outAddress.toString(), wallet.changeAddresses[0]) - assert.equal(out.value, 10000) - }) - - it('skips change if it is not above dust threshold', function() { - var tx1 = wallet.createTx(to, value - 546) - assert.equal(tx1.outs.length, 1) - - var tx2 = wallet.createTx(to, value - 547) - assert.equal(tx2.outs.length, 2) - }) - }) - }) - - describe('signing', function() { - afterEach(function() { - TransactionBuilder.prototype.sign.restore() - }) - - it('signs the inputs with respective keys', function() { - var fee = 30000 - sinon.spy(TransactionBuilder.prototype, "sign") - - wallet.createTx(to, value, { fixedFee: fee }) - - var priv1 = wallet.getPrivateKeyForAddress(address1) - var priv2 = wallet.getPrivateKeyForAddress(address2) - - // FIXME: boo (required) side effects - priv1.pub.Q.affineX, priv2.pub.Q.affineX - - assert(TransactionBuilder.prototype.sign.calledWith(0, priv2)) - assert(TransactionBuilder.prototype.sign.calledWith(1, priv1)) - }) - }) - - describe('when value is below dust threshold', function() { - it('throws an error', function() { - var value = 546 - - assert.throws(function() { - wallet.createTx(to, value) - }, /546 must be above dust threshold \(546 Satoshis\)/) - }) - }) - - describe('when there is not enough money', function() { - it('throws an error', function() { - var value = 1400001 - - assert.throws(function() { - wallet.createTx(to, value) - }, /Not enough funds \(incl. fee\): 1410000 < 1410001/) - }) - }) - }) - - function assertEqual(obj1, obj2){ - assert.equal(obj1.toString(), obj2.toString()) - } - - function assertNotEqual(obj1, obj2){ - assert.notEqual(obj1.toString(), obj2.toString()) - } - - // quick and dirty: does not deal with functions on object - function cloneObject(obj){ - return JSON.parse(JSON.stringify(obj)) - } -})