Merge pull request #364 from bitcoinjs/standard

use standardjs formatting
This commit is contained in:
Daniel Cousens 2015-02-25 14:46:29 +11:00
commit 7513e73f74
43 changed files with 1256 additions and 1200 deletions

View file

@ -5,7 +5,8 @@ node_js:
- "0.11" - "0.11"
- "0.10" - "0.10"
env: env:
- TEST_SUITE=unit
- TEST_SUITE=integration
- TEST_SUITE=coveralls - TEST_SUITE=coveralls
- TEST_SUITE=integration
- TEST_SUITE=standard
- TEST_SUITE=unit
script: "npm run-script $TEST_SUITE" script: "npm run-script $TEST_SUITE"

View file

@ -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
}

View file

@ -36,7 +36,7 @@
"coverage": "istanbul cover _mocha -- test/*.js", "coverage": "istanbul cover _mocha -- test/*.js",
"coveralls": "npm run-script coverage && coveralls < coverage/lcov.info", "coveralls": "npm run-script coverage && coveralls < coverage/lcov.info",
"integration": "mocha --reporter list test/integration/*.js", "integration": "mocha --reporter list test/integration/*.js",
"jshint": "jshint --config jshint.json src/*.js ; true", "standard": "standard",
"test": "npm run-script unit", "test": "npm run-script unit",
"unit": "istanbul test mocha -- --reporter list test/*.js" "unit": "istanbul test mocha -- --reporter list test/*.js"
}, },
@ -57,9 +57,9 @@
"cb-helloblock": "^0.4.10", "cb-helloblock": "^0.4.10",
"coveralls": "^2.11.2", "coveralls": "^2.11.2",
"istanbul": "^0.3.5", "istanbul": "^0.3.5",
"jshint": "^2.5.11",
"mocha": "^2.1.0", "mocha": "^2.1.0",
"mocha-lcov-reporter": "0.0.1", "mocha-lcov-reporter": "0.0.1",
"sinon": "^1.12.2" "sinon": "^1.12.2",
"standard": "^2.7.3"
} }
} }

View file

@ -4,7 +4,7 @@ var typeForce = require('typeforce')
var networks = require('./networks') var networks = require('./networks')
var scripts = require('./scripts') var scripts = require('./scripts')
function findScriptTypeByVersion(version) { function findScriptTypeByVersion (version) {
for (var networkName in networks) { for (var networkName in networks) {
var network = networks[networkName] var network = networks[networkName]
@ -13,7 +13,7 @@ function findScriptTypeByVersion(version) {
} }
} }
function Address(hash, version) { function Address (hash, version) {
typeForce('Buffer', hash) typeForce('Buffer', hash)
assert.strictEqual(hash.length, 20, 'Invalid hash length') assert.strictEqual(hash.length, 20, 'Invalid hash length')
@ -23,7 +23,7 @@ function Address(hash, version) {
this.version = version this.version = version
} }
Address.fromBase58Check = function(string) { Address.fromBase58Check = function (string) {
var payload = base58check.decode(string) var payload = base58check.decode(string)
var version = payload.readUInt8(0) var version = payload.readUInt8(0)
var hash = payload.slice(1) var hash = payload.slice(1)
@ -31,7 +31,7 @@ Address.fromBase58Check = function(string) {
return new Address(hash, version) return new Address(hash, version)
} }
Address.fromOutputScript = function(script, network) { Address.fromOutputScript = function (script, network) {
network = network || networks.bitcoin network = network || networks.bitcoin
if (scripts.isPubKeyHashOutput(script)) return new Address(script.chunks[2], network.pubKeyHash) if (scripts.isPubKeyHashOutput(script)) return new Address(script.chunks[2], network.pubKeyHash)
@ -48,7 +48,7 @@ Address.prototype.toBase58Check = function () {
return base58check.encode(payload) return base58check.encode(payload)
} }
Address.prototype.toOutputScript = function() { Address.prototype.toOutputScript = function () {
var scriptType = findScriptTypeByVersion(this.version) var scriptType = findScriptTypeByVersion(this.version)
if (scriptType === 'pubkeyhash') return scripts.pubKeyHashOutput(this.hash) if (scriptType === 'pubkeyhash') return scripts.pubKeyHashOutput(this.hash)

View file

@ -1,13 +1,13 @@
var bs58check = require('bs58check') var bs58check = require('bs58check')
function decode() { function decode () {
console.warn('bs58check will be removed in 2.0.0. require("bs58check") instead.'); console.warn('bs58check will be removed in 2.0.0. require("bs58check") instead.')
return bs58check.decode.apply(undefined, arguments) return bs58check.decode.apply(undefined, arguments)
} }
function encode() { function encode () {
console.warn('bs58check will be removed in 2.0.0. require("bs58check") instead.'); console.warn('bs58check will be removed in 2.0.0. require("bs58check") instead.')
return bs58check.encode.apply(undefined, arguments) return bs58check.encode.apply(undefined, arguments)
} }

View file

@ -3,9 +3,8 @@ var bufferutils = require('./bufferutils')
var crypto = require('./crypto') var crypto = require('./crypto')
var Transaction = require('./transaction') var Transaction = require('./transaction')
var Script = require('./script')
function Block() { function Block () {
this.version = 1 this.version = 1
this.prevHash = null this.prevHash = null
this.merkleRoot = null this.merkleRoot = null
@ -14,16 +13,16 @@ function Block() {
this.nonce = 0 this.nonce = 0
} }
Block.fromBuffer = function(buffer) { Block.fromBuffer = function (buffer) {
assert(buffer.length >= 80, 'Buffer too small (< 80 bytes)') assert(buffer.length >= 80, 'Buffer too small (< 80 bytes)')
var offset = 0 var offset = 0
function readSlice(n) { function readSlice (n) {
offset += n offset += n
return buffer.slice(offset - n, offset) return buffer.slice(offset - n, offset)
} }
function readUInt32() { function readUInt32 () {
var i = buffer.readUInt32LE(offset) var i = buffer.readUInt32LE(offset)
offset += 4 offset += 4
return i return i
@ -39,14 +38,14 @@ Block.fromBuffer = function(buffer) {
if (buffer.length === 80) return block if (buffer.length === 80) return block
function readVarInt() { function readVarInt () {
var vi = bufferutils.readVarInt(buffer, offset) var vi = bufferutils.readVarInt(buffer, offset)
offset += vi.size offset += vi.size
return vi.number return vi.number
} }
// FIXME: poor performance // FIXME: poor performance
function readTransaction() { function readTransaction () {
var tx = Transaction.fromBuffer(buffer.slice(offset), true) var tx = Transaction.fromBuffer(buffer.slice(offset), true)
offset += tx.toBuffer().length offset += tx.toBuffer().length
@ -64,35 +63,35 @@ Block.fromBuffer = function(buffer) {
return block return block
} }
Block.fromHex = function(hex) { Block.fromHex = function (hex) {
return Block.fromBuffer(new Buffer(hex, 'hex')) return Block.fromBuffer(new Buffer(hex, 'hex'))
} }
Block.prototype.getHash = function() { Block.prototype.getHash = function () {
return crypto.hash256(this.toBuffer(true)) return crypto.hash256(this.toBuffer(true))
} }
Block.prototype.getId = function() { Block.prototype.getId = function () {
return bufferutils.reverse(this.getHash()).toString('hex') return bufferutils.reverse(this.getHash()).toString('hex')
} }
Block.prototype.getUTCDate = function() { Block.prototype.getUTCDate = function () {
var date = new Date(0) // epoch var date = new Date(0) // epoch
date.setUTCSeconds(this.timestamp) date.setUTCSeconds(this.timestamp)
return date return date
} }
Block.prototype.toBuffer = function(headersOnly) { Block.prototype.toBuffer = function (headersOnly) {
var buffer = new Buffer(80) var buffer = new Buffer(80)
var offset = 0 var offset = 0
function writeSlice(slice) { function writeSlice (slice) {
slice.copy(buffer, offset) slice.copy(buffer, offset)
offset += slice.length offset += slice.length
} }
function writeUInt32(i) { function writeUInt32 (i) {
buffer.writeUInt32LE(i, offset) buffer.writeUInt32LE(i, offset)
offset += 4 offset += 4
} }
@ -107,14 +106,14 @@ Block.prototype.toBuffer = function(headersOnly) {
if (headersOnly || !this.transactions) return buffer if (headersOnly || !this.transactions) return buffer
var txLenBuffer = bufferutils.varIntBuffer(this.transactions.length) 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 tx.toBuffer()
}) })
return Buffer.concat([buffer, txLenBuffer].concat(txBuffers)) return Buffer.concat([buffer, txLenBuffer].concat(txBuffers))
} }
Block.prototype.toHex = function(headersOnly) { Block.prototype.toHex = function (headersOnly) {
return this.toBuffer(headersOnly).toString('hex') return this.toBuffer(headersOnly).toString('hex')
} }

View file

@ -2,25 +2,25 @@ var assert = require('assert')
var opcodes = require('./opcodes') var opcodes = require('./opcodes')
// https://github.com/feross/buffer/blob/master/index.js#L1127 // 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(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 >= 0, 'specified a negative value for writing an unsigned value')
assert(value <= max, 'value is larger than maximum value for type') assert(value <= max, 'value is larger than maximum value for type')
assert(Math.floor(value) === value, 'value has a fractional component') assert(Math.floor(value) === value, 'value has a fractional component')
} }
function pushDataSize(i) { function pushDataSize (i) {
return i < opcodes.OP_PUSHDATA1 ? 1 return i < opcodes.OP_PUSHDATA1 ? 1
: i < 0xff ? 2 : i < 0xff ? 2
: i < 0xffff ? 3 : i < 0xffff ? 3
: 5 : 5
} }
function readPushDataInt(buffer, offset) { function readPushDataInt (buffer, offset) {
var opcode = buffer.readUInt8(offset) var opcode = buffer.readUInt8(offset)
var number, size var number, size
// ~6 bit // ~6 bit
if (opcode < opcodes.OP_PUSHDATA1) { if (opcode < opcodes.OP_PUSHDATA1) {
number = opcode number = opcode
size = 1 size = 1
@ -41,7 +41,6 @@ function readPushDataInt(buffer, offset) {
number = buffer.readUInt32LE(offset + 1) number = buffer.readUInt32LE(offset + 1)
size = 5 size = 5
} }
return { return {
@ -51,7 +50,7 @@ function readPushDataInt(buffer, offset) {
} }
} }
function readUInt64LE(buffer, offset) { function readUInt64LE (buffer, offset) {
var a = buffer.readUInt32LE(offset) var a = buffer.readUInt32LE(offset)
var b = buffer.readUInt32LE(offset + 4) var b = buffer.readUInt32LE(offset + 4)
b *= 0x100000000 b *= 0x100000000
@ -61,11 +60,11 @@ function readUInt64LE(buffer, offset) {
return b + a return b + a
} }
function readVarInt(buffer, offset) { function readVarInt (buffer, offset) {
var t = buffer.readUInt8(offset) var t = buffer.readUInt8(offset)
var number, size var number, size
// 8 bit // 8 bit
if (t < 253) { if (t < 253) {
number = t number = t
size = 1 size = 1
@ -92,7 +91,7 @@ function readVarInt(buffer, offset) {
} }
} }
function writePushDataInt(buffer, number, offset) { function writePushDataInt (buffer, number, offset) {
var size = pushDataSize(number) var size = pushDataSize(number)
// ~6 bit // ~6 bit
@ -113,27 +112,26 @@ function writePushDataInt(buffer, number, offset) {
} else { } else {
buffer.writeUInt8(opcodes.OP_PUSHDATA4, offset) buffer.writeUInt8(opcodes.OP_PUSHDATA4, offset)
buffer.writeUInt32LE(number, offset + 1) buffer.writeUInt32LE(number, offset + 1)
} }
return size return size
} }
function writeUInt64LE(buffer, value, offset) { function writeUInt64LE (buffer, value, offset) {
verifuint(value, 0x001fffffffffffff) verifuint(value, 0x001fffffffffffff)
buffer.writeInt32LE(value & -1, offset) buffer.writeInt32LE(value & -1, offset)
buffer.writeUInt32LE(Math.floor(value / 0x100000000), offset + 4) buffer.writeUInt32LE(Math.floor(value / 0x100000000), offset + 4)
} }
function varIntSize(i) { function varIntSize (i) {
return i < 253 ? 1 return i < 253 ? 1
: i < 0x10000 ? 3 : i < 0x10000 ? 3
: i < 0x100000000 ? 5 : i < 0x100000000 ? 5
: 9 : 9
} }
function writeVarInt(buffer, number, offset) { function writeVarInt (buffer, number, offset) {
var size = varIntSize(number) var size = varIntSize(number)
// 8 bit // 8 bit
@ -159,7 +157,7 @@ function writeVarInt(buffer, number, offset) {
return size return size
} }
function varIntBuffer(i) { function varIntBuffer (i) {
var size = varIntSize(i) var size = varIntSize(i)
var buffer = new Buffer(size) var buffer = new Buffer(size)
writeVarInt(buffer, i, 0) writeVarInt(buffer, i, 0)
@ -167,7 +165,7 @@ function varIntBuffer(i) {
return buffer return buffer
} }
function reverse(buffer) { function reverse (buffer) {
var buffer2 = new Buffer(buffer) var buffer2 = new Buffer(buffer)
Array.prototype.reverse.call(buffer2) Array.prototype.reverse.call(buffer2)
return buffer2 return buffer2

View file

@ -1,32 +1,32 @@
var crypto = require('crypto') var crypto = require('crypto')
function hash160(buffer) { function hash160 (buffer) {
return ripemd160(sha256(buffer)) return ripemd160(sha256(buffer))
} }
function hash256(buffer) { function hash256 (buffer) {
return sha256(sha256(buffer)) return sha256(sha256(buffer))
} }
function ripemd160(buffer) { function ripemd160 (buffer) {
return crypto.createHash('rmd160').update(buffer).digest() return crypto.createHash('rmd160').update(buffer).digest()
} }
function sha1(buffer) { function sha1 (buffer) {
return crypto.createHash('sha1').update(buffer).digest() return crypto.createHash('sha1').update(buffer).digest()
} }
function sha256(buffer) { function sha256 (buffer) {
return crypto.createHash('sha256').update(buffer).digest() return crypto.createHash('sha256').update(buffer).digest()
} }
// FIXME: Name not consistent with others // FIXME: Name not consistent with others
function HmacSHA256(buffer, secret) { function HmacSHA256 (buffer, secret) {
console.warn('Hmac* functions are deprecated for removal in 2.0.0, use node crypto instead') console.warn('Hmac* functions are deprecated for removal in 2.0.0, use node crypto instead')
return crypto.createHmac('sha256', secret).update(buffer).digest() return crypto.createHmac('sha256', secret).update(buffer).digest()
} }
function HmacSHA512(buffer, secret) { function HmacSHA512 (buffer, secret) {
console.warn('Hmac* functions are deprecated for removal in 2.0.0, use node crypto instead') console.warn('Hmac* functions are deprecated for removal in 2.0.0, use node crypto instead')
return crypto.createHmac('sha512', secret).update(buffer).digest() return crypto.createHmac('sha512', secret).update(buffer).digest()
} }

View file

@ -9,17 +9,17 @@ var ZERO = new Buffer([0])
var ONE = new Buffer([1]) var ONE = new Buffer([1])
// https://tools.ietf.org/html/rfc6979#section-3.2 // 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('Buffer', hash)
typeForce('BigInteger', d) typeForce('BigInteger', d)
// FIXME: remove/uncomment for 2.0.0 // FIXME: remove/uncomment for 2.0.0
// typeForce('Function', checkSig) // typeForce('Function', checkSig)
if (typeof checkSig !== 'function') { if (typeof checkSig !== 'function') {
console.warn('deterministicGenerateK requires a checkSig callback in 2.0.0, see #337 for more information') console.warn('deterministicGenerateK requires a checkSig callback in 2.0.0, see #337 for more information')
checkSig = function(k) { checkSig = function (k) {
var G = curve.G var G = curve.G
var n = curve.n var n = curve.n
var e = BigInteger.fromBuffer(hash) var e = BigInteger.fromBuffer(hash)
@ -101,14 +101,14 @@ function deterministicGenerateK(curve, hash, d, checkSig) {
return T return T
} }
function sign(curve, hash, d) { function sign (curve, hash, d) {
var r, s var r, s
var e = BigInteger.fromBuffer(hash) var e = BigInteger.fromBuffer(hash)
var n = curve.n var n = curve.n
var G = curve.G var G = curve.G
deterministicGenerateK(curve, hash, d, function(k) { deterministicGenerateK(curve, hash, d, function (k) {
var Q = G.multiply(k) var Q = G.multiply(k)
if (curve.isInfinity(Q)) if (curve.isInfinity(Q))
@ -135,7 +135,7 @@ function sign(curve, hash, d) {
return new ECSignature(r, s) return new ECSignature(r, s)
} }
function verifyRaw(curve, e, signature, Q) { function verifyRaw (curve, e, signature, Q) {
var n = curve.n var n = curve.n
var G = curve.G var G = curve.G
@ -146,7 +146,7 @@ function verifyRaw(curve, e, signature, Q) {
if (r.signum() <= 0 || r.compareTo(n) >= 0) return false if (r.signum() <= 0 || r.compareTo(n) >= 0) return false
if (s.signum() <= 0 || s.compareTo(n) >= 0) return false if (s.signum() <= 0 || s.compareTo(n) >= 0) return false
// c = s^-1 mod n // c = s^-1 mod n
var c = s.modInverse(n) var c = s.modInverse(n)
// 1.4.4 Compute u1 = es^1 mod n // 1.4.4 Compute u1 = es^1 mod n
@ -161,11 +161,11 @@ function verifyRaw(curve, e, signature, Q) {
// 1.4.5 (cont.) Enforce R is not at infinity // 1.4.5 (cont.) Enforce R is not at infinity
if (curve.isInfinity(R)) return false if (curve.isInfinity(R)) return false
// 1.4.8 If v = r, output "valid", and if v != r, output "invalid" // 1.4.8 If v = r, output "valid", and if v != r, output "invalid"
return v.equals(r) 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.2 H = Hash(M), already done by the user
// 1.4.3 e = H // 1.4.3 e = H
var e = BigInteger.fromBuffer(hash) var e = BigInteger.fromBuffer(hash)
@ -181,7 +181,7 @@ function verify(curve, hash, signature, Q) {
* *
* http://www.secg.org/download/aid-780/sec1-v2.pdf * 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') assert.strictEqual(i & 3, i, 'Recovery param is more than two bits')
var n = curve.n var n = curve.n
@ -232,7 +232,7 @@ function recoverPubKey(curve, e, signature, i) {
* This function simply tries all four cases and returns the value * This function simply tries all four cases and returns the value
* that resulted in a successful pubkey recovery. * 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++) { for (var i = 0; i < 4; i++) {
var Qprime = recoverPubKey(curve, e, signature, i) var Qprime = recoverPubKey(curve, e, signature, i)

View file

@ -11,7 +11,7 @@ var ECPubKey = require('./ecpubkey')
var ecurve = require('ecurve') var ecurve = require('ecurve')
var secp256k1 = ecurve.getCurveByName('secp256k1') 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.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') 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 ECKey.curve = secp256k1
// Static constructors // Static constructors
ECKey.fromWIF = function(string) { ECKey.fromWIF = function (string) {
var payload = base58check.decode(string) var payload = base58check.decode(string)
var compressed = false var compressed = false
@ -46,7 +46,7 @@ ECKey.fromWIF = function(string) {
return new ECKey(d, compressed) return new ECKey(d, compressed)
} }
ECKey.makeRandom = function(compressed, rng) { ECKey.makeRandom = function (compressed, rng) {
rng = rng || crypto.randomBytes rng = rng || crypto.randomBytes
var buffer = rng(32) var buffer = rng(32)
@ -60,7 +60,7 @@ ECKey.makeRandom = function(compressed, rng) {
} }
// Export functions // Export functions
ECKey.prototype.toWIF = function(network) { ECKey.prototype.toWIF = function (network) {
network = network || networks.bitcoin network = network || networks.bitcoin
var bufferLen = this.pub.compressed ? 34 : 33 var bufferLen = this.pub.compressed ? 34 : 33
@ -77,7 +77,7 @@ ECKey.prototype.toWIF = function(network) {
} }
// Operations // Operations
ECKey.prototype.sign = function(hash) { ECKey.prototype.sign = function (hash) {
return ecdsa.sign(ECKey.curve, hash, this.d) return ecdsa.sign(ECKey.curve, hash, this.d)
} }

View file

@ -8,8 +8,9 @@ var Address = require('./address')
var ecurve = require('ecurve') var ecurve = require('ecurve')
var secp256k1 = ecurve.getCurveByName('secp256k1') var secp256k1 = ecurve.getCurveByName('secp256k1')
function ECPubKey(Q, compressed) { function ECPubKey (Q, compressed) {
if (compressed === undefined) compressed = true if (compressed === undefined)
compressed = true
typeForce('Point', Q) typeForce('Point', Q)
typeForce('Boolean', compressed) typeForce('Boolean', compressed)
@ -22,32 +23,32 @@ function ECPubKey(Q, compressed) {
ECPubKey.curve = secp256k1 ECPubKey.curve = secp256k1
// Static constructors // Static constructors
ECPubKey.fromBuffer = function(buffer) { ECPubKey.fromBuffer = function (buffer) {
var Q = ecurve.Point.decodeFrom(ECPubKey.curve, buffer) var Q = ecurve.Point.decodeFrom(ECPubKey.curve, buffer)
return new ECPubKey(Q, Q.compressed) return new ECPubKey(Q, Q.compressed)
} }
ECPubKey.fromHex = function(hex) { ECPubKey.fromHex = function (hex) {
return ECPubKey.fromBuffer(new Buffer(hex, 'hex')) return ECPubKey.fromBuffer(new Buffer(hex, 'hex'))
} }
// Operations // Operations
ECPubKey.prototype.getAddress = function(network) { ECPubKey.prototype.getAddress = function (network) {
network = network || networks.bitcoin network = network || networks.bitcoin
return new Address(crypto.hash160(this.toBuffer()), network.pubKeyHash) 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) return ecdsa.verify(ECPubKey.curve, hash, signature, this.Q)
} }
// Export functions // Export functions
ECPubKey.prototype.toBuffer = function() { ECPubKey.prototype.toBuffer = function () {
return this.Q.getEncoded(this.compressed) return this.Q.getEncoded(this.compressed)
} }
ECPubKey.prototype.toHex = function() { ECPubKey.prototype.toHex = function () {
return this.toBuffer().toString('hex') return this.toBuffer().toString('hex')
} }

View file

@ -3,7 +3,7 @@ var typeForce = require('typeforce')
var BigInteger = require('bigi') var BigInteger = require('bigi')
function ECSignature(r, s) { function ECSignature (r, s) {
typeForce('BigInteger', r) typeForce('BigInteger', r)
typeForce('BigInteger', s) typeForce('BigInteger', s)
@ -11,7 +11,7 @@ function ECSignature(r, s) {
this.s = s this.s = s
} }
ECSignature.parseCompact = function(buffer) { ECSignature.parseCompact = function (buffer) {
assert.equal(buffer.length, 65, 'Invalid signature length') assert.equal(buffer.length, 65, 'Invalid signature length')
var i = buffer.readUInt8(0) - 27 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(0), 0x30, 'Not a DER sequence')
assert.equal(buffer.readUInt8(1), buffer.length - 2, 'Invalid sequence length') assert.equal(buffer.readUInt8(1), buffer.length - 2, 'Invalid sequence length')
assert.equal(buffer.readUInt8(2), 0x02, 'Expected a DER integer') 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) // 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 hashType = buffer.readUInt8(buffer.length - 1)
var hashTypeMod = hashType & ~0x80 var hashTypeMod = hashType & ~0x80
@ -81,8 +81,9 @@ ECSignature.parseScriptSignature = function(buffer) {
} }
} }
ECSignature.prototype.toCompact = function(i, compressed) { ECSignature.prototype.toCompact = function (i, compressed) {
if (compressed) i += 4 if (compressed)
i += 4
i += 27 i += 27
var buffer = new Buffer(65) var buffer = new Buffer(65)
@ -94,7 +95,7 @@ ECSignature.prototype.toCompact = function(i, compressed) {
return buffer return buffer
} }
ECSignature.prototype.toDER = function() { ECSignature.prototype.toDER = function () {
var rBa = this.r.toDERInteger() var rBa = this.r.toDERInteger()
var sBa = this.s.toDERInteger() var sBa = this.s.toDERInteger()
@ -114,7 +115,7 @@ ECSignature.prototype.toDER = function() {
return new Buffer(sequence) return new Buffer(sequence)
} }
ECSignature.prototype.toScriptSignature = function(hashType) { ECSignature.prototype.toScriptSignature = function (hashType) {
var hashTypeMod = hashType & ~0x80 var hashTypeMod = hashType & ~0x80
assert(hashTypeMod > 0x00 && hashTypeMod < 0x04, 'Invalid hashType ' + hashType) assert(hashTypeMod > 0x00 && hashTypeMod < 0x04, 'Invalid hashType ' + hashType)

View file

@ -12,13 +12,11 @@ var ECPubKey = require('./ecpubkey')
var ecurve = require('ecurve') var ecurve = require('ecurve')
var curve = ecurve.getCurveByName('secp256k1') var curve = ecurve.getCurveByName('secp256k1')
function findBIP32NetworkByVersion(version) { function findBIP32NetworkByVersion (version) {
for (var name in networks) { for (var name in networks) {
var network = networks[name] var network = networks[name]
if (version === network.bip32.private || if (version === network.bip32.private || version === network.bip32.public) {
version === network.bip32.public) {
return network return network
} }
} }
@ -26,7 +24,7 @@ function findBIP32NetworkByVersion(version) {
assert(false, 'Could not find network for ' + version.toString(16)) assert(false, 'Could not find network for ' + version.toString(16))
} }
function HDNode(K, chainCode, network) { function HDNode (K, chainCode, network) {
network = network || networks.bitcoin network = network || networks.bitcoin
typeForce('Buffer', chainCode) typeForce('Buffer', chainCode)
@ -58,7 +56,7 @@ HDNode.MASTER_SECRET = new Buffer('Bitcoin seed')
HDNode.HIGHEST_BIT = 0x80000000 HDNode.HIGHEST_BIT = 0x80000000
HDNode.LENGTH = 78 HDNode.LENGTH = 78
HDNode.fromSeedBuffer = function(seed, network) { HDNode.fromSeedBuffer = function (seed, network) {
typeForce('Buffer', seed) typeForce('Buffer', seed)
assert(seed.length >= 16, 'Seed should be at least 128 bits') assert(seed.length >= 16, 'Seed should be at least 128 bits')
@ -75,16 +73,16 @@ HDNode.fromSeedBuffer = function(seed, network) {
return new HDNode(pIL, IR, 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) return HDNode.fromSeedBuffer(new Buffer(hex, 'hex'), network)
} }
HDNode.fromBase58 = function(string, network) { HDNode.fromBase58 = function (string, network) {
return HDNode.fromBuffer(base58check.decode(string), network, true) return HDNode.fromBuffer(base58check.decode(string), network, true)
} }
// FIXME: remove in 2.x.y // FIXME: remove in 2.x.y
HDNode.fromBuffer = function(buffer, network, __ignoreDeprecation) { HDNode.fromBuffer = function (buffer, network, __ignoreDeprecation) {
if (!__ignoreDeprecation) { if (!__ignoreDeprecation) {
console.warn('HDNode.fromBuffer() is deprecated for removal in 2.x.y, use fromBase58 instead') console.warn('HDNode.fromBuffer() is deprecated for removal in 2.x.y, use fromBase58 instead')
} }
@ -95,7 +93,7 @@ HDNode.fromBuffer = function(buffer, network, __ignoreDeprecation) {
var version = buffer.readUInt32BE(0) var version = buffer.readUInt32BE(0)
if (network) { 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 // auto-detect
} else { } else {
@ -120,7 +118,7 @@ HDNode.fromBuffer = function(buffer, network, __ignoreDeprecation) {
var chainCode = buffer.slice(13, 45) var chainCode = buffer.slice(13, 45)
var data, hd var data, hd
// 33 bytes: private key data (0x00 + k) // 33 bytes: private key data (0x00 + k)
if (version === network.bip32.private) { if (version === network.bip32.private) {
assert.strictEqual(buffer.readUInt8(45), 0x00, 'Invalid private key') assert.strictEqual(buffer.readUInt8(45), 0x00, 'Invalid private key')
data = buffer.slice(46, 78) data = buffer.slice(46, 78)
@ -148,23 +146,23 @@ HDNode.fromBuffer = function(buffer, network, __ignoreDeprecation) {
} }
// FIXME: remove in 2.x.y // FIXME: remove in 2.x.y
HDNode.fromHex = function(hex, network) { HDNode.fromHex = function (hex, network) {
return HDNode.fromBuffer(new Buffer(hex, 'hex'), network) return HDNode.fromBuffer(new Buffer(hex, 'hex'), network)
} }
HDNode.prototype.getIdentifier = function() { HDNode.prototype.getIdentifier = function () {
return bcrypto.hash160(this.pubKey.toBuffer()) return bcrypto.hash160(this.pubKey.toBuffer())
} }
HDNode.prototype.getFingerprint = function() { HDNode.prototype.getFingerprint = function () {
return this.getIdentifier().slice(0, 4) return this.getIdentifier().slice(0, 4)
} }
HDNode.prototype.getAddress = function() { HDNode.prototype.getAddress = function () {
return this.pubKey.getAddress(this.network) 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) var neutered = new HDNode(this.pubKey.Q, this.chainCode, this.network)
neutered.depth = this.depth neutered.depth = this.depth
neutered.index = this.index neutered.index = this.index
@ -173,12 +171,12 @@ HDNode.prototype.neutered = function() {
return neutered return neutered
} }
HDNode.prototype.toBase58 = function(isPrivate) { HDNode.prototype.toBase58 = function (isPrivate) {
return base58check.encode(this.toBuffer(isPrivate, true)) return base58check.encode(this.toBuffer(isPrivate, true))
} }
// FIXME: remove in 2.x.y // FIXME: remove in 2.x.y
HDNode.prototype.toBuffer = function(isPrivate, __ignoreDeprecation) { HDNode.prototype.toBuffer = function (isPrivate, __ignoreDeprecation) {
if (isPrivate === undefined) { if (isPrivate === undefined) {
isPrivate = !!this.privKey isPrivate = !!this.privKey
@ -221,7 +219,6 @@ HDNode.prototype.toBuffer = function(isPrivate, __ignoreDeprecation) {
buffer.writeUInt8(0, 45) buffer.writeUInt8(0, 45)
this.privKey.d.toBuffer(32).copy(buffer, 46) this.privKey.d.toBuffer(32).copy(buffer, 46)
} else { } else {
// X9.62 encoding for public keys // X9.62 encoding for public keys
this.pubKey.toBuffer().copy(buffer, 45) this.pubKey.toBuffer().copy(buffer, 45)
} }
@ -230,12 +227,12 @@ HDNode.prototype.toBuffer = function(isPrivate, __ignoreDeprecation) {
} }
// FIXME: remove in 2.x.y // FIXME: remove in 2.x.y
HDNode.prototype.toHex = function(isPrivate) { HDNode.prototype.toHex = function (isPrivate) {
return this.toBuffer(isPrivate).toString('hex') return this.toBuffer(isPrivate).toString('hex')
} }
// https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#child-key-derivation-ckd-functions // 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 isHardened = index >= HDNode.HIGHEST_BIT
var indexBuffer = new Buffer(4) var indexBuffer = new Buffer(4)
indexBuffer.writeUInt32BE(index, 0) indexBuffer.writeUInt32BE(index, 0)
@ -307,7 +304,7 @@ HDNode.prototype.derive = function(index) {
return hd return hd
} }
HDNode.prototype.deriveHardened = function(index) { HDNode.prototype.deriveHardened = function (index) {
// Only derives hardened private keys by default // Only derives hardened private keys by default
return this.derive(index + HDNode.HIGHEST_BIT) return this.derive(index + HDNode.HIGHEST_BIT)
} }

View file

@ -10,7 +10,7 @@ var ECSignature = require('./ecsignature')
var ecurve = require('ecurve') var ecurve = require('ecurve')
var ecparams = ecurve.getCurveByName('secp256k1') var ecparams = ecurve.getCurveByName('secp256k1')
function magicHash(message, network) { function magicHash (message, network) {
var magicPrefix = new Buffer(network.magicPrefix) var magicPrefix = new Buffer(network.magicPrefix)
var messageBuffer = new Buffer(message) var messageBuffer = new Buffer(message)
var lengthBuffer = bufferutils.varIntBuffer(messageBuffer.length) var lengthBuffer = bufferutils.varIntBuffer(messageBuffer.length)
@ -19,7 +19,7 @@ function magicHash(message, network) {
return crypto.hash256(buffer) return crypto.hash256(buffer)
} }
function sign(privKey, message, network) { function sign (privKey, message, network) {
network = network || networks.bitcoin network = network || networks.bitcoin
var hash = magicHash(message, network) var hash = magicHash(message, network)
@ -31,7 +31,7 @@ function sign(privKey, message, network) {
} }
// TODO: network could be implied from address // TODO: network could be implied from address
function verify(address, signature, message, network) { function verify (address, signature, message, network) {
if (!Buffer.isBuffer(signature)) { if (!Buffer.isBuffer(signature)) {
signature = new Buffer(signature, 'base64') signature = new Buffer(signature, 'base64')
} }

View file

@ -127,16 +127,16 @@ var networks = {
} }
} }
function estimateFee(type) { function estimateFee (type) {
return function(tx) { return function (tx) {
var network = networks[type] var network = networks[type]
var baseFee = network.feePerKb var baseFee = network.feePerKb
var byteSize = tx.toBuffer().length var byteSize = tx.toBuffer().length
var fee = baseFee * Math.ceil(byteSize / 1000) 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) { if (e.value < network.dustSoftThreshold) {
fee += baseFee fee += baseFee
} }

View file

@ -1,138 +1,138 @@
module.exports = { module.exports = {
// push value // push value
OP_FALSE : 0, OP_FALSE: 0,
OP_0 : 0, OP_0: 0,
OP_PUSHDATA1 : 76, OP_PUSHDATA1: 76,
OP_PUSHDATA2 : 77, OP_PUSHDATA2: 77,
OP_PUSHDATA4 : 78, OP_PUSHDATA4: 78,
OP_1NEGATE : 79, OP_1NEGATE: 79,
OP_RESERVED : 80, OP_RESERVED: 80,
OP_1 : 81, OP_1: 81,
OP_TRUE : 81, OP_TRUE: 81,
OP_2 : 82, OP_2: 82,
OP_3 : 83, OP_3: 83,
OP_4 : 84, OP_4: 84,
OP_5 : 85, OP_5: 85,
OP_6 : 86, OP_6: 86,
OP_7 : 87, OP_7: 87,
OP_8 : 88, OP_8: 88,
OP_9 : 89, OP_9: 89,
OP_10 : 90, OP_10: 90,
OP_11 : 91, OP_11: 91,
OP_12 : 92, OP_12: 92,
OP_13 : 93, OP_13: 93,
OP_14 : 94, OP_14: 94,
OP_15 : 95, OP_15: 95,
OP_16 : 96, OP_16: 96,
// control // control
OP_NOP : 97, OP_NOP: 97,
OP_VER : 98, OP_VER: 98,
OP_IF : 99, OP_IF: 99,
OP_NOTIF : 100, OP_NOTIF: 100,
OP_VERIF : 101, OP_VERIF: 101,
OP_VERNOTIF : 102, OP_VERNOTIF: 102,
OP_ELSE : 103, OP_ELSE: 103,
OP_ENDIF : 104, OP_ENDIF: 104,
OP_VERIFY : 105, OP_VERIFY: 105,
OP_RETURN : 106, OP_RETURN: 106,
// stack ops // stack ops
OP_TOALTSTACK : 107, OP_TOALTSTACK: 107,
OP_FROMALTSTACK : 108, OP_FROMALTSTACK: 108,
OP_2DROP : 109, OP_2DROP: 109,
OP_2DUP : 110, OP_2DUP: 110,
OP_3DUP : 111, OP_3DUP: 111,
OP_2OVER : 112, OP_2OVER: 112,
OP_2ROT : 113, OP_2ROT: 113,
OP_2SWAP : 114, OP_2SWAP: 114,
OP_IFDUP : 115, OP_IFDUP: 115,
OP_DEPTH : 116, OP_DEPTH: 116,
OP_DROP : 117, OP_DROP: 117,
OP_DUP : 118, OP_DUP: 118,
OP_NIP : 119, OP_NIP: 119,
OP_OVER : 120, OP_OVER: 120,
OP_PICK : 121, OP_PICK: 121,
OP_ROLL : 122, OP_ROLL: 122,
OP_ROT : 123, OP_ROT: 123,
OP_SWAP : 124, OP_SWAP: 124,
OP_TUCK : 125, OP_TUCK: 125,
// splice ops // splice ops
OP_CAT : 126, OP_CAT: 126,
OP_SUBSTR : 127, OP_SUBSTR: 127,
OP_LEFT : 128, OP_LEFT: 128,
OP_RIGHT : 129, OP_RIGHT: 129,
OP_SIZE : 130, OP_SIZE: 130,
// bit logic // bit logic
OP_INVERT : 131, OP_INVERT: 131,
OP_AND : 132, OP_AND: 132,
OP_OR : 133, OP_OR: 133,
OP_XOR : 134, OP_XOR: 134,
OP_EQUAL : 135, OP_EQUAL: 135,
OP_EQUALVERIFY : 136, OP_EQUALVERIFY: 136,
OP_RESERVED1 : 137, OP_RESERVED1: 137,
OP_RESERVED2 : 138, OP_RESERVED2: 138,
// numeric // numeric
OP_1ADD : 139, OP_1ADD: 139,
OP_1SUB : 140, OP_1SUB: 140,
OP_2MUL : 141, OP_2MUL: 141,
OP_2DIV : 142, OP_2DIV: 142,
OP_NEGATE : 143, OP_NEGATE: 143,
OP_ABS : 144, OP_ABS: 144,
OP_NOT : 145, OP_NOT: 145,
OP_0NOTEQUAL : 146, OP_0NOTEQUAL: 146,
OP_ADD : 147, OP_ADD: 147,
OP_SUB : 148, OP_SUB: 148,
OP_MUL : 149, OP_MUL: 149,
OP_DIV : 150, OP_DIV: 150,
OP_MOD : 151, OP_MOD: 151,
OP_LSHIFT : 152, OP_LSHIFT: 152,
OP_RSHIFT : 153, OP_RSHIFT: 153,
OP_BOOLAND : 154, OP_BOOLAND: 154,
OP_BOOLOR : 155, OP_BOOLOR: 155,
OP_NUMEQUAL : 156, OP_NUMEQUAL: 156,
OP_NUMEQUALVERIFY : 157, OP_NUMEQUALVERIFY: 157,
OP_NUMNOTEQUAL : 158, OP_NUMNOTEQUAL: 158,
OP_LESSTHAN : 159, OP_LESSTHAN: 159,
OP_GREATERTHAN : 160, OP_GREATERTHAN: 160,
OP_LESSTHANOREQUAL : 161, OP_LESSTHANOREQUAL: 161,
OP_GREATERTHANOREQUAL : 162, OP_GREATERTHANOREQUAL: 162,
OP_MIN : 163, OP_MIN: 163,
OP_MAX : 164, OP_MAX: 164,
OP_WITHIN : 165, OP_WITHIN: 165,
// crypto // crypto
OP_RIPEMD160 : 166, OP_RIPEMD160: 166,
OP_SHA1 : 167, OP_SHA1: 167,
OP_SHA256 : 168, OP_SHA256: 168,
OP_HASH160 : 169, OP_HASH160: 169,
OP_HASH256 : 170, OP_HASH256: 170,
OP_CODESEPARATOR : 171, OP_CODESEPARATOR: 171,
OP_CHECKSIG : 172, OP_CHECKSIG: 172,
OP_CHECKSIGVERIFY : 173, OP_CHECKSIGVERIFY: 173,
OP_CHECKMULTISIG : 174, OP_CHECKMULTISIG: 174,
OP_CHECKMULTISIGVERIFY : 175, OP_CHECKMULTISIGVERIFY: 175,
// expansion // expansion
OP_NOP1 : 176, OP_NOP1: 176,
OP_NOP2 : 177, OP_NOP2: 177,
OP_NOP3 : 178, OP_NOP3: 178,
OP_NOP4 : 179, OP_NOP4: 179,
OP_NOP5 : 180, OP_NOP5: 180,
OP_NOP6 : 181, OP_NOP6: 181,
OP_NOP7 : 182, OP_NOP7: 182,
OP_NOP8 : 183, OP_NOP8: 183,
OP_NOP9 : 184, OP_NOP9: 184,
OP_NOP10 : 185, OP_NOP10: 185,
// template matching params // template matching params
OP_PUBKEYHASH : 253, OP_PUBKEYHASH: 253,
OP_PUBKEY : 254, OP_PUBKEY: 254,
OP_INVALIDOPCODE : 255 OP_INVALIDOPCODE: 255
} }

View file

@ -4,7 +4,7 @@ var crypto = require('./crypto')
var typeForce = require('typeforce') var typeForce = require('typeforce')
var opcodes = require('./opcodes') var opcodes = require('./opcodes')
function Script(buffer, chunks) { function Script (buffer, chunks) {
typeForce('Buffer', buffer) typeForce('Buffer', buffer)
typeForce('Array', chunks) typeForce('Array', chunks)
@ -12,13 +12,14 @@ function Script(buffer, chunks) {
this.chunks = chunks this.chunks = chunks
} }
Script.fromASM = function(asm) { Script.fromASM = function (asm) {
var strChunks = asm.split(' ') var strChunks = asm.split(' ')
var chunks = strChunks.map(function (strChunk) {
var chunks = strChunks.map(function(strChunk) { // opcode
if (strChunk in opcodes) { if (strChunk in opcodes) {
return opcodes[strChunk] return opcodes[strChunk]
// data chunk
} else { } else {
return new Buffer(strChunk, 'hex') return new Buffer(strChunk, 'hex')
} }
@ -27,13 +28,14 @@ Script.fromASM = function(asm) {
return Script.fromChunks(chunks) return Script.fromChunks(chunks)
} }
Script.fromBuffer = function(buffer) { Script.fromBuffer = function (buffer) {
var chunks = [] var chunks = []
var i = 0 var i = 0
while (i < buffer.length) { while (i < buffer.length) {
var opcode = buffer.readUInt8(i) var opcode = buffer.readUInt8(i)
// data chunk
if ((opcode > opcodes.OP_0) && (opcode <= opcodes.OP_PUSHDATA4)) { if ((opcode > opcodes.OP_0) && (opcode <= opcodes.OP_PUSHDATA4)) {
var d = bufferutils.readPushDataInt(buffer, i) var d = bufferutils.readPushDataInt(buffer, i)
i += d.size i += d.size
@ -43,6 +45,7 @@ Script.fromBuffer = function(buffer) {
chunks.push(data) chunks.push(data)
// opcode
} else { } else {
chunks.push(opcode) chunks.push(opcode)
@ -53,27 +56,31 @@ Script.fromBuffer = function(buffer) {
return new Script(buffer, chunks) return new Script(buffer, chunks)
} }
Script.fromChunks = function(chunks) { Script.fromChunks = function (chunks) {
typeForce('Array', chunks) typeForce('Array', chunks)
var bufferSize = chunks.reduce(function(accum, chunk) { var bufferSize = chunks.reduce(function (accum, chunk) {
// data chunk
if (Buffer.isBuffer(chunk)) { if (Buffer.isBuffer(chunk)) {
return accum + bufferutils.pushDataSize(chunk.length) + chunk.length return accum + bufferutils.pushDataSize(chunk.length) + chunk.length
} }
// opcode
return accum + 1 return accum + 1
}, 0.0) }, 0.0)
var buffer = new Buffer(bufferSize) var buffer = new Buffer(bufferSize)
var offset = 0 var offset = 0
chunks.forEach(function(chunk) { chunks.forEach(function (chunk) {
// data chunk
if (Buffer.isBuffer(chunk)) { if (Buffer.isBuffer(chunk)) {
offset += bufferutils.writePushDataInt(buffer, chunk.length, offset) offset += bufferutils.writePushDataInt(buffer, chunk.length, offset)
chunk.copy(buffer, offset) chunk.copy(buffer, offset)
offset += chunk.length offset += chunk.length
// opcode
} else { } else {
buffer.writeUInt8(chunk, offset) buffer.writeUInt8(chunk, offset)
offset += 1 offset += 1
@ -84,19 +91,19 @@ Script.fromChunks = function(chunks) {
return new Script(buffer, chunks) return new Script(buffer, chunks)
} }
Script.fromHex = function(hex) { Script.fromHex = function (hex) {
return Script.fromBuffer(new Buffer(hex, 'hex')) return Script.fromBuffer(new Buffer(hex, 'hex'))
} }
Script.EMPTY = Script.fromChunks([]) Script.EMPTY = Script.fromChunks([])
Script.prototype.getHash = function() { Script.prototype.getHash = function () {
return crypto.hash160(this.buffer) return crypto.hash160(this.buffer)
} }
// FIXME: doesn't work for data chunks, maybe time to use buffertools.compare... // FIXME: doesn't work for data chunks, maybe time to use buffertools.compare...
Script.prototype.without = function(needle) { Script.prototype.without = function (needle) {
return Script.fromChunks(this.chunks.filter(function(op) { return Script.fromChunks(this.chunks.filter(function (op) {
return op !== needle return op !== needle
})) }))
} }
@ -107,22 +114,24 @@ for (var op in opcodes) {
reverseOps[code] = op reverseOps[code] = op
} }
Script.prototype.toASM = function() { Script.prototype.toASM = function () {
return this.chunks.map(function(chunk) { return this.chunks.map(function (chunk) {
// data chunk
if (Buffer.isBuffer(chunk)) { if (Buffer.isBuffer(chunk)) {
return chunk.toString('hex') return chunk.toString('hex')
// opcode
} else { } else {
return reverseOps[chunk] return reverseOps[chunk]
} }
}).join(' ') }).join(' ')
} }
Script.prototype.toBuffer = function() { Script.prototype.toBuffer = function () {
return this.buffer return this.buffer
} }
Script.prototype.toHex = function() { Script.prototype.toHex = function () {
return this.toBuffer().toString('hex') return this.toBuffer().toString('hex')
} }

View file

@ -8,13 +8,14 @@ var curve = ecurve.getCurveByName('secp256k1')
var ECSignature = require('./ecsignature') var ECSignature = require('./ecsignature')
var Script = require('./script') var Script = require('./script')
function isCanonicalPubKey(buffer) { function isCanonicalPubKey (buffer) {
if (!Buffer.isBuffer(buffer)) return false if (!Buffer.isBuffer(buffer)) return false
try { try {
ecurve.Point.decodeFrom(curve, buffer) ecurve.Point.decodeFrom(curve, buffer)
} catch (e) { } catch (e) {
if (!(e.message.match(/Invalid sequence (length|tag)/))) throw e if (!(e.message.match(/Invalid sequence (length|tag)/)))
throw e
return false return false
} }
@ -22,13 +23,14 @@ function isCanonicalPubKey(buffer) {
return true return true
} }
function isCanonicalSignature(buffer) { function isCanonicalSignature (buffer) {
if (!Buffer.isBuffer(buffer)) return false if (!Buffer.isBuffer(buffer)) return false
try { try {
ECSignature.parseScriptSignature(buffer) ECSignature.parseScriptSignature(buffer)
} catch(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 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 return false
} }
@ -36,13 +38,13 @@ function isCanonicalSignature(buffer) {
return true return true
} }
function isPubKeyHashInput(script) { function isPubKeyHashInput (script) {
return script.chunks.length === 2 && return script.chunks.length === 2 &&
isCanonicalSignature(script.chunks[0]) && isCanonicalSignature(script.chunks[0]) &&
isCanonicalPubKey(script.chunks[1]) isCanonicalPubKey(script.chunks[1])
} }
function isPubKeyHashOutput(script) { function isPubKeyHashOutput (script) {
return script.chunks.length === 5 && return script.chunks.length === 5 &&
script.chunks[0] === ops.OP_DUP && script.chunks[0] === ops.OP_DUP &&
script.chunks[1] === ops.OP_HASH160 && script.chunks[1] === ops.OP_HASH160 &&
@ -52,18 +54,18 @@ function isPubKeyHashOutput(script) {
script.chunks[4] === ops.OP_CHECKSIG script.chunks[4] === ops.OP_CHECKSIG
} }
function isPubKeyInput(script) { function isPubKeyInput (script) {
return script.chunks.length === 1 && return script.chunks.length === 1 &&
isCanonicalSignature(script.chunks[0]) isCanonicalSignature(script.chunks[0])
} }
function isPubKeyOutput(script) { function isPubKeyOutput (script) {
return script.chunks.length === 2 && return script.chunks.length === 2 &&
isCanonicalPubKey(script.chunks[0]) && isCanonicalPubKey(script.chunks[0]) &&
script.chunks[1] === ops.OP_CHECKSIG script.chunks[1] === ops.OP_CHECKSIG
} }
function isScriptHashInput(script, allowIncomplete) { function isScriptHashInput (script, allowIncomplete) {
if (script.chunks.length < 2) return false if (script.chunks.length < 2) return false
var lastChunk = script.chunks[script.chunks.length - 1] var lastChunk = script.chunks[script.chunks.length - 1]
@ -81,7 +83,7 @@ function isScriptHashInput(script, allowIncomplete) {
return classifyInput(scriptSig, allowIncomplete) === classifyOutput(scriptPubKey) return classifyInput(scriptSig, allowIncomplete) === classifyOutput(scriptPubKey)
} }
function isScriptHashOutput(script) { function isScriptHashOutput (script) {
return script.chunks.length === 3 && return script.chunks.length === 3 &&
script.chunks[0] === ops.OP_HASH160 && script.chunks[0] === ops.OP_HASH160 &&
Buffer.isBuffer(script.chunks[1]) && Buffer.isBuffer(script.chunks[1]) &&
@ -91,12 +93,12 @@ function isScriptHashOutput(script) {
// allowIncomplete is to account for combining signatures // allowIncomplete is to account for combining signatures
// See https://github.com/bitcoin/bitcoin/blob/f425050546644a36b0b8e0eb2f6934a3e0f6f80f/src/script/sign.cpp#L195-L197 // 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.length < 2) return false
if (script.chunks[0] !== ops.OP_0) return false if (script.chunks[0] !== ops.OP_0) return false
if (allowIncomplete) { 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) return chunk === ops.OP_0 || isCanonicalSignature(chunk)
}) })
} }
@ -104,7 +106,7 @@ function isMultisigInput(script, allowIncomplete) {
return script.chunks.slice(1).every(isCanonicalSignature) return script.chunks.slice(1).every(isCanonicalSignature)
} }
function isMultisigOutput(script) { function isMultisigOutput (script) {
if (script.chunks.length < 4) return false if (script.chunks.length < 4) return false
if (script.chunks[script.chunks.length - 1] !== ops.OP_CHECKMULTISIG) return false if (script.chunks[script.chunks.length - 1] !== ops.OP_CHECKMULTISIG) return false
@ -128,11 +130,11 @@ function isMultisigOutput(script) {
return pubKeys.every(isCanonicalPubKey) return pubKeys.every(isCanonicalPubKey)
} }
function isNullDataOutput(script) { function isNullDataOutput (script) {
return script.chunks[0] === ops.OP_RETURN return script.chunks[0] === ops.OP_RETURN
} }
function classifyOutput(script) { function classifyOutput (script) {
typeForce('Script', script) typeForce('Script', script)
if (isPubKeyHashOutput(script)) { if (isPubKeyHashOutput(script)) {
@ -150,7 +152,7 @@ function classifyOutput(script) {
return 'nonstandard' return 'nonstandard'
} }
function classifyInput(script, allowIncomplete) { function classifyInput (script, allowIncomplete) {
typeForce('Script', script) typeForce('Script', script)
if (isPubKeyHashInput(script)) { if (isPubKeyHashInput(script)) {
@ -168,7 +170,7 @@ function classifyInput(script, allowIncomplete) {
// Standard Script Templates // Standard Script Templates
// {pubKey} OP_CHECKSIG // {pubKey} OP_CHECKSIG
function pubKeyOutput(pubKey) { function pubKeyOutput (pubKey) {
return Script.fromChunks([ return Script.fromChunks([
pubKey.toBuffer(), pubKey.toBuffer(),
ops.OP_CHECKSIG ops.OP_CHECKSIG
@ -176,7 +178,7 @@ function pubKeyOutput(pubKey) {
} }
// OP_DUP OP_HASH160 {pubKeyHash} OP_EQUALVERIFY OP_CHECKSIG // OP_DUP OP_HASH160 {pubKeyHash} OP_EQUALVERIFY OP_CHECKSIG
function pubKeyHashOutput(hash) { function pubKeyHashOutput (hash) {
typeForce('Buffer', hash) typeForce('Buffer', hash)
return Script.fromChunks([ return Script.fromChunks([
@ -189,7 +191,7 @@ function pubKeyHashOutput(hash) {
} }
// OP_HASH160 {scriptHash} OP_EQUAL // OP_HASH160 {scriptHash} OP_EQUAL
function scriptHashOutput(hash) { function scriptHashOutput (hash) {
typeForce('Buffer', hash) typeForce('Buffer', hash)
return Script.fromChunks([ return Script.fromChunks([
@ -200,12 +202,12 @@ function scriptHashOutput(hash) {
} }
// m [pubKeys ...] n OP_CHECKMULTISIG // m [pubKeys ...] n OP_CHECKMULTISIG
function multisigOutput(m, pubKeys) { function multisigOutput (m, pubKeys) {
typeForce(['ECPubKey'], pubKeys) typeForce(['ECPubKey'], pubKeys)
assert(pubKeys.length >= m, 'Not enough pubKeys provided') assert(pubKeys.length >= m, 'Not enough pubKeys provided')
var pubKeyBuffers = pubKeys.map(function(pubKey) { var pubKeyBuffers = pubKeys.map(function (pubKey) {
return pubKey.toBuffer() return pubKey.toBuffer()
}) })
var n = pubKeys.length var n = pubKeys.length
@ -219,21 +221,21 @@ function multisigOutput(m, pubKeys) {
} }
// {signature} // {signature}
function pubKeyInput(signature) { function pubKeyInput (signature) {
typeForce('Buffer', signature) typeForce('Buffer', signature)
return Script.fromChunks([signature]) return Script.fromChunks([signature])
} }
// {signature} {pubKey} // {signature} {pubKey}
function pubKeyHashInput(signature, pubKey) { function pubKeyHashInput (signature, pubKey) {
typeForce('Buffer', signature) typeForce('Buffer', signature)
return Script.fromChunks([signature, pubKey.toBuffer()]) return Script.fromChunks([signature, pubKey.toBuffer()])
} }
// <scriptSig> {serialized scriptPubKey script} // <scriptSig> {serialized scriptPubKey script}
function scriptHashInput(scriptSig, scriptPubKey) { function scriptHashInput (scriptSig, scriptPubKey) {
return Script.fromChunks([].concat( return Script.fromChunks([].concat(
scriptSig.chunks, scriptSig.chunks,
scriptPubKey.toBuffer() scriptPubKey.toBuffer()
@ -241,7 +243,7 @@ function scriptHashInput(scriptSig, scriptPubKey) {
} }
// OP_0 [signatures ...] // OP_0 [signatures ...]
function multisigInput(signatures, scriptPubKey) { function multisigInput (signatures, scriptPubKey) {
if (scriptPubKey) { if (scriptPubKey) {
assert(isMultisigOutput(scriptPubKey)) assert(isMultisigOutput(scriptPubKey))
@ -251,7 +253,7 @@ function multisigInput(signatures, scriptPubKey) {
var n = nOp - (ops.OP_1 - 1) var n = nOp - (ops.OP_1 - 1)
var count = 0 var count = 0
signatures.forEach(function(signature) { signatures.forEach(function (signature) {
count += (signature !== ops.OP_0) count += (signature !== ops.OP_0)
}) })
@ -262,7 +264,7 @@ function multisigInput(signatures, scriptPubKey) {
return Script.fromChunks([].concat(ops.OP_0, signatures)) return Script.fromChunks([].concat(ops.OP_0, signatures))
} }
function nullDataOutput(data) { function nullDataOutput (data) {
return Script.fromChunks([ops.OP_RETURN, data]) return Script.fromChunks([ops.OP_RETURN, data])
} }
@ -288,7 +290,7 @@ module.exports = {
pubKeyHashInput: pubKeyHashInput, pubKeyHashInput: pubKeyHashInput,
scriptHashInput: scriptHashInput, scriptHashInput: scriptHashInput,
multisigInput: multisigInput, multisigInput: multisigInput,
dataOutput: function(data) { dataOutput: function (data) {
console.warn('dataOutput is deprecated, use nullDataOutput by 2.0.0') console.warn('dataOutput is deprecated, use nullDataOutput by 2.0.0')
return nullDataOutput(data) return nullDataOutput(data)
}, },

View file

@ -9,7 +9,7 @@ var Address = require('./address')
var ECSignature = require('./ecsignature') var ECSignature = require('./ecsignature')
var Script = require('./script') var Script = require('./script')
function Transaction() { function Transaction () {
this.version = 1 this.version = 1
this.locktime = 0 this.locktime = 0
this.ins = [] this.ins = []
@ -22,36 +22,36 @@ Transaction.SIGHASH_NONE = 0x02
Transaction.SIGHASH_SINGLE = 0x03 Transaction.SIGHASH_SINGLE = 0x03
Transaction.SIGHASH_ANYONECANPAY = 0x80 Transaction.SIGHASH_ANYONECANPAY = 0x80
Transaction.fromBuffer = function(buffer, __disableAssert) { Transaction.fromBuffer = function (buffer, __disableAssert) {
var offset = 0 var offset = 0
function readSlice(n) { function readSlice (n) {
offset += n offset += n
return buffer.slice(offset - n, offset) return buffer.slice(offset - n, offset)
} }
function readUInt32() { function readUInt32 () {
var i = buffer.readUInt32LE(offset) var i = buffer.readUInt32LE(offset)
offset += 4 offset += 4
return i return i
} }
function readUInt64() { function readUInt64 () {
var i = bufferutils.readUInt64LE(buffer, offset) var i = bufferutils.readUInt64LE(buffer, offset)
offset += 8 offset += 8
return i return i
} }
function readVarInt() { function readVarInt () {
var vi = bufferutils.readVarInt(buffer, offset) var vi = bufferutils.readVarInt(buffer, offset)
offset += vi.size offset += vi.size
return vi.number return vi.number
} }
function readScript() { function readScript () {
return Script.fromBuffer(readSlice(readVarInt())) return Script.fromBuffer(readSlice(readVarInt()))
} }
function readGenerationScript() { function readGenerationScript () {
return new Script(readSlice(readVarInt()), []) return new Script(readSlice(readVarInt()), [])
} }
@ -69,7 +69,6 @@ Transaction.fromBuffer = function(buffer, __disableAssert) {
script: readGenerationScript(), script: readGenerationScript(),
sequence: readUInt32() sequence: readUInt32()
}) })
} else { } else {
tx.ins.push({ tx.ins.push({
hash: hash, hash: hash,
@ -97,12 +96,12 @@ Transaction.fromBuffer = function(buffer, __disableAssert) {
return tx return tx
} }
Transaction.fromHex = function(hex) { Transaction.fromHex = function (hex) {
return Transaction.fromBuffer(new Buffer(hex, 'hex')) return Transaction.fromBuffer(new Buffer(hex, 'hex'))
} }
Transaction.isCoinbaseHash = function(buffer) { Transaction.isCoinbaseHash = function (buffer) {
return Array.prototype.every.call(buffer, function(x) { return Array.prototype.every.call(buffer, function (x) {
return x === 0 return x === 0
}) })
} }
@ -117,7 +116,7 @@ Transaction.isCoinbaseHash = function(buffer) {
* *
* Note that this method does not sign the created input. * 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) { if (sequence === undefined || sequence === null) {
sequence = Transaction.DEFAULT_SEQUENCE sequence = Transaction.DEFAULT_SEQUENCE
} }
@ -127,10 +126,8 @@ Transaction.prototype.addInput = function(hash, index, sequence, script) {
if (typeof hash === 'string') { if (typeof hash === 'string') {
// TxId hex is big-endian, we need little-endian // TxId hex is big-endian, we need little-endian
hash = bufferutils.reverse(new Buffer(hash, 'hex')) hash = bufferutils.reverse(new Buffer(hash, 'hex'))
} else if (hash instanceof Transaction) { } else if (hash instanceof Transaction) {
hash = hash.getHash() hash = hash.getHash()
} }
typeForce('Buffer', hash) typeForce('Buffer', hash)
@ -142,11 +139,11 @@ Transaction.prototype.addInput = function(hash, index, sequence, script) {
// Add the input and return the input's index // Add the input and return the input's index
return (this.ins.push({ return (this.ins.push({
hash: hash, hash: hash,
index: index, index: index,
script: script, script: script,
sequence: sequence sequence: sequence
}) - 1) }) - 1)
} }
/** /**
@ -158,7 +155,7 @@ Transaction.prototype.addInput = function(hash, index, sequence, script) {
* - An Address object and a value * - An Address object and a value
* - A scriptPubKey Script and a value * - A scriptPubKey Script and a value
*/ */
Transaction.prototype.addOutput = function(scriptPubKey, value) { Transaction.prototype.addOutput = function (scriptPubKey, value) {
// Attempt to get a valid address if it's a base58 address string // Attempt to get a valid address if it's a base58 address string
if (typeof scriptPubKey === 'string') { if (typeof scriptPubKey === 'string') {
scriptPubKey = Address.fromBase58Check(scriptPubKey) scriptPubKey = Address.fromBase58Check(scriptPubKey)
@ -174,9 +171,9 @@ Transaction.prototype.addOutput = function(scriptPubKey, value) {
// Add the output and return the output's index // Add the output and return the output's index
return (this.outs.push({ return (this.outs.push({
script: scriptPubKey, script: scriptPubKey,
value: value value: value
}) - 1) }) - 1)
} }
Transaction.prototype.clone = function () { Transaction.prototype.clone = function () {
@ -184,7 +181,7 @@ Transaction.prototype.clone = function () {
newTx.version = this.version newTx.version = this.version
newTx.locktime = this.locktime newTx.locktime = this.locktime
newTx.ins = this.ins.map(function(txIn) { newTx.ins = this.ins.map(function (txIn) {
return { return {
hash: txIn.hash, hash: txIn.hash,
index: txIn.index, index: txIn.index,
@ -193,7 +190,7 @@ Transaction.prototype.clone = function () {
} }
}) })
newTx.outs = this.outs.map(function(txOut) { newTx.outs = this.outs.map(function (txOut) {
return { return {
script: txOut.script, script: txOut.script,
value: txOut.value value: txOut.value
@ -211,7 +208,7 @@ Transaction.prototype.clone = function () {
* hashType, serializes and finally hashes the result. This hash can then be * hashType, serializes and finally hashes the result. This hash can then be
* used to sign the transaction input in question. * used to sign the transaction input in question.
*/ */
Transaction.prototype.hashForSignature = function(inIndex, prevOutScript, hashType) { Transaction.prototype.hashForSignature = function (inIndex, prevOutScript, hashType) {
// FIXME: remove in 2.x.y // FIXME: remove in 2.x.y
if (arguments[0] instanceof Script) { if (arguments[0] instanceof Script) {
console.warn('hashForSignature(prevOutScript, inIndex, ...) has been deprecated. Use hashForSignature(inIndex, prevOutScript, ...)') console.warn('hashForSignature(prevOutScript, inIndex, ...) has been deprecated. Use hashForSignature(inIndex, prevOutScript, ...)')
@ -233,18 +230,17 @@ Transaction.prototype.hashForSignature = function(inIndex, prevOutScript, hashTy
var hashScript = prevOutScript.without(opcodes.OP_CODESEPARATOR) var hashScript = prevOutScript.without(opcodes.OP_CODESEPARATOR)
// Blank out other inputs' signatures // Blank out other inputs' signatures
txTmp.ins.forEach(function(txIn) { txTmp.ins.forEach(function (txIn) {
txIn.script = Script.EMPTY txIn.script = Script.EMPTY
}) })
txTmp.ins[inIndex].script = hashScript txTmp.ins[inIndex].script = hashScript
var hashTypeModifier = hashType & 0x1f var hashTypeModifier = hashType & 0x1f
if (hashTypeModifier === Transaction.SIGHASH_NONE) { if (hashTypeModifier === Transaction.SIGHASH_NONE) {
assert(false, 'SIGHASH_NONE not yet supported') assert(false, 'SIGHASH_NONE not yet supported')
} else if (hashTypeModifier === Transaction.SIGHASH_SINGLE) { } else if (hashTypeModifier === Transaction.SIGHASH_SINGLE) {
assert(false, 'SIGHASH_SINGLE not yet supported') assert(false, 'SIGHASH_SINGLE not yet supported')
} }
if (hashType & Transaction.SIGHASH_ANYONECANPAY) { if (hashType & Transaction.SIGHASH_ANYONECANPAY) {
@ -268,37 +264,41 @@ Transaction.prototype.getId = function () {
} }
Transaction.prototype.toBuffer = function () { Transaction.prototype.toBuffer = function () {
function scriptSize(script) { function scriptSize (script) {
var length = script.buffer.length var length = script.buffer.length
return bufferutils.varIntSize(length) + length return bufferutils.varIntSize(length) + length
} }
var buffer = new Buffer( var buffer = new Buffer(
8 + 8 +
bufferutils.varIntSize(this.ins.length) + bufferutils.varIntSize(this.ins.length) +
bufferutils.varIntSize(this.outs.length) + bufferutils.varIntSize(this.outs.length) +
this.ins.reduce(function(sum, input) { return sum + 40 + scriptSize(input.script) }, 0) + this.ins.reduce(function (sum, input) {
this.outs.reduce(function(sum, output) { return sum + 8 + scriptSize(output.script) }, 0) return sum + 40 + scriptSize(input.script)
}, 0) +
this.outs.reduce(function (sum, output) {
return sum + 8 + scriptSize(output.script)
}, 0)
) )
var offset = 0 var offset = 0
function writeSlice(slice) { function writeSlice (slice) {
slice.copy(buffer, offset) slice.copy(buffer, offset)
offset += slice.length offset += slice.length
} }
function writeUInt32(i) { function writeUInt32 (i) {
buffer.writeUInt32LE(i, offset) buffer.writeUInt32LE(i, offset)
offset += 4 offset += 4
} }
function writeUInt64(i) { function writeUInt64 (i) {
bufferutils.writeUInt64LE(buffer, i, offset) bufferutils.writeUInt64LE(buffer, i, offset)
offset += 8 offset += 8
} }
function writeVarInt(i) { function writeVarInt (i) {
var n = bufferutils.writeVarInt(buffer, i, offset) var n = bufferutils.writeVarInt(buffer, i, offset)
offset += n offset += n
} }
@ -306,7 +306,7 @@ Transaction.prototype.toBuffer = function () {
writeUInt32(this.version) writeUInt32(this.version)
writeVarInt(this.ins.length) writeVarInt(this.ins.length)
this.ins.forEach(function(txIn) { this.ins.forEach(function (txIn) {
writeSlice(txIn.hash) writeSlice(txIn.hash)
writeUInt32(txIn.index) writeUInt32(txIn.index)
writeVarInt(txIn.script.buffer.length) writeVarInt(txIn.script.buffer.length)
@ -315,7 +315,7 @@ Transaction.prototype.toBuffer = function () {
}) })
writeVarInt(this.outs.length) writeVarInt(this.outs.length)
this.outs.forEach(function(txOut) { this.outs.forEach(function (txOut) {
writeUInt64(txOut.value) writeUInt64(txOut.value)
writeVarInt(txOut.script.buffer.length) writeVarInt(txOut.script.buffer.length)
writeSlice(txOut.script.buffer) writeSlice(txOut.script.buffer)
@ -326,11 +326,11 @@ Transaction.prototype.toBuffer = function () {
return buffer return buffer
} }
Transaction.prototype.toHex = function() { Transaction.prototype.toHex = function () {
return this.toBuffer().toString('hex') return this.toBuffer().toString('hex')
} }
Transaction.prototype.setInputScript = function(index, script) { Transaction.prototype.setInputScript = function (index, script) {
typeForce('Number', index) typeForce('Number', index)
typeForce('Script', script) typeForce('Script', script)
@ -338,8 +338,8 @@ Transaction.prototype.setInputScript = function(index, script) {
} }
// FIXME: remove in 2.x.y // FIXME: remove in 2.x.y
Transaction.prototype.sign = function(index, privKey, hashType) { Transaction.prototype.sign = function (index, privKey, hashType) {
console.warn("Transaction.prototype.sign is deprecated. Use TransactionBuilder instead.") console.warn('Transaction.prototype.sign is deprecated. Use TransactionBuilder instead.')
var prevOutScript = privKey.pub.getAddress().toOutputScript() var prevOutScript = privKey.pub.getAddress().toOutputScript()
var signature = this.signInput(index, prevOutScript, privKey, hashType) var signature = this.signInput(index, prevOutScript, privKey, hashType)
@ -349,8 +349,8 @@ Transaction.prototype.sign = function(index, privKey, hashType) {
} }
// FIXME: remove in 2.x.y // FIXME: remove in 2.x.y
Transaction.prototype.signInput = function(index, prevOutScript, privKey, hashType) { Transaction.prototype.signInput = function (index, prevOutScript, privKey, hashType) {
console.warn("Transaction.prototype.signInput is deprecated. Use TransactionBuilder instead.") console.warn('Transaction.prototype.signInput is deprecated. Use TransactionBuilder instead.')
hashType = hashType || Transaction.SIGHASH_ALL hashType = hashType || Transaction.SIGHASH_ALL
@ -361,8 +361,8 @@ Transaction.prototype.signInput = function(index, prevOutScript, privKey, hashTy
} }
// FIXME: remove in 2.x.y // FIXME: remove in 2.x.y
Transaction.prototype.validateInput = function(index, prevOutScript, pubKey, buffer) { Transaction.prototype.validateInput = function (index, prevOutScript, pubKey, buffer) {
console.warn("Transaction.prototype.validateInput is deprecated. Use TransactionBuilder instead.") console.warn('Transaction.prototype.validateInput is deprecated. Use TransactionBuilder instead.')
var parsed = ECSignature.parseScriptSignature(buffer) var parsed = ECSignature.parseScriptSignature(buffer)
var hash = this.hashForSignature(index, prevOutScript, parsed.hashType) var hash = this.hashForSignature(index, prevOutScript, parsed.hashType)

View file

@ -7,7 +7,7 @@ var ECSignature = require('./ecsignature')
var Script = require('./script') var Script = require('./script')
var Transaction = require('./transaction') var Transaction = require('./transaction')
function extractInput(txIn) { function extractInput (txIn) {
var redeemScript var redeemScript
var scriptSig = txIn.script var scriptSig = txIn.script
var prevOutScript var prevOutScript
@ -21,7 +21,6 @@ function extractInput(txIn) {
scriptSig = Script.fromChunks(scriptSig.chunks.slice(0, -1)) scriptSig = Script.fromChunks(scriptSig.chunks.slice(0, -1))
scriptType = scripts.classifyInput(scriptSig, true) scriptType = scripts.classifyInput(scriptSig, true)
} else { } else {
scriptType = prevOutType scriptType = prevOutType
} }
@ -53,7 +52,7 @@ function extractInput(txIn) {
} }
case 'multisig': { 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 if (chunk === ops.OP_0) return chunk
var parsed = ECSignature.parseScriptSignature(chunk) var parsed = ECSignature.parseScriptSignature(chunk)
@ -81,7 +80,7 @@ function extractInput(txIn) {
} }
} }
function TransactionBuilder() { function TransactionBuilder () {
this.prevTxMap = {} this.prevTxMap = {}
this.prevOutScripts = {} this.prevOutScripts = {}
this.prevOutTypes = {} this.prevOutTypes = {}
@ -90,7 +89,7 @@ function TransactionBuilder() {
this.tx = new Transaction() this.tx = new Transaction()
} }
TransactionBuilder.fromTransaction = function(transaction) { TransactionBuilder.fromTransaction = function (transaction) {
var txb = new TransactionBuilder() var txb = new TransactionBuilder()
// Copy other transaction fields // Copy other transaction fields
@ -98,17 +97,17 @@ TransactionBuilder.fromTransaction = function(transaction) {
txb.tx.locktime = transaction.locktime txb.tx.locktime = transaction.locktime
// Extract/add inputs // Extract/add inputs
transaction.ins.forEach(function(txIn) { transaction.ins.forEach(function (txIn) {
txb.addInput(txIn.hash, txIn.index, txIn.sequence) txb.addInput(txIn.hash, txIn.index, txIn.sequence)
}) })
// Extract/add outputs // Extract/add outputs
transaction.outs.forEach(function(txOut) { transaction.outs.forEach(function (txOut) {
txb.addOutput(txOut.script, txOut.value) txb.addOutput(txOut.script, txOut.value)
}) })
// Extract/add signatures // Extract/add signatures
txb.inputs = transaction.ins.map(function(txIn) { txb.inputs = transaction.ins.map(function (txIn) {
// TODO: remove me after testcase added // TODO: remove me after testcase added
assert(!Transaction.isCoinbaseHash(txIn.hash), 'coinbase inputs not supported') assert(!Transaction.isCoinbaseHash(txIn.hash), 'coinbase inputs not supported')
@ -121,22 +120,24 @@ TransactionBuilder.fromTransaction = function(transaction) {
return txb return txb
} }
TransactionBuilder.prototype.addInput = function(prevTx, index, sequence, prevOutScript) { TransactionBuilder.prototype.addInput = function (prevTx, index, sequence, prevOutScript) {
var prevOutHash var prevOutHash
// txId
if (typeof prevTx === 'string') { if (typeof prevTx === 'string') {
prevOutHash = new Buffer(prevTx, 'hex') prevOutHash = new Buffer(prevTx, 'hex')
// TxId hex is big-endian, we want little-endian hash // TxId hex is big-endian, we want little-endian hash
Array.prototype.reverse.call(prevOutHash) Array.prototype.reverse.call(prevOutHash)
// Transaction
} else if (prevTx instanceof Transaction) { } else if (prevTx instanceof Transaction) {
prevOutHash = prevTx.getHash() prevOutHash = prevTx.getHash()
prevOutScript = prevTx.outs[index].script prevOutScript = prevTx.outs[index].script
// txHash
} else { } else {
prevOutHash = prevTx prevOutHash = prevTx
} }
var input = {} var input = {}
@ -147,11 +148,11 @@ TransactionBuilder.prototype.addInput = function(prevTx, index, sequence, prevOu
switch (prevOutType) { switch (prevOutType) {
case 'multisig': case 'multisig':
input.pubKeys = prevOutScript.chunks.slice(1, -2).map(ECPubKey.fromBuffer) input.pubKeys = prevOutScript.chunks.slice(1, -2).map(ECPubKey.fromBuffer)
break break
case 'pubkey': case 'pubkey':
input.pubKeys = prevOutScript.chunks.slice(0, 1).map(ECPubKey.fromBuffer) input.pubKeys = prevOutScript.chunks.slice(0, 1).map(ECPubKey.fromBuffer)
break break
} }
if (prevOutType !== 'scripthash') { if (prevOutType !== 'scripthash') {
@ -162,7 +163,7 @@ TransactionBuilder.prototype.addInput = function(prevTx, index, sequence, prevOu
input.prevOutType = prevOutType input.prevOutType = prevOutType
} }
assert(this.inputs.every(function(input2) { assert(this.inputs.every(function (input2) {
if (input2.hashType === undefined) return true if (input2.hashType === undefined) return true
return input2.hashType & Transaction.SIGHASH_ANYONECANPAY return input2.hashType & Transaction.SIGHASH_ANYONECANPAY
@ -178,8 +179,8 @@ TransactionBuilder.prototype.addInput = function(prevTx, index, sequence, prevOu
return vin return vin
} }
TransactionBuilder.prototype.addOutput = function(scriptPubKey, value) { TransactionBuilder.prototype.addOutput = function (scriptPubKey, value) {
assert(this.inputs.every(function(input) { assert(this.inputs.every(function (input) {
if (input.hashType === undefined) return true if (input.hashType === undefined) return true
return (input.hashType & 0x1f) === Transaction.SIGHASH_SINGLE return (input.hashType & 0x1f) === Transaction.SIGHASH_SINGLE
@ -188,12 +189,20 @@ TransactionBuilder.prototype.addOutput = function(scriptPubKey, value) {
return this.tx.addOutput(scriptPubKey, value) return this.tx.addOutput(scriptPubKey, value)
} }
TransactionBuilder.prototype.build = function() { return this.__build(false) } TransactionBuilder.prototype.build = function () {
TransactionBuilder.prototype.buildIncomplete = function() { return this.__build(true) } 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) { if (!allowIncomplete) {
assert(this.tx.ins.length > 0, 'Transaction has no inputs') assert(this.tx.ins.length > 0, 'Transaction has no inputs')
assert(this.tx.outs.length > 0, 'Transaction has no outputs') assert(this.tx.outs.length > 0, 'Transaction has no outputs')
@ -202,7 +211,7 @@ TransactionBuilder.prototype.__build = function(allowIncomplete) {
var tx = this.tx.clone() var tx = this.tx.clone()
// Create script signatures from signature meta-data // Create script signatures from signature meta-data
this.inputs.forEach(function(input, index) { this.inputs.forEach(function (input, index) {
var scriptType = input.scriptType var scriptType = input.scriptType
var scriptSig var scriptSig
@ -217,11 +226,11 @@ TransactionBuilder.prototype.__build = function(allowIncomplete) {
case 'pubkeyhash': case 'pubkeyhash':
var pkhSignature = input.signatures[0].toScriptSignature(input.hashType) var pkhSignature = input.signatures[0].toScriptSignature(input.hashType)
scriptSig = scripts.pubKeyHashInput(pkhSignature, input.pubKeys[0]) scriptSig = scripts.pubKeyHashInput(pkhSignature, input.pubKeys[0])
break break
case 'multisig': case 'multisig':
// Array.prototype.map is sparse-compatible // 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) return signature.toScriptSignature(input.hashType)
}) })
@ -234,12 +243,12 @@ TransactionBuilder.prototype.__build = function(allowIncomplete) {
var redeemScript = allowIncomplete ? undefined : input.redeemScript var redeemScript = allowIncomplete ? undefined : input.redeemScript
scriptSig = scripts.multisigInput(msSignatures, redeemScript) scriptSig = scripts.multisigInput(msSignatures, redeemScript)
break break
case 'pubkey': case 'pubkey':
var pkSignature = input.signatures[0].toScriptSignature(input.hashType) var pkSignature = input.signatures[0].toScriptSignature(input.hashType)
scriptSig = scripts.pubKeyInput(pkSignature) scriptSig = scripts.pubKeyInput(pkSignature)
break break
} }
} }
@ -257,17 +266,17 @@ TransactionBuilder.prototype.__build = function(allowIncomplete) {
return tx 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) assert(index in this.inputs, 'No input at index: ' + index)
hashType = hashType || Transaction.SIGHASH_ALL hashType = hashType || Transaction.SIGHASH_ALL
var input = this.inputs[index] var input = this.inputs[index]
var canSign = input.hashType && var canSign = input.hashType &&
input.prevOutScript && input.prevOutScript &&
input.prevOutType && input.prevOutType &&
input.pubKeys && input.pubKeys &&
input.scriptType && input.scriptType &&
input.signatures input.signatures
// are we almost ready to sign? // are we almost ready to sign?
if (canSign) { if (canSign) {
@ -280,6 +289,7 @@ TransactionBuilder.prototype.sign = function(index, privKey, redeemScript, hashT
// no? prepare // no? prepare
} else { } else {
// must be pay-to-scriptHash?
if (redeemScript) { if (redeemScript) {
// if we have a prevOutScript, enforce scriptHash equality to the redeemScript // if we have a prevOutScript, enforce scriptHash equality to the redeemScript
if (input.prevOutScript) { if (input.prevOutScript) {
@ -296,7 +306,7 @@ TransactionBuilder.prototype.sign = function(index, privKey, redeemScript, hashT
switch (scriptType) { switch (scriptType) {
case 'multisig': case 'multisig':
pubKeys = redeemScript.chunks.slice(1, -2).map(ECPubKey.fromBuffer) pubKeys = redeemScript.chunks.slice(1, -2).map(ECPubKey.fromBuffer)
break break
case 'pubkeyhash': case 'pubkeyhash':
var pkh1 = redeemScript.chunks[2] var pkh1 = redeemScript.chunks[2]
@ -304,11 +314,11 @@ TransactionBuilder.prototype.sign = function(index, privKey, redeemScript, hashT
assert.deepEqual(pkh1, pkh2, 'privateKey cannot sign for this input') assert.deepEqual(pkh1, pkh2, 'privateKey cannot sign for this input')
pubKeys = [privKey.pub] pubKeys = [privKey.pub]
break break
case 'pubkey': case 'pubkey':
pubKeys = redeemScript.chunks.slice(0, 1).map(ECPubKey.fromBuffer) pubKeys = redeemScript.chunks.slice(0, 1).map(ECPubKey.fromBuffer)
break break
} }
if (!input.prevOutScript) { if (!input.prevOutScript) {
@ -320,10 +330,11 @@ TransactionBuilder.prototype.sign = function(index, privKey, redeemScript, hashT
input.redeemScript = redeemScript input.redeemScript = redeemScript
input.scriptType = scriptType input.scriptType = scriptType
// cannot be pay-to-scriptHash
} else { } else {
assert.notEqual(input.prevOutType, 'scripthash', 'PrevOutScript is P2SH, missing redeemScript') assert.notEqual(input.prevOutType, 'scripthash', 'PrevOutScript is P2SH, missing redeemScript')
// can we sign this? // can we otherwise sign this?
if (input.scriptType) { if (input.scriptType) {
assert(input.pubKeys, input.scriptType + ' not supported') assert(input.pubKeys, input.scriptType + ' not supported')
@ -333,7 +344,6 @@ TransactionBuilder.prototype.sign = function(index, privKey, redeemScript, hashT
input.prevOutType = 'pubkeyhash' input.prevOutType = 'pubkeyhash'
input.pubKeys = [privKey.pub] input.pubKeys = [privKey.pub]
input.scriptType = input.prevOutType input.scriptType = input.prevOutType
} }
} }
@ -342,7 +352,7 @@ TransactionBuilder.prototype.sign = function(index, privKey, redeemScript, hashT
} }
// enforce in order signing of public keys // 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 if (!privKey.pub.Q.equals(pubKey.Q)) return false
assert(!input.signatures[i], 'Signature already exists') assert(!input.signatures[i], 'Signature already exists')

View file

@ -9,7 +9,7 @@ var HDNode = require('./hdnode')
var TransactionBuilder = require('./transaction_builder') var TransactionBuilder = require('./transaction_builder')
var Script = require('./script') var Script = require('./script')
function Wallet(seed, network) { function Wallet (seed, network) {
console.warn('Wallet is deprecated and will be removed in 2.0.0, see #296') console.warn('Wallet is deprecated and will be removed in 2.0.0, see #296')
seed = seed || crypto.randomBytes(32) seed = seed || crypto.randomBytes(32)
@ -34,7 +34,7 @@ function Wallet(seed, network) {
// FIXME: remove in 2.0.0 // FIXME: remove in 2.0.0
var me = this var me = this
this.newMasterKey = function(seed) { this.newMasterKey = function (seed) {
console.warn('newMasterKey is deprecated, please make a new Wallet instance instead') console.warn('newMasterKey is deprecated, please make a new Wallet instance instead')
seed = seed || crypto.randomBytes(32) seed = seed || crypto.randomBytes(32)
@ -51,13 +51,21 @@ function Wallet(seed, network) {
me.unspentMap = {} me.unspentMap = {}
} }
this.getMasterKey = function() { return masterKey } this.getMasterKey = function () {
this.getAccountZero = function() { return accountZero } return masterKey
this.getExternalAccount = function() { return externalAccount } }
this.getInternalAccount = function() { return internalAccount } this.getAccountZero = function () {
return accountZero
}
this.getExternalAccount = function () {
return externalAccount
}
this.getInternalAccount = function () {
return internalAccount
}
} }
Wallet.prototype.createTransaction = function(to, value, options) { Wallet.prototype.createTransaction = function (to, value, options) {
// FIXME: remove in 2.0.0 // FIXME: remove in 2.0.0
if (typeof options !== 'object') { if (typeof options !== 'object') {
if (options !== undefined) { if (options !== undefined) {
@ -79,11 +87,11 @@ Wallet.prototype.createTransaction = function(to, value, options) {
var minConf = options.minConf === undefined ? 0 : options.minConf // FIXME: change minConf:1 by default in 2.0.0 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 // filter by minConf, then pending and sort by descending value
var unspents = this.unspents.filter(function(unspent) { var unspents = this.unspents.filter(function (unspent) {
return unspent.confirmations >= minConf return unspent.confirmations >= minConf
}).filter(function(unspent) { }).filter(function (unspent) {
return !unspent.pending return !unspent.pending
}).sort(function(o1, o2) { }).sort(function (o1, o2) {
return o2.value - o1.value return o2.value - o1.value
}) })
@ -122,29 +130,30 @@ Wallet.prototype.createTransaction = function(to, value, options) {
} }
// FIXME: remove in 2.0.0 // FIXME: remove in 2.0.0
Wallet.prototype.processPendingTx = function(tx){ Wallet.prototype.processPendingTx = function (tx) {
this.__processTx(tx, true) this.__processTx(tx, true)
} }
// FIXME: remove in 2.0.0 // FIXME: remove in 2.0.0
Wallet.prototype.processConfirmedTx = function(tx){ Wallet.prototype.processConfirmedTx = function (tx) {
this.__processTx(tx, false) this.__processTx(tx, false)
} }
// FIXME: remove in 2.0.0 // FIXME: remove in 2.0.0
Wallet.prototype.__processTx = function(tx, isPending) { Wallet.prototype.__processTx = function (tx, isPending) {
console.warn('processTransaction is considered harmful, see issue #260 for more information') console.warn('processTransaction is considered harmful, see issue #260 for more information')
var txId = tx.getId() var txId = tx.getId()
var txHash = tx.getHash() var txHash = tx.getHash()
tx.outs.forEach(function(txOut, i) { tx.outs.forEach(function (txOut, i) {
var address var address
try { try {
address = Address.fromOutputScript(txOut.script, this.network).toString() address = Address.fromOutputScript(txOut.script, this.network).toString()
} catch(e) { } catch (e) {
if (!(e.message.match(/has no matching Address/))) throw e if (!(e.message.match(/has no matching Address/)))
throw e
} }
var myAddresses = this.addresses.concat(this.changeAddresses) var myAddresses = this.addresses.concat(this.changeAddresses)
@ -168,7 +177,7 @@ Wallet.prototype.__processTx = function(tx, isPending) {
} }
}, this) }, this)
tx.ins.forEach(function(txIn, i) { tx.ins.forEach(function (txIn) {
// copy and convert to big-endian hex // copy and convert to big-endian hex
var txInId = bufferutils.reverse(txIn.hash).toString('hex') var txInId = bufferutils.reverse(txIn.hash).toString('hex')
@ -180,18 +189,17 @@ Wallet.prototype.__processTx = function(tx, isPending) {
if (isPending) { if (isPending) {
unspent.pending = true unspent.pending = true
unspent.spent = true unspent.spent = true
} else { } else {
delete this.unspentMap[lookup] delete this.unspentMap[lookup]
this.unspents = this.unspents.filter(function(unspent2) { this.unspents = this.unspents.filter(function (unspent2) {
return unspent !== unspent2 return unspent !== unspent2
}) })
} }
}, this) }, this)
} }
Wallet.prototype.generateAddress = function() { Wallet.prototype.generateAddress = function () {
var k = this.addresses.length var k = this.addresses.length
var address = this.getExternalAccount().derive(k).getAddress() var address = this.getExternalAccount().derive(k).getAddress()
@ -200,7 +208,7 @@ Wallet.prototype.generateAddress = function() {
return this.getReceiveAddress() return this.getReceiveAddress()
} }
Wallet.prototype.generateChangeAddress = function() { Wallet.prototype.generateChangeAddress = function () {
var k = this.changeAddresses.length var k = this.changeAddresses.length
var address = this.getInternalAccount().derive(k).getAddress() var address = this.getInternalAccount().derive(k).getAddress()
@ -209,7 +217,7 @@ Wallet.prototype.generateChangeAddress = function() {
return this.getChangeAddress() return this.getChangeAddress()
} }
Wallet.prototype.getAddress = function() { Wallet.prototype.getAddress = function () {
if (this.addresses.length === 0) { if (this.addresses.length === 0) {
this.generateAddress() this.generateAddress()
} }
@ -217,21 +225,21 @@ Wallet.prototype.getAddress = function() {
return this.addresses[this.addresses.length - 1] return this.addresses[this.addresses.length - 1]
} }
Wallet.prototype.getBalance = function(minConf) { Wallet.prototype.getBalance = function (minConf) {
minConf = minConf || 0 minConf = minConf || 0
return this.unspents.filter(function(unspent) { return this.unspents.filter(function (unspent) {
return unspent.confirmations >= minConf return unspent.confirmations >= minConf
// FIXME: remove spent filter in 2.0.0 // FIXME: remove spent filter in 2.0.0
}).filter(function(unspent) { }).filter(function (unspent) {
return !unspent.spent return !unspent.spent
}).reduce(function(accum, unspent) { }).reduce(function (accum, unspent) {
return accum + unspent.value return accum + unspent.value
}, 0) }, 0)
} }
Wallet.prototype.getChangeAddress = function() { Wallet.prototype.getChangeAddress = function () {
if (this.changeAddresses.length === 0) { if (this.changeAddresses.length === 0) {
this.generateChangeAddress() this.generateChangeAddress()
} }
@ -239,15 +247,15 @@ Wallet.prototype.getChangeAddress = function() {
return this.changeAddresses[this.changeAddresses.length - 1] return this.changeAddresses[this.changeAddresses.length - 1]
} }
Wallet.prototype.getInternalPrivateKey = function(index) { Wallet.prototype.getInternalPrivateKey = function (index) {
return this.getInternalAccount().derive(index).privKey return this.getInternalAccount().derive(index).privKey
} }
Wallet.prototype.getPrivateKey = function(index) { Wallet.prototype.getPrivateKey = function (index) {
return this.getExternalAccount().derive(index).privKey return this.getExternalAccount().derive(index).privKey
} }
Wallet.prototype.getPrivateKeyForAddress = function(address) { Wallet.prototype.getPrivateKeyForAddress = function (address) {
var index var index
if ((index = this.addresses.indexOf(address)) > -1) { if ((index = this.addresses.indexOf(address)) > -1) {
@ -261,16 +269,16 @@ Wallet.prototype.getPrivateKeyForAddress = function(address) {
assert(false, 'Unknown address. Make sure the address is from the keychain and has been generated') assert(false, 'Unknown address. Make sure the address is from the keychain and has been generated')
} }
Wallet.prototype.getUnspentOutputs = function(minConf) { Wallet.prototype.getUnspentOutputs = function (minConf) {
minConf = minConf || 0 minConf = minConf || 0
return this.unspents.filter(function(unspent) { return this.unspents.filter(function (unspent) {
return unspent.confirmations >= minConf return unspent.confirmations >= minConf
// FIXME: remove spent filter in 2.0.0 // FIXME: remove spent filter in 2.0.0
}).filter(function(unspent) { }).filter(function (unspent) {
return !unspent.spent return !unspent.spent
}).map(function(unspent) { }).map(function (unspent) {
return { return {
address: unspent.address, address: unspent.address,
confirmations: unspent.confirmations, confirmations: unspent.confirmations,
@ -285,9 +293,9 @@ Wallet.prototype.getUnspentOutputs = function(minConf) {
}) })
} }
Wallet.prototype.setUnspentOutputs = function(unspents) { Wallet.prototype.setUnspentOutputs = function (unspents) {
this.unspentMap = {} this.unspentMap = {}
this.unspents = unspents.map(function(unspent) { this.unspents = unspents.map(function (unspent) {
// FIXME: remove unspent.hash in 2.0.0 // FIXME: remove unspent.hash in 2.0.0
var txId = unspent.txId || unspent.hash var txId = unspent.txId || unspent.hash
var index = unspent.index var index = unspent.index
@ -308,7 +316,9 @@ Wallet.prototype.setUnspentOutputs = function(unspents) {
typeForce('Number', unspent.value) typeForce('Number', unspent.value)
assert.equal(txId.length, 64, 'Expected valid txId, got ' + txId) assert.equal(txId.length, 64, 'Expected valid txId, got ' + txId)
assert.doesNotThrow(function() { Address.fromBase58Check(unspent.address) }, 'Expected Base58 Address, got ' + unspent.address) assert.doesNotThrow(function () {
Address.fromBase58Check(unspent.address)
}, 'Expected Base58 Address, got ' + unspent.address)
assert(isFinite(index), 'Expected finite index, got ' + index) assert(isFinite(index), 'Expected finite index, got ' + index)
// FIXME: remove branch in 2.0.0 // FIXME: remove branch in 2.0.0
@ -337,8 +347,8 @@ Wallet.prototype.setUnspentOutputs = function(unspents) {
}, this) }, this)
} }
Wallet.prototype.signWith = function(tx, addresses) { Wallet.prototype.signWith = function (tx, addresses) {
addresses.forEach(function(address, i) { addresses.forEach(function (address, i) {
var privKey = this.getPrivateKeyForAddress(address) var privKey = this.getPrivateKeyForAddress(address)
tx.sign(i, privKey) tx.sign(i, privKey)
@ -347,7 +357,7 @@ Wallet.prototype.signWith = function(tx, addresses) {
return tx return tx
} }
function estimatePaddedFee(tx, network) { function estimatePaddedFee (tx, network) {
var tmpTx = tx.clone() var tmpTx = tx.clone()
tmpTx.addOutput(Script.EMPTY, network.dustSoftThreshold || 0) tmpTx.addOutput(Script.EMPTY, network.dustSoftThreshold || 0)

View file

@ -1,3 +1,5 @@
/* global describe, it */
var assert = require('assert') var assert = require('assert')
var networks = require('../src/networks') var networks = require('../src/networks')
@ -6,10 +8,10 @@ var Script = require('../src/script')
var fixtures = require('./fixtures/address.json') var fixtures = require('./fixtures/address.json')
describe('Address', function() { describe('Address', function () {
describe('Constructor', function() { describe('Constructor', function () {
it('does not mutate the input', function() { it('does not mutate the input', function () {
fixtures.valid.forEach(function(f) { fixtures.valid.forEach(function (f) {
var hash = new Buffer(f.hash, 'hex') var hash = new Buffer(f.hash, 'hex')
var addr = new Address(hash, f.version) var addr = new Address(hash, f.version)
@ -19,9 +21,9 @@ describe('Address', function() {
}) })
}) })
describe('fromBase58Check', function() { describe('fromBase58Check', function () {
fixtures.valid.forEach(function(f) { fixtures.valid.forEach(function (f) {
it('imports ' + f.script + ' (' + f.network + ') correctly', function() { it('imports ' + f.script + ' (' + f.network + ') correctly', function () {
var addr = Address.fromBase58Check(f.base58check) var addr = Address.fromBase58Check(f.base58check)
assert.equal(addr.version, f.version) assert.equal(addr.version, f.version)
@ -29,18 +31,18 @@ describe('Address', function() {
}) })
}) })
fixtures.invalid.fromBase58Check.forEach(function(f) { fixtures.invalid.fromBase58Check.forEach(function (f) {
it('throws on ' + f.description, function() { it('throws on ' + f.description, function () {
assert.throws(function() { assert.throws(function () {
Address.fromBase58Check(f.base58check) Address.fromBase58Check(f.base58check)
}, new RegExp(f.exception)) }, new RegExp(f.exception))
}) })
}) })
}) })
describe('fromOutputScript', function() { describe('fromOutputScript', function () {
fixtures.valid.forEach(function(f) { fixtures.valid.forEach(function (f) {
it('imports ' + f.script + ' (' + f.network + ') correctly', function() { it('imports ' + f.script + ' (' + f.network + ') correctly', function () {
var script = Script.fromASM(f.script) var script = Script.fromASM(f.script)
var addr = Address.fromOutputScript(script, networks[f.network]) var addr = Address.fromOutputScript(script, networks[f.network])
@ -49,20 +51,20 @@ describe('Address', function() {
}) })
}) })
fixtures.invalid.fromOutputScript.forEach(function(f) { fixtures.invalid.fromOutputScript.forEach(function (f) {
it('throws when ' + f.description, function() { it('throws when ' + f.description, function () {
var script = Script.fromASM(f.script) var script = Script.fromASM(f.script)
assert.throws(function() { assert.throws(function () {
Address.fromOutputScript(script) Address.fromOutputScript(script)
}, new RegExp(f.description)) }, new RegExp(f.description))
}) })
}) })
}) })
describe('toBase58Check', function() { describe('toBase58Check', function () {
fixtures.valid.forEach(function(f) { fixtures.valid.forEach(function (f) {
it('exports ' + f.script + ' (' + f.network + ') correctly', function() { it('exports ' + f.script + ' (' + f.network + ') correctly', function () {
var addr = Address.fromBase58Check(f.base58check) var addr = Address.fromBase58Check(f.base58check)
var result = addr.toBase58Check() var result = addr.toBase58Check()
@ -71,9 +73,9 @@ describe('Address', function() {
}) })
}) })
describe('toOutputScript', function() { describe('toOutputScript', function () {
fixtures.valid.forEach(function(f) { fixtures.valid.forEach(function (f) {
it('imports ' + f.script + ' (' + f.network + ') correctly', function() { it('imports ' + f.script + ' (' + f.network + ') correctly', function () {
var addr = Address.fromBase58Check(f.base58check) var addr = Address.fromBase58Check(f.base58check)
var script = addr.toOutputScript() var script = addr.toOutputScript()
@ -81,11 +83,11 @@ describe('Address', function() {
}) })
}) })
fixtures.invalid.toOutputScript.forEach(function(f) { fixtures.invalid.toOutputScript.forEach(function (f) {
it('throws when ' + f.description, function() { it('throws when ' + f.description, function () {
var addr = new Address(new Buffer(f.hash, 'hex'), f.version) var addr = new Address(new Buffer(f.hash, 'hex'), f.version)
assert.throws(function() { assert.throws(function () {
addr.toOutputScript() addr.toOutputScript()
}, new RegExp(f.description)) }, new RegExp(f.description))
}) })

View file

@ -1,16 +1,18 @@
/* global describe, it, beforeEach */
var assert = require('assert') var assert = require('assert')
var base58check = require('../src/base58check') var base58check = require('../src/base58check')
var bs58check = require('bs58check') var bs58check = require('bs58check')
var sinon = require('sinon') var sinon = require('sinon')
describe('base58check', function() { describe('base58check', function () {
var param var param
beforeEach(function() { beforeEach(function () {
param = {} param = {}
}) })
it('wraps bs58check.decode', sinon.test(function() { it('wraps bs58check.decode', sinon.test(function () {
var expectation = this.mock(bs58check).expects('decode') var expectation = this.mock(bs58check).expects('decode')
expectation.once().calledWith(param) expectation.once().calledWith(param)
expectation.onCall(0).returns('foo') expectation.onCall(0).returns('foo')
@ -18,7 +20,7 @@ describe('base58check', function() {
assert.equal(base58check.decode(param), 'foo') assert.equal(base58check.decode(param), 'foo')
})) }))
it('wraps bs58check.encode', sinon.test(function() { it('wraps bs58check.encode', sinon.test(function () {
var expectation = this.mock(bs58check).expects('encode') var expectation = this.mock(bs58check).expects('encode')
expectation.once().calledWith(param) expectation.once().calledWith(param)
expectation.onCall(0).returns('foo') expectation.onCall(0).returns('foo')

View file

@ -1,7 +1,7 @@
var assert = require('assert') /* global describe, it */
var assert = require('assert')
var base58 = require('bs58') var base58 = require('bs58')
//var base58check = require('bs58check')
var Bitcoin = require('../') var Bitcoin = require('../')
var Address = Bitcoin.Address var Address = Bitcoin.Address
@ -12,29 +12,29 @@ var ECSignature = Bitcoin.ECSignature
var Transaction = Bitcoin.Transaction var Transaction = Bitcoin.Transaction
var Script = Bitcoin.Script var Script = Bitcoin.Script
var base58_encode_decode = require("./fixtures/core/base58_encode_decode.json") 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_invalid = require('./fixtures/core/base58_keys_invalid.json')
var base58_keys_valid = require("./fixtures/core/base58_keys_valid.json") var base58_keys_valid = require('./fixtures/core/base58_keys_valid.json')
var sig_canonical = require("./fixtures/core/sig_canonical.json") var sig_canonical = require('./fixtures/core/sig_canonical.json')
var sig_noncanonical = require("./fixtures/core/sig_noncanonical.json") var sig_noncanonical = require('./fixtures/core/sig_noncanonical.json')
var sighash = require("./fixtures/core/sighash.json") var sighash = require('./fixtures/core/sighash.json')
var tx_valid = require("./fixtures/core/tx_valid.json") var tx_valid = require('./fixtures/core/tx_valid.json')
describe('Bitcoin-core', function() { describe('Bitcoin-core', function () {
// base58_encode_decode // base58_encode_decode
describe('base58', function() { describe('base58', function () {
base58_encode_decode.forEach(function(f) { base58_encode_decode.forEach(function (f) {
var fhex = f[0] var fhex = f[0]
var fb58 = f[1] var fb58 = f[1]
it('can decode ' + fb58, function() { it('can decode ' + fb58, function () {
var buffer = base58.decode(fb58) var buffer = base58.decode(fb58)
var actual = new Buffer(buffer).toString('hex') var actual = new Buffer(buffer).toString('hex')
assert.equal(actual, fhex) assert.equal(actual, fhex)
}) })
it('can encode ' + fhex, function() { it('can encode ' + fhex, function () {
var buffer = new Buffer(fhex, 'hex') var buffer = new Buffer(fhex, 'hex')
var actual = base58.encode(buffer) var actual = base58.encode(buffer)
@ -44,32 +44,33 @@ describe('Bitcoin-core', function() {
}) })
// base58_keys_valid // base58_keys_valid
describe('Address', function() { describe('Address', function () {
base58_keys_valid.forEach(function(f) { var typeMap = {
'pubkey': 'pubKeyHash',
'script': 'scriptHash'
}
base58_keys_valid.forEach(function (f) {
var string = f[0] var string = f[0]
var hex = f[1] var hex = f[1]
var params = f[2] var params = f[2]
var network = networks.bitcoin var network = networks.bitcoin
if (params.isPrivkey) return 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) var address = Address.fromBase58Check(string)
assert.equal(address.hash.toString('hex'), hex) assert.equal(address.hash.toString('hex'), hex)
if (params.addrType === 'pubkey') { assert.equal(address.version, network[typeMap[params.addrType]])
assert.equal(address.version, network.pubKeyHash)
} else if (params.addrType === 'script') {
assert.equal(address.version, network.scriptHash)
}
}) })
}) })
}) })
// base58_keys_invalid // base58_keys_invalid
describe('Address', function() { describe('Address', function () {
var allowedNetworks = [ var allowedNetworks = [
networks.bitcoin.pubkeyhash, networks.bitcoin.pubkeyhash,
networks.bitcoin.scripthash, networks.bitcoin.scripthash,
@ -77,11 +78,11 @@ describe('Bitcoin-core', function() {
networks.testnet.scripthash networks.testnet.scripthash
] ]
base58_keys_invalid.forEach(function(f) { base58_keys_invalid.forEach(function (f) {
var string = f[0] var string = f[0]
it('throws on ' + string, function() { it('throws on ' + string, function () {
assert.throws(function() { assert.throws(function () {
var address = Address.fromBase58Check(string) var address = Address.fromBase58Check(string)
assert.notEqual(allowedNetworks.indexOf(address.version), -1, 'Invalid network') assert.notEqual(allowedNetworks.indexOf(address.version), -1, 'Invalid network')
@ -91,8 +92,8 @@ describe('Bitcoin-core', function() {
}) })
// base58_keys_valid // base58_keys_valid
describe('ECKey', function() { describe('ECKey', function () {
base58_keys_valid.forEach(function(f) { base58_keys_valid.forEach(function (f) {
var string = f[0] var string = f[0]
var hex = f[1] var hex = f[1]
var params = f[2] var params = f[2]
@ -101,29 +102,29 @@ describe('Bitcoin-core', function() {
if (!params.isPrivkey) return if (!params.isPrivkey) return
var privKey = ECKey.fromWIF(string) var privKey = ECKey.fromWIF(string)
it('imports ' + string + ' correctly', function() { it('imports ' + string + ' correctly', function () {
assert.equal(privKey.d.toHex(), hex) assert.equal(privKey.d.toHex(), hex)
assert.equal(privKey.pub.compressed, params.isCompressed) 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) assert.equal(privKey.toWIF(network), string)
}) })
}) })
}) })
// base58_keys_invalid // base58_keys_invalid
describe('ECKey', function() { describe('ECKey', function () {
var allowedNetworks = [ var allowedNetworks = [
networks.bitcoin.wif, networks.bitcoin.wif,
networks.testnet.wif networks.testnet.wif
] ]
base58_keys_invalid.forEach(function(f) { base58_keys_invalid.forEach(function (f) {
var string = f[0] var string = f[0]
it('throws on ' + string, function() { it('throws on ' + string, function () {
assert.throws(function() { assert.throws(function () {
ECKey.fromWIF(string) ECKey.fromWIF(string)
var version = base58check.decode(string).readUInt8(0) var version = base58check.decode(string).readUInt8(0)
@ -134,23 +135,23 @@ describe('Bitcoin-core', function() {
}) })
// tx_valid // tx_valid
describe('Transaction', function() { describe('Transaction', function () {
tx_valid.forEach(function(f) { tx_valid.forEach(function (f) {
// Objects that are only a single string are ignored // Objects that are only a single string are ignored
if (f.length === 1) return if (f.length === 1) return
var inputs = f[0] var inputs = f[0]
var fhex = f[1] 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) var transaction = Transaction.fromHex(fhex)
transaction.ins.forEach(function(txin, i) { transaction.ins.forEach(function (txin, i) {
var input = inputs[i] var input = inputs[i]
var prevOutHash = input[0] var prevOutHash = input[0]
var prevOutIndex = input[1] 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 var actualHash = txin.hash
@ -167,8 +168,8 @@ describe('Bitcoin-core', function() {
}) })
// sighash // sighash
describe('Transaction', function() { describe('Transaction', function () {
sighash.forEach(function(f) { sighash.forEach(function (f) {
// Objects that are only a single string are ignored // Objects that are only a single string are ignored
if (f.length === 1) return if (f.length === 1) return
@ -178,7 +179,7 @@ describe('Bitcoin-core', function() {
var hashType = f[3] var hashType = f[3]
var expectedHash = f[4] var expectedHash = f[4]
it('should hash ' + txHex + ' correctly', function() { it('should hash ' + txHex + ' correctly', function () {
var transaction = Transaction.fromHex(txHex) var transaction = Transaction.fromHex(txHex)
assert.equal(transaction.toHex(), txHex) assert.equal(transaction.toHex(), txHex)
@ -190,7 +191,8 @@ describe('Bitcoin-core', function() {
actualHash = transaction.hashForSignature(inIndex, script, hashType) actualHash = transaction.hashForSignature(inIndex, script, hashType)
} catch (e) { } catch (e) {
// don't fail if we don't support it yet, TODO // 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) { if (actualHash !== undefined) {
@ -203,18 +205,18 @@ describe('Bitcoin-core', function() {
}) })
}) })
describe('ECSignature', function() { describe('ECSignature', function () {
sig_canonical.forEach(function(hex) { sig_canonical.forEach(function (hex) {
var buffer = new Buffer(hex, 'hex') var buffer = new Buffer(hex, 'hex')
it('can parse ' + hex, function() { it('can parse ' + hex, function () {
var parsed = ECSignature.parseScriptSignature(buffer) var parsed = ECSignature.parseScriptSignature(buffer)
var actual = parsed.signature.toScriptSignature(parsed.hashType) var actual = parsed.signature.toScriptSignature(parsed.hashType)
assert.equal(actual.toString('hex'), hex) assert.equal(actual.toString('hex'), hex)
}) })
}) })
sig_noncanonical.forEach(function(hex, i) { sig_noncanonical.forEach(function (hex, i) {
if (i === 0) return if (i === 0) return
if (i % 2 !== 0) return if (i % 2 !== 0) return
@ -223,8 +225,8 @@ describe('Bitcoin-core', function() {
var buffer = new Buffer(hex, 'hex') var buffer = new Buffer(hex, 'hex')
it('throws on ' + description, function() { it('throws on ' + description, function () {
assert.throws(function() { assert.throws(function () {
ECSignature.parseScriptSignature(buffer) ECSignature.parseScriptSignature(buffer)
}) })
}) })

View file

@ -1,13 +1,15 @@
/* global describe, it, beforeEach */
var assert = require('assert') var assert = require('assert')
var Block = require('../src/block') var Block = require('../src/block')
var fixtures = require('./fixtures/block') var fixtures = require('./fixtures/block')
describe('Block', function() { describe('Block', function () {
describe('fromBuffer/fromHex', function() { describe('fromBuffer/fromHex', function () {
fixtures.valid.forEach(function(f) { fixtures.valid.forEach(function (f) {
it('imports the block: ' + f.description + ' correctly', function() { it('imports the block: ' + f.description + ' correctly', function () {
var block = Block.fromHex(f.hex) var block = Block.fromHex(f.hex)
assert.equal(block.version, f.version) assert.equal(block.version, f.version)
@ -19,66 +21,66 @@ describe('Block', function() {
}) })
}) })
fixtures.invalid.forEach(function(f) { fixtures.invalid.forEach(function (f) {
it('throws on ' + f.exception, function() { it('throws on ' + f.exception, function () {
assert.throws(function() { assert.throws(function () {
Block.fromHex(f.hex) Block.fromHex(f.hex)
}, new RegExp(f.exception)) }, new RegExp(f.exception))
}) })
}) })
}) })
describe('toBuffer/toHex', function() { describe('toBuffer/toHex', function () {
fixtures.valid.forEach(function(f) { fixtures.valid.forEach(function (f) {
var block var block
beforeEach(function() { beforeEach(function () {
block = Block.fromHex(f.hex) 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) assert.equal(block.toHex(), f.hex)
}) })
}) })
}) })
describe('getHash', function() { describe('getHash', function () {
fixtures.valid.forEach(function(f) { fixtures.valid.forEach(function (f) {
var block var block
beforeEach(function() { beforeEach(function () {
block = Block.fromHex(f.hex) 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) assert.equal(block.getHash().toString('hex'), f.hash)
}) })
}) })
}) })
describe('getId', function() { describe('getId', function () {
fixtures.valid.forEach(function(f) { fixtures.valid.forEach(function (f) {
var block var block
beforeEach(function() { beforeEach(function () {
block = Block.fromHex(f.hex) 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) assert.equal(block.getId(), f.id)
}) })
}) })
}) })
describe('getUTCDate', function() { describe('getUTCDate', function () {
fixtures.valid.forEach(function(f) { fixtures.valid.forEach(function (f) {
var block var block
beforeEach(function() { beforeEach(function () {
block = Block.fromHex(f.hex) 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() var utcDate = block.getUTCDate().getTime()
assert.equal(utcDate, f.timestamp * 1e3) assert.equal(utcDate, f.timestamp * 1e3)

View file

@ -1,12 +1,14 @@
/* global describe, it */
var assert = require('assert') var assert = require('assert')
var bufferutils = require('../src/bufferutils') var bufferutils = require('../src/bufferutils')
var fixtures = require('./fixtures/bufferutils.json') var fixtures = require('./fixtures/bufferutils.json')
describe('bufferutils', function() { describe('bufferutils', function () {
describe('pushDataSize', function() { describe('pushDataSize', function () {
fixtures.valid.forEach(function(f) { fixtures.valid.forEach(function (f) {
it('determines the pushDataSize of ' + f.dec + ' correctly', function() { it('determines the pushDataSize of ' + f.dec + ' correctly', function () {
if (!f.hexPD) return if (!f.hexPD) return
var size = bufferutils.pushDataSize(f.dec) var size = bufferutils.pushDataSize(f.dec)
@ -16,11 +18,11 @@ describe('bufferutils', function() {
}) })
}) })
describe('readPushDataInt', function() { describe('readPushDataInt', function () {
fixtures.valid.forEach(function(f) { fixtures.valid.forEach(function (f) {
if (!f.hexPD) return if (!f.hexPD) return
it('decodes ' + f.hexPD + ' correctly', function() { it('decodes ' + f.hexPD + ' correctly', function () {
var buffer = new Buffer(f.hexPD, 'hex') var buffer = new Buffer(f.hexPD, 'hex')
var d = bufferutils.readPushDataInt(buffer, 0) var d = bufferutils.readPushDataInt(buffer, 0)
var fopcode = parseInt(f.hexPD.substr(0, 2), 16) var fopcode = parseInt(f.hexPD.substr(0, 2), 16)
@ -32,9 +34,9 @@ describe('bufferutils', function() {
}) })
}) })
describe('readUInt64LE', function() { describe('readUInt64LE', function () {
fixtures.valid.forEach(function(f) { fixtures.valid.forEach(function (f) {
it('decodes ' + f.hex64 + ' correctly', function() { it('decodes ' + f.hex64 + ' correctly', function () {
var buffer = new Buffer(f.hex64, 'hex') var buffer = new Buffer(f.hex64, 'hex')
var number = bufferutils.readUInt64LE(buffer, 0) var number = bufferutils.readUInt64LE(buffer, 0)
@ -42,20 +44,20 @@ describe('bufferutils', function() {
}) })
}) })
fixtures.invalid.forEach(function(f) { fixtures.invalid.forEach(function (f) {
it('throws on ' + f.description, function() { it('throws on ' + f.description, function () {
var buffer = new Buffer(f.hex64, 'hex') var buffer = new Buffer(f.hex64, 'hex')
assert.throws(function() { assert.throws(function () {
bufferutils.readUInt64LE(buffer, 0) bufferutils.readUInt64LE(buffer, 0)
}, new RegExp(f.exception)) }, new RegExp(f.exception))
}) })
}) })
}) })
describe('readVarInt', function() { describe('readVarInt', function () {
fixtures.valid.forEach(function(f) { fixtures.valid.forEach(function (f) {
it('decodes ' + f.hexVI + ' correctly', function() { it('decodes ' + f.hexVI + ' correctly', function () {
var buffer = new Buffer(f.hexVI, 'hex') var buffer = new Buffer(f.hexVI, 'hex')
var d = bufferutils.readVarInt(buffer, 0) var d = bufferutils.readVarInt(buffer, 0)
@ -64,20 +66,20 @@ describe('bufferutils', function() {
}) })
}) })
fixtures.invalid.forEach(function(f) { fixtures.invalid.forEach(function (f) {
it('throws on ' + f.description, function() { it('throws on ' + f.description, function () {
var buffer = new Buffer(f.hexVI, 'hex') var buffer = new Buffer(f.hexVI, 'hex')
assert.throws(function() { assert.throws(function () {
bufferutils.readVarInt(buffer, 0) bufferutils.readVarInt(buffer, 0)
}, new RegExp(f.exception)) }, new RegExp(f.exception))
}) })
}) })
}) })
describe('reverse', function() { describe('reverse', function () {
fixtures.valid.forEach(function(f) { fixtures.valid.forEach(function (f) {
it('reverses ' + f.hex64 + ' correctly', function() { it('reverses ' + f.hex64 + ' correctly', function () {
var buffer = new Buffer(f.hex64, 'hex') var buffer = new Buffer(f.hex64, 'hex')
var buffer2 = bufferutils.reverse(buffer) var buffer2 = bufferutils.reverse(buffer)
@ -88,9 +90,9 @@ describe('bufferutils', function() {
}) })
}) })
describe('varIntBuffer', function() { describe('varIntBuffer', function () {
fixtures.valid.forEach(function(f) { fixtures.valid.forEach(function (f) {
it('encodes ' + f.dec + ' correctly', function() { it('encodes ' + f.dec + ' correctly', function () {
var buffer = bufferutils.varIntBuffer(f.dec) var buffer = bufferutils.varIntBuffer(f.dec)
assert.equal(buffer.toString('hex'), f.hexVI) assert.equal(buffer.toString('hex'), f.hexVI)
@ -98,9 +100,9 @@ describe('bufferutils', function() {
}) })
}) })
describe('varIntSize', function() { describe('varIntSize', function () {
fixtures.valid.forEach(function(f) { fixtures.valid.forEach(function (f) {
it('determines the varIntSize of ' + f.dec + ' correctly', function() { it('determines the varIntSize of ' + f.dec + ' correctly', function () {
var size = bufferutils.varIntSize(f.dec) var size = bufferutils.varIntSize(f.dec)
assert.equal(size, f.hexVI.length / 2) assert.equal(size, f.hexVI.length / 2)
@ -108,11 +110,11 @@ describe('bufferutils', function() {
}) })
}) })
describe('writePushDataInt', function() { describe('writePushDataInt', function () {
fixtures.valid.forEach(function(f) { fixtures.valid.forEach(function (f) {
if (!f.hexPD) return if (!f.hexPD) return
it('encodes ' + f.dec + ' correctly', function() { it('encodes ' + f.dec + ' correctly', function () {
var buffer = new Buffer(5) var buffer = new Buffer(5)
buffer.fill(0) buffer.fill(0)
@ -122,9 +124,9 @@ describe('bufferutils', function() {
}) })
}) })
describe('writeUInt64LE', function() { describe('writeUInt64LE', function () {
fixtures.valid.forEach(function(f) { fixtures.valid.forEach(function (f) {
it('encodes ' + f.dec + ' correctly', function() { it('encodes ' + f.dec + ' correctly', function () {
var buffer = new Buffer(8) var buffer = new Buffer(8)
buffer.fill(0) buffer.fill(0)
@ -133,21 +135,21 @@ describe('bufferutils', function() {
}) })
}) })
fixtures.invalid.forEach(function(f) { fixtures.invalid.forEach(function (f) {
it('throws on ' + f.description, function() { it('throws on ' + f.description, function () {
var buffer = new Buffer(8) var buffer = new Buffer(8)
buffer.fill(0) buffer.fill(0)
assert.throws(function() { assert.throws(function () {
bufferutils.writeUInt64LE(buffer, f.dec, 0) bufferutils.writeUInt64LE(buffer, f.dec, 0)
}, new RegExp(f.exception)) }, new RegExp(f.exception))
}) })
}) })
}) })
describe('writeVarInt', function() { describe('writeVarInt', function () {
fixtures.valid.forEach(function(f) { fixtures.valid.forEach(function (f) {
it('encodes ' + f.dec + ' correctly', function() { it('encodes ' + f.dec + ' correctly', function () {
var buffer = new Buffer(9) var buffer = new Buffer(9)
buffer.fill(0) buffer.fill(0)
@ -156,12 +158,12 @@ describe('bufferutils', function() {
}) })
}) })
fixtures.invalid.forEach(function(f) { fixtures.invalid.forEach(function (f) {
it('throws on ' + f.description, function() { it('throws on ' + f.description, function () {
var buffer = new Buffer(9) var buffer = new Buffer(9)
buffer.fill(0) buffer.fill(0)
assert.throws(function() { assert.throws(function () {
bufferutils.writeVarInt(buffer, f.dec, 0) bufferutils.writeVarInt(buffer, f.dec, 0)
}, new RegExp(f.exception)) }, new RegExp(f.exception))
}) })

View file

@ -1,12 +1,14 @@
/* global describe, it */
var assert = require('assert') var assert = require('assert')
var crypto = require('../src/crypto') var crypto = require('../src/crypto')
var fixtures = require('./fixtures/crypto.json') var fixtures = require('./fixtures/crypto.json')
describe('Crypto', function() { describe('Crypto', function () {
describe('HASH160', function() { describe('HASH160', function () {
it('matches the test vectors', function() { it('matches the test vectors', function () {
fixtures.before.hex.forEach(function(hex, i) { fixtures.before.hex.forEach(function (hex, i) {
var data = new Buffer(hex, 'hex') var data = new Buffer(hex, 'hex')
var actual = crypto.hash160(data).toString('hex') var actual = crypto.hash160(data).toString('hex')
@ -15,9 +17,9 @@ describe('Crypto', function() {
}) })
}) })
describe('HASH256', function() { describe('HASH256', function () {
it('matches the test vectors', function() { it('matches the test vectors', function () {
fixtures.before.hex.forEach(function(hex, i) { fixtures.before.hex.forEach(function (hex, i) {
var data = new Buffer(hex, 'hex') var data = new Buffer(hex, 'hex')
var actual = crypto.hash256(data).toString('hex') var actual = crypto.hash256(data).toString('hex')
@ -26,9 +28,9 @@ describe('Crypto', function() {
}) })
}) })
describe('RIPEMD160', function() { describe('RIPEMD160', function () {
it('matches the test vectors', function() { it('matches the test vectors', function () {
fixtures.before.hex.forEach(function(hex, i) { fixtures.before.hex.forEach(function (hex, i) {
var data = new Buffer(hex, 'hex') var data = new Buffer(hex, 'hex')
var actual = crypto.ripemd160(data).toString('hex') var actual = crypto.ripemd160(data).toString('hex')
@ -37,9 +39,9 @@ describe('Crypto', function() {
}) })
}) })
describe('SHA1', function() { describe('SHA1', function () {
it('matches the test vectors', function() { it('matches the test vectors', function () {
fixtures.before.hex.forEach(function(hex, i) { fixtures.before.hex.forEach(function (hex, i) {
var data = new Buffer(hex, 'hex') var data = new Buffer(hex, 'hex')
var actual = crypto.sha1(data).toString('hex') var actual = crypto.sha1(data).toString('hex')
@ -48,9 +50,9 @@ describe('Crypto', function() {
}) })
}) })
describe('SHA256', function() { describe('SHA256', function () {
it('matches the test vectors', function() { it('matches the test vectors', function () {
fixtures.before.hex.forEach(function(hex, i) { fixtures.before.hex.forEach(function (hex, i) {
var data = new Buffer(hex, 'hex') var data = new Buffer(hex, 'hex')
var actual = crypto.sha256(data).toString('hex') var actual = crypto.sha256(data).toString('hex')
@ -59,9 +61,9 @@ describe('Crypto', function() {
}) })
}) })
describe('HmacSHA256', function() { describe('HmacSHA256', function () {
it('matches the test vectors', function() { it('matches the test vectors', function () {
fixtures.before.hex.forEach(function(hex, i) { fixtures.before.hex.forEach(function (hex, i) {
var data = new Buffer(hex, 'hex') var data = new Buffer(hex, 'hex')
var secret = new Buffer(fixtures.before.secret) var secret = new Buffer(fixtures.before.secret)
var actual = crypto.HmacSHA256(data, secret).toString('hex') var actual = crypto.HmacSHA256(data, secret).toString('hex')
@ -71,9 +73,9 @@ describe('Crypto', function() {
}) })
}) })
describe('HmacSHA512', function() { describe('HmacSHA512', function () {
it('matches the test vectors', function() { it('matches the test vectors', function () {
fixtures.before.hex.forEach(function(hex, i) { fixtures.before.hex.forEach(function (hex, i) {
var data = new Buffer(hex, 'hex') var data = new Buffer(hex, 'hex')
var secret = new Buffer(fixtures.before.secret) var secret = new Buffer(fixtures.before.secret)
var actual = crypto.HmacSHA512(data, secret).toString('hex') var actual = crypto.HmacSHA512(data, secret).toString('hex')

View file

@ -1,3 +1,5 @@
/* global describe, it */
var assert = require('assert') var assert = require('assert')
var crypto = require('../src/crypto') var crypto = require('../src/crypto')
var ecdsa = require('../src/ecdsa') var ecdsa = require('../src/ecdsa')
@ -13,12 +15,14 @@ var curve = ecurve.getCurveByName('secp256k1')
var fixtures = require('./fixtures/ecdsa.json') var fixtures = require('./fixtures/ecdsa.json')
describe('ecdsa', function() { describe('ecdsa', function () {
describe('deterministicGenerateK', function() { describe('deterministicGenerateK', function () {
function checkSig() { return true } function checkSig () {
return true
}
fixtures.valid.ecdsa.forEach(function(f) { fixtures.valid.ecdsa.forEach(function (f) {
it('for \"' + f.message + '\"', function() { it('for "' + f.message + '"', function () {
var d = BigInteger.fromHex(f.d) var d = BigInteger.fromHex(f.d)
var h1 = crypto.sha256(f.message) var h1 = crypto.sha256(f.message)
@ -28,8 +32,8 @@ describe('ecdsa', function() {
}) })
// FIXME: remove in 2.0.0 // FIXME: remove in 2.0.0
fixtures.valid.ecdsa.forEach(function(f) { fixtures.valid.ecdsa.forEach(function (f) {
it('(deprecated) for \"' + f.message + '\"', function() { it('(deprecated) for "' + f.message + '"', function () {
var d = BigInteger.fromHex(f.d) var d = BigInteger.fromHex(f.d)
var h1 = crypto.sha256(f.message) var h1 = crypto.sha256(f.message)
@ -38,7 +42,7 @@ describe('ecdsa', function() {
}) })
}) })
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') this.mock(BigInteger).expects('fromBuffer')
.exactly(3) .exactly(3)
.onCall(0).returns(new BigInteger('0')) // < 1 .onCall(0).returns(new BigInteger('0')) // < 1
@ -52,7 +56,7 @@ describe('ecdsa', function() {
assert.equal(k.toString(), '42') 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') this.mock(BigInteger).expects('fromBuffer')
.exactly(4) .exactly(4)
.onCall(0).returns(new BigInteger('0')) // < 1 .onCall(0).returns(new BigInteger('0')) // < 1
@ -72,13 +76,13 @@ describe('ecdsa', function() {
assert.equal(k.toString(), '53') assert.equal(k.toString(), '53')
})) }))
fixtures.valid.rfc6979.forEach(function(f) { fixtures.valid.rfc6979.forEach(function (f) {
it('produces the expected k values for ' + f.message + ' if k wasn\'t suitable', function() { it('produces the expected k values for ' + f.message + " if k wasn't suitable", function () {
var d = BigInteger.fromHex(f.d) var d = BigInteger.fromHex(f.d)
var h1 = crypto.sha256(f.message) var h1 = crypto.sha256(f.message)
var results = [] var results = []
ecdsa.deterministicGenerateK(curve, h1, d, function(k) { ecdsa.deterministicGenerateK(curve, h1, d, function (k) {
results.push(k) results.push(k)
return results.length === 16 return results.length === 16
@ -91,9 +95,9 @@ describe('ecdsa', function() {
}) })
}) })
describe('recoverPubKey', function() { describe('recoverPubKey', function () {
fixtures.valid.ecdsa.forEach(function(f) { fixtures.valid.ecdsa.forEach(function (f) {
it('recovers the pubKey for ' + f.d, function() { it('recovers the pubKey for ' + f.d, function () {
var d = BigInteger.fromHex(f.d) var d = BigInteger.fromHex(f.d)
var Q = curve.G.multiply(d) var Q = curve.G.multiply(d)
var signature = { var signature = {
@ -108,7 +112,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 hash = message.magicHash('1111', networks.bitcoin)
var e = BigInteger.fromBuffer(hash) var e = BigInteger.fromBuffer(hash)
@ -121,8 +125,8 @@ describe('ecdsa', function() {
'027eea09d46ac7fb6aa2e96f9c576677214ffdc238eb167734a9b39d1eb4c3d30d' '027eea09d46ac7fb6aa2e96f9c576677214ffdc238eb167734a9b39d1eb4c3d30d'
] ]
points.forEach(function(expectedHex, i) { points.forEach(function (expectedHex, i) {
it('recovers an expected point for i of ' + i, function() { it('recovers an expected point for i of ' + i, function () {
var Qprime = ecdsa.recoverPubKey(curve, e, signature, i) var Qprime = ecdsa.recoverPubKey(curve, e, signature, i)
var QprimeHex = Qprime.getEncoded().toString('hex') var QprimeHex = Qprime.getEncoded().toString('hex')
@ -131,21 +135,21 @@ describe('ecdsa', function() {
}) })
}) })
fixtures.invalid.recoverPubKey.forEach(function(f) { fixtures.invalid.recoverPubKey.forEach(function (f) {
it('throws on ' + f.description, function() { it('throws on ' + f.description, function () {
var e = BigInteger.fromHex(f.e) var e = BigInteger.fromHex(f.e)
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))
assert.throws(function() { assert.throws(function () {
ecdsa.recoverPubKey(curve, e, signature, f.i) ecdsa.recoverPubKey(curve, e, signature, f.i)
}, new RegExp(f.exception)) }, new RegExp(f.exception))
}) })
}) })
}) })
describe('sign', function() { describe('sign', function () {
fixtures.valid.ecdsa.forEach(function(f) { fixtures.valid.ecdsa.forEach(function (f) {
it('produces a deterministic signature for \"' + f.message + '\"', function() { it('produces a deterministic signature for "' + f.message + '"', function () {
var d = BigInteger.fromHex(f.d) var d = BigInteger.fromHex(f.d)
var hash = crypto.sha256(f.message) var hash = crypto.sha256(f.message)
var signature = ecdsa.sign(curve, hash, d) var signature = ecdsa.sign(curve, hash, d)
@ -155,7 +159,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 hash = crypto.sha256('Vires in numeris')
var sig = ecdsa.sign(curve, hash, BigInteger.ONE) var sig = ecdsa.sign(curve, hash, BigInteger.ONE)
@ -165,15 +169,15 @@ describe('ecdsa', function() {
}) })
}) })
describe('verify/verifyRaw', function() { describe('verify/verifyRaw', function () {
fixtures.valid.ecdsa.forEach(function(f) { fixtures.valid.ecdsa.forEach(function (f) {
it('verifies a valid signature for \"' + f.message + '\"', function() { it('verifies a valid signature for "' + f.message + '"', function () {
var d = BigInteger.fromHex(f.d) var d = BigInteger.fromHex(f.d)
var H = crypto.sha256(f.message) var H = crypto.sha256(f.message)
var e = BigInteger.fromBuffer(H) var e = BigInteger.fromBuffer(H)
var signature = new ECSignature( var signature = new ECSignature(
new BigInteger(f.signature.r), new BigInteger(f.signature.r),
new BigInteger(f.signature.s) new BigInteger(f.signature.s)
) )
var Q = curve.G.multiply(d) var Q = curve.G.multiply(d)
@ -182,14 +186,14 @@ describe('ecdsa', function() {
}) })
}) })
fixtures.invalid.verifyRaw.forEach(function(f) { fixtures.invalid.verifyRaw.forEach(function (f) {
it('fails to verify with ' + f.description, function() { it('fails to verify with ' + f.description, function () {
var H = crypto.sha256(f.message) var H = crypto.sha256(f.message)
var e = BigInteger.fromBuffer(H) var e = BigInteger.fromBuffer(H)
var d = BigInteger.fromHex(f.d) var d = BigInteger.fromHex(f.d)
var signature = new ECSignature( var signature = new ECSignature(
new BigInteger(f.signature.r), new BigInteger(f.signature.r),
new BigInteger(f.signature.s) new BigInteger(f.signature.s)
) )
var Q = curve.G.multiply(d) var Q = curve.G.multiply(d)

View file

@ -1,3 +1,6 @@
/* global describe, it, beforeEach, afterEach */
/* eslint-disable no-new */
var assert = require('assert') var assert = require('assert')
var crypto = require('crypto') var crypto = require('crypto')
var ecurve = require('ecurve') var ecurve = require('ecurve')
@ -9,22 +12,22 @@ var ECKey = require('../src/eckey')
var fixtures = require('./fixtures/eckey.json') var fixtures = require('./fixtures/eckey.json')
describe('ECKey', function() { describe('ECKey', function () {
describe('constructor', function() { describe('constructor', function () {
it('defaults to compressed', function() { it('defaults to compressed', function () {
var privKey = new ECKey(BigInteger.ONE) var privKey = new ECKey(BigInteger.ONE)
assert.equal(privKey.pub.compressed, true) 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) var privKey = new ECKey(BigInteger.ONE, false)
assert.equal(privKey.pub.compressed, false) assert.equal(privKey.pub.compressed, false)
}) })
fixtures.valid.forEach(function(f) { fixtures.valid.forEach(function (f) {
it('calculates the matching pubKey for ' + f.d, function() { it('calculates the matching pubKey for ' + f.d, function () {
var d = new BigInteger(f.d) var d = new BigInteger(f.d)
var privKey = new ECKey(d) var privKey = new ECKey(d)
@ -32,18 +35,18 @@ describe('ECKey', function() {
}) })
}) })
fixtures.invalid.constructor.forEach(function(f) { fixtures.invalid.constructor.forEach(function (f) {
it('throws on ' + f.d, function() { it('throws on ' + f.d, function () {
var d = new BigInteger(f.d) var d = new BigInteger(f.d)
assert.throws(function() { assert.throws(function () {
new ECKey(d) new ECKey(d)
}, new RegExp(f.exception)) }, 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') var secp256k1 = ecurve.getCurveByName('secp256k1')
for (var property in secp256k1) { for (var property in secp256k1) {
@ -58,10 +61,10 @@ describe('ECKey', function() {
} }
}) })
describe('fromWIF', function() { describe('fromWIF', function () {
fixtures.valid.forEach(function(f) { fixtures.valid.forEach(function (f) {
f.WIFs.forEach(function(wif) { f.WIFs.forEach(function (wif) {
it('imports ' + wif.string + ' correctly', function() { it('imports ' + wif.string + ' correctly', function () {
var privKey = ECKey.fromWIF(wif.string) var privKey = ECKey.fromWIF(wif.string)
assert.equal(privKey.d.toString(), f.d) assert.equal(privKey.d.toString(), f.d)
@ -70,19 +73,19 @@ describe('ECKey', function() {
}) })
}) })
fixtures.invalid.WIF.forEach(function(f) { fixtures.invalid.WIF.forEach(function (f) {
it('throws on ' + f.string, function() { it('throws on ' + f.string, function () {
assert.throws(function() { assert.throws(function () {
ECKey.fromWIF(f.string) ECKey.fromWIF(f.string)
}, new RegExp(f.exception)) }, new RegExp(f.exception))
}) })
}) })
}) })
describe('toWIF', function() { describe('toWIF', function () {
fixtures.valid.forEach(function(f) { fixtures.valid.forEach(function (f) {
f.WIFs.forEach(function(wif) { f.WIFs.forEach(function (wif) {
it('exports ' + wif.string + ' correctly', function() { it('exports ' + wif.string + ' correctly', function () {
var privKey = ECKey.fromWIF(wif.string) var privKey = ECKey.fromWIF(wif.string)
var network = networks[wif.network] var network = networks[wif.network]
var result = privKey.toWIF(network) var result = privKey.toWIF(network)
@ -93,34 +96,34 @@ describe('ECKey', function() {
}) })
}) })
describe('makeRandom', function() { describe('makeRandom', function () {
var exWIF = 'KwMWvwRJeFqxYyhZgNwYuYjbQENDAPAudQx5VEmKJrUZcq6aL2pv' var exWIF = 'KwMWvwRJeFqxYyhZgNwYuYjbQENDAPAudQx5VEmKJrUZcq6aL2pv'
var exPrivKey = ECKey.fromWIF(exWIF) var exPrivKey = ECKey.fromWIF(exWIF)
var exBuffer = exPrivKey.d.toBuffer(32) var exBuffer = exPrivKey.d.toBuffer(32)
describe('uses default crypto RNG', function() { describe('uses default crypto RNG', function () {
beforeEach(function() { beforeEach(function () {
sinon.stub(crypto, 'randomBytes').returns(exBuffer) sinon.stub(crypto, 'randomBytes').returns(exBuffer)
}) })
afterEach(function() { afterEach(function () {
crypto.randomBytes.restore() crypto.randomBytes.restore()
}) })
it('generates a ECKey', function() { it('generates a ECKey', function () {
var privKey = ECKey.makeRandom() var privKey = ECKey.makeRandom()
assert.equal(privKey.toWIF(), exWIF) 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(true).pub.compressed, true)
assert.equal(ECKey.makeRandom(false).pub.compressed, false) assert.equal(ECKey.makeRandom(false).pub.compressed, false)
}) })
}) })
it('allows a custom RNG to be used', function() { it('allows a custom RNG to be used', function () {
function rng(size) { function rng (size) {
return exBuffer.slice(0, 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 hash = crypto.randomBytes(32)
var priv = ECKey.makeRandom() var priv = ECKey.makeRandom()
var signature = priv.sign(hash) 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)) 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() var priv2 = ECKey.makeRandom()
assert(!priv2.pub.verify(hash, signature)) assert(!priv2.pub.verify(hash, signature))

View file

@ -1,3 +1,5 @@
/* global describe, it, beforeEach */
var assert = require('assert') var assert = require('assert')
var crypto = require('../src/crypto') var crypto = require('../src/crypto')
var networks = require('../src/networks') var networks = require('../src/networks')
@ -10,10 +12,10 @@ var curve = ecurve.getCurveByName('secp256k1')
var fixtures = require('./fixtures/ecpubkey.json') var fixtures = require('./fixtures/ecpubkey.json')
describe('ECPubKey', function() { describe('ECPubKey', function () {
var Q var Q
beforeEach(function() { beforeEach(function () {
Q = ecurve.Point.fromAffine( Q = ecurve.Point.fromAffine(
curve, curve,
new BigInteger(fixtures.Q.x), new BigInteger(fixtures.Q.x),
@ -21,21 +23,21 @@ describe('ECPubKey', function() {
) )
}) })
describe('constructor', function() { describe('constructor', function () {
it('defaults to compressed', function() { it('defaults to compressed', function () {
var pubKey = new ECPubKey(Q) var pubKey = new ECPubKey(Q)
assert.equal(pubKey.compressed, true) assert.equal(pubKey.compressed, true)
}) })
it('supports the uncompressed flag', function() { it('supports the uncompressed flag', function () {
var pubKey = new ECPubKey(Q, false) var pubKey = new ECPubKey(Q, false)
assert.equal(pubKey.compressed, 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') var secp256k1 = ecurve.getCurveByName('secp256k1')
for (var property in secp256k1) { for (var property in secp256k1) {
@ -50,8 +52,8 @@ describe('ECPubKey', function() {
} }
}) })
describe('fromHex/toHex', function() { describe('fromHex/toHex', function () {
it('supports compressed points', function() { it('supports compressed points', function () {
var pubKey = ECPubKey.fromHex(fixtures.compressed.hex) var pubKey = ECPubKey.fromHex(fixtures.compressed.hex)
assert(pubKey.Q.equals(Q)) assert(pubKey.Q.equals(Q))
@ -59,7 +61,7 @@ describe('ECPubKey', function() {
assert.equal(pubKey.compressed, true) assert.equal(pubKey.compressed, true)
}) })
it('supports uncompressed points', function() { it('supports uncompressed points', function () {
var pubKey = ECPubKey.fromHex(fixtures.uncompressed.hex) var pubKey = ECPubKey.fromHex(fixtures.uncompressed.hex)
assert(pubKey.Q.equals(Q)) assert(pubKey.Q.equals(Q))
@ -68,22 +70,22 @@ describe('ECPubKey', function() {
}) })
}) })
describe('getAddress', function() { describe('getAddress', function () {
it('calculates the expected hash (compressed)', function() { it('calculates the expected hash (compressed)', function () {
var pubKey = new ECPubKey(Q, true) var pubKey = new ECPubKey(Q, true)
var address = pubKey.getAddress() var address = pubKey.getAddress()
assert.equal(address.hash.toString('hex'), fixtures.compressed.hash160) 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 pubKey = new ECPubKey(Q, false)
var address = pubKey.getAddress() var address = pubKey.getAddress()
assert.equal(address.hash.toString('hex'), fixtures.uncompressed.hash160) 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 pubKey = new ECPubKey(Q)
var address = pubKey.getAddress(networks.testnet) var address = pubKey.getAddress(networks.testnet)
@ -92,9 +94,9 @@ describe('ECPubKey', function() {
}) })
}) })
describe('verify', function() { describe('verify', function () {
var pubKey, signature var pubKey, signature
beforeEach(function() { beforeEach(function () {
pubKey = new ECPubKey(Q) pubKey = new ECPubKey(Q)
signature = { 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) var hash = crypto.sha256(fixtures.message)
assert(pubKey.verify(hash, signature)) 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') var hash = crypto.sha256('mushrooms')
assert(!pubKey.verify(hash, signature)) assert(!pubKey.verify(hash, signature))

View file

@ -1,3 +1,5 @@
/* global describe, it */
var assert = require('assert') var assert = require('assert')
var BigInteger = require('bigi') var BigInteger = require('bigi')
@ -5,13 +7,13 @@ var ECSignature = require('../src/ecsignature')
var fixtures = require('./fixtures/ecsignature.json') var fixtures = require('./fixtures/ecsignature.json')
describe('ECSignature', function() { describe('ECSignature', function () {
describe('toCompact', function() { describe('toCompact', function () {
fixtures.valid.forEach(function(f) { fixtures.valid.forEach(function (f) {
it('exports ' + f.compact.hex + ' correctly', function() { it('exports ' + f.compact.hex + ' correctly', function () {
var signature = new ECSignature( var signature = new ECSignature(
new BigInteger(f.signature.r), new BigInteger(f.signature.r),
new BigInteger(f.signature.s) new BigInteger(f.signature.s)
) )
var buffer = signature.toCompact(f.compact.i, f.compact.compressed) var buffer = signature.toCompact(f.compact.i, f.compact.compressed)
@ -20,9 +22,9 @@ describe('ECSignature', function() {
}) })
}) })
describe('parseCompact', function() { describe('parseCompact', function () {
fixtures.valid.forEach(function(f) { fixtures.valid.forEach(function (f) {
it('imports ' + f.compact.hex + ' correctly', function() { it('imports ' + f.compact.hex + ' correctly', function () {
var buffer = new Buffer(f.compact.hex, 'hex') var buffer = new Buffer(f.compact.hex, 'hex')
var parsed = ECSignature.parseCompact(buffer) var parsed = ECSignature.parseCompact(buffer)
@ -33,23 +35,23 @@ describe('ECSignature', function() {
}) })
}) })
fixtures.invalid.compact.forEach(function(f) { fixtures.invalid.compact.forEach(function (f) {
it('throws on ' + f.hex, function() { it('throws on ' + f.hex, function () {
var buffer = new Buffer(f.hex, 'hex') var buffer = new Buffer(f.hex, 'hex')
assert.throws(function() { assert.throws(function () {
ECSignature.parseCompact(buffer) ECSignature.parseCompact(buffer)
}, new RegExp(f.exception)) }, new RegExp(f.exception))
}) })
}) })
}) })
describe('toDER', function() { describe('toDER', function () {
fixtures.valid.forEach(function(f) { fixtures.valid.forEach(function (f) {
it('exports ' + f.DER + ' correctly', function() { it('exports ' + f.DER + ' correctly', function () {
var signature = new ECSignature( var signature = new ECSignature(
new BigInteger(f.signature.r), new BigInteger(f.signature.r),
new BigInteger(f.signature.s) new BigInteger(f.signature.s)
) )
var DER = signature.toDER() var DER = signature.toDER()
@ -58,9 +60,9 @@ describe('ECSignature', function() {
}) })
}) })
describe('fromDER', function() { describe('fromDER', function () {
fixtures.valid.forEach(function(f) { fixtures.valid.forEach(function (f) {
it('imports ' + f.DER + ' correctly', function() { it('imports ' + f.DER + ' correctly', function () {
var buffer = new Buffer(f.DER, 'hex') var buffer = new Buffer(f.DER, 'hex')
var signature = ECSignature.fromDER(buffer) var signature = ECSignature.fromDER(buffer)
@ -69,23 +71,23 @@ describe('ECSignature', function() {
}) })
}) })
fixtures.invalid.DER.forEach(function(f) { fixtures.invalid.DER.forEach(function (f) {
it('throws on ' + f.hex, function() { it('throws on ' + f.hex, function () {
var buffer = new Buffer(f.hex, 'hex') var buffer = new Buffer(f.hex, 'hex')
assert.throws(function() { assert.throws(function () {
ECSignature.fromDER(buffer) ECSignature.fromDER(buffer)
}, new RegExp(f.exception)) }, new RegExp(f.exception))
}) })
}) })
}) })
describe('toScriptSignature', function() { describe('toScriptSignature', function () {
fixtures.valid.forEach(function(f) { fixtures.valid.forEach(function (f) {
it('exports ' + f.scriptSignature.hex + ' correctly', function() { it('exports ' + f.scriptSignature.hex + ' correctly', function () {
var signature = new ECSignature( var signature = new ECSignature(
new BigInteger(f.signature.r), new BigInteger(f.signature.r),
new BigInteger(f.signature.s) new BigInteger(f.signature.s)
) )
var scriptSignature = signature.toScriptSignature(f.scriptSignature.hashType) var scriptSignature = signature.toScriptSignature(f.scriptSignature.hashType)
@ -93,23 +95,23 @@ describe('ECSignature', function() {
}) })
}) })
fixtures.invalid.scriptSignature.forEach(function(f) { fixtures.invalid.scriptSignature.forEach(function (f) {
it('throws ' + f.exception, function() { it('throws ' + f.exception, function () {
var signature = new ECSignature( var signature = new ECSignature(
new BigInteger(f.signature.r), new BigInteger(f.signature.r),
new BigInteger(f.signature.s) new BigInteger(f.signature.s)
) )
assert.throws(function() { assert.throws(function () {
signature.toScriptSignature(f.hashType) signature.toScriptSignature(f.hashType)
}, new RegExp(f.exception)) }, new RegExp(f.exception))
}) })
}) })
}) })
describe('parseScriptSignature', function() { describe('parseScriptSignature', function () {
fixtures.valid.forEach(function(f) { fixtures.valid.forEach(function (f) {
it('imports ' + f.scriptSignature.hex + ' correctly', function() { it('imports ' + f.scriptSignature.hex + ' correctly', function () {
var buffer = new Buffer(f.scriptSignature.hex, 'hex') var buffer = new Buffer(f.scriptSignature.hex, 'hex')
var parsed = ECSignature.parseScriptSignature(buffer) var parsed = ECSignature.parseScriptSignature(buffer)
@ -119,11 +121,11 @@ describe('ECSignature', function() {
}) })
}) })
fixtures.invalid.scriptSignature.forEach(function(f) { fixtures.invalid.scriptSignature.forEach(function (f) {
it('throws on ' + f.hex, function() { it('throws on ' + f.hex, function () {
var buffer = new Buffer(f.hex, 'hex') var buffer = new Buffer(f.hex, 'hex')
assert.throws(function() { assert.throws(function () {
ECSignature.parseScriptSignature(buffer) ECSignature.parseScriptSignature(buffer)
}, new RegExp(f.exception)) }, new RegExp(f.exception))
}) })

View file

@ -1,3 +1,6 @@
/* global describe, it */
/* eslint-disable no-new */
var assert = require('assert') var assert = require('assert')
var networks = require('../src/networks') var networks = require('../src/networks')
@ -11,50 +14,50 @@ var curve = ecurve.getCurveByName('secp256k1')
var fixtures = require('./fixtures/hdnode.json') var fixtures = require('./fixtures/hdnode.json')
describe('HDNode', function() { describe('HDNode', function () {
describe('Constructor', function() { describe('Constructor', function () {
var d = BigInteger.ONE var d = BigInteger.ONE
var Q = curve.G.multiply(d) var Q = curve.G.multiply(d)
var chainCode = new Buffer(32) var chainCode = new Buffer(32)
chainCode.fill(1) 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) var hd = new HDNode(d, chainCode)
assert(hd.pubKey.Q.equals(Q)) assert(hd.pubKey.Q.equals(Q))
}) })
it('allows initialization directly from an ECKey', function() { it('allows initialization directly from an ECKey', function () {
var ek = new ECKey(d) var ek = new ECKey(d)
var hd = new HDNode(ek, chainCode) var hd = new HDNode(ek, chainCode)
assert.equal(hd.privKey, ek) assert.equal(hd.privKey, ek)
}) })
it('allows initialization directly from an ECPubKey', function() { it('allows initialization directly from an ECPubKey', function () {
var ek = new ECPubKey(Q) var ek = new ECPubKey(Q)
var hd = new HDNode(ek, chainCode) var hd = new HDNode(ek, chainCode)
assert.equal(hd.pubKey, ek) assert.equal(hd.pubKey, ek)
}) })
it('throws if ECKey is not compressed', function() { it('throws if ECKey is not compressed', function () {
var ek = new ECKey(d, false) var ek = new ECKey(d, false)
assert.throws(function() { assert.throws(function () {
new HDNode(ek, chainCode) new HDNode(ek, chainCode)
}, /ECKey must be compressed/) }, /ECKey must be compressed/)
}) })
it('throws if ECPubKey is not compressed', function() { it('throws if ECPubKey is not compressed', function () {
var ek = new ECPubKey(Q, false) var ek = new ECPubKey(Q, false)
assert.throws(function() { assert.throws(function () {
new HDNode(ek, chainCode) new HDNode(ek, chainCode)
}, /ECPubKey must be compressed/) }, /ECPubKey must be compressed/)
}) })
it('only uses compressed points', function() { it('only uses compressed points', function () {
var hd = new HDNode(Q, chainCode) var hd = new HDNode(Q, chainCode)
var hdP = new HDNode(d, chainCode) var hdP = new HDNode(d, chainCode)
@ -62,41 +65,41 @@ describe('HDNode', function() {
assert.strictEqual(hdP.pubKey.compressed, true) 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) var hd = new HDNode(Q, chainCode)
assert.strictEqual(hd.depth, 0) assert.strictEqual(hd.depth, 0)
assert.strictEqual(hd.index, 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) var hd = new HDNode(Q, chainCode)
assert.equal(hd.network, networks.bitcoin) assert.equal(hd.network, networks.bitcoin)
}) })
it('supports alternative networks', function() { it('supports alternative networks', function () {
var hd = new HDNode(Q, chainCode, networks.testnet) var hd = new HDNode(Q, chainCode, networks.testnet)
assert.equal(hd.network, networks.testnet) assert.equal(hd.network, networks.testnet)
}) })
it('throws when an invalid length chain code is given', function() { it('throws when an invalid length chain code is given', function () {
assert.throws(function() { assert.throws(function () {
new HDNode(d, chainCode.slice(0, 20), networks.testnet) new HDNode(d, chainCode.slice(0, 20), networks.testnet)
}, /Expected chainCode length of 32, got 20/) }, /Expected chainCode length of 32, got 20/)
}) })
it('throws when an unknown network is given', function() { it('throws when an unknown network is given', function () {
assert.throws(function() { assert.throws(function () {
new HDNode(d, chainCode, {}) new HDNode(d, chainCode, {})
}, /Unknown BIP32 constants for network/) }, /Unknown BIP32 constants for network/)
}) })
}) })
describe('fromSeed*', function() { describe('fromSeed*', function () {
fixtures.valid.forEach(function(f) { fixtures.valid.forEach(function (f) {
it('calculates privKey and chainCode for ' + f.master.fingerprint, function() { it('calculates privKey and chainCode for ' + f.master.fingerprint, function () {
var network = networks[f.network] var network = networks[f.network]
var hd = HDNode.fromSeedHex(f.master.seed, network) var hd = HDNode.fromSeedHex(f.master.seed, network)
@ -105,22 +108,22 @@ describe('HDNode', function() {
}) })
}) })
it('throws on low entropy seed', function() { it('throws on low entropy seed', function () {
assert.throws(function() { assert.throws(function () {
HDNode.fromSeedHex('ffffffffff') HDNode.fromSeedHex('ffffffffff')
}, /Seed should be at least 128 bits/) }, /Seed should be at least 128 bits/)
}) })
it('throws on too high entropy seed', function() { it('throws on too high entropy seed', function () {
assert.throws(function() { assert.throws(function () {
HDNode.fromSeedHex('ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff') HDNode.fromSeedHex('ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff')
}, /Seed should be at most 512 bits/) }, /Seed should be at most 512 bits/)
}) })
}) })
describe('toBase58', function() { describe('toBase58', function () {
fixtures.valid.forEach(function(f) { fixtures.valid.forEach(function (f) {
it('exports ' + f.master.base58 + ' (public) correctly', function() { it('exports ' + f.master.base58 + ' (public) correctly', function () {
var network = networks[f.network] var network = networks[f.network]
var hd = HDNode.fromSeedHex(f.master.seed, network).neutered() var hd = HDNode.fromSeedHex(f.master.seed, network).neutered()
@ -128,8 +131,8 @@ describe('HDNode', function() {
}) })
}) })
fixtures.valid.forEach(function(f) { fixtures.valid.forEach(function (f) {
it('exports ' + f.master.base58Priv + ' (private) correctly', function() { it('exports ' + f.master.base58Priv + ' (private) correctly', function () {
var network = networks[f.network] var network = networks[f.network]
var hd = HDNode.fromSeedHex(f.master.seed, network) var hd = HDNode.fromSeedHex(f.master.seed, network)
@ -138,35 +141,35 @@ describe('HDNode', function() {
}) })
// FIXME: remove in 2.x.y // FIXME: remove in 2.x.y
it('fails when there is no private key', function() { it('fails when there is no private key', function () {
var hd = HDNode.fromBase58(fixtures.valid[0].master.base58) var hd = HDNode.fromBase58(fixtures.valid[0].master.base58)
assert.throws(function() { assert.throws(function () {
hd.toBase58(true) hd.toBase58(true)
}, /Missing private key/) }, /Missing private key/)
}) })
}) })
describe('fromBase58', function() { describe('fromBase58', function () {
fixtures.valid.forEach(function(f) { fixtures.valid.forEach(function (f) {
it('imports ' + f.master.base58 + ' (public) correctly', function() { it('imports ' + f.master.base58 + ' (public) correctly', function () {
var hd = HDNode.fromBase58(f.master.base58) var hd = HDNode.fromBase58(f.master.base58)
assert.equal(hd.toBase58(), f.master.base58) assert.equal(hd.toBase58(), f.master.base58)
}) })
}) })
fixtures.valid.forEach(function(f) { fixtures.valid.forEach(function (f) {
it('imports ' + f.master.base58Priv + ' (private) correctly', function() { it('imports ' + f.master.base58Priv + ' (private) correctly', function () {
var hd = HDNode.fromBase58(f.master.base58Priv) var hd = HDNode.fromBase58(f.master.base58Priv)
assert.equal(hd.toBase58(), f.master.base58Priv) assert.equal(hd.toBase58(), f.master.base58Priv)
}) })
}) })
fixtures.invalid.fromBase58.forEach(function(f) { fixtures.invalid.fromBase58.forEach(function (f) {
it('throws on ' + f.string, function() { it('throws on ' + f.string, function () {
assert.throws(function() { assert.throws(function () {
var network = networks[f.network] var network = networks[f.network]
HDNode.fromBase58(f.string, network) HDNode.fromBase58(f.string, network)
@ -175,43 +178,43 @@ describe('HDNode', function() {
}) })
}) })
describe('fromBuffer/fromHex', function() { describe('fromBuffer/fromHex', function () {
fixtures.valid.forEach(function(f) { fixtures.valid.forEach(function (f) {
it('imports ' + f.master.hex + ' (public) correctly', function() { it('imports ' + f.master.hex + ' (public) correctly', function () {
var hd = HDNode.fromHex(f.master.hex) var hd = HDNode.fromHex(f.master.hex)
assert.equal(hd.toBuffer().toString('hex'), f.master.hex) assert.equal(hd.toBuffer().toString('hex'), f.master.hex)
}) })
}) })
fixtures.valid.forEach(function(f) { fixtures.valid.forEach(function (f) {
it('imports ' + f.master.hexPriv + ' (private) correctly', function() { it('imports ' + f.master.hexPriv + ' (private) correctly', function () {
var hd = HDNode.fromHex(f.master.hexPriv) var hd = HDNode.fromHex(f.master.hexPriv)
assert.equal(hd.toBuffer().toString('hex'), f.master.hexPriv) assert.equal(hd.toBuffer().toString('hex'), f.master.hexPriv)
}) })
}) })
fixtures.invalid.fromBuffer.forEach(function(f) { fixtures.invalid.fromBuffer.forEach(function (f) {
it('throws on ' + f.hex, function() { it('throws on ' + f.hex, function () {
assert.throws(function() { assert.throws(function () {
HDNode.fromHex(f.hex) HDNode.fromHex(f.hex)
}, new RegExp(f.exception)) }, new RegExp(f.exception))
}) })
}) })
}) })
describe('toBuffer/toHex', function() { describe('toBuffer/toHex', function () {
fixtures.valid.forEach(function(f) { fixtures.valid.forEach(function (f) {
it('exports ' + f.master.hex + ' (public) correctly', function() { it('exports ' + f.master.hex + ' (public) correctly', function () {
var hd = HDNode.fromSeedHex(f.master.seed).neutered() var hd = HDNode.fromSeedHex(f.master.seed).neutered()
assert.equal(hd.toHex(), f.master.hex) assert.equal(hd.toHex(), f.master.hex)
}) })
}) })
fixtures.valid.forEach(function(f) { fixtures.valid.forEach(function (f) {
it('exports ' + f.master.hexPriv + ' (private) correctly', function() { it('exports ' + f.master.hexPriv + ' (private) correctly', function () {
var network = networks[f.network] var network = networks[f.network]
var hd = HDNode.fromSeedHex(f.master.seed, network) var hd = HDNode.fromSeedHex(f.master.seed, network)
@ -220,38 +223,38 @@ describe('HDNode', function() {
}) })
// FIXME: remove in 2.x.y // FIXME: remove in 2.x.y
it('fails when there is no private key', function() { it('fails when there is no private key', function () {
var hd = HDNode.fromHex(fixtures.valid[0].master.hex) var hd = HDNode.fromHex(fixtures.valid[0].master.hex)
assert.throws(function() { assert.throws(function () {
hd.toHex(true) hd.toHex(true)
}, /Missing private key/) }, /Missing private key/)
}) })
}) })
describe('getIdentifier', function() { describe('getIdentifier', function () {
var f = fixtures.valid[0] 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) var hd = HDNode.fromBase58(f.master.base58)
assert.equal(hd.getIdentifier().toString('hex'), f.master.identifier) assert.equal(hd.getIdentifier().toString('hex'), f.master.identifier)
}) })
}) })
describe('getFingerprint', function() { describe('getFingerprint', function () {
var f = fixtures.valid[0] 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) var hd = HDNode.fromBase58(f.master.base58)
assert.equal(hd.getFingerprint().toString('hex'), f.master.fingerprint) assert.equal(hd.getFingerprint().toString('hex'), f.master.fingerprint)
}) })
}) })
describe('getAddress', function() { describe('getAddress', function () {
fixtures.valid.forEach(function(f) { fixtures.valid.forEach(function (f) {
it('returns ' + f.master.address + ' for ' + f.master.fingerprint, function() { it('returns ' + f.master.address + ' for ' + f.master.fingerprint, function () {
var hd = HDNode.fromBase58(f.master.base58) var hd = HDNode.fromBase58(f.master.base58)
assert.equal(hd.getAddress().toString(), f.master.address) assert.equal(hd.getAddress().toString(), f.master.address)
@ -259,10 +262,10 @@ describe('HDNode', function() {
}) })
}) })
describe('neutered', function() { describe('neutered', function () {
var f = fixtures.valid[0] 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 hd = HDNode.fromBase58(f.master.base58)
var hdn = hd.neutered() var hdn = hd.neutered()
@ -274,8 +277,8 @@ describe('HDNode', function() {
}) })
}) })
describe('derive', function() { describe('derive', function () {
function verifyVector(hd, network, v, depth) { function verifyVector (hd, network, v, depth) {
assert.equal(hd.privKey.toWIF(network), v.wif) assert.equal(hd.privKey.toWIF(network), v.wif)
assert.equal(hd.pubKey.toHex(), v.pubKey) assert.equal(hd.pubKey.toHex(), v.pubKey)
assert.equal(hd.chainCode.toString('hex'), v.chainCode) assert.equal(hd.chainCode.toString('hex'), v.chainCode)
@ -288,16 +291,15 @@ describe('HDNode', function() {
} }
} }
fixtures.valid.forEach(function(f) { fixtures.valid.forEach(function (f) {
var network = networks[f.network] var network = networks[f.network]
var hd = HDNode.fromSeedHex(f.master.seed, network) var hd = HDNode.fromSeedHex(f.master.seed, network)
// FIXME: test data is only testing Private -> private for now // FIXME: test data is only testing Private -> private for now
f.children.forEach(function(c, i) { f.children.forEach(function (c, i) {
it(c.description + ' from ' + f.master.fingerprint, function() { it(c.description + ' from ' + f.master.fingerprint, function () {
if (c.hardened) { if (c.hardened) {
hd = hd.deriveHardened(c.m) hd = hd.deriveHardened(c.m)
} else { } else {
hd = hd.derive(c.m) hd = hd.derive(c.m)
} }
@ -307,7 +309,7 @@ describe('HDNode', function() {
}) })
}) })
it('works for Private -> public (neutered)', function() { it('works for Private -> public (neutered)', function () {
var f = fixtures.valid[1] var f = fixtures.valid[1]
var c = f.children[0] var c = f.children[0]
@ -317,7 +319,7 @@ describe('HDNode', function() {
assert.equal(child.toBase58(), c.base58) 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 f = fixtures.valid[0]
var c = f.children[0] var c = f.children[0]
@ -327,7 +329,7 @@ describe('HDNode', function() {
assert.equal(child.toBase58(), c.base58) assert.equal(child.toBase58(), c.base58)
}) })
it('works for Public -> public', function() { it('works for Public -> public', function () {
var f = fixtures.valid[1] var f = fixtures.valid[1]
var c = f.children[0] var c = f.children[0]
@ -337,13 +339,13 @@ describe('HDNode', function() {
assert.equal(child.toBase58(), c.base58) 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 f = fixtures.valid[0]
var c = f.children[0] var c = f.children[0]
var master = HDNode.fromBase58(f.master.base58) var master = HDNode.fromBase58(f.master.base58)
assert.throws(function() { assert.throws(function () {
master.deriveHardened(c.m) master.deriveHardened(c.m)
}, /Could not derive hardened child key/) }, /Could not derive hardened child key/)
}) })

View file

@ -1,9 +1,11 @@
/* global describe, it */
var assert = require('assert') var assert = require('assert')
var bitcoin = require('../../') var bitcoin = require('../../')
var blockchain = new (require('cb-helloblock'))('testnet') var blockchain = new (require('cb-helloblock'))('testnet')
describe('bitcoinjs-lib (advanced)', function() { describe('bitcoinjs-lib (advanced)', function () {
it('can sign a Bitcoin message', function() { it('can sign a Bitcoin message', function () {
var key = bitcoin.ECKey.fromWIF('5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss') var key = bitcoin.ECKey.fromWIF('5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss')
var message = 'This is an example of a signed message.' var message = 'This is an example of a signed message.'
@ -11,7 +13,7 @@ describe('bitcoinjs-lib (advanced)', function() {
assert.equal(signature.toString('base64'), 'G9L5yLFjti0QTHhPyFrZCT1V/MMnBtXKmoiKDZ78NDBjERki6ZTQZdSMCtkgoNmp17By9ItJr8o7ChX0XxY91nk=') 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 address = '1HZwkjkeaoZfTSaJxDw6aKkxp45agDiEzN'
var signature = 'HJLQlDWLyb1Ef8bQKEISzFbDAKctIlaqOpGbrk3YVtRsjmC61lpE5ErkPRUFtDKtx98vHFGUWlFhsh3DiW6N0rE' var signature = 'HJLQlDWLyb1Ef8bQKEISzFbDAKctIlaqOpGbrk3YVtRsjmC61lpE5ErkPRUFtDKtx98vHFGUWlFhsh3DiW6N0rE'
var message = 'This is an example of a signed message.' var message = 'This is an example of a signed message.'
@ -19,16 +21,16 @@ describe('bitcoinjs-lib (advanced)', function() {
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) this.timeout(20000)
var key = bitcoin.ECKey.fromWIF("L1uyy5qTuGrVXrmrsvHWHgVzW9kKdrp27wBC7Vs6nZDTF2BRUVwy") var key = bitcoin.ECKey.fromWIF('L1uyy5qTuGrVXrmrsvHWHgVzW9kKdrp27wBC7Vs6nZDTF2BRUVwy')
var address = key.pub.getAddress(bitcoin.networks.testnet).toString() 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) if (err) return done(err)
blockchain.addresses.unspents(address, function(err, unspents) { blockchain.addresses.unspents(address, function (err, unspents) {
if (err) return done(err) if (err) return done(err)
var tx = new bitcoin.TransactionBuilder() var tx = new bitcoin.TransactionBuilder()
@ -43,11 +45,11 @@ describe('bitcoinjs-lib (advanced)', function() {
var txBuilt = tx.build() var txBuilt = tx.build()
blockchain.transactions.propagate(txBuilt.toHex(), function(err) { blockchain.transactions.propagate(txBuilt.toHex(), function (err) {
if (err) return done(err) if (err) return done(err)
// check that the message was propagated // 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) if (err) return done(err)
var actual = bitcoin.Transaction.fromHex(transaction.txHex) var actual = bitcoin.Transaction.fromHex(transaction.txHex)

View file

@ -1,11 +1,13 @@
/* global describe, it */
var assert = require('assert') var assert = require('assert')
var bigi = require('bigi') var bigi = require('bigi')
var bitcoin = require('../../') var bitcoin = require('../../')
var crypto = require('crypto') var crypto = require('crypto')
var sinon = require('sinon') var sinon = require('sinon')
describe('bitcoinjs-lib (basic)', function() { describe('bitcoinjs-lib (basic)', function () {
it('can generate a random bitcoin address', sinon.test(function() { it('can generate a random bitcoin address', sinon.test(function () {
// for testing only // for testing only
this.mock(crypto).expects('randomBytes') this.mock(crypto).expects('randomBytes')
.onCall(0).returns(new Buffer('zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz')) .onCall(0).returns(new Buffer('zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz'))
@ -17,7 +19,7 @@ describe('bitcoinjs-lib (basic)', function() {
assert.equal(address, '1F5VhMHukdnUES9kfXqzPzMeF1GPHKiF64') 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 hash = bitcoin.crypto.sha256('correct horse battery staple')
var d = bigi.fromBuffer(hash) var d = bigi.fromBuffer(hash)
@ -26,19 +28,19 @@ describe('bitcoinjs-lib (basic)', function() {
assert.equal(key.pub.getAddress().toString(), '1C7zdTfnkzmr13HfA2vNm5SJYRK6nEKyq8') 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 key = bitcoin.ECKey.fromWIF('Kxr9tQED9H44gCmp6HAdmemAzU3n84H3dGkuWTKvE23JgHMW8gct')
var address = key.pub.getAddress().toString() var address = key.pub.getAddress().toString()
assert.equal(address, '19AAjaTUbRjQCMuVczepkoPswiZRhjtg31') assert.equal(address, '19AAjaTUbRjQCMuVczepkoPswiZRhjtg31')
}) })
it('can create a Transaction', function() { it('can create a Transaction', function () {
var key = bitcoin.ECKey.fromWIF("L1uyy5qTuGrVXrmrsvHWHgVzW9kKdrp27wBC7Vs6nZDTF2BRUVwy") var key = bitcoin.ECKey.fromWIF('L1uyy5qTuGrVXrmrsvHWHgVzW9kKdrp27wBC7Vs6nZDTF2BRUVwy')
var tx = new bitcoin.TransactionBuilder() var tx = new bitcoin.TransactionBuilder()
tx.addInput("aa94ab02c182214f090e99a0d57021caffd0f195a81c24602b1028b130b63e31", 0) tx.addInput('aa94ab02c182214f090e99a0d57021caffd0f195a81c24602b1028b130b63e31', 0)
tx.addOutput("1Gokm82v6DmtwKEB8AiVhm82hyFSsEvBDK", 15000) tx.addOutput('1Gokm82v6DmtwKEB8AiVhm82hyFSsEvBDK', 15000)
tx.sign(0, key) tx.sign(0, key)
assert.equal(tx.build().toHex(), '0100000001313eb630b128102b60241ca895f1d0ffca2170d5a0990e094f2182c102ab94aa000000006b483045022100aefbcf847900b01dd3e3debe054d3b6d03d715d50aea8525f5ea3396f168a1fb022013d181d05b15b90111808b22ef4f9ebe701caf2ab48db269691fdf4e9048f4f60121029f50f51d63b345039a290c94bffd3180c99ed659ff6ea6b1242bca47eb93b59fffffffff01983a0000000000001976a914ad618cf4333b3b248f9744e8e81db2964d0ae39788ac00000000') assert.equal(tx.build().toHex(), '0100000001313eb630b128102b60241ca895f1d0ffca2170d5a0990e094f2182c102ab94aa000000006b483045022100aefbcf847900b01dd3e3debe054d3b6d03d715d50aea8525f5ea3396f168a1fb022013d181d05b15b90111808b22ef4f9ebe701caf2ab48db269691fdf4e9048f4f60121029f50f51d63b345039a290c94bffd3180c99ed659ff6ea6b1242bca47eb93b59fffffffff01983a0000000000001976a914ad618cf4333b3b248f9744e8e81db2964d0ae39788ac00000000')

View file

@ -1,3 +1,5 @@
/* global describe, it */
var assert = require('assert') var assert = require('assert')
var async = require('async') var async = require('async')
var bigi = require('bigi') var bigi = require('bigi')
@ -5,8 +7,8 @@ var bitcoin = require('../../')
var blockchain = new (require('cb-helloblock'))('bitcoin') var blockchain = new (require('cb-helloblock'))('bitcoin')
var crypto = require('crypto') var crypto = require('crypto')
describe('bitcoinjs-lib (crypto)', function() { describe('bitcoinjs-lib (crypto)', function () {
it('can generate a single-key stealth address', function() { it('can generate a single-key stealth address', function () {
var receiver = bitcoin.ECKey.fromWIF('5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss') var receiver = bitcoin.ECKey.fromWIF('5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss')
// XXX: ephemeral, must be random (and secret to sender) to preserve privacy // XXX: ephemeral, must be random (and secret to sender) to preserve privacy
@ -39,10 +41,10 @@ describe('bitcoinjs-lib (crypto)', function() {
}) })
// TODO // 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() { 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) { function recoverParent (master, child) {
assert(!master.privKey, 'You already have the parent private key') assert(!master.privKey, 'You already have the parent private key')
assert(child.privKey, 'Missing child private key') assert(child.privKey, 'Missing child private key')
@ -87,33 +89,35 @@ describe('bitcoinjs-lib (crypto)', function() {
assert.equal(recovered.toBase58(), master.toBase58()) 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 = [ var inputs = [
{ {
txId: "f4c16475f2a6e9c602e4a287f9db3040e319eb9ece74761a4b84bc820fbeef50", txId: 'f4c16475f2a6e9c602e4a287f9db3040e319eb9ece74761a4b84bc820fbeef50',
vout: 0 vout: 0
}, },
{ {
txId: "f4c16475f2a6e9c602e4a287f9db3040e319eb9ece74761a4b84bc820fbeef50", txId: 'f4c16475f2a6e9c602e4a287f9db3040e319eb9ece74761a4b84bc820fbeef50',
vout: 1 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 // first retrieve the relevant transactions
blockchain.transactions.get(txIds, function(err, results) { blockchain.transactions.get(txIds, function (err, results) {
assert.ifError(err) assert.ifError(err)
var transactions = {} var transactions = {}
results.forEach(function(tx) { results.forEach(function (tx) {
transactions[tx.txId] = bitcoin.Transaction.fromHex(tx.txHex) transactions[tx.txId] = bitcoin.Transaction.fromHex(tx.txHex)
}) })
var tasks = [] var tasks = []
// now we need to collect/transform a bit of data from the selected inputs // 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 transaction = transactions[input.txId]
var script = transaction.ins[input.vout].script var script = transaction.ins[input.vout].script
assert(bitcoin.scripts.isPubKeyHashInput(script), 'Expected pubKeyHash 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 prevOutTxId = bitcoin.bufferutils.reverse(transaction.ins[input.vout].hash).toString('hex')
var prevVout = transaction.ins[input.vout].index var prevVout = transaction.ins[input.vout].index
tasks.push(function(callback) { tasks.push(function (callback) {
blockchain.transactions.get(prevOutTxId, function(err, result) { blockchain.transactions.get(prevOutTxId, function (err, result) {
if (err) return callback(err) if (err) return callback(err)
var prevOut = bitcoin.Transaction.fromHex(result.txHex) 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 // finally, run the tasks, then on to the math
async.parallel(tasks, function(err) { async.parallel(tasks, function (err) {
if (err) throw err if (err)
throw err
var n = bitcoin.ECKey.curve.n var n = bitcoin.ECKey.curve.n
for (var i = 0; i < inputs.length; ++i) { for (var i = 0; i < inputs.length; ++i) {
@ -170,8 +175,8 @@ describe('bitcoinjs-lib (crypto)', function() {
// d1 = (s1 * k - z1) / r // d1 = (s1 * k - z1) / r
// d2 = (s2 * k - z2) / r // d2 = (s2 * k - z2) / r
var k = zz.multiply(ss.modInverse(n)).mod(n) 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 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 d2 = ((s2.multiply(k).mod(n)).subtract(z2).mod(n)).multiply(rInv).mod(n)
// enforce matching private keys // enforce matching private keys
assert.equal(d1.toString(), d2.toString()) assert.equal(d1.toString(), d2.toString())

View file

@ -1,9 +1,11 @@
/* global describe, it */
var assert = require('assert') var assert = require('assert')
var bitcoin = require('../../') var bitcoin = require('../../')
var blockchain = new (require('cb-helloblock'))('testnet') var blockchain = new (require('cb-helloblock'))('testnet')
describe('bitcoinjs-lib (multisig)', function() { describe('bitcoinjs-lib (multisig)', function () {
it('can create a 2-of-3 multisig P2SH address', function() { it('can create a 2-of-3 multisig P2SH address', function () {
var pubKeys = [ var pubKeys = [
'026477115981fe981a6918a6297d9803c4dc04f328f22041bedff886bbc2962e01', '026477115981fe981a6918a6297d9803c4dc04f328f22041bedff886bbc2962e01',
'02c96db2302d19b43d4c69368babace7854cc84eb9e061cde51cfa77ca4a22b8b9', '02c96db2302d19b43d4c69368babace7854cc84eb9e061cde51cfa77ca4a22b8b9',
@ -17,29 +19,33 @@ describe('bitcoinjs-lib (multisig)', function() {
assert.equal(address, '36NUkt6FWUi3LAWBqWRdDmdTWbt91Yvfu7') 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) this.timeout(20000)
var privKeys = [ var privKeys = [
'91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx', '91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx',
'91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgww7vXtT' '91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgww7vXtT'
].map(bitcoin.ECKey.fromWIF) ].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 redeemScript = bitcoin.scripts.multisigOutput(2, pubKeys) // 2 of 2
var scriptPubKey = bitcoin.scripts.scriptHashOutput(redeemScript.getHash()) var scriptPubKey = bitcoin.scripts.scriptHashOutput(redeemScript.getHash())
var address = bitcoin.Address.fromOutputScript(scriptPubKey, bitcoin.networks.testnet).toString() var address = bitcoin.Address.fromOutputScript(scriptPubKey, bitcoin.networks.testnet).toString()
// Attempt to send funds to the source address // 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) if (err) return done(err)
// get latest unspents from the address // 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) if (err) return done(err)
// filter small unspents // 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 // use the oldest unspent
var unspent = unspents.pop() var unspent = unspents.pop()
@ -52,16 +58,16 @@ describe('bitcoinjs-lib (multisig)', function() {
txb.addOutput(targetAddress, 1e4) txb.addOutput(targetAddress, 1e4)
// sign w/ each private key // sign w/ each private key
privKeys.forEach(function(privKey) { privKeys.forEach(function (privKey) {
txb.sign(0, privKey, redeemScript) txb.sign(0, privKey, redeemScript)
}) })
// broadcast our transaction // broadcast our transaction
blockchain.transactions.propagate(txb.build().toHex(), function(err) { blockchain.transactions.propagate(txb.build().toHex(), function (err) {
if (err) return done(err) if (err) return done(err)
// check that the funds (1e4 Satoshis) indeed arrived at the intended address // 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) if (err) return done(err)
assert.equal(result.balance, 1e4) assert.equal(result.balance, 1e4)

View file

@ -1,3 +1,5 @@
/* global describe, it */
var assert = require('assert') var assert = require('assert')
var networks = require('../src/networks') var networks = require('../src/networks')
@ -8,10 +10,10 @@ var Message = require('../src/message')
var fixtures = require('./fixtures/message.json') var fixtures = require('./fixtures/message.json')
describe('Message', function() { describe('Message', function () {
describe('magicHash', function() { describe('magicHash', function () {
fixtures.valid.magicHash.forEach(function(f) { fixtures.valid.magicHash.forEach(function (f) {
it('produces the correct magicHash for \"' + f.message + '\" (' + f.network + ')', function() { it('produces the correct magicHash for "' + f.message + '" (' + f.network + ')', function () {
var network = networks[f.network] var network = networks[f.network]
var actual = Message.magicHash(f.message, network) var actual = Message.magicHash(f.message, network)
@ -20,8 +22,8 @@ describe('Message', function() {
}) })
}) })
describe('verify', function() { describe('verify', function () {
it('accepts an Address object', function() { it('accepts an Address object', function () {
var f = fixtures.valid.verify[0] var f = fixtures.valid.verify[0]
var network = networks[f.network] var network = networks[f.network]
@ -29,8 +31,8 @@ describe('Message', function() {
assert(Message.verify(address, f.signature, f.message, network)) assert(Message.verify(address, f.signature, f.message, network))
}) })
fixtures.valid.verify.forEach(function(f) { fixtures.valid.verify.forEach(function (f) {
it('verifies a valid signature for \"' + f.message + '\" (' + f.network + ')', function() { it('verifies a valid signature for "' + f.message + '" (' + f.network + ')', function () {
var network = networks[f.network] 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))
@ -41,16 +43,16 @@ describe('Message', function() {
}) })
}) })
fixtures.invalid.verify.forEach(function(f) { fixtures.invalid.verify.forEach(function (f) {
it(f.description, function() { it(f.description, function () {
assert(!Message.verify(f.address, f.signature, f.message)) assert(!Message.verify(f.address, f.signature, f.message))
}) })
}) })
}) })
describe('signing', function() { describe('signing', function () {
fixtures.valid.signing.forEach(function(f) { fixtures.valid.signing.forEach(function (f) {
it(f.description, function() { it(f.description, function () {
var network = networks[f.network] var network = networks[f.network]
var privKey = new ECKey(new BigInteger(f.d), false) var privKey = new ECKey(new BigInteger(f.d), false)

View file

@ -1,3 +1,5 @@
/* global describe, it, before, after */
var assert = require('assert') var assert = require('assert')
var networks = require('../src/networks') var networks = require('../src/networks')
var sinon = require('sinon') var sinon = require('sinon')
@ -7,36 +9,36 @@ var Transaction = require('../src/transaction')
var fixtures = require('./fixtures/network') var fixtures = require('./fixtures/network')
describe('networks', function() { describe('networks', function () {
var txToBuffer var txToBuffer
before(function(){ before(function () {
txToBuffer = sinon.stub(Transaction.prototype, "toBuffer") txToBuffer = sinon.stub(Transaction.prototype, 'toBuffer')
}) })
after(function(){ after(function () {
Transaction.prototype.toBuffer.restore() Transaction.prototype.toBuffer.restore()
}) })
describe('constants', function() { describe('constants', function () {
fixtures.valid.constants.forEach(function(f) { fixtures.valid.constants.forEach(function (f) {
var network = networks[f.network] var network = networks[f.network]
Object.keys(f.bip32).forEach(function(name) { Object.keys(f.bip32).forEach(function (name) {
var extb58 = f.bip32[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) assert.equal(HDNode.fromBase58(extb58, network).network, network)
}) })
}) })
}) })
}) })
describe('estimateFee', function() { describe('estimateFee', function () {
fixtures.valid.estimateFee.forEach(function(f) { fixtures.valid.estimateFee.forEach(function (f) {
describe('(' + f.network + ')', function() { describe('(' + f.network + ')', function () {
var network = networks[f.network] 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) var buffer = new Buffer(f.txSize)
txToBuffer.returns(buffer) txToBuffer.returns(buffer)

View file

@ -1,3 +1,6 @@
/* global describe, it */
/* eslint-disable no-new */
var assert = require('assert') var assert = require('assert')
var opcodes = require('../src/opcodes') var opcodes = require('../src/opcodes')
@ -5,9 +8,9 @@ var Script = require('../src/script')
var fixtures = require('./fixtures/script.json') var fixtures = require('./fixtures/script.json')
describe('Script', function() { describe('Script', function () {
describe('constructor', function() { describe('constructor', function () {
it('accepts valid parameters', function() { it('accepts valid parameters', function () {
var buffer = new Buffer([1]) var buffer = new Buffer([1])
var chunks = [1] var chunks = [1]
var script = new Script(buffer, chunks) var script = new Script(buffer, chunks)
@ -16,30 +19,32 @@ describe('Script', function() {
assert.equal(script.chunks, chunks) assert.equal(script.chunks, chunks)
}) })
it('throws an error when input is not an array', function() { it('throws an error when input is not an array', function () {
assert.throws(function(){ new Script({}) }, /Expected Buffer, got/) assert.throws(function () {
new Script({})
}, /Expected Buffer, got/)
}) })
}) })
describe('fromASM/toASM', function() { describe('fromASM/toASM', function () {
fixtures.valid.forEach(function(f) { fixtures.valid.forEach(function (f) {
it('decodes/encodes ' + f.description, function() { it('decodes/encodes ' + f.description, function () {
assert.equal(Script.fromASM(f.asm).toASM(), f.asm) assert.equal(Script.fromASM(f.asm).toASM(), f.asm)
}) })
}) })
}) })
describe('fromHex/toHex', function() { describe('fromHex/toHex', function () {
fixtures.valid.forEach(function(f) { fixtures.valid.forEach(function (f) {
it('decodes/encodes ' + f.description, function() { it('decodes/encodes ' + f.description, function () {
assert.equal(Script.fromHex(f.hex).toHex(), f.hex) assert.equal(Script.fromHex(f.hex).toHex(), f.hex)
}) })
}) })
}) })
describe('getHash', function() { describe('getHash', function () {
fixtures.valid.forEach(function(f) { fixtures.valid.forEach(function (f) {
it('produces a HASH160 of \"' + f.asm + '\"', function() { it('produces a HASH160 of "' + f.asm + '"', function () {
var script = Script.fromHex(f.hex) var script = Script.fromHex(f.hex)
assert.equal(script.getHash().toString('hex'), f.hash) assert.equal(script.getHash().toString('hex'), f.hash)
@ -47,8 +52,8 @@ describe('Script', function() {
}) })
}) })
describe('fromChunks', function() { describe('fromChunks', function () {
it('should match expected behaviour', function() { it('should match expected behaviour', function () {
var hash = new Buffer(32) var hash = new Buffer(32)
hash.fill(0) hash.fill(0)
@ -62,17 +67,17 @@ describe('Script', function() {
}) })
}) })
describe('without', function() { describe('without', function () {
var hex = 'a914e8c300c87986efa94c37c0519929019ef86eb5b487' var hex = 'a914e8c300c87986efa94c37c0519929019ef86eb5b487'
var script = Script.fromHex(hex) 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) var subScript = script.without(opcodes.OP_HASH160)
assert.equal(subScript.toHex(), '14e8c300c87986efa94c37c0519929019ef86eb5b487') 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) var subScript = script.without(opcodes.OP_EQUAL)
assert.notEqual(subScript.toHex(), hex) assert.notEqual(subScript.toHex(), hex)

View file

@ -1,3 +1,5 @@
/* global describe, it */
var assert = require('assert') var assert = require('assert')
var ops = require('../src/opcodes') var ops = require('../src/opcodes')
var scripts = require('../src/scripts') var scripts = require('../src/scripts')
@ -7,16 +9,16 @@ var Script = require('../src/script')
var fixtures = require('./fixtures/scripts.json') var fixtures = require('./fixtures/scripts.json')
describe('Scripts', function() { describe('Scripts', function () {
// TODO // TODO
describe.skip('isCanonicalPubKey', function() {}) describe.skip('isCanonicalPubKey', function () {})
describe.skip('isCanonicalSignature', function() {}) describe.skip('isCanonicalSignature', function () {})
describe('classifyInput', function() { describe('classifyInput', function () {
fixtures.valid.forEach(function(f) { fixtures.valid.forEach(function (f) {
if (!f.scriptSig) return 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 script = Script.fromASM(f.scriptSig)
var type = scripts.classifyInput(script) 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.scriptSig) return
if (!f.typeIncomplete) 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 script = Script.fromASM(f.scriptSig)
var type = scripts.classifyInput(script, true) var type = scripts.classifyInput(script, true)
@ -37,11 +39,11 @@ describe('Scripts', function() {
}) })
}) })
describe('classifyOutput', function() { describe('classifyOutput', function () {
fixtures.valid.forEach(function(f) { fixtures.valid.forEach(function (f) {
if (!f.scriptPubKey) return 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 script = Script.fromASM(f.scriptPubKey)
var type = scripts.classifyOutput(script) 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 inputFnName = 'is' + type + 'Input'
var outputFnName = 'is' + type + 'Output' var outputFnName = 'is' + type + 'Output'
var inputFn = scripts[inputFnName] var inputFn = scripts[inputFnName]
var outputFn= scripts[outputFnName] var outputFn = scripts[outputFnName]
describe('is' + type + 'Input', function() { describe('is' + type + 'Input', function () {
fixtures.valid.forEach(function(f) { fixtures.valid.forEach(function (f) {
var expected = type.toLowerCase() === f.type var expected = type.toLowerCase() === f.type
if (inputFn && f.scriptSig) { if (inputFn && f.scriptSig) {
it('returns ' + expected + ' for ' + f.scriptSig, function() { it('returns ' + expected + ' for ' + f.scriptSig, function () {
var script = Script.fromASM(f.scriptSig) var script = Script.fromASM(f.scriptSig)
assert.equal(inputFn(script), expected) assert.equal(inputFn(script), expected)
@ -71,7 +73,7 @@ describe('Scripts', function() {
if (f.typeIncomplete) { if (f.typeIncomplete) {
var expectedIncomplete = type.toLowerCase() === 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) var script = Script.fromASM(f.scriptSig)
assert.equal(inputFn(script, true), expectedIncomplete) assert.equal(inputFn(script, true), expectedIncomplete)
@ -82,9 +84,9 @@ describe('Scripts', function() {
if (!(inputFnName in fixtures.invalid)) return if (!(inputFnName in fixtures.invalid)) return
fixtures.invalid[inputFnName].forEach(function(f) { fixtures.invalid[inputFnName].forEach(function (f) {
if (inputFn && f.scriptSig) { if (inputFn && f.scriptSig) {
it('returns false for ' + f.scriptSig, function() { it('returns false for ' + f.scriptSig, function () {
var script = Script.fromASM(f.scriptSig) var script = Script.fromASM(f.scriptSig)
assert.equal(inputFn(script), false) assert.equal(inputFn(script), false)
@ -93,12 +95,12 @@ describe('Scripts', function() {
}) })
}) })
describe('is' + type + 'Output', function() { describe('is' + type + 'Output', function () {
fixtures.valid.forEach(function(f) { fixtures.valid.forEach(function (f) {
var expected = type.toLowerCase() === f.type var expected = type.toLowerCase() === f.type
if (outputFn && f.scriptPubKey) { if (outputFn && f.scriptPubKey) {
it('returns ' + expected + ' for ' + f.scriptPubKey, function() { it('returns ' + expected + ' for ' + f.scriptPubKey, function () {
var script = Script.fromASM(f.scriptPubKey) var script = Script.fromASM(f.scriptPubKey)
assert.equal(outputFn(script), expected) assert.equal(outputFn(script), expected)
@ -108,9 +110,9 @@ describe('Scripts', function() {
if (!(outputFnName in fixtures.invalid)) return if (!(outputFnName in fixtures.invalid)) return
fixtures.invalid[outputFnName].forEach(function(f) { fixtures.invalid[outputFnName].forEach(function (f) {
if (outputFn && f.scriptPubKey) { if (outputFn && f.scriptPubKey) {
it('returns false for ' + f.scriptPubKey, function() { it('returns false for ' + f.scriptPubKey, function () {
var script = Script.fromASM(f.scriptPubKey) var script = Script.fromASM(f.scriptPubKey)
assert.equal(outputFn(script), false) assert.equal(outputFn(script), false)
@ -120,11 +122,11 @@ describe('Scripts', function() {
}) })
}) })
describe('pubKeyInput', function() { describe('pubKeyInput', function () {
fixtures.valid.forEach(function(f) { fixtures.valid.forEach(function (f) {
if (f.type !== 'pubkey') return if (f.type !== 'pubkey') return
it('returns ' + f.scriptSig, function() { it('returns ' + f.scriptSig, function () {
var signature = new Buffer(f.signature, 'hex') var signature = new Buffer(f.signature, 'hex')
var scriptSig = scripts.pubKeyInput(signature) var scriptSig = scripts.pubKeyInput(signature)
@ -133,11 +135,11 @@ describe('Scripts', function() {
}) })
}) })
describe('pubKeyOutput', function() { describe('pubKeyOutput', function () {
fixtures.valid.forEach(function(f) { fixtures.valid.forEach(function (f) {
if (f.type !== 'pubkey') return if (f.type !== 'pubkey') return
it('returns ' + f.scriptPubKey, function() { it('returns ' + f.scriptPubKey, function () {
var pubKey = ECPubKey.fromHex(f.pubKey) var pubKey = ECPubKey.fromHex(f.pubKey)
var scriptPubKey = scripts.pubKeyOutput(pubKey) var scriptPubKey = scripts.pubKeyOutput(pubKey)
@ -146,13 +148,13 @@ describe('Scripts', function() {
}) })
}) })
describe('pubKeyHashInput', function() { describe('pubKeyHashInput', function () {
fixtures.valid.forEach(function(f) { fixtures.valid.forEach(function (f) {
if (f.type !== 'pubkeyhash') return if (f.type !== 'pubkeyhash') return
var pubKey = ECPubKey.fromHex(f.pubKey) var pubKey = ECPubKey.fromHex(f.pubKey)
it('returns ' + f.scriptSig, function() { it('returns ' + f.scriptSig, function () {
var signature = new Buffer(f.signature, 'hex') var signature = new Buffer(f.signature, 'hex')
var scriptSig = scripts.pubKeyHashInput(signature, pubKey) var scriptSig = scripts.pubKeyHashInput(signature, pubKey)
@ -161,26 +163,26 @@ describe('Scripts', function() {
}) })
}) })
describe('pubKeyHashOutput', function() { describe('pubKeyHashOutput', function () {
fixtures.valid.forEach(function(f) { fixtures.valid.forEach(function (f) {
if (f.type !== 'pubkeyhash') return if (f.type !== 'pubkeyhash') return
var pubKey = ECPubKey.fromHex(f.pubKey) var pubKey = ECPubKey.fromHex(f.pubKey)
var address = pubKey.getAddress() var address = pubKey.getAddress()
it('returns ' + f.scriptPubKey, function() { it('returns ' + f.scriptPubKey, function () {
var scriptPubKey = scripts.pubKeyHashOutput(address.hash) var scriptPubKey = scripts.pubKeyHashOutput(address.hash)
assert.equal(scriptPubKey.toASM(), f.scriptPubKey) assert.equal(scriptPubKey.toASM(), f.scriptPubKey)
}) })
}) })
}) })
describe('multisigInput', function() { describe('multisigInput', function () {
fixtures.valid.forEach(function(f) { fixtures.valid.forEach(function (f) {
if (f.type !== 'multisig') return if (f.type !== 'multisig') return
it('returns ' + f.scriptSig, function() { it('returns ' + f.scriptSig, function () {
var signatures = f.signatures.map(function(signature) { var signatures = f.signatures.map(function (signature) {
return signature ? new Buffer(signature, 'hex') : ops.OP_0 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 pubKeys = f.pubKeys.map(ECPubKey.fromHex)
var scriptPubKey = scripts.multisigOutput(pubKeys.length, pubKeys) var scriptPubKey = scripts.multisigOutput(pubKeys.length, pubKeys)
it('throws on ' + f.exception, function() { it('throws on ' + f.exception, function () {
var signatures = f.signatures.map(function(signature) { var signatures = f.signatures.map(function (signature) {
return signature ? new Buffer(signature, 'hex') : ops.OP_0 return signature ? new Buffer(signature, 'hex') : ops.OP_0
}) })
assert.throws(function() { assert.throws(function () {
scripts.multisigInput(signatures, scriptPubKey) scripts.multisigInput(signatures, scriptPubKey)
}, new RegExp(f.exception)) }, new RegExp(f.exception))
}) })
}) })
}) })
describe('multisigOutput', function() { describe('multisigOutput', function () {
fixtures.valid.forEach(function(f) { fixtures.valid.forEach(function (f) {
if (f.type !== 'multisig') return if (f.type !== 'multisig') return
var pubKeys = f.pubKeys.map(ECPubKey.fromHex) var pubKeys = f.pubKeys.map(ECPubKey.fromHex)
var scriptPubKey = scripts.multisigOutput(pubKeys.length, pubKeys) var scriptPubKey = scripts.multisigOutput(pubKeys.length, pubKeys)
it('returns ' + f.scriptPubKey, function() { it('returns ' + f.scriptPubKey, function () {
assert.equal(scriptPubKey.toASM(), f.scriptPubKey) 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) var pubKeys = f.pubKeys.map(ECPubKey.fromHex)
it('throws on ' + f.exception, function() { it('throws on ' + f.exception, function () {
assert.throws(function() { assert.throws(function () {
scripts.multisigOutput(f.m, pubKeys) scripts.multisigOutput(f.m, pubKeys)
}, new RegExp(f.exception)) }, new RegExp(f.exception))
}) })
}) })
}) })
describe('scriptHashInput', function() { describe('scriptHashInput', function () {
fixtures.valid.forEach(function(f) { fixtures.valid.forEach(function (f) {
if (f.type !== 'scripthash') return if (f.type !== 'scripthash') return
var redeemScript = Script.fromASM(f.redeemScript) var redeemScript = Script.fromASM(f.redeemScript)
var redeemScriptSig = Script.fromASM(f.redeemScriptSig) var redeemScriptSig = Script.fromASM(f.redeemScriptSig)
it('returns ' + f.scriptSig, function() { it('returns ' + f.scriptSig, function () {
var scriptSig = scripts.scriptHashInput(redeemScriptSig, redeemScript) var scriptSig = scripts.scriptHashInput(redeemScriptSig, redeemScript)
assert.equal(scriptSig.toASM(), f.scriptSig) assert.equal(scriptSig.toASM(), f.scriptSig)
@ -243,13 +245,13 @@ describe('Scripts', function() {
}) })
}) })
describe('scriptHashOutput', function() { describe('scriptHashOutput', function () {
fixtures.valid.forEach(function(f) { fixtures.valid.forEach(function (f) {
if (f.type !== 'scripthash') return if (f.type !== 'scripthash') return
var redeemScript = Script.fromASM(f.redeemScript) var redeemScript = Script.fromASM(f.redeemScript)
it('returns ' + f.scriptPubKey, function() { it('returns ' + f.scriptPubKey, function () {
var scriptPubKey = scripts.scriptHashOutput(redeemScript.getHash()) var scriptPubKey = scripts.scriptHashOutput(redeemScript.getHash())
assert.equal(scriptPubKey.toASM(), f.scriptPubKey) assert.equal(scriptPubKey.toASM(), f.scriptPubKey)
@ -257,14 +259,14 @@ describe('Scripts', function() {
}) })
}) })
describe('nullDataOutput', function() { describe('nullDataOutput', function () {
fixtures.valid.forEach(function(f) { fixtures.valid.forEach(function (f) {
if (f.type !== 'nulldata') return if (f.type !== 'nulldata') return
var data = new Buffer(f.data, 'hex') var data = new Buffer(f.data, 'hex')
var scriptPubKey = scripts.nullDataOutput(data) var scriptPubKey = scripts.nullDataOutput(data)
it('returns ' + f.scriptPubKey, function() { it('returns ' + f.scriptPubKey, function () {
assert.equal(scriptPubKey.toASM(), f.scriptPubKey) assert.equal(scriptPubKey.toASM(), f.scriptPubKey)
}) })
}) })

View file

@ -1,3 +1,5 @@
/* global describe, it, beforeEach */
var assert = require('assert') var assert = require('assert')
var scripts = require('../src/scripts') var scripts = require('../src/scripts')
@ -8,19 +10,18 @@ var Script = require('../src/script')
var fixtures = require('./fixtures/transaction') var fixtures = require('./fixtures/transaction')
describe('Transaction', function() { describe('Transaction', function () {
function fromRaw(raw) { function fromRaw (raw) {
var tx = new Transaction() var tx = new Transaction()
tx.version = raw.version tx.version = raw.version
tx.locktime = raw.locktime tx.locktime = raw.locktime
raw.ins.forEach(function(txIn) { raw.ins.forEach(function (txIn) {
var txHash = new Buffer(txIn.hash, 'hex') var txHash = new Buffer(txIn.hash, 'hex')
var script var script
if (txIn.data) { if (txIn.data) {
script = new Script(new Buffer(txIn.data, 'hex'), []) script = new Script(new Buffer(txIn.data, 'hex'), [])
} else if (txIn.script) { } else if (txIn.script) {
script = Script.fromASM(txIn.script) script = Script.fromASM(txIn.script)
} }
@ -28,34 +29,34 @@ describe('Transaction', function() {
tx.addInput(txHash, txIn.index, txIn.sequence, script) 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) tx.addOutput(Script.fromASM(txOut.script), txOut.value)
}) })
return tx return tx
} }
describe('fromBuffer/fromHex', function() { describe('fromBuffer/fromHex', function () {
fixtures.valid.forEach(function(f) { fixtures.valid.forEach(function (f) {
it('imports ' + f.id + ' correctly', function() { it('imports ' + f.id + ' correctly', function () {
var actual = Transaction.fromHex(f.hex) var actual = Transaction.fromHex(f.hex)
assert.deepEqual(actual.toHex(), f.hex) assert.deepEqual(actual.toHex(), f.hex)
}) })
}) })
fixtures.invalid.fromBuffer.forEach(function(f) { fixtures.invalid.fromBuffer.forEach(function (f) {
it('throws on ' + f.exception, function() { it('throws on ' + f.exception, function () {
assert.throws(function() { assert.throws(function () {
Transaction.fromHex(f.hex) Transaction.fromHex(f.hex)
}, new RegExp(f.exception)) }, new RegExp(f.exception))
}) })
}) })
}) })
describe('toBuffer/toHex', function() { describe('toBuffer/toHex', function () {
fixtures.valid.forEach(function(f) { fixtures.valid.forEach(function (f) {
it('exports ' + f.id + ' correctly', function() { it('exports ' + f.id + ' correctly', function () {
var actual = fromRaw(f.raw) var actual = fromRaw(f.raw)
assert.deepEqual(actual.toHex(), f.hex) assert.deepEqual(actual.toHex(), f.hex)
@ -63,81 +64,81 @@ describe('Transaction', function() {
}) })
}) })
describe('addInput', function() { describe('addInput', function () {
// FIXME: not as pretty as could be // FIXME: not as pretty as could be
// Probably a bit representative of the API // Probably a bit representative of the API
var prevTxHash, prevTxId, prevTx var prevTxHash, prevTxId, prevTx
beforeEach(function() { beforeEach(function () {
var f = fixtures.valid[0] var f = fixtures.valid[0]
prevTx = Transaction.fromHex(f.hex) prevTx = Transaction.fromHex(f.hex)
prevTxHash = prevTx.getHash() prevTxHash = prevTx.getHash()
prevTxId = prevTx.getId() prevTxId = prevTx.getId()
}) })
it('accepts a transaction id', function() { it('accepts a transaction id', function () {
var tx = new Transaction() var tx = new Transaction()
tx.addInput(prevTxId, 0) tx.addInput(prevTxId, 0)
assert.deepEqual(tx.ins[0].hash, prevTxHash) assert.deepEqual(tx.ins[0].hash, prevTxHash)
}) })
it('accepts a transaction hash', function() { it('accepts a transaction hash', function () {
var tx = new Transaction() var tx = new Transaction()
tx.addInput(prevTxHash, 0) tx.addInput(prevTxHash, 0)
assert.deepEqual(tx.ins[0].hash, prevTxHash) assert.deepEqual(tx.ins[0].hash, prevTxHash)
}) })
it('accepts a Transaction object', function() { it('accepts a Transaction object', function () {
var tx = new Transaction() var tx = new Transaction()
tx.addInput(prevTx, 0) tx.addInput(prevTx, 0)
assert.deepEqual(tx.ins[0].hash, prevTxHash) assert.deepEqual(tx.ins[0].hash, prevTxHash)
}) })
it('returns an index', function() { it('returns an index', function () {
var tx = new Transaction() var tx = new Transaction()
assert.equal(tx.addInput(prevTxHash, 0), 0) assert.equal(tx.addInput(prevTxHash, 0), 0)
assert.equal(tx.addInput(prevTxHash, 0), 1) assert.equal(tx.addInput(prevTxHash, 0), 1)
}) })
it('defaults to DEFAULT_SEQUENCE', function() { it('defaults to DEFAULT_SEQUENCE', function () {
var tx = new Transaction() var tx = new Transaction()
tx.addInput(prevTxHash, 0) tx.addInput(prevTxHash, 0)
assert.equal(tx.ins[0].sequence, Transaction.DEFAULT_SEQUENCE) 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() var tx = new Transaction()
tx.addInput(prevTxHash, 0) tx.addInput(prevTxHash, 0)
assert.equal(tx.ins[0].script, Script.EMPTY) assert.equal(tx.ins[0].script, Script.EMPTY)
}) })
fixtures.invalid.addInput.forEach(function(f) { fixtures.invalid.addInput.forEach(function (f) {
it('throws on ' + f.exception, function() { it('throws on ' + f.exception, function () {
var tx = new Transaction() var tx = new Transaction()
var hash = new Buffer(f.hash, 'hex') var hash = new Buffer(f.hash, 'hex')
assert.throws(function() { assert.throws(function () {
tx.addInput(hash, f.index) tx.addInput(hash, f.index)
}, new RegExp(f.exception)) }, new RegExp(f.exception))
}) })
}) })
}) })
describe('addOutput', function() { describe('addOutput', function () {
// FIXME: not as pretty as could be // FIXME: not as pretty as could be
// Probably a bit representative of the API // Probably a bit representative of the API
var destAddressB58, destAddress, destScript var destAddressB58, destAddress, destScript
beforeEach(function() { beforeEach(function () {
destAddressB58 = '15mMHKL96tWAUtqF3tbVf99Z8arcmnJrr3' destAddressB58 = '15mMHKL96tWAUtqF3tbVf99Z8arcmnJrr3'
destAddress = Address.fromBase58Check(destAddressB58) destAddress = Address.fromBase58Check(destAddressB58)
destScript = destAddress.toOutputScript() destScript = destAddress.toOutputScript()
}) })
it('accepts an address string', function() { it('accepts an address string', function () {
var tx = new Transaction() var tx = new Transaction()
tx.addOutput(destAddressB58, 40000) tx.addOutput(destAddressB58, 40000)
@ -145,7 +146,7 @@ describe('Transaction', function() {
assert.equal(tx.outs[0].value, 40000) assert.equal(tx.outs[0].value, 40000)
}) })
it('accepts an Address', function() { it('accepts an Address', function () {
var tx = new Transaction() var tx = new Transaction()
tx.addOutput(destAddress, 40000) tx.addOutput(destAddress, 40000)
@ -153,7 +154,7 @@ describe('Transaction', function() {
assert.equal(tx.outs[0].value, 40000) assert.equal(tx.outs[0].value, 40000)
}) })
it('accepts a scriptPubKey', function() { it('accepts a scriptPubKey', function () {
var tx = new Transaction() var tx = new Transaction()
tx.addOutput(destScript, 40000) tx.addOutput(destScript, 40000)
@ -161,35 +162,35 @@ describe('Transaction', function() {
assert.equal(tx.outs[0].value, 40000) assert.equal(tx.outs[0].value, 40000)
}) })
it('returns an index', function() { it('returns an index', function () {
var tx = new Transaction() var tx = new Transaction()
assert.equal(tx.addOutput(destScript, 40000), 0) assert.equal(tx.addOutput(destScript, 40000), 0)
assert.equal(tx.addOutput(destScript, 40000), 1) assert.equal(tx.addOutput(destScript, 40000), 1)
}) })
}) })
describe('clone', function() { describe('clone', function () {
fixtures.valid.forEach(function(f) { fixtures.valid.forEach(function (f) {
var actual, expected var actual, expected
beforeEach(function() { beforeEach(function () {
expected = Transaction.fromHex(f.hex) expected = Transaction.fromHex(f.hex)
actual = expected.clone() actual = expected.clone()
}) })
it('should have value equality', function() { it('should have value equality', function () {
assert.deepEqual(actual, expected) assert.deepEqual(actual, expected)
}) })
it('should not have reference equality', function() { it('should not have reference equality', function () {
assert.notEqual(actual, expected) assert.notEqual(actual, expected)
}) })
}) })
}) })
describe('getId', function() { describe('getId', function () {
fixtures.valid.forEach(function(f) { fixtures.valid.forEach(function (f) {
it('should return the id for ' + f.id, function() { it('should return the id for ' + f.id, function () {
var tx = Transaction.fromHex(f.hex) var tx = Transaction.fromHex(f.hex)
var actual = tx.getId() var actual = tx.getId()
@ -198,9 +199,9 @@ describe('Transaction', function() {
}) })
}) })
describe('getHash', function() { describe('getHash', function () {
fixtures.valid.forEach(function(f) { fixtures.valid.forEach(function (f) {
it('should return the hash for ' + f.id, function() { it('should return the hash for ' + f.id, function () {
var tx = Transaction.fromHex(f.hex) var tx = Transaction.fromHex(f.hex)
var actual = tx.getHash().toString('hex') var actual = tx.getHash().toString('hex')
@ -213,8 +214,8 @@ describe('Transaction', function() {
// hashForSignature: [Function], // hashForSignature: [Function],
// FIXME: remove in 2.x.y // FIXME: remove in 2.x.y
describe('signInput/validateInput', function() { describe('signInput/validateInput', function () {
it('works for multi-sig redeem script', function() { it('works for multi-sig redeem script', function () {
var tx = new Transaction() var tx = new Transaction()
tx.addInput('d6f72aab8ff86ff6289842a0424319bf2ddba85dc7c52757912297f948286389', 0) tx.addInput('d6f72aab8ff86ff6289842a0424319bf2ddba85dc7c52757912297f948286389', 0)
tx.addOutput('mrCDrCybB6J1vRfbwM5hemdJz73FwDBC8r', 1) tx.addOutput('mrCDrCybB6J1vRfbwM5hemdJz73FwDBC8r', 1)
@ -222,13 +223,15 @@ describe('Transaction', function() {
var privKeys = [ var privKeys = [
'5HpHagT65TZzG1PH3CSu63k8DbpvD8s5ip4nEB3kEsreAnchuDf', '5HpHagT65TZzG1PH3CSu63k8DbpvD8s5ip4nEB3kEsreAnchuDf',
'5HpHagT65TZzG1PH3CSu63k8DbpvD8s5ip4nEB3kEsreAvUcVfH' '5HpHagT65TZzG1PH3CSu63k8DbpvD8s5ip4nEB3kEsreAvUcVfH'
].map(function(wif) { ].map(function (wif) {
return ECKey.fromWIF(wif) return ECKey.fromWIF(wif)
}) })
var pubKeys = privKeys.map(function(eck) { return eck.pub }) var pubKeys = privKeys.map(function (eck) {
return eck.pub
})
var redeemScript = scripts.multisigOutput(2, pubKeys) var redeemScript = scripts.multisigOutput(2, pubKeys)
var signatures = privKeys.map(function(privKey) { var signatures = privKeys.map(function (privKey) {
return tx.signInput(0, redeemScript, privKey) return tx.signInput(0, redeemScript, privKey)
}) })
@ -236,7 +239,7 @@ describe('Transaction', function() {
var scriptSig = scripts.scriptHashInput(redeemScriptSig, redeemScript) var scriptSig = scripts.scriptHashInput(redeemScriptSig, redeemScript)
tx.setInputScript(0, scriptSig) tx.setInputScript(0, scriptSig)
signatures.forEach(function(sig, i){ signatures.forEach(function (sig, i) {
assert(tx.validateInput(0, redeemScript, privKeys[i].pub, sig)) assert(tx.validateInput(0, redeemScript, privKeys[i].pub, sig))
}) })

View file

@ -1,3 +1,5 @@
/* global describe, it, beforeEach */
var assert = require('assert') var assert = require('assert')
var BigInteger = require('bigi') var BigInteger = require('bigi')
@ -8,8 +10,8 @@ var TransactionBuilder = require('../src/transaction_builder')
var fixtures = require('./fixtures/transaction_builder') var fixtures = require('./fixtures/transaction_builder')
function construct(txb, f, sign) { function construct (txb, f, sign) {
f.inputs.forEach(function(input) { f.inputs.forEach(function (input) {
var prevTxScript var prevTxScript
if (input.prevTxScript) { if (input.prevTxScript) {
@ -19,15 +21,15 @@ function construct(txb, f, sign) {
txb.addInput(input.txId, input.vout, input.sequence, prevTxScript) 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) var script = Script.fromASM(output.script)
txb.addOutput(script, output.value) txb.addOutput(script, output.value)
}) })
if (sign === undefined || sign) { if (sign === undefined || sign) {
f.inputs.forEach(function(input, index) { f.inputs.forEach(function (input, index) {
input.signs.forEach(function(sign) { input.signs.forEach(function (sign) {
var privKey = ECKey.fromWIF(sign.privKey) var privKey = ECKey.fromWIF(sign.privKey)
var redeemScript var redeemScript
@ -41,17 +43,19 @@ function construct(txb, f, sign) {
} }
// FIXME: add support for locktime/version in TransactionBuilder API // FIXME: add support for locktime/version in TransactionBuilder API
if (f.version !== undefined) txb.tx.version = f.version if (f.version !== undefined)
if (f.locktime !== undefined) txb.tx.locktime = f.locktime txb.tx.version = f.version
if (f.locktime !== undefined)
txb.tx.locktime = f.locktime
} }
describe('TransactionBuilder', function() { describe('TransactionBuilder', function () {
var privAddress, privScript var privAddress, privScript
var prevTx, prevTxHash var prevTx, prevTxHash
var privKey var privKey
var txb var txb
beforeEach(function() { beforeEach(function () {
txb = new TransactionBuilder() txb = new TransactionBuilder()
prevTx = new Transaction() prevTx = new Transaction()
@ -64,8 +68,8 @@ describe('TransactionBuilder', function() {
privScript = privAddress.toOutputScript() privScript = privAddress.toOutputScript()
}) })
describe('addInput', function() { describe('addInput', function () {
it('accepts a txHash, index [and sequence number]', function() { it('accepts a txHash, index [and sequence number]', function () {
var vin = txb.addInput(prevTxHash, 1, 54) var vin = txb.addInput(prevTxHash, 1, 54)
assert.equal(vin, 0) assert.equal(vin, 0)
@ -76,7 +80,7 @@ describe('TransactionBuilder', function() {
assert.equal(txb.inputs[0].prevOutScript, undefined) 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) var vin = txb.addInput(prevTxHash, 1, 54, prevTx.outs[1].script)
assert.equal(vin, 0) assert.equal(vin, 0)
@ -87,7 +91,7 @@ describe('TransactionBuilder', function() {
assert.equal(txb.inputs[0].prevOutScript, prevTx.outs[1].script) 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) var vin = txb.addInput(prevTx, 1, 54)
assert.equal(vin, 0) assert.equal(vin, 0)
@ -98,40 +102,40 @@ describe('TransactionBuilder', function() {
assert.equal(txb.inputs[0].prevOutScript, prevTx.outs[1].script) 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, 0), 0)
assert.equal(txb.addInput(prevTxHash, 1), 1) 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.addInput(prevTxHash, 0)
txb.sign(0, privKey) txb.sign(0, privKey)
assert.throws(function() { assert.throws(function () {
txb.addInput(prevTxHash, 0) txb.addInput(prevTxHash, 0)
}, /No, this would invalidate signatures/) }, /No, this would invalidate signatures/)
}) })
}) })
describe('addOutput', function() { describe('addOutput', function () {
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.addInput(prevTxHash, 0)
txb.addOutput(privScript, 2000) txb.addOutput(privScript, 2000)
txb.sign(0, privKey) txb.sign(0, privKey)
assert.throws(function() { assert.throws(function () {
txb.addOutput(privScript, 9000) txb.addOutput(privScript, 9000)
}, /No, this would invalidate signatures/) }, /No, this would invalidate signatures/)
}) })
}) })
describe('sign', function() { describe('sign', function () {
fixtures.invalid.sign.forEach(function(f) { fixtures.invalid.sign.forEach(function (f) {
it('throws on ' + f.exception + ' (' + f.description + ')', function() { it('throws on ' + f.exception + ' (' + f.description + ')', function () {
construct(txb, f, false) construct(txb, f, false)
f.inputs.forEach(function(input, index) { f.inputs.forEach(function (input, index) {
input.signs.forEach(function(sign) { input.signs.forEach(function (sign) {
var privKey = ECKey.fromWIF(sign.privKey) var privKey = ECKey.fromWIF(sign.privKey)
var redeemScript var redeemScript
@ -141,9 +145,8 @@ describe('TransactionBuilder', function() {
if (!sign.throws) { if (!sign.throws) {
txb.sign(index, privKey, redeemScript, sign.hashType) txb.sign(index, privKey, redeemScript, sign.hashType)
} else { } else {
assert.throws(function() { assert.throws(function () {
txb.sign(index, privKey, redeemScript, sign.hashType) txb.sign(index, privKey, redeemScript, sign.hashType)
}, new RegExp(f.exception)) }, new RegExp(f.exception))
} }
@ -153,9 +156,9 @@ describe('TransactionBuilder', function() {
}) })
}) })
describe('build', function() { describe('build', function () {
fixtures.valid.build.forEach(function(f) { fixtures.valid.build.forEach(function (f) {
it('builds \"' + f.description + '\"', function() { it('builds "' + f.description + '"', function () {
construct(txb, f) construct(txb, f)
var tx = txb.build() var tx = txb.build()
@ -163,35 +166,34 @@ describe('TransactionBuilder', function() {
}) })
}) })
fixtures.invalid.build.forEach(function(f) { fixtures.invalid.build.forEach(function (f) {
describe('for ' + (f.description || f.exception), function() { describe('for ' + (f.description || f.exception), function () {
beforeEach(function() { beforeEach(function () {
if (f.txHex) { if (f.txHex) {
var tx = Transaction.fromHex(f.txHex) var tx = Transaction.fromHex(f.txHex)
txb = TransactionBuilder.fromTransaction(tx) txb = TransactionBuilder.fromTransaction(tx)
} else { } else {
construct(txb, f) construct(txb, f)
} }
}) })
it('throws', function() { it('throws', function () {
assert.throws(function() { assert.throws(function () {
txb.build() txb.build()
}, new RegExp(f.exception)) }, new RegExp(f.exception))
}) })
if (f.alwaysThrows) return if (f.alwaysThrows) return
it('doesn\'t throw if building incomplete', function() { it("doesn't throw if building incomplete", function () {
txb.buildIncomplete() txb.buildIncomplete()
}) })
}) })
}) })
}) })
describe('fromTransaction', function() { describe('fromTransaction', function () {
fixtures.valid.build.forEach(function(f) { fixtures.valid.build.forEach(function (f) {
it('builds the correct TransactionBuilder for ' + f.description, function() { it('builds the correct TransactionBuilder for ' + f.description, function () {
var tx = Transaction.fromHex(f.txHex) var tx = Transaction.fromHex(f.txHex)
var txb = TransactionBuilder.fromTransaction(tx) var txb = TransactionBuilder.fromTransaction(tx)
@ -199,25 +201,25 @@ describe('TransactionBuilder', function() {
}) })
}) })
fixtures.invalid.fromTransaction.forEach(function(f) { fixtures.invalid.fromTransaction.forEach(function (f) {
it('throws on ' + f.exception, function() { it('throws on ' + f.exception, function () {
var tx = Transaction.fromHex(f.txHex) var tx = Transaction.fromHex(f.txHex)
assert.throws(function() { assert.throws(function () {
TransactionBuilder.fromTransaction(tx) TransactionBuilder.fromTransaction(tx)
}, new RegExp(f.exception)) }, 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 = [ var privKeys = [
"91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgww7vXtT", '91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgww7vXtT',
"91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx" '91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx'
].map(ECKey.fromWIF) ].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.addInput('4971f016798a167331bcbc67248313fbc444c6e92e4416efd06964425588f5cf', 0)
txb.addOutput("1BgGZ9tcN4rm9KBzDn7KprQz87SZ26SAMH", 10000) txb.addOutput('1BgGZ9tcN4rm9KBzDn7KprQz87SZ26SAMH', 10000)
txb.sign(0, privKeys[0], redeemScript) txb.sign(0, privKeys[0], redeemScript)
var tx = txb.buildIncomplete() var tx = txb.buildIncomplete()

View file

@ -1,3 +1,5 @@
/* global describe, it, beforeEach, afterEach */
var assert = require('assert') var assert = require('assert')
var bufferutils = require('../src/bufferutils') var bufferutils = require('../src/bufferutils')
var crypto = require('../src/crypto') var crypto = require('../src/crypto')
@ -15,72 +17,72 @@ var fixtureTxes = require('./fixtures/mainnet_tx')
var fixtureTx1Hex = fixtureTxes.prevTx var fixtureTx1Hex = fixtureTxes.prevTx
var fixtureTx2Hex = fixtureTxes.tx var fixtureTx2Hex = fixtureTxes.tx
function fakeTxHash(i) { function fakeTxHash (i) {
var hash = new Buffer(32) var hash = new Buffer(32)
hash.fill(i) hash.fill(i)
return hash return hash
} }
function fakeTxId(i) { function fakeTxId (i) {
var hash = fakeTxHash(i) var hash = fakeTxHash(i)
Array.prototype.reverse.call(hash) Array.prototype.reverse.call(hash)
return hash.toString('hex') return hash.toString('hex')
} }
describe('Wallet', function() { describe('Wallet', function () {
var seed var seed
beforeEach(function() { beforeEach(function () {
seed = crypto.sha256("don't use a string seed like this in real life") seed = crypto.sha256("don't use a string seed like this in real life")
}) })
describe('constructor', function() { describe('constructor', function () {
var wallet var wallet
beforeEach(function() { beforeEach(function () {
wallet = new Wallet(seed) wallet = new Wallet(seed)
}) })
it('defaults to Bitcoin network', function() { it('defaults to Bitcoin network', function () {
assert.equal(wallet.getMasterKey().network, networks.bitcoin) assert.equal(wallet.getMasterKey().network, networks.bitcoin)
}) })
it("generates m/0' as the main account", function() { it("generates m/0' as the main account", function () {
var mainAccount = wallet.getAccountZero() var mainAccount = wallet.getAccountZero()
assert.equal(mainAccount.index, 0 + HDNode.HIGHEST_BIT) assert.equal(mainAccount.index, 0 + HDNode.HIGHEST_BIT)
assert.equal(mainAccount.depth, 1) assert.equal(mainAccount.depth, 1)
}) })
it("generates m/0'/0 as the external account", function() { it("generates m/0'/0 as the external account", function () {
var account = wallet.getExternalAccount() var account = wallet.getExternalAccount()
assert.equal(account.index, 0) assert.equal(account.index, 0)
assert.equal(account.depth, 2) assert.equal(account.depth, 2)
}) })
it("generates m/0'/1 as the internal account", function() { it("generates m/0'/1 as the internal account", function () {
var account = wallet.getInternalAccount() var account = wallet.getInternalAccount()
assert.equal(account.index, 1) assert.equal(account.index, 1)
assert.equal(account.depth, 2) assert.equal(account.depth, 2)
}) })
describe('when seed is not specified', function() { describe('when seed is not specified', function () {
it('generates a seed', function() { it('generates a seed', function () {
var wallet = new Wallet() var wallet = new Wallet()
assert(wallet.getMasterKey()) assert(wallet.getMasterKey())
}) })
}) })
describe('constructor options', function() { describe('constructor options', function () {
beforeEach(function() { beforeEach(function () {
wallet = new Wallet(seed, networks.testnet) wallet = new Wallet(seed, networks.testnet)
}) })
it('uses the network if specified', function() { it('uses the network if specified', function () {
assert.equal(wallet.getMasterKey().network, networks.testnet) assert.equal(wallet.getMasterKey().network, networks.testnet)
}) })
}) })
}) })
describe('newMasterKey', function() { describe('newMasterKey', function () {
it('resets accounts', function() { it('resets accounts', function () {
var wallet = new Wallet() var wallet = new Wallet()
var oldAccountZero = wallet.getAccountZero() var oldAccountZero = wallet.getAccountZero()
var oldExternalAccount = wallet.getExternalAccount() var oldExternalAccount = wallet.getExternalAccount()
@ -92,7 +94,7 @@ describe('Wallet', function() {
assertNotEqual(wallet.getInternalAccount(), oldInternalAccount) assertNotEqual(wallet.getInternalAccount(), oldInternalAccount)
}) })
it('resets addresses', function() { it('resets addresses', function () {
var wallet = new Wallet() var wallet = new Wallet()
wallet.generateAddress() wallet.generateAddress()
wallet.generateChangeAddress() wallet.generateChangeAddress()
@ -107,12 +109,12 @@ describe('Wallet', function() {
}) })
}) })
describe('generateAddress', function() { describe('generateAddress', function () {
it('generate receiving addresses', function() { it('generate receiving addresses', function () {
var wallet = new Wallet(seed, networks.testnet) var wallet = new Wallet(seed, networks.testnet)
var expectedAddresses = [ var expectedAddresses = [
"n1GyUANZand9Kw6hGSV9837cCC9FFUQzQa", 'n1GyUANZand9Kw6hGSV9837cCC9FFUQzQa',
"n2fiWrHqD6GM5GiEqkbWAc6aaZQp3ba93X" 'n2fiWrHqD6GM5GiEqkbWAc6aaZQp3ba93X'
] ]
assert.equal(wallet.generateAddress(), expectedAddresses[0]) assert.equal(wallet.generateAddress(), expectedAddresses[0])
@ -121,28 +123,18 @@ describe('Wallet', function() {
}) })
}) })
describe('generateChangeAddress', function() { describe('generateChangeAddress', function () {
var wallet it('generates change addresses', function () {
beforeEach(function() {
wallet = new Wallet(seed)
})
it('generates change addresses', function() {
var wallet = new Wallet(seed, networks.testnet) var wallet = new Wallet(seed, networks.testnet)
var expectedAddresses = ["mnXiDR4MKsFxcKJEZjx4353oXvo55iuptn"] var expectedAddresses = ['mnXiDR4MKsFxcKJEZjx4353oXvo55iuptn']
assert.equal(wallet.generateChangeAddress(), expectedAddresses[0]) assert.equal(wallet.generateChangeAddress(), expectedAddresses[0])
assert.deepEqual(wallet.changeAddresses, expectedAddresses) assert.deepEqual(wallet.changeAddresses, expectedAddresses)
}) })
}) })
describe('getPrivateKey', function() { describe('getPrivateKey', function () {
var wallet it('returns the private key at the given index of external account', function () {
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) var wallet = new Wallet(seed, networks.testnet)
assertEqual(wallet.getPrivateKey(0), wallet.getExternalAccount().derive(0).privKey) assertEqual(wallet.getPrivateKey(0), wallet.getExternalAccount().derive(0).privKey)
@ -150,13 +142,8 @@ describe('Wallet', function() {
}) })
}) })
describe('getInternalPrivateKey', function() { describe('getInternalPrivateKey', function () {
var wallet it('returns the private key at the given index of internal account', function () {
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) var wallet = new Wallet(seed, networks.testnet)
assertEqual(wallet.getInternalPrivateKey(0), wallet.getInternalAccount().derive(0).privKey) assertEqual(wallet.getInternalPrivateKey(0), wallet.getInternalAccount().derive(0).privKey)
@ -164,59 +151,54 @@ describe('Wallet', function() {
}) })
}) })
describe('getPrivateKeyForAddress', function() { describe('getPrivateKeyForAddress', function () {
var wallet it('returns the private key for the given address', function () {
beforeEach(function() {
wallet = new Wallet(seed)
})
it('returns the private key for the given address', function() {
var wallet = new Wallet(seed, networks.testnet) var wallet = new Wallet(seed, networks.testnet)
wallet.generateChangeAddress() wallet.generateChangeAddress()
wallet.generateAddress() wallet.generateAddress()
wallet.generateAddress() wallet.generateAddress()
assertEqual( assertEqual(
wallet.getPrivateKeyForAddress("n2fiWrHqD6GM5GiEqkbWAc6aaZQp3ba93X"), wallet.getPrivateKeyForAddress('n2fiWrHqD6GM5GiEqkbWAc6aaZQp3ba93X'),
wallet.getExternalAccount().derive(1).privKey wallet.getExternalAccount().derive(1).privKey
) )
assertEqual( assertEqual(
wallet.getPrivateKeyForAddress("mnXiDR4MKsFxcKJEZjx4353oXvo55iuptn"), wallet.getPrivateKeyForAddress('mnXiDR4MKsFxcKJEZjx4353oXvo55iuptn'),
wallet.getInternalAccount().derive(0).privKey wallet.getInternalAccount().derive(0).privKey
) )
}) })
it('raises an error when address is not found', function() { it('raises an error when address is not found', function () {
var wallet = new Wallet(seed, networks.testnet) var wallet = new Wallet(seed, networks.testnet)
assert.throws(function() { assert.throws(function () {
wallet.getPrivateKeyForAddress("n2fiWrHqD6GM5GiEqkbWAc6aaZQp3ba93X") wallet.getPrivateKeyForAddress('n2fiWrHqD6GM5GiEqkbWAc6aaZQp3ba93X')
}, /Unknown address. Make sure the address is from the keychain and has been generated/) }, /Unknown address. Make sure the address is from the keychain and has been generated/)
}) })
}) })
describe('Unspent Outputs', function() { describe('Unspent Outputs', function () {
var utxo, expectedOutputKey var utxo
var wallet var wallet
beforeEach(function() { beforeEach(function () {
utxo = { utxo = {
"address" : "1AZpKpcfCzKDUeTFBQUL4MokQai3m3HMXv", 'address': '1AZpKpcfCzKDUeTFBQUL4MokQai3m3HMXv',
"confirmations": 1, 'confirmations': 1,
"index": 0, 'index': 0,
"txId": fakeTxId(6), 'txId': fakeTxId(6),
"value": 20000, 'value': 20000,
"pending": false 'pending': false
} }
}) })
describe('on construction', function() { describe('on construction', function () {
beforeEach(function() { beforeEach(function () {
wallet = new Wallet(seed, networks.bitcoin) wallet = new Wallet(seed, networks.bitcoin)
wallet.setUnspentOutputs([utxo]) wallet.setUnspentOutputs([utxo])
}) })
it('matches the expected behaviour', function() { it('matches the expected behaviour', function () {
var output = wallet.unspents[0] var output = wallet.unspents[0]
assert.equal(output.address, utxo.address) assert.equal(output.address, utxo.address)
@ -224,8 +206,8 @@ describe('Wallet', function() {
}) })
}) })
describe('getBalance', function() { describe('getBalance', function () {
beforeEach(function() { beforeEach(function () {
var utxo1 = cloneObject(utxo) var utxo1 = cloneObject(utxo)
utxo1.hash = fakeTxId(5) utxo1.hash = fakeTxId(5)
@ -233,18 +215,18 @@ describe('Wallet', function() {
wallet.setUnspentOutputs([utxo, utxo1]) wallet.setUnspentOutputs([utxo, utxo1])
}) })
it('sums over utxo values', function() { it('sums over utxo values', function () {
assert.equal(wallet.getBalance(), 40000) assert.equal(wallet.getBalance(), 40000)
}) })
}) })
describe('getUnspentOutputs', function() { describe('getUnspentOutputs', function () {
beforeEach(function() { beforeEach(function () {
wallet = new Wallet(seed, networks.bitcoin) wallet = new Wallet(seed, networks.bitcoin)
wallet.setUnspentOutputs([utxo]) wallet.setUnspentOutputs([utxo])
}) })
it('parses wallet unspents to the expected format', function() { it('parses wallet unspents to the expected format', function () {
var outputs = wallet.getUnspentOutputs() var outputs = wallet.getUnspentOutputs()
var output = outputs[0] var output = outputs[0]
@ -261,7 +243,7 @@ describe('Wallet', function() {
assert.equal(utxo.confirmations, output.confirmations) assert.equal(utxo.confirmations, output.confirmations)
}) })
it("ignores spent unspents (outputs with 'spent' property)", function() { it("ignores spent unspents (outputs with 'spent' property)", function () {
var unspent = wallet.unspents[0] var unspent = wallet.unspents[0]
unspent.pending = true unspent.pending = true
unspent.spent = true unspent.spent = true
@ -270,12 +252,11 @@ describe('Wallet', function() {
}) })
}) })
describe('setUnspentOutputs', function() { describe('setUnspentOutputs', function () {
var utxo var utxo
var expectedOutputKey
var wallet var wallet
beforeEach(function() { beforeEach(function () {
utxo = { utxo = {
hash: fakeTxId(0), hash: fakeTxId(0),
index: 0, index: 0,
@ -286,7 +267,7 @@ describe('Wallet', function() {
wallet = new Wallet(seed, networks.bitcoin) wallet = new Wallet(seed, networks.bitcoin)
}) })
it('matches the expected behaviour', function() { it('matches the expected behaviour', function () {
wallet.setUnspentOutputs([utxo]) wallet.setUnspentOutputs([utxo])
var output = wallet.unspents[0] var output = wallet.unspents[0]
@ -294,12 +275,12 @@ describe('Wallet', function() {
assert.equal(output.address, utxo.address) assert.equal(output.address, utxo.address)
}) })
describe('required fields', function() { describe('required fields', function () {
['index', 'address', 'hash', 'value'].forEach(function(field){ ['index', 'address', 'hash', 'value'].forEach(function (field) {
it("throws an error when " + field + " is missing", function() { it('throws an error when ' + field + ' is missing', function () {
delete utxo[field] delete utxo[field]
assert.throws(function() { assert.throws(function () {
wallet.setUnspentOutputs([utxo]) wallet.setUnspentOutputs([utxo])
}) })
}) })
@ -307,16 +288,16 @@ describe('Wallet', function() {
}) })
}) })
describe('Process transaction', function() { describe('Process transaction', function () {
var wallet var wallet
beforeEach(function() { beforeEach(function () {
wallet = new Wallet(seed) wallet = new Wallet(seed)
}) })
var addresses var addresses
var tx var tx
beforeEach(function() { beforeEach(function () {
addresses = [ addresses = [
'115qa7iPZqn6as57hxLL8E9VUnhmGQxKWi', '115qa7iPZqn6as57hxLL8E9VUnhmGQxKWi',
'1Bu3bhwRmevHLAy1JrRB6AfcxfgDG2vXRd', '1Bu3bhwRmevHLAy1JrRB6AfcxfgDG2vXRd',
@ -326,24 +307,24 @@ describe('Wallet', function() {
tx = Transaction.fromHex(fixtureTx1Hex) tx = Transaction.fromHex(fixtureTx1Hex)
}) })
describe("processPendingTx", function() { describe('processPendingTx', function () {
it("incoming: sets the pending flag on output", function() { it('incoming: sets the pending flag on output', function () {
wallet.addresses = [addresses[0]] wallet.addresses = [addresses[0]]
wallet.processPendingTx(tx) wallet.processPendingTx(tx)
verifyOutputAdded(0, true) verifyOutputAdded(0, true)
}) })
describe("when tx ins outpoint contains a known txhash:i", function() { describe('when tx ins outpoint contains a known txhash:i', function () {
var spendTx var spendTx
beforeEach(function() { beforeEach(function () {
wallet.addresses = [addresses[0]] wallet.addresses = [addresses[0]]
wallet.processConfirmedTx(tx) wallet.processConfirmedTx(tx)
spendTx = Transaction.fromHex(fixtureTx2Hex) spendTx = Transaction.fromHex(fixtureTx2Hex)
}) })
it("outgoing: sets the pending flag and 'spent' on output", function() { it("outgoing: sets the pending flag and 'spent' on output", function () {
var txIn = spendTx.ins[0] var txIn = spendTx.ins[0]
var txInId = new Buffer(txIn.hash) var txInId = new Buffer(txIn.hash)
Array.prototype.reverse.call(txInId) Array.prototype.reverse.call(txInId)
@ -359,8 +340,8 @@ describe('Wallet', function() {
}) })
}) })
describe('processConfirmedTx', function() { describe('processConfirmedTx', function () {
it('does not throw on scripts with no corresponding Address', function() { it('does not throw on scripts with no corresponding Address', function () {
var pubKey = wallet.getPrivateKey(0).pub var pubKey = wallet.getPrivateKey(0).pub
var script = scripts.pubKeyOutput(pubKey) var script = scripts.pubKeyOutput(pubKey)
var tx2 = new Transaction() var tx2 = new Transaction()
@ -371,8 +352,8 @@ describe('Wallet', function() {
wallet.processConfirmedTx(tx2) wallet.processConfirmedTx(tx2)
}) })
describe("when tx outs contains an address owned by the wallet, an 'output' gets added to wallet.unspentMap", function() { 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() { it('works for receive address', function () {
var totalOuts = outputCount() var totalOuts = outputCount()
wallet.addresses = [addresses[0]] wallet.addresses = [addresses[0]]
@ -382,7 +363,7 @@ describe('Wallet', function() {
verifyOutputAdded(0, false) verifyOutputAdded(0, false)
}) })
it("works for change address", function() { it('works for change address', function () {
var totalOuts = outputCount() var totalOuts = outputCount()
wallet.changeAddresses = [addresses[1]] wallet.changeAddresses = [addresses[1]]
@ -392,26 +373,26 @@ describe('Wallet', function() {
verifyOutputAdded(1, false) verifyOutputAdded(1, false)
}) })
function outputCount() { function outputCount () {
return Object.keys(wallet.unspentMap).length return Object.keys(wallet.unspentMap).length
} }
}) })
describe("when tx ins contains a known txhash:i", function() { describe('when tx ins contains a known txhash:i', function () {
var spendTx var spendTx
beforeEach(function() { beforeEach(function () {
wallet.addresses = [addresses[0]] // the address fixtureTx2 used as input wallet.addresses = [addresses[0]] // the address fixtureTx2 used as input
wallet.processConfirmedTx(tx) wallet.processConfirmedTx(tx)
spendTx = Transaction.fromHex(fixtureTx2Hex) spendTx = Transaction.fromHex(fixtureTx2Hex)
}) })
it("does not add to wallet.unspentMap", function() { it('does not add to wallet.unspentMap', function () {
wallet.processConfirmedTx(spendTx) wallet.processConfirmedTx(spendTx)
assert.deepEqual(wallet.unspentMap, {}) assert.deepEqual(wallet.unspentMap, {})
}) })
it("deletes corresponding 'unspent'", function() { it("deletes corresponding 'unspent'", function () {
var txIn = spendTx.ins[0] var txIn = spendTx.ins[0]
var txInId = bufferutils.reverse(txIn.hash).toString('hex') var txInId = bufferutils.reverse(txIn.hash).toString('hex')
@ -424,16 +405,15 @@ describe('Wallet', function() {
}) })
}) })
it("does nothing when none of the involved addresses belong to the wallet", function() { it('does nothing when none of the involved addresses belong to the wallet', function () {
wallet.processConfirmedTx(tx) wallet.processConfirmedTx(tx)
assert.deepEqual(wallet.unspentMap, {}) assert.deepEqual(wallet.unspentMap, {})
}) })
function verifyOutputAdded (index, pending) {
function verifyOutputAdded(index, pending) {
var txOut = tx.outs[index] var txOut = tx.outs[index]
var key = tx.getId() + ":" + index var key = tx.getId() + ':' + index
var output = wallet.unspentMap[key] var output = wallet.unspentMap[key]
assert.deepEqual(output.txHash, tx.getHash()) assert.deepEqual(output.txHash, tx.getHash())
assert.equal(output.value, txOut.value) assert.equal(output.value, txOut.value)
@ -444,37 +424,37 @@ describe('Wallet', function() {
} }
}) })
describe('createTx', function() { describe('createTx', function () {
var wallet var wallet
var address1, address2 var address1, address2
var to, value var to, value
beforeEach(function() { beforeEach(function () {
to = 'mt7MyTVVEWnbwpF5hBn6fgnJcv95Syk2ue' to = 'mt7MyTVVEWnbwpF5hBn6fgnJcv95Syk2ue'
value = 500000 value = 500000
address1 = "n1GyUANZand9Kw6hGSV9837cCC9FFUQzQa" address1 = 'n1GyUANZand9Kw6hGSV9837cCC9FFUQzQa'
address2 = "n2fiWrHqD6GM5GiEqkbWAc6aaZQp3ba93X" address2 = 'n2fiWrHqD6GM5GiEqkbWAc6aaZQp3ba93X'
// set up 3 utxos // set up 3 utxos
var utxos = [ var utxos = [
{ {
"txId": fakeTxId(1), 'txId': fakeTxId(1),
"index": 0, 'index': 0,
"address": address1, 'address': address1,
"value": 400000 // not enough for value 'value': 400000 // not enough for value
}, },
{ {
"txId": fakeTxId(2), 'txId': fakeTxId(2),
"index": 1, 'index': 1,
"address": address1, 'address': address1,
"value": 500000 // enough for only value 'value': 500000 // enough for only value
}, },
{ {
"txId": fakeTxId(3), 'txId': fakeTxId(3),
"index": 0, 'index': 0,
"address" : address2, 'address': address2,
"value": 510000 // enough for value and fee 'value': 510000 // enough for value and fee
} }
] ]
@ -484,27 +464,31 @@ describe('Wallet', function() {
wallet.generateAddress() wallet.generateAddress()
}) })
describe('transaction fee', function() { describe('transaction fee', function () {
it('allows fee to be specified', function() { it('allows fee to be specified', function () {
var fee = 30000 var fee = 30000
var tx = wallet.createTx(to, value, { fixedFee: fee }) var tx = wallet.createTx(to, value, {
fixedFee: fee
})
assert.equal(getFee(wallet, tx), fee) assert.equal(getFee(wallet, tx), fee)
}) })
it('allows fee to be set to zero', function() { it('allows fee to be set to zero', function () {
value = 510000 value = 510000
var fee = 0 var fee = 0
var tx = wallet.createTx(to, value, { fixedFee: fee }) var tx = wallet.createTx(to, value, {
fixedFee: fee
})
assert.equal(getFee(wallet, tx), fee) assert.equal(getFee(wallet, tx), fee)
}) })
it('does not overestimate fees when network has dustSoftThreshold', function() { it('does not overestimate fees when network has dustSoftThreshold', function () {
var utxo = { var utxo = {
txId: fakeTxId(0), txId: fakeTxId(0),
index: 0, index: 0,
address: "LeyySKbQrRRwodKEj1W4a8y3YQupPLw5os", address: 'LeyySKbQrRRwodKEj1W4a8y3YQupPLw5os',
value: 500000 value: 500000
} }
@ -518,21 +502,21 @@ describe('Wallet', function() {
assert.equal(getFee(wallet, tx), 100000) assert.equal(getFee(wallet, tx), 100000)
}) })
function getFee(wallet, tx) { function getFee (wallet, tx) {
var inputValue = tx.ins.reduce(function(accum, input) { var inputValue = tx.ins.reduce(function (accum, input) {
var txId = bufferutils.reverse(input.hash).toString('hex') var txId = bufferutils.reverse(input.hash).toString('hex')
return accum + wallet.unspentMap[txId + ':' + input.index].value return accum + wallet.unspentMap[txId + ':' + input.index].value
}, 0) }, 0)
return tx.outs.reduce(function(accum, output) { return tx.outs.reduce(function (accum, output) {
return accum - output.value return accum - output.value
}, inputValue) }, inputValue)
} }
}) })
describe('choosing utxo', function() { describe('choosing utxo', function () {
it('takes fees into account', function() { it('takes fees into account', function () {
var tx = wallet.createTx(to, value) var tx = wallet.createTx(to, value)
assert.equal(tx.ins.length, 1) assert.equal(tx.ins.length, 1)
@ -540,7 +524,7 @@ describe('Wallet', function() {
assert.equal(tx.ins[0].index, 0) assert.equal(tx.ins[0].index, 0)
}) })
it('uses confirmed outputs', function() { it('uses confirmed outputs', function () {
var tx2 = new Transaction() var tx2 = new Transaction()
tx2.addInput(fakeTxId(4), 0) tx2.addInput(fakeTxId(4), 0)
tx2.addOutput(address2, 530000) tx2.addOutput(address2, 530000)
@ -553,7 +537,7 @@ describe('Wallet', function() {
assert.equal(tx.ins[0].index, 0) assert.equal(tx.ins[0].index, 0)
}) })
it('ignores pending outputs', function() { it('ignores pending outputs', function () {
var tx2 = new Transaction() var tx2 = new Transaction()
tx2.addInput(fakeTxId(4), 0) tx2.addInput(fakeTxId(4), 0)
tx2.addOutput(address2, 530000) tx2.addOutput(address2, 530000)
@ -567,8 +551,8 @@ describe('Wallet', function() {
}) })
}) })
describe('changeAddress', function() { describe('changeAddress', function () {
it('should allow custom changeAddress', function() { it('should allow custom changeAddress', function () {
var changeAddress = 'mfrFjnKZUvTcvdAK2fUX5D8v1Epu5H8JCk' var changeAddress = 'mfrFjnKZUvTcvdAK2fUX5D8v1Epu5H8JCk'
var fromValue = 510000 var fromValue = 510000
var toValue = fromValue / 2 var toValue = fromValue / 2
@ -591,8 +575,8 @@ describe('Wallet', function() {
}) })
}) })
describe('transaction outputs', function() { describe('transaction outputs', function () {
it('includes the specified address and amount', function() { it('includes the specified address and amount', function () {
var tx = wallet.createTx(to, value) var tx = wallet.createTx(to, value)
assert.equal(tx.outs.length, 1) assert.equal(tx.outs.length, 1)
@ -603,12 +587,14 @@ describe('Wallet', function() {
assert.equal(out.value, value) assert.equal(out.value, value)
}) })
describe('change', function() { describe('change', function () {
it('uses the last change address if there is any', function() { it('uses the last change address if there is any', function () {
var fee = 0 var fee = 0
wallet.generateChangeAddress() wallet.generateChangeAddress()
wallet.generateChangeAddress() wallet.generateChangeAddress()
var tx = wallet.createTx(to, value, { fixedFee: fee }) var tx = wallet.createTx(to, value, {
fixedFee: fee
})
assert.equal(tx.outs.length, 2) assert.equal(tx.outs.length, 2)
var out = tx.outs[1] var out = tx.outs[1]
@ -618,11 +604,13 @@ describe('Wallet', function() {
assert.equal(out.value, 10000) assert.equal(out.value, 10000)
}) })
it('generates a change address if there is not any', function() { it('generates a change address if there is not any', function () {
var fee = 0 var fee = 0
assert.equal(wallet.changeAddresses.length, 0) assert.equal(wallet.changeAddresses.length, 0)
var tx = wallet.createTx(to, value, { fixedFee: fee }) var tx = wallet.createTx(to, value, {
fixedFee: fee
})
assert.equal(wallet.changeAddresses.length, 1) assert.equal(wallet.changeAddresses.length, 1)
var out = tx.outs[1] var out = tx.outs[1]
@ -632,7 +620,7 @@ describe('Wallet', function() {
assert.equal(out.value, 10000) assert.equal(out.value, 10000)
}) })
it('skips change if it is not above dust threshold', function() { it('skips change if it is not above dust threshold', function () {
var tx1 = wallet.createTx(to, value - 546) var tx1 = wallet.createTx(to, value - 546)
assert.equal(tx1.outs.length, 1) assert.equal(tx1.outs.length, 1)
@ -642,59 +630,62 @@ describe('Wallet', function() {
}) })
}) })
describe('signing', function() { describe('signing', function () {
afterEach(function() { afterEach(function () {
TransactionBuilder.prototype.sign.restore() TransactionBuilder.prototype.sign.restore()
}) })
it('signs the inputs with respective keys', function() { it('signs the inputs with respective keys', function () {
var fee = 30000 var fee = 30000
sinon.spy(TransactionBuilder.prototype, "sign") sinon.spy(TransactionBuilder.prototype, 'sign')
wallet.createTx(to, value, { fixedFee: fee }) wallet.createTx(to, value, {
fixedFee: fee
})
var priv1 = wallet.getPrivateKeyForAddress(address1) var priv1 = wallet.getPrivateKeyForAddress(address1)
var priv2 = wallet.getPrivateKeyForAddress(address2) var priv2 = wallet.getPrivateKeyForAddress(address2)
// FIXME: boo (required) side effects // FIXME: boo, toString invokes reqiuired affine coordinate side effects
priv1.pub.Q.affineX, priv2.pub.Q.affineX priv1.pub.Q.toString()
priv2.pub.Q.toString()
assert(TransactionBuilder.prototype.sign.calledWith(0, priv2)) assert(TransactionBuilder.prototype.sign.calledWith(0, priv2))
assert(TransactionBuilder.prototype.sign.calledWith(1, priv1)) assert(TransactionBuilder.prototype.sign.calledWith(1, priv1))
}) })
}) })
describe('when value is below dust threshold', function() { describe('when value is below dust threshold', function () {
it('throws an error', function() { it('throws an error', function () {
var value = 546 var value = 546
assert.throws(function() { assert.throws(function () {
wallet.createTx(to, value) wallet.createTx(to, value)
}, /546 must be above dust threshold \(546 Satoshis\)/) }, /546 must be above dust threshold \(546 Satoshis\)/)
}) })
}) })
describe('when there is not enough money', function() { describe('when there is not enough money', function () {
it('throws an error', function() { it('throws an error', function () {
var value = 1400001 var value = 1400001
assert.throws(function() { assert.throws(function () {
wallet.createTx(to, value) wallet.createTx(to, value)
}, /Not enough funds \(incl. fee\): 1410000 < 1410001/) }, /Not enough funds \(incl. fee\): 1410000 < 1410001/)
}) })
}) })
}) })
function assertEqual(obj1, obj2){ function assertEqual (obj1, obj2) {
assert.equal(obj1.toString(), obj2.toString()) assert.equal(obj1.toString(), obj2.toString())
} }
function assertNotEqual(obj1, obj2){ function assertNotEqual (obj1, obj2) {
assert.notEqual(obj1.toString(), obj2.toString()) assert.notEqual(obj1.toString(), obj2.toString())
} }
// quick and dirty: does not deal with functions on object // quick and dirty: does not deal with functions on object
function cloneObject(obj){ function cloneObject (obj) {
return JSON.parse(JSON.stringify(obj)) return JSON.parse(JSON.stringify(obj))
} }
}) })